1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Gui module
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qrhi_p_p.h"
38#include <qmath.h>
39#include <QLoggingCategory>
40
41#include "qrhinull_p_p.h"
42#ifndef QT_NO_OPENGL
43#include "qrhigles2_p_p.h"
44#endif
45#if QT_CONFIG(vulkan)
46#include "qrhivulkan_p_p.h"
47#endif
48#ifdef Q_OS_WIN
49#include "qrhid3d11_p_p.h"
50#endif
51#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
52#include "qrhimetal_p_p.h"
53#endif
54
55QT_BEGIN_NAMESPACE
56
57Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
58
59/*!
60 \class QRhi
61 \internal
62 \inmodule QtGui
63
64 \brief Accelerated 2D/3D graphics API abstraction.
65
66 The Qt Rendering Hardware Interface is an abstraction for hardware accelerated
67 graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL},
68 \l{https://www.khronos.org/opengles/}{OpenGL ES},
69 \l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D},
70 \l{https://developer.apple.com/metal/}{Metal}, and
71 \l{https://www.khronos.org/vulkan/}{Vulkan}.
72
73 Some of the main design goals are:
74
75 \list
76
77 \li Simple, minimal, understandable, extensible. Follow the proven path of the
78 Qt Quick scenegraph.
79
80 \li Aim to be a product - and in the bigger picture, part of a product (Qt) -
81 that is usable out of the box both by internal (such as, Qt Quick) and,
82 eventually, external users.
83
84 \li Not a complete 1:1 wrapper for any of the underlying APIs. The feature set
85 is tuned towards the needs of Qt's 2D and 3D offering (QPainter, Qt Quick, Qt
86 3D Studio). Iterate and evolve in a sustainable manner.
87
88 \li Intrinsically cross-platform, without reinventing: abstracting
89 cross-platform aspects of certain APIs (such as, OpenGL context creation and
90 windowing system interfaces, Vulkan instance and surface management) is not in
91 scope here. These are delegated to the existing QtGui facilities (QWindow,
92 QOpenGLContext, QVulkanInstance) and its backing QPA architecture.
93
94 \endlist
95
96 Each QRhi instance is backed by a backend for a specific graphics API. The
97 selection of the backend is a run time choice and is up to the application
98 or library that creates the QRhi instance. Some backends are available on
99 multiple platforms (OpenGL, Vulkan, Null), while APIs specific to a given
100 platform are only available when running on the platform in question (Metal
101 on macOS/iOS/tvOS, Direct3D on Windows).
102
103 The available backends currently are:
104
105 \list
106
107 \li OpenGL 2.1 or OpenGL ES 2.0 or newer. Some extensions are utilized when
108 present, for example to enable multisample framebuffers.
109
110 \li Direct3D 11.1
111
112 \li Metal
113
114 \li Vulkan 1.0, optionally with some extensions that are part of Vulkan 1.1
115
116 \li Null - A "dummy" backend that issues no graphics calls at all.
117
118 \endlist
119
120 In order to allow shader code to be written once in Qt applications and
121 libraries, all shaders are expected to be written in a single language
122 which is then compiled into SPIR-V. Versions for various shading language
123 are then generated from that, together with reflection information (inputs,
124 outputs, shader resources). This is then packed into easily and efficiently
125 serializable QShader instances. The compilers and tools to generate such
126 shaders are not part of QRhi, but the core classes for using such shaders,
127 QShader and QShaderDescription, are.
128
129 \section2 Design Fundamentals
130
131 A QRhi cannot be instantiated directly. Instead, use the create()
132 function. Delete the QRhi instance normally to release the graphics device.
133
134 \section3 Resources
135
136 Instances of classes deriving from QRhiResource, such as, QRhiBuffer,
137 QRhiTexture, etc., encapsulate zero, one, or more native graphics
138 resources. Instances of such classes are always created via the \c new
139 functions of the QRhi, such as, newBuffer(), newTexture(),
140 newTextureRenderTarget(), newSwapChain().
141
142 \badcode
143 vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
144 if (!vbuf->create()) { error }
145 ...
146 delete vbuf;
147 \endcode
148
149 \list
150
151 \li The returned value from functions like newBuffer() is always owned by
152 the caller.
153
154 \li Just creating a QRhiResource subclass never allocates or initializes any
155 native resources. That is only done when calling the \c create() function of a
156 subclass, for example, QRhiBuffer::create() or QRhiTexture::create().
157
158 \li The exception is
159 QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() and
160 QRhiSwapChain::newCompatibleRenderPassDescriptor(). There is no \c create()
161 operation for these and the returned object is immediately active.
162
163 \li The resource objects themselves are treated as immutable: once a
164 resource has create() called, changing any parameters via the setters, such as,
165 QRhiTexture::setPixelSize(), has no effect, unless the underlying native
166 resource is released and \c create() is called again. See more about resource
167 reuse in the sections below.
168
169 \li The underlying native resources are scheduled for releasing by the
170 QRhiResource destructor, or by calling QRhiResource::destroy(). Backends
171 often queue release requests and defer executing them to an unspecified
172 time, this is hidden from the applications. This way applications do not
173 have to worry about releasing native resources that may still be in use by
174 an in-flight frame.
175
176 \li Note that this does not mean that a QRhiResource can freely be
177 destroy()'ed or deleted within a frame (that is, in a
178 \l{QRhiCommandBuffer::beginFrame()}{beginFrame()} -
179 \l{QRhiCommandBuffer::endFrame()}{endFrame()} section). As a general rule,
180 all referenced QRhiResource objects must stay unchanged until the frame is
181 submitted by calling \l{QRhiCommandBuffer::endFrame()}{endFrame()}. To ease
182 this, QRhiResource::deleteLater() is provided as a convenience.
183
184 \endlist
185
186 \section3 Command buffers and deferred command execution
187
188 Regardless of the design and capabilities of the underlying graphics API,
189 all QRhi backends implement some level of command buffers. No
190 QRhiCommandBuffer function issues any native bind or draw command (such as,
191 \c glDrawElements) directly. Commands are always recorded in a queue,
192 either native or provided by the QRhi backend. The command buffer is
193 submitted, and so execution starts only upon QRhi::endFrame() or
194 QRhi::finish().
195
196 The deferred nature has consequences for some types of objects. For example,
197 writing to a dynamic buffer multiple times within a frame, in case such
198 buffers are backed by host-visible memory, will result in making the
199 results of all writes are visible to all draw calls in the command buffer
200 of the frame, regardless of when the dynamic buffer update was recorded
201 relative to a draw call.
202
203 Furthermore, instances of QRhiResource subclasses must be treated immutable
204 within a frame in which they are referenced in any way. Create
205 all resources upfront, before starting to record commands for the next
206 frame. Reusing a QRhiResource instance within a frame (by calling \c create()
207 then referencing it again in the same \c{beginFrame - endFrame} section)
208 should be avoided as it may lead to unexpected results, depending on the
209 backend.
210
211 As a general rule, all referenced QRhiResource objects must stay valid and
212 unmodified until the frame is submitted by calling
213 \l{QRhiCommandBuffer::endFrame()}{endFrame()}. On the other hand, calling
214 \l{QRhiResource::destroy()}{destroy()} or deleting the QRhiResource are
215 always safe once the frame is submitted, regardless of the status of the
216 underlying native resources (which may still be in use by the GPU - but
217 that is taken care of internally).
218
219 Unlike APIs like OpenGL, upload and copy type of commands cannot be mixed
220 with draw commands. The typical renderer will involve a sequence similar to
221 the following: \c{(re)create resources} - \c{begin frame} - \c{record
222 uploads and copies} - \c{start renderpass} - \c{record draw calls} - \c{end
223 renderpass} - \c{end frame}. Recording copy type of operations happens via
224 QRhiResourceUpdateBatch. Such operations are committed typically on
225 \l{QRhiCommandBuffer::beginPass()}{beginPass()}.
226
227 When working with legacy rendering engines designed for OpenGL, the
228 migration to QRhi often involves redesigning from having a single \c render
229 step (that performs copies and uploads, clears buffers, and issues draw
230 calls, all mixed together) to a clearly separated, two phase \c prepare -
231 \c render setup where the \c render step only starts a renderpass and
232 records draw calls, while all resource creation and queuing of updates,
233 uploads and copies happens beforehand, in the \c prepare step.
234
235 QRhi does not at the moment allow freely creating and submitting command
236 buffers. This may be lifted in the future to some extent, in particular if
237 compute support is introduced, but the model of well defined
238 \c{frame-start} and \c{frame-end} points, combined with a dedicated,
239 "frame" command buffer, where \c{frame-end} implies presenting, is going to
240 remain the primary way of operating since this is what fits Qt's various UI
241 technologies best.
242
243 \section3 Threading
244
245 A QRhi instance and the associated resources can be created and used on any
246 thread but all usage must be limited to that one single thread. When
247 rendering to multiple QWindows in an application, having a dedicated thread
248 and QRhi instance for each window is often advisable, as this can eliminate
249 issues with unexpected throttling caused by presenting to multiple windows.
250 Conceptually that is then the same as how Qt Quick scene graph's threaded
251 render loop operates when working directly with OpenGL: one thread for each
252 window, one QOpenGLContext for each thread. When moving onto QRhi,
253 QOpenGLContext is replaced by QRhi, making the migration straightforward.
254
255 When it comes to externally created native objects, such as OpenGL contexts
256 passed in via QRhiGles2NativeHandles, it is up to the application to ensure
257 they are not misused by other threads.
258
259 Resources are not shareable between QRhi instances. This is an intentional
260 choice since QRhi hides most queue, command buffer, and resource
261 synchronization related tasks, and provides no API for them. Safe and
262 efficient concurrent use of graphics resources from multiple threads is
263 tied to those concepts, however, and is thus a topic that is currently out
264 of scope, but may be introduced in the future.
265
266 \note The Metal backend requires that an autorelease pool is available on
267 the rendering thread, ideally wrapping each iteration of the render loop.
268 This needs no action from the users of QRhi when rendering on the main
269 (gui) thread, but becomes important when a separate, dedicated render
270 thread is used.
271
272 \section3 Resource synchronization
273
274 QRhi does not expose APIs for resource barriers or image layout
275 transitions. Such synchronization is done implicitly by the backends, where
276 applicable (for example, Vulkan), by tracking resource usage as necessary.
277 Buffer and image barriers are inserted before render or compute passes
278 transparently to the application.
279
280 \note Resources within a render or compute pass are expected to be bound to
281 a single usage during that pass. For example, a buffer can be used as
282 vertex, index, uniform, or storage buffer, but not a combination of them
283 within a single pass. However, it is perfectly fine to use a buffer as a
284 storage buffer in a compute pass, and then as a vertex buffer in a render
285 pass, for example, assuming the buffer declared both usages upon creation.
286
287 \note Textures have this rule relaxed in certain cases, because using two
288 subresources (typically two different mip levels) of the same texture for
289 different access (one for load, one for store) is supported even within the
290 same pass.
291
292 \section3 Resource reuse
293
294 From the user's point of view a QRhiResource is reusable immediately after
295 calling QRhiResource::destroy(). With the exception of swapchains, calling
296 \c create() on an already created object does an implicit \c destroy(). This
297 provides a handy shortcut to reuse a QRhiResource instance with different
298 parameters, with a new native graphics object underneath.
299
300 The importance of reusing the same object lies in the fact that some
301 objects reference other objects: for example, a QRhiShaderResourceBindings
302 can reference QRhiBuffer, QRhiTexture, and QRhiSampler instances. If in a
303 later frame one of these buffers need to be resized or a sampler parameter
304 needs changing, destroying and creating a whole new QRhiBuffer or
305 QRhiSampler would invalidate all references to the old instance. By just
306 changing the appropriate parameters via QRhiBuffer::setSize() or similar
307 and then calling QRhiBuffer::create(), everything works as expected and
308 there is no need to touch the QRhiShaderResourceBindings at all, even
309 though there is a good chance that under the hood the QRhiBuffer is now
310 backed by a whole new native buffer.
311
312 \badcode
313 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
314 ubuf->create();
315
316 srb = rhi->newShaderResourceBindings()
317 srb->setBindings({
318 QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf)
319 });
320 srb->create();
321
322 ...
323
324 // now in a later frame we need to grow the buffer to a larger size
325 ubuf->setSize(512);
326 ubuf->create(); // same as ubuf->destroy(); ubuf->create();
327
328 // that's it, srb needs no changes whatsoever
329 \endcode
330
331 \section3 Pooled objects
332
333 In addition to resources, there are pooled objects as well, such as,
334 QRhiResourceUpdateBatch. An instance is retrieved via a \c next function,
335 such as, nextResourceUpdateBatch(). The caller does not own the returned
336 instance in this case. The only valid way of operating here is calling
337 functions on the QRhiResourceUpdateBatch and then passing it to
338 QRhiCommandBuffer::beginPass() or QRhiCommandBuffer::endPass(). These
339 functions take care of returning the batch to the pool. Alternatively, a
340 batch can be "canceled" and returned to the pool without processing by
341 calling QRhiResourceUpdateBatch::destroy().
342
343 A typical pattern is thus:
344
345 \badcode
346 QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
347 ...
348 resUpdates->updateDynamicBuffer(ubuf, 0, 64, mvp.constData());
349 if (!image.isNull()) {
350 resUpdates->uploadTexture(texture, image);
351 image = QImage();
352 }
353 ...
354 QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
355 cb->beginPass(swapchain->currentFrameRenderTarget(), clearCol, clearDs, resUpdates);
356 \endcode
357
358 \section3 Swapchain specifics
359
360 QRhiSwapChain features some special semantics due to the peculiar nature of
361 swapchains.
362
363 \list
364
365 \li It has no \c create() but rather a QRhiSwapChain::createOrResize().
366 Repeatedly calling this function is \b not the same as calling
367 QRhiSwapChain::destroy() followed by QRhiSwapChain::createOrResize(). This
368 is because swapchains often have ways to handle the case where buffers need
369 to be resized in a manner that is more efficient than a brute force
370 destroying and recreating from scratch.
371
372 \li An active QRhiSwapChain must be released by calling
373 \l{QRhiSwapChain::destroy()}{destroy()}, or by destroying the object, before
374 the QWindow's underlying QPlatformWindow, and so the associated native
375 window object, is destroyed. It should not be postponed because releasing
376 the swapchain may become problematic (and with some APIs, like Vulkan, is
377 explicitly disallowed) when the native window is not around anymore, for
378 example because the QPlatformWindow got destroyed upon getting a
379 QWindow::close(). Therefore, releasing the swapchain must happen whenever
380 the targeted QWindow sends the
381 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed event. If the event does
382 not arrive before the destruction of the QWindow - this can happen when
383 using QCoreApplication::quit() -, then check QWindow::handle() after the
384 event loop exits and invoke the swapchain release when non-null (meaning
385 the underlying native window is still around).
386
387 \endlist
388
389 \section3 Ownership
390
391 The general rule is no ownership transfer. Creating a QRhi with an already
392 existing graphics device does not mean the QRhi takes ownership of the
393 device object. Similarly, ownership is not given away when a device or
394 texture object is "exported" via QRhi::nativeHandles() or
395 QRhiTexture::nativeHandles(). Most importantly, passing pointers in structs
396 and via setters does not transfer ownership.
397
398 \section2 Troubleshooting
399
400 Errors are printed to the output via qWarning(). Additional debug messages
401 can be enabled via the following logging categories. Messages from these
402 categories are not printed by default unless explicitly enabled via
403 QRhi::EnableProfiling or the facilities of QLoggingCategory (such as, the
404 \c QT_LOGGING_RULES environment variable).
405
406 \list
407 \li \c{qt.rhi.general}
408 \endlist
409
410 It is strongly advised to inspect the output with the logging categories
411 (\c{qt.rhi.*}) enabled whenever a QRhi-based application is not behaving as
412 expected.
413 */
414
415/*!
416 \enum QRhi::Implementation
417 Describes which graphics API-specific backend gets used by a QRhi instance.
418
419 \value Null
420 \value Vulkan
421 \value OpenGLES2
422 \value D3D11
423 \value Metal
424 */
425
426/*!
427 \enum QRhi::Flag
428 Describes what special features to enable.
429
430 \value EnableProfiling Enables gathering timing (CPU, GPU) and resource
431 (QRhiBuffer, QRhiTexture, etc.) information and additional metadata. See
432 QRhiProfiler. Avoid enabling in production builds as it may involve a
433 performance penalty. Also enables debug messages from the \c{qt.rhi.*}
434 logging categories.
435
436 \value EnableDebugMarkers Enables debug marker groups. Without this frame
437 debugging features like making debug groups and custom resource name
438 visible in external GPU debugging tools will not be available and functions
439 like QRhiCommandBuffer::debugMarkBegin() will become a no-op. Avoid
440 enabling in production builds as it may involve a performance penalty.
441
442 \value PreferSoftwareRenderer Indicates that backends should prefer
443 choosing an adapter or physical device that renders in software on the CPU.
444 For example, with Direct3D there is typically a "Basic Render Driver"
445 adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag
446 requests the backend to choose that adapter over any other, as long as no
447 specific adapter was forced by other backend-specific means. With Vulkan
448 this maps to preferring physical devices with
449 \c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not
450 possible to decide if an adapter/device is software-based, this flag is
451 ignored. It may also be ignored with graphics APIs that have no concept and
452 means of enumerating adapters/devices.
453 */
454
455/*!
456 \enum QRhi::FrameOpResult
457 Describes the result of operations that can have a soft failure.
458
459 \value FrameOpSuccess Success
460
461 \value FrameOpError Unspecified error
462
463 \value FrameOpSwapChainOutOfDate The swapchain is in an inconsistent state
464 internally. This can be recoverable by attempting to repeat the operation
465 (such as, beginFrame()) later.
466
467 \value FrameOpDeviceLost The graphics device was lost. This can be
468 recoverable by attempting to repeat the operation (such as, beginFrame())
469 after releasing and reinitializing all objects backed by native graphics
470 resources. See isDeviceLost().
471 */
472
473/*!
474 \enum QRhi::Feature
475 Flag values to indicate what features are supported by the backend currently in use.
476
477 \value MultisampleTexture Indicates that textures with a sample count larger
478 than 1 are supported.
479
480 \value MultisampleRenderBuffer Indicates that renderbuffers with a sample
481 count larger than 1 are supported.
482
483 \value DebugMarkers Indicates that debug marker groups (and so
484 QRhiCommandBuffer::debugMarkBegin()) are supported.
485
486 \value Timestamps Indicates that command buffer timestamps are supported.
487 Relevant for QRhiProfiler::gpuFrameTimes().
488
489 \value Instancing Indicates that instanced drawing is supported.
490
491 \value CustomInstanceStepRate Indicates that instance step rates other than
492 1 are supported.
493
494 \value PrimitiveRestart Indicates that restarting the assembly of
495 primitives when encountering an index value of 0xFFFF
496 (\l{QRhiCommandBuffer::IndexUInt16}{IndexUInt16}) or 0xFFFFFFFF
497 (\l{QRhiCommandBuffer::IndexUInt32}{IndexUInt32}) is enabled, for certain
498 primitive topologies at least. QRhi will try to enable this with all
499 backends, but in some cases it will not be supported. Dynamically
500 controlling primitive restart is not possible since with some APIs
501 primitive restart with a fixed index is always on. Applications must assume
502 that whenever this feature is reported as supported, the above mentioned
503 index values \c may be treated specially, depending on the topology. The
504 only two topologies where primitive restart is guaranteed to behave
505 identically across backends, as long as this feature is reported as
506 supported, are \l{QRhiGraphicsPipeline::LineStrip}{LineStrip} and
507 \l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}.
508
509 \value NonDynamicUniformBuffers Indicates that creating buffers with the
510 usage \l{QRhiBuffer::UniformBuffer}{UniformBuffer} and the types
511 \l{QRhiBuffer::Immutable}{Immutable} or \l{QRhiBuffer::Static}{Static} is
512 supported. When reported as unsupported, uniform (constant) buffers must be
513 created as \l{QRhiBuffer::Dynamic}{Dynamic}. (which is recommended
514 regardless)
515
516 \value NonFourAlignedEffectiveIndexBufferOffset Indicates that effective
517 index buffer offsets (\c{indexOffset + firstIndex * indexComponentSize})
518 that are not 4 byte aligned are supported. When not supported, attempting
519 to issue a \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} with a
520 non-aligned effective offset may lead to unspecified behavior.
521
522 \value NPOTTextureRepeat Indicates that the
523 \l{QRhiSampler::Repeat}{Repeat} wrap mode and mipmap filtering modes are
524 supported for textures with a non-power-of-two size. In practice this can
525 only be false with OpenGL ES 2.0 implementations without
526 \c{GL_OES_texture_npot}.
527
528 \value RedOrAlpha8IsRed Indicates that the
529 \l{QRhiTexture::RED_OR_ALPHA8}{RED_OR_ALPHA8} format maps to a one
530 component 8-bit \c red format. This is the case for all backends except
531 OpenGL, where \c{GL_ALPHA}, a one component 8-bit \c alpha format, is used
532 instead. This is relevant for shader code that samples from the texture.
533
534 \value ElementIndexUint Indicates that 32-bit unsigned integer elements are
535 supported in the index buffer. In practice this is true everywhere except
536 when running on plain OpenGL ES 2.0 implementations without the necessary
537 extension. When false, only 16-bit unsigned elements are supported in the
538 index buffer.
539
540 \value Compute Indicates that compute shaders, image load/store, and
541 storage buffers are supported.
542
543 \value WideLines Indicates that lines with a width other than 1 are
544 supported. When reported as not supported, the line width set on the
545 graphics pipeline state is ignored. This can always be false with some
546 backends (D3D11, Metal). With Vulkan, the value depends on the
547 implementation. With OpenGL, wide lines are not supported in core profile
548 contexts.
549
550 \value VertexShaderPointSize Indicates that the size of rasterized points
551 set via \c{gl_PointSize} in the vertex shader is taken into account. When
552 reported as not supported, drawing points with a size other than 1 is not
553 supported. Setting \c{gl_PointSize} in the shader is still valid then, but
554 is ignored. (for example, when generating HLSL, the assignment is silently
555 dropped from the generated code) Note that some APIs (Metal, Vulkan)
556 require the point size to be set in the shader explicitly whenever drawing
557 points, even when the size is 1, as they do not automatically default to 1.
558
559 \value BaseVertex Indicates that \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()}
560 supports the \c vertexOffset argument. When reported as not supported, the
561 vertexOffset value in an indexed draw is ignored.
562
563 \value BaseInstance Indicates that instanced draw commands support the \c
564 firstInstance argument. When reported as not supported, the firstInstance
565 value is ignored and the instance ID starts from 0.
566
567 \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology()
568 supports QRhiGraphicsPipeline::TriangleFan.
569
570 \value ReadBackNonUniformBuffer Indicates that
571 \l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is
572 supported for QRhiBuffer instances with a usage different than
573 UniformBuffer. While this is supported in the majority of cases, it will be
574 unsupported with OpenGL ES older than 3.0.
575
576 \value ReadBackNonBaseMipLevel Indicates that specifying a mip level other
577 than 0 is supported when reading back texture contents. When not supported,
578 specifying a non-zero level in QRhiReadbackDescription leads to returning
579 an all-zero image. In practice this feature will be unsupported with OpenGL
580 ES 2.0, while it will likely be supported everywhere else.
581
582 \value TexelFetch Indicates that texelFetch() is available in shaders. In
583 practice this will be reported as unsupported with OpenGL ES 2.0 and OpenGL
584 2.x contexts, because GLSL 100 es and versions before 130 do not support
585 this function.
586
587 \value RenderToNonBaseMipLevel Indicates that specifying a mip level other
588 than 0 is supported when creating a QRhiTextureRenderTarget with a
589 QRhiTexture as its color attachment. When not supported, create() will fail
590 whenever the target mip level is not zero. In practice this feature will be
591 unsupported with OpenGL ES 2.0, while it will likely be supported everywhere
592 else.
593
594 \value IntAttributes Indicates that specifying input attributes with
595 signed and unsigned integer types for a shader pipeline is supported. When
596 not supported, build() will succeed but just show a warning message and the
597 values of the target attributes will be broken. In practice this feature
598 will be unsupported with OpenGL ES 2.0 and OpenGL 2.x, while it will likely
599 be supported everywhere else.
600
601 \value ScreenSpaceDerivatives Indicates that functions such as dFdx(),
602 dFdy(), and fwidth() are supported in shaders.
603
604 \value ReadBackAnyTextureFormat Indicates that reading back texture
605 contents can be expected to work for any QRhiTexture::Format. When reported
606 as false, which will typically happen with OpenGL, only the formats
607 QRhiTexture::RGBA8 and QRhiTexture::BGRA8 are guaranteed to be supported
608 for readbacks. In addition, with OpenGL, but not OpenGL ES, reading back
609 the 1 byte per component formats QRhiTexture::R8 and
610 QRhiTexture::RED_OR_ALPHA8 are supported as well. Backends other than
611 OpenGL can be expected to return true for this feature.
612 */
613
614/*!
615 \enum QRhi::BeginFrameFlag
616 Flag values for QRhi::beginFrame()
617 */
618
619/*!
620 \enum QRhi::EndFrameFlag
621 Flag values for QRhi::endFrame()
622
623 \value SkipPresent Specifies that no present command is to be queued or no
624 swapBuffers call is to be made. This way no image is presented. Generating
625 multiple frames with all having this flag set is not recommended (except,
626 for example, for benchmarking purposes - but keep in mind that backends may
627 behave differently when it comes to waiting for command completion without
628 presenting so the results are not comparable between them)
629 */
630
631/*!
632 \enum QRhi::ResourceLimit
633 Describes the resource limit to query.
634
635 \value TextureSizeMin Minimum texture width and height. This is typically
636 1. The minimum texture size is handled gracefully, meaning attempting to
637 create a texture with an empty size will instead create a texture with the
638 minimum size.
639
640 \value TextureSizeMax Maximum texture width and height. This depends on the
641 graphics API and sometimes the platform or implementation as well.
642 Typically the value is in the range 4096 - 16384. Attempting to create
643 textures larger than this is expected to fail.
644
645 \value MaxColorAttachments The maximum number of color attachments for a
646 QRhiTextureRenderTarget, in case multiple render targets are supported. When
647 MRT is not supported, the value is 1. Otherwise this is typically 8, but
648 watch out for the fact that OpenGL only mandates 4 as the minimum, and that
649 is what some OpenGL ES implementations provide.
650
651 \value FramesInFlight The number of frames the backend may keep "in
652 flight": with backends like Vulkan or Metal, it is the responsibility of
653 QRhi to block whenever starting a new frame and finding the CPU is already
654 \c{N - 1} frames ahead of the GPU (because the command buffer submitted in
655 frame no. \c{current} - \c{N} has not yet completed). The value N is what
656 is returned from here, and is typically 2. This can be relevant to
657 applications that integrate rendering done directly with the graphics API,
658 as such rendering code may want to perform double (if the value is 2)
659 buffering for resources, such as, buffers, similarly to the QRhi backends
660 themselves. The current frame slot index (a value running 0, 1, .., N-1,
661 then wrapping around) is retrievable from QRhi::currentFrameSlot(). The
662 value is 1 for backends where the graphics API offers no such low level
663 control over the command submission process. Note that pipelining may still
664 happen even when this value is 1 (some backends, such as D3D11, are
665 designed to attempt to enable this, for instance, by using an update
666 strategy for uniform buffers that does not stall the pipeline), but that is
667 then not controlled by QRhi and so not reflected here in the API.
668
669 \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted}
670 frames (including the one that contains the readback) after which an
671 asynchronous texture or buffer readback is guaranteed to complete upon
672 \l{QRhi::beginFrame()}{starting a new frame}.
673
674 \value MaxThreadGroupsPerDimension The maximum number of compute
675 work/thread groups that can be dispatched. Effectively the maximum value
676 for the arguments of QRhiCommandBuffer::dispatch(). Typically 65535.
677
678 \value MaxThreadsPerThreadGroup The maximum number of invocations in a
679 single local work group, or in other terminology, the maximum number of
680 threads in a thread group. Effectively the maximum value for the product of
681 \c local_size_x, \c local_size_y, and \c local_size_z in the compute
682 shader. Typical values are 128, 256, 512, 1024, or 1536. Watch out that
683 both OpenGL ES and Vulkan specify only 128 as the minimum required limit
684 for implementations. While uncommon for Vulkan, some OpenGL ES 3.1
685 implementations for mobile/embedded devices only support the spec-mandated
686 minimum value.
687
688 \value MaxThreadGroupX The maximum size of a work/thread group in the X
689 dimension. Effectively the maximum value of \c local_size_x in the compute
690 shader. Typically 256 or 1024.
691
692 \value MaxThreadGroupY The maximum size of a work/thread group in the Y
693 dimension. Effectively the maximum value of \c local_size_y in the compute
694 shader. Typically 256 or 1024.
695
696 \value MaxThreadGroupZ The maximum size of a work/thread group in the Z
697 dimension. Effectively the maximum value of \c local_size_z in the compute
698 shader. Typically 64 or 256.
699 */
700
701/*!
702 \class QRhiInitParams
703 \internal
704 \inmodule QtGui
705 \brief Base class for backend-specific initialization parameters.
706
707 Contains fields that are relevant to all backends.
708 */
709
710/*!
711 \class QRhiDepthStencilClearValue
712 \internal
713 \inmodule QtGui
714 \brief Specifies clear values for a depth or stencil buffer.
715 */
716
717/*!
718 \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue()
719
720 Constructs a depth/stencil clear value with depth clear value 1.0f and
721 stencil clear value 0.
722 */
723
724/*!
725 Constructs a depth/stencil clear value with depth clear value \a d and
726 stencil clear value \a s.
727 */
728QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s)
729 : m_d(d),
730 m_s(s)
731{
732}
733
734/*!
735 \return \c true if the values in the two QRhiDepthStencilClearValue objects
736 \a a and \a b are equal.
737
738 \relates QRhiDepthStencilClearValue
739 */
740bool operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
741{
742 return a.depthClearValue() == b.depthClearValue()
743 && a.stencilClearValue() == b.stencilClearValue();
744}
745
746/*!
747 \return \c false if the values in the two QRhiDepthStencilClearValue
748 objects \a a and \a b are equal; otherwise returns \c true.
749
750 \relates QRhiDepthStencilClearValue
751*/
752bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
753{
754 return !(a == b);
755}
756
757/*!
758 \return the hash value for \a v, using \a seed to seed the calculation.
759
760 \relates QRhiDepthStencilClearValue
761 */
762size_t qHash(const QRhiDepthStencilClearValue &v, size_t seed) noexcept
763{
764 return seed * (uint(qFloor(qreal(v.depthClearValue()) * 100)) + v.stencilClearValue());
765}
766
767#ifndef QT_NO_DEBUG_STREAM
768QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
769{
770 QDebugStateSaver saver(dbg);
771 dbg.nospace() << "QRhiDepthStencilClearValue(depth-clear=" << v.depthClearValue()
772 << " stencil-clear=" << v.stencilClearValue()
773 << ')';
774 return dbg;
775}
776#endif
777
778/*!
779 \class QRhiViewport
780 \internal
781 \inmodule QtGui
782 \brief Specifies a viewport rectangle.
783
784 Used with QRhiCommandBuffer::setViewport().
785
786 QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
787 bottom-left. Negative width or height are not allowed.
788
789 Typical usage is like the following:
790
791 \badcode
792 const QSize outputSizeInPixels = swapchain->currentPixelSize();
793 const QRhiViewport viewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height());
794 cb->beginPass(swapchain->currentFrameRenderTarget(), { 0, 0, 0, 1 }, { 1, 0 });
795 cb->setGraphicsPipeline(ps);
796 cb->setViewport(viewport);
797 ...
798 \endcode
799
800 \sa QRhiCommandBuffer::setViewport(), QRhi::clipSpaceCorrMatrix(), QRhiScissor
801 */
802
803/*!
804 \fn QRhiViewport::QRhiViewport()
805
806 Constructs a viewport description with an empty rectangle and a depth range
807 of 0.0f - 1.0f.
808
809 \sa QRhi::clipSpaceCorrMatrix()
810 */
811
812/*!
813 Constructs a viewport description with the rectangle specified by \a x, \a
814 y, \a w, \a h and the depth range \a minDepth and \a maxDepth.
815
816 \note \a x and \a y are assumed to be the bottom-left position. \a w and \a
817 h should not be negative, the viewport will be ignored by
818 QRhiCommandBuffer::setViewport() otherwise.
819
820 \sa QRhi::clipSpaceCorrMatrix()
821 */
822QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, float maxDepth)
823 : m_rect { { x, y, w, h } },
824 m_minDepth(minDepth),
825 m_maxDepth(maxDepth)
826{
827}
828
829/*!
830 \return \c true if the values in the two QRhiViewport objects
831 \a a and \a b are equal.
832
833 \relates QRhiViewport
834 */
835bool operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept
836{
837 return a.viewport() == b.viewport()
838 && a.minDepth() == b.minDepth()
839 && a.maxDepth() == b.maxDepth();
840}
841
842/*!
843 \return \c false if the values in the two QRhiViewport
844 objects \a a and \a b are equal; otherwise returns \c true.
845
846 \relates QRhiViewport
847*/
848bool operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept
849{
850 return !(a == b);
851}
852
853/*!
854 \return the hash value for \a v, using \a seed to seed the calculation.
855
856 \relates QRhiViewport
857 */
858size_t qHash(const QRhiViewport &v, size_t seed) noexcept
859{
860 const std::array<float, 4> r = v.viewport();
861 return seed + uint(r[0]) + uint(r[1]) + uint(r[2]) + uint(r[3])
862 + uint(qFloor(qreal(v.minDepth()) * 100)) + uint(qFloor(qreal(v.maxDepth()) * 100));
863}
864
865#ifndef QT_NO_DEBUG_STREAM
866QDebug operator<<(QDebug dbg, const QRhiViewport &v)
867{
868 QDebugStateSaver saver(dbg);
869 const std::array<float, 4> r = v.viewport();
870 dbg.nospace() << "QRhiViewport(bottom-left-x=" << r[0]
871 << " bottom-left-y=" << r[1]
872 << " width=" << r[2]
873 << " height=" << r[3]
874 << " minDepth=" << v.minDepth()
875 << " maxDepth=" << v.maxDepth()
876 << ')';
877 return dbg;
878}
879#endif
880
881/*!
882 \class QRhiScissor
883 \internal
884 \inmodule QtGui
885 \brief Specifies a scissor rectangle.
886
887 Used with QRhiCommandBuffer::setScissor(). Setting a scissor rectangle is
888 only possible with a QRhiGraphicsPipeline that has
889 QRhiGraphicsPipeline::UsesScissor set.
890
891 QRhi assumes OpenGL-style scissor coordinates, meaning x and y are
892 bottom-left. Negative width or height are not allowed. However, apart from
893 that, the flexible OpenGL semantics apply: negative x and y, partially out
894 of bounds rectangles, etc. will be handled gracefully, clamping as
895 appropriate. Therefore, any rendering logic targeting OpenGL can feed
896 scissor rectangles into QRhiScissor as-is, without any adaptation.
897
898 \sa QRhiCommandBuffer::setScissor(), QRhiViewport
899 */
900
901/*!
902 \fn QRhiScissor::QRhiScissor()
903
904 Constructs an empty scissor.
905 */
906
907/*!
908 Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and
909 \a h.
910
911 \note \a x and \a y are assumed to be the bottom-left position. Negative \a w
912 or \a h are not allowed, such scissor rectangles will be ignored by
913 QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply:
914 negative x and y, partially out of bounds rectangles, etc. will be handled
915 gracefully, clamping as appropriate.
916 */
917QRhiScissor::QRhiScissor(int x, int y, int w, int h)
918 : m_rect { { x, y, w, h } }
919{
920}
921
922/*!
923 \return \c true if the values in the two QRhiScissor objects
924 \a a and \a b are equal.
925
926 \relates QRhiScissor
927 */
928bool operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept
929{
930 return a.scissor() == b.scissor();
931}
932
933/*!
934 \return \c false if the values in the two QRhiScissor
935 objects \a a and \a b are equal; otherwise returns \c true.
936
937 \relates QRhiScissor
938*/
939bool operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept
940{
941 return !(a == b);
942}
943
944/*!
945 \return the hash value for \a v, using \a seed to seed the calculation.
946
947 \relates QRhiScissor
948 */
949size_t qHash(const QRhiScissor &v, size_t seed) noexcept
950{
951 const std::array<int, 4> r = v.scissor();
952 return seed + uint(r[0]) + uint(r[1]) + uint(r[2]) + uint(r[3]);
953}
954
955#ifndef QT_NO_DEBUG_STREAM
956QDebug operator<<(QDebug dbg, const QRhiScissor &s)
957{
958 QDebugStateSaver saver(dbg);
959 const std::array<int, 4> r = s.scissor();
960 dbg.nospace() << "QRhiScissor(bottom-left-x=" << r[0]
961 << " bottom-left-y=" << r[1]
962 << " width=" << r[2]
963 << " height=" << r[3]
964 << ')';
965 return dbg;
966}
967#endif
968
969/*!
970 \class QRhiVertexInputBinding
971 \internal
972 \inmodule QtGui
973 \brief Describes a vertex input binding.
974
975 Specifies the stride (in bytes, must be a multiple of 4), the
976 classification and optionally the instance step rate.
977
978 As an example, assume a vertex shader with the following inputs:
979
980 \badcode
981 layout(location = 0) in vec4 position;
982 layout(location = 1) in vec2 texcoord;
983 \endcode
984
985 Now let's assume also that 3 component vertex positions \c{(x, y, z)} and 2
986 component texture coordinates \c{(u, v)} are provided in a non-interleaved
987 format in a buffer (or separate buffers even). Definining two bindings
988 could then be done like this:
989
990 \badcode
991 QRhiVertexInputLayout inputLayout;
992 inputLayout.setBindings({
993 { 3 * sizeof(float) },
994 { 2 * sizeof(float) }
995 });
996 \endcode
997
998 Only the stride is interesting here since instancing is not used. The
999 binding number is given by the index of the QRhiVertexInputBinding
1000 element in the bindings vector of the QRhiVertexInputLayout.
1001
1002 Once a graphics pipeline with this vertex input layout is bound, the vertex
1003 inputs could be set up like the following for drawing a cube with 36
1004 vertices, assuming we have a single buffer with first the positions and
1005 then the texture coordinates:
1006
1007 \badcode
1008 const QRhiCommandBuffer::VertexInput vbufBindings[] = {
1009 { cubeBuf, 0 },
1010 { cubeBuf, 36 * 3 * sizeof(float) }
1011 };
1012 cb->setVertexInput(0, 2, vbufBindings);
1013 \endcode
1014
1015 Note how the index defined by \c {startBinding + i}, where \c i is the
1016 index in the second argument of
1017 \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}, matches the
1018 index of the corresponding entry in the \c bindings vector of the
1019 QRhiVertexInputLayout.
1020
1021 \note the stride must always be a multiple of 4.
1022
1023 \sa QRhiCommandBuffer::setVertexInput()
1024 */
1025
1026/*!
1027 \enum QRhiVertexInputBinding::Classification
1028 Describes the input data classification.
1029
1030 \value PerVertex Data is per-vertex
1031 \value PerInstance Data is per-instance
1032 */
1033
1034/*!
1035 \fn QRhiVertexInputBinding::QRhiVertexInputBinding()
1036
1037 Constructs a default vertex input binding description.
1038 */
1039
1040/*!
1041 Constructs a vertex input binding description with the specified \a stride,
1042 classification \a cls, and instance step rate \a stepRate.
1043
1044 \note \a stepRate other than 1 is only supported when
1045 QRhi::CustomInstanceStepRate is reported to be supported.
1046 */
1047QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cls, int stepRate)
1048 : m_stride(stride),
1049 m_classification(cls),
1050 m_instanceStepRate(stepRate)
1051{
1052}
1053
1054/*!
1055 \return \c true if the values in the two QRhiVertexInputBinding objects
1056 \a a and \a b are equal.
1057
1058 \relates QRhiVertexInputBinding
1059 */
1060bool operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
1061{
1062 return a.stride() == b.stride()
1063 && a.classification() == b.classification()
1064 && a.instanceStepRate() == b.instanceStepRate();
1065}
1066
1067/*!
1068 \return \c false if the values in the two QRhiVertexInputBinding
1069 objects \a a and \a b are equal; otherwise returns \c true.
1070
1071 \relates QRhiVertexInputBinding
1072*/
1073bool operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
1074{
1075 return !(a == b);
1076}
1077
1078/*!
1079 \return the hash value for \a v, using \a seed to seed the calculation.
1080
1081 \relates QRhiVertexInputBinding
1082 */
1083size_t qHash(const QRhiVertexInputBinding &v, size_t seed) noexcept
1084{
1085 return seed + v.stride() + v.classification();
1086}
1087
1088#ifndef QT_NO_DEBUG_STREAM
1089QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
1090{
1091 QDebugStateSaver saver(dbg);
1092 dbg.nospace() << "QRhiVertexInputBinding(stride=" << b.stride()
1093 << " cls=" << b.classification()
1094 << " step-rate=" << b.instanceStepRate()
1095 << ')';
1096 return dbg;
1097}
1098#endif
1099
1100/*!
1101 \class QRhiVertexInputAttribute
1102 \internal
1103 \inmodule QtGui
1104 \brief Describes a single vertex input element.
1105
1106 The members specify the binding number, location, format, and offset for a
1107 single vertex input element.
1108
1109 \note For HLSL it is assumed that the vertex shader uses
1110 \c{TEXCOORD<location>} as the semantic for each input. Hence no separate
1111 semantic name and index.
1112
1113 As an example, assume a vertex shader with the following inputs:
1114
1115 \badcode
1116 layout(location = 0) in vec4 position;
1117 layout(location = 1) in vec2 texcoord;
1118 \endcode
1119
1120 Now let's assume that we have 3 component vertex positions \c{(x, y, z)}
1121 and 2 component texture coordinates \c{(u, v)} are provided in a
1122 non-interleaved format in a buffer (or separate buffers even). Once two
1123 bindings are defined, the attributes could be specified as:
1124
1125 \badcode
1126 QRhiVertexInputLayout inputLayout;
1127 inputLayout.setBindings({
1128 { 3 * sizeof(float) },
1129 { 2 * sizeof(float) }
1130 });
1131 inputLayout.setAttributes({
1132 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
1133 { 1, 1, QRhiVertexInputAttribute::Float2, 0 }
1134 });
1135 \endcode
1136
1137 Once a graphics pipeline with this vertex input layout is bound, the vertex
1138 inputs could be set up like the following for drawing a cube with 36
1139 vertices, assuming we have a single buffer with first the positions and
1140 then the texture coordinates:
1141
1142 \badcode
1143 const QRhiCommandBuffer::VertexInput vbufBindings[] = {
1144 { cubeBuf, 0 },
1145 { cubeBuf, 36 * 3 * sizeof(float) }
1146 };
1147 cb->setVertexInput(0, 2, vbufBindings);
1148 \endcode
1149
1150 When working with interleaved data, there will typically be just one
1151 binding, with multiple attributes referring to that same buffer binding
1152 point:
1153
1154 \badcode
1155 QRhiVertexInputLayout inputLayout;
1156 inputLayout.setBindings({
1157 { 5 * sizeof(float) }
1158 });
1159 inputLayout.setAttributes({
1160 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
1161 { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) }
1162 });
1163 \endcode
1164
1165 and then:
1166
1167 \badcode
1168 const QRhiCommandBuffer::VertexInput vbufBinding(interleavedCubeBuf, 0);
1169 cb->setVertexInput(0, 1, &vbufBinding);
1170 \endcode
1171
1172 \sa QRhiCommandBuffer::setVertexInput()
1173 */
1174
1175/*!
1176 \enum QRhiVertexInputAttribute::Format
1177 Specifies the type of the element data.
1178
1179 \value Float4 Four component float vector
1180 \value Float3 Three component float vector
1181 \value Float2 Two component float vector
1182 \value Float Float
1183 \value UNormByte4 Four component normalized unsigned byte vector
1184 \value UNormByte2 Two component normalized unsigned byte vector
1185 \value UNormByte Normalized unsigned byte
1186 \value UInt4 Four component unsigned integer vector
1187 \value UInt3 Three component unsigned integer vector
1188 \value UInt2 Two component unsigned integer vector
1189 \value UInt Unsigned integer
1190 \value SInt4 Four component signed integer vector
1191 \value SInt3 Three component signed integer vector
1192 \value SInt2 Two component signed integer vector
1193 \value SInt Signed integer
1194 */
1195
1196/*!
1197 \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute()
1198
1199 Constructs a default vertex input attribute description.
1200 */
1201
1202/*!
1203 Constructs a vertex input attribute description with the specified \a
1204 binding number, \a location, \a format, and \a offset.
1205
1206 \a matrixSlice should be -1 except when this attribute corresponds to a row
1207 or column of a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming
1208 4 consecutive vertex input locations), in which case it is the index of the
1209 row or column. \c{location - matrixSlice} must always be equal to the \c
1210 location for the first row or column of the unrolled matrix.
1211 */
1212QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice)
1213 : m_binding(binding),
1214 m_location(location),
1215 m_format(format),
1216 m_offset(offset),
1217 m_matrixSlice(matrixSlice)
1218{
1219}
1220
1221/*!
1222 \return \c true if the values in the two QRhiVertexInputAttribute objects
1223 \a a and \a b are equal.
1224
1225 \relates QRhiVertexInputAttribute
1226 */
1227bool operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
1228{
1229 return a.binding() == b.binding()
1230 && a.location() == b.location()
1231 && a.format() == b.format()
1232 && a.offset() == b.offset();
1233}
1234
1235/*!
1236 \return \c false if the values in the two QRhiVertexInputAttribute
1237 objects \a a and \a b are equal; otherwise returns \c true.
1238
1239 \relates QRhiVertexInputAttribute
1240*/
1241bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
1242{
1243 return !(a == b);
1244}
1245
1246/*!
1247 \return the hash value for \a v, using \a seed to seed the calculation.
1248
1249 \relates QRhiVertexInputAttribute
1250 */
1251size_t qHash(const QRhiVertexInputAttribute &v, size_t seed) noexcept
1252{
1253 return seed + uint(v.binding()) + uint(v.location()) + uint(v.format()) + v.offset();
1254}
1255
1256#ifndef QT_NO_DEBUG_STREAM
1257QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a)
1258{
1259 QDebugStateSaver saver(dbg);
1260 dbg.nospace() << "QRhiVertexInputAttribute(binding=" << a.binding()
1261 << " location=" << a.location()
1262 << " format=" << a.format()
1263 << " offset=" << a.offset()
1264 << ')';
1265 return dbg;
1266}
1267#endif
1268
1269/*!
1270 \class QRhiVertexInputLayout
1271 \internal
1272 \inmodule QtGui
1273 \brief Describes the layout of vertex inputs consumed by a vertex shader.
1274
1275 The vertex input layout is defined by the collections of
1276 QRhiVertexInputBinding and QRhiVertexInputAttribute.
1277 */
1278
1279/*!
1280 \fn QRhiVertexInputLayout::QRhiVertexInputLayout()
1281
1282 Constructs an empty vertex input layout description.
1283 */
1284
1285/*!
1286 \return \c true if the values in the two QRhiVertexInputLayout objects
1287 \a a and \a b are equal.
1288
1289 \relates QRhiVertexInputLayout
1290 */
1291bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
1292{
1293 return a.m_bindings == b.m_bindings && a.m_attributes == b.m_attributes;
1294}
1295
1296/*!
1297 \return \c false if the values in the two QRhiVertexInputLayout
1298 objects \a a and \a b are equal; otherwise returns \c true.
1299
1300 \relates QRhiVertexInputLayout
1301*/
1302bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
1303{
1304 return !(a == b);
1305}
1306
1307/*!
1308 \return the hash value for \a v, using \a seed to seed the calculation.
1309
1310 \relates QRhiVertexInputLayout
1311 */
1312size_t qHash(const QRhiVertexInputLayout &v, size_t seed) noexcept
1313{
1314 return qHash(v.m_bindings, seed) + qHash(v.m_attributes, seed);
1315}
1316
1317#ifndef QT_NO_DEBUG_STREAM
1318template<typename T, qsizetype N>
1319QDebug operator<<(QDebug dbg, const QVarLengthArray<T, N> &vla)
1320{
1321 return QtPrivate::printSequentialContainer(dbg, "VLA", vla);
1322}
1323
1324QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
1325{
1326 QDebugStateSaver saver(dbg);
1327 dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.m_bindings
1328 << " attributes=" << v.m_attributes
1329 << ')';
1330 return dbg;
1331}
1332#endif
1333
1334/*!
1335 \class QRhiShaderStage
1336 \internal
1337 \inmodule QtGui
1338 \brief Specifies the type and the shader code for a shader stage in the pipeline.
1339 */
1340
1341/*!
1342 \enum QRhiShaderStage::Type
1343 Specifies the type of the shader stage.
1344
1345 \value Vertex Vertex stage
1346 \value Fragment Fragment (pixel) stage
1347 \value Compute Compute stage (this may not always be supported at run time)
1348 */
1349
1350/*!
1351 \fn QRhiShaderStage::QRhiShaderStage()
1352
1353 Constructs a shader stage description for the vertex stage with an empty
1354 QShader.
1355 */
1356
1357/*!
1358 Constructs a shader stage description with the \a type of the stage and the
1359 \a shader.
1360
1361 The shader variant \a v defaults to QShader::StandardShader. A
1362 QShader contains multiple source and binary versions of a shader.
1363 In addition, it can also contain variants of the shader with slightly
1364 modified code. \a v can then be used to select the desired variant.
1365 */
1366QRhiShaderStage::QRhiShaderStage(Type type, const QShader &shader, QShader::Variant v)
1367 : m_type(type),
1368 m_shader(shader),
1369 m_shaderVariant(v)
1370{
1371}
1372
1373/*!
1374 \return \c true if the values in the two QRhiShaderStage objects
1375 \a a and \a b are equal.
1376
1377 \relates QRhiShaderStage
1378 */
1379bool operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
1380{
1381 return a.type() == b.type()
1382 && a.shader() == b.shader()
1383 && a.shaderVariant() == b.shaderVariant();
1384}
1385
1386/*!
1387 \return \c false if the values in the two QRhiShaderStage
1388 objects \a a and \a b are equal; otherwise returns \c true.
1389
1390 \relates QRhiShaderStage
1391*/
1392bool operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
1393{
1394 return !(a == b);
1395}
1396
1397/*!
1398 \return the hash value for \a v, using \a seed to seed the calculation.
1399
1400 \relates QRhiShaderStage
1401 */
1402size_t qHash(const QRhiShaderStage &v, size_t seed) noexcept
1403{
1404 return v.type() + qHash(v.shader(), seed) + v.shaderVariant();
1405}
1406
1407#ifndef QT_NO_DEBUG_STREAM
1408QDebug operator<<(QDebug dbg, const QRhiShaderStage &s)
1409{
1410 QDebugStateSaver saver(dbg);
1411 dbg.nospace() << "QRhiShaderStage(type=" << s.type()
1412 << " shader=" << s.shader()
1413 << " variant=" << s.shaderVariant()
1414 << ')';
1415 return dbg;
1416}
1417#endif
1418
1419/*!
1420 \class QRhiColorAttachment
1421 \internal
1422 \inmodule QtGui
1423 \brief Describes the a single color attachment of a render target.
1424
1425 A color attachment is either a QRhiTexture or a QRhiRenderBuffer. The
1426 former, when texture() is set, is used in most cases.
1427
1428 \note texture() and renderBuffer() cannot be both set (be non-null at the
1429 same time).
1430
1431 Setting renderBuffer instead is recommended only when multisampling is
1432 needed. Relying on QRhi::MultisampleRenderBuffer is a better choice than
1433 QRhi::MultisampleTexture in practice since the former is available in more
1434 run time configurations (e.g. when running on OpenGL ES 3.0 which has no
1435 support for multisample textures, but does support multisample
1436 renderbuffers).
1437
1438 When targeting a non-multisample texture, the layer() and level()
1439 indicate the targeted layer (face index \c{0-5} for cubemaps) and mip
1440 level.
1441
1442 When texture() or renderBuffer() is multisample, resolveTexture() can be
1443 set optionally. When set, samples are resolved automatically into that
1444 (non-multisample) texture at the end of the render pass. When rendering
1445 into a multisample renderbuffers, this is the only way to get resolved,
1446 non-multisample content out of them. Multisample textures allow sampling in
1447 shaders so for them this is just one option.
1448
1449 \note when resolving is enabled, the multisample data may not be written
1450 out at all. This means that the multisample texture() must not be used
1451 afterwards with shaders for sampling when resolveTexture() is set.
1452 */
1453
1454/*!
1455 \fn QRhiColorAttachment::QRhiColorAttachment()
1456
1457 Constructs an empty color attachment description.
1458 */
1459
1460/*!
1461 Constructs a color attachment description that specifies \a texture as the
1462 associated color buffer.
1463 */
1464QRhiColorAttachment::QRhiColorAttachment(QRhiTexture *texture)
1465 : m_texture(texture)
1466{
1467}
1468
1469/*!
1470 Constructs a color attachment description that specifies \a renderBuffer as
1471 the associated color buffer.
1472 */
1473QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer)
1474 : m_renderBuffer(renderBuffer)
1475{
1476}
1477
1478/*!
1479 \class QRhiTextureRenderTargetDescription
1480 \internal
1481 \inmodule QtGui
1482 \brief Describes the color and depth or depth/stencil attachments of a render target.
1483
1484 A texture render target has zero or more textures as color attachments,
1485 zero or one renderbuffer as combined depth/stencil buffer or zero or one
1486 texture as depth buffer.
1487
1488 \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
1489 non-null at the same time).
1490 */
1491
1492/*!
1493 \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription()
1494
1495 Constructs an empty texture render target description.
1496 */
1497
1498/*!
1499 Constructs a texture render target description with one attachment
1500 described by \a colorAttachment.
1501 */
1502QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment)
1503{
1504 m_colorAttachments.append(colorAttachment);
1505}
1506
1507/*!
1508 Constructs a texture render target description with two attachments, a
1509 color attachment described by \a colorAttachment, and a depth/stencil
1510 attachment with \a depthStencilBuffer.
1511 */
1512QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment,
1513 QRhiRenderBuffer *depthStencilBuffer)
1514 : m_depthStencilBuffer(depthStencilBuffer)
1515{
1516 m_colorAttachments.append(colorAttachment);
1517}
1518
1519/*!
1520 Constructs a texture render target description with two attachments, a
1521 color attachment described by \a colorAttachment, and a depth attachment
1522 with \a depthTexture.
1523
1524 \note \a depthTexture must have a suitable format, such as QRhiTexture::D16
1525 or QRhiTexture::D32F.
1526 */
1527QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment,
1528 QRhiTexture *depthTexture)
1529 : m_depthTexture(depthTexture)
1530{
1531 m_colorAttachments.append(colorAttachment);
1532}
1533
1534/*!
1535 \class QRhiTextureSubresourceUploadDescription
1536 \internal
1537 \inmodule QtGui
1538 \brief Describes the source for one mip level in a layer in a texture upload operation.
1539
1540 The source content is specified either as a QImage or as a raw blob. The
1541 former is only allowed for uncompressed textures with a format that can be
1542 mapped to QImage, while the latter is supported for all formats, including
1543 floating point and compressed.
1544
1545 \note image() and data() cannot be both set at the same time.
1546
1547 destinationTopLeft() specifies the top-left corner of the target
1548 rectangle. Defaults to (0, 0).
1549
1550 An empty sourceSize() (the default) indicates that size is assumed to be
1551 the size of the subresource. With QImage-based uploads this implies that
1552 the size of the source image() must match the subresource. When providing
1553 raw data instead, sufficient number of bytes must be provided in data().
1554
1555 sourceTopLeft() is supported only for QImage-based uploads, and specifies
1556 the top-left corner of the source rectangle.
1557
1558 \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
1559 internally, depending on the format and the backend.
1560
1561 When providing raw data, the stride (row pitch, row length in bytes) of the
1562 provided data must be equal to \c{width * pixelSize} where \c pixelSize is
1563 the number of bytes used for one pixel, and there must be no additional
1564 padding between rows. There is no row start alignment requirement.
1565
1566 \note The format of the source data must be compatible with the texture
1567 format. With many graphics APIs the data is copied as-is into a staging
1568 buffer, there is no intermediate format conversion provided by QRhi. This
1569 applies to floating point formats as well, with, for example, RGBA16F
1570 requiring half floats in the source data.
1571 */
1572
1573/*!
1574 \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription()
1575
1576 Constructs an empty subresource description.
1577
1578 \note an empty QRhiTextureSubresourceUploadDescription is not useful on its
1579 own and should not be submitted to a QRhiTextureUploadEntry. At minimum
1580 image or data must be set first.
1581 */
1582
1583/*!
1584 Constructs a mip level description with a \a image.
1585
1586 The \l{QImage::size()}{size} of \a image must match the size of the mip
1587 level. For level 0 that is the \l{QRhiTexture::pixelSize()}{texture size}.
1588
1589 The bit depth of \a image must be compatible with the
1590 \l{QRhiTexture::Format}{texture format}.
1591
1592 To describe a partial upload, call setSourceSize(), setSourceTopLeft(), or
1593 setDestinationTopLeft() afterwards.
1594 */
1595QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QImage &image)
1596 : m_image(image)
1597{
1598}
1599
1600/*!
1601 Constructs a mip level description with the image data is specified by \a
1602 data and \a size. This is suitable for floating point and compressed
1603 formats as well.
1604
1605 \a data can safely be destroyed or changed once this function returns.
1606 */
1607QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const void *data, int size)
1608 : m_data(reinterpret_cast<const char *>(data), size)
1609{
1610}
1611
1612/*!
1613 \class QRhiTextureUploadEntry
1614 \internal
1615 \inmodule QtGui
1616 \brief Describes one layer (face for cubemaps) in a texture upload operation.
1617 */
1618
1619/*!
1620 \fn QRhiTextureUploadEntry::QRhiTextureUploadEntry()
1621
1622 Constructs an empty QRhiTextureUploadEntry targeting layer 0 and level 0.
1623
1624 \note an empty QRhiTextureUploadEntry should not be submitted without
1625 setting a QRhiTextureSubresourceUploadDescription via setDescription()
1626 first.
1627 */
1628
1629/*!
1630 Constructs a QRhiTextureUploadEntry targeting the given \a layer and mip
1631 \a level, with the subresource contents described by \a desc.
1632 */
1633QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
1634 const QRhiTextureSubresourceUploadDescription &desc)
1635 : m_layer(layer),
1636 m_level(level),
1637 m_desc(desc)
1638{
1639}
1640
1641/*!
1642 \class QRhiTextureUploadDescription
1643 \internal
1644 \inmodule QtGui
1645 \brief Describes a texture upload operation.
1646
1647 Used with QRhiResourceUpdateBatch::uploadTexture(). That function has two
1648 variants: one taking a QImage and one taking a
1649 QRhiTextureUploadDescription. The former is a convenience version,
1650 internally creating a QRhiTextureUploadDescription with a single image
1651 targeting level 0 for layer 0. However, when cubemaps, pre-generated mip
1652 images, or compressed textures are involved, applications will have to work
1653 directly with this class instead.
1654
1655 QRhiTextureUploadDescription also enables specifying batched uploads, which
1656 are useful for example when generating an atlas or glyph cache texture:
1657 multiple, partial uploads for the same subresource (meaning the same layer
1658 and level) are supported, and can be, depending on the backend and the
1659 underlying graphics API, more efficient when batched into the same
1660 QRhiTextureUploadDescription as opposed to issuing individual
1661 \l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} commands for
1662 each of them.
1663
1664 \note Cubemaps have one layer for each of the six faces in the order +X,
1665 -X, +Y, -Y, +Z, -Z.
1666
1667 For example, specifying the faces of a cubemap could look like the following:
1668
1669 \badcode
1670 QImage faces[6];
1671 ...
1672 QList<QRhiTextureUploadEntry> entries;
1673 for (int i = 0; i < 6; ++i)
1674 entries.append(QRhiTextureUploadEntry(i, 0, faces[i]));
1675 QRhiTextureUploadDescription desc(entries);
1676 resourceUpdates->uploadTexture(texture, desc);
1677 \endcode
1678
1679 Another example that specifies mip images for a compressed texture:
1680
1681 \badcode
1682 QRhiTextureUploadDescription desc;
1683 const int mipCount = rhi->mipLevelsForSize(compressedTexture->pixelSize());
1684 for (int level = 0; level < mipCount; ++level) {
1685 const QByteArray compressedDataForLevel = ..
1686 desc.append(QRhiTextureUploadEntry(0, level, compressedDataForLevel));
1687 }
1688 resourceUpdates->uploadTexture(compressedTexture, desc);
1689 \endcode
1690
1691 With partial uploads targeting the same subresource, it is recommended to
1692 batch them into a single upload request, whenever possible:
1693
1694 \badcode
1695 QRhiTextureSubresourceUploadDescription subresDesc(image);
1696 subresDesc.setSourceSize(QSize(10, 10));
1697 subResDesc.setDestinationTopLeft(QPoint(50, 40));
1698 QRhiTextureUploadEntry entry(0, 0, subresDesc); // layer 0, level 0
1699
1700 QRhiTextureSubresourceUploadDescription subresDesc2(image);
1701 subresDesc2.setSourceSize(QSize(30, 40));
1702 subResDesc2.setDestinationTopLeft(QPoint(100, 200));
1703 QRhiTextureUploadEntry entry2(0, 0, subresDesc2); // layer 0, level 0, i.e. same subresource
1704
1705 QRhiTextureUploadDescription desc({ entry, entry2});
1706 resourceUpdates->uploadTexture(texture, desc);
1707 \endcode
1708 */
1709
1710/*!
1711 \fn QRhiTextureUploadDescription::QRhiTextureUploadDescription()
1712
1713 Constructs an empty texture upload description.
1714 */
1715
1716/*!
1717 Constructs a texture upload description with a single subresource upload
1718 described by \a entry.
1719 */
1720QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry)
1721{
1722 m_entries.append(entry);
1723}
1724
1725/*!
1726 Constructs a texture upload description with the specified \a list of entries.
1727
1728 \note \a list can also contain multiple QRhiTextureUploadEntry elements
1729 with the same layer and level. This makes sense when those uploads are
1730 partial, meaning their subresource description has a source size or image
1731 smaller than the subresource dimensions, and can be more efficient than
1732 issuing separate uploadTexture()'s.
1733 */
1734QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list)
1735 : m_entries(list)
1736{
1737}
1738
1739/*!
1740 \class QRhiTextureCopyDescription
1741 \internal
1742 \inmodule QtGui
1743 \brief Describes a texture-to-texture copy operation.
1744
1745 An empty pixelSize() indicates that the entire subresource is to be copied.
1746 A default constructed copy description therefore leads to copying the
1747 entire subresource at level 0 of layer 0.
1748
1749 \note The source texture must be created with
1750 QRhiTexture::UsedAsTransferSource.
1751
1752 \note The source and destination rectangles defined by pixelSize(),
1753 sourceTopLeft(), and destinationTopLeft() must fit the source and
1754 destination textures, respectively. The behavior is undefined otherwise.
1755 */
1756
1757/*!
1758 \fn QRhiTextureCopyDescription::QRhiTextureCopyDescription()
1759
1760 Constructs an empty texture copy description.
1761 */
1762
1763/*!
1764 \class QRhiReadbackDescription
1765 \internal
1766 \inmodule QtGui
1767 \brief Describes a readback (reading back texture contents from possibly GPU-only memory) operation.
1768
1769 The source of the readback operation is either a QRhiTexture or the
1770 current backbuffer of the currently targeted QRhiSwapChain. When
1771 texture() is not set, the swapchain is used. Otherwise the specified
1772 QRhiTexture is treated as the source.
1773
1774 \note Textures used in readbacks must be created with
1775 QRhiTexture::UsedAsTransferSource.
1776
1777 \note Swapchains used in readbacks must be created with
1778 QRhiSwapChain::UsedAsTransferSource.
1779
1780 layer() and level() are only applicable when the source is a QRhiTexture.
1781
1782 \note Multisample textures cannot be read back. Readbacks are supported for
1783 multisample swapchain buffers however.
1784 */
1785
1786/*!
1787 \fn QRhiReadbackDescription::QRhiReadbackDescription()
1788
1789 Constructs an empty texture readback description.
1790
1791 \note The source texture is set to null by default, which is still a valid
1792 readback: it specifies that the backbuffer of the current swapchain is to
1793 be read back. (current meaning the frame's target swapchain at the time of
1794 committing the QRhiResourceUpdateBatch with the
1795 \l{QRhiResourceUpdateBatch::readBackTexture()}{texture readback} on it)
1796 */
1797
1798/*!
1799 Constructs an texture readback description that specifies that level 0 of
1800 layer 0 of \a texture is to be read back.
1801
1802 \note \a texture can also be null in which case this constructor is
1803 identical to the argumentless variant.
1804 */
1805QRhiReadbackDescription::QRhiReadbackDescription(QRhiTexture *texture)
1806 : m_texture(texture)
1807{
1808}
1809
1810/*!
1811 \class QRhiReadbackResult
1812 \internal
1813 \inmodule QtGui
1814 \brief Describes the results of a potentially asynchronous readback operation.
1815
1816 When \l completed is set, the function is invoked when the \l data is
1817 available. \l format and \l pixelSize are set upon completion together with
1818 \l data.
1819 */
1820
1821/*!
1822 \class QRhiNativeHandles
1823 \internal
1824 \inmodule QtGui
1825 \brief Base class for classes exposing backend-specific collections of native resource objects.
1826 */
1827
1828/*!
1829 \class QRhiResource
1830 \internal
1831 \inmodule QtGui
1832 \brief Base class for classes encapsulating native resource objects.
1833 */
1834
1835/*!
1836 \fn QRhiResource::Type QRhiResource::resourceType() const
1837
1838 \return the type of the resource.
1839 */
1840
1841/*!
1842 \internal
1843 */
1844QRhiResource::QRhiResource(QRhiImplementation *rhi)
1845 : m_rhi(rhi)
1846{
1847 m_id = QRhiGlobalObjectIdGenerator::newId();
1848}
1849
1850/*!
1851 Destructor.
1852
1853 Releases (or requests deferred releasing of) the underlying native graphics
1854 resources, if there are any.
1855
1856 \note Resources referenced by commands for the current frame should not be
1857 released until the frame is submitted by QRhi::endFrame().
1858
1859 \sa destroy()
1860 */
1861QRhiResource::~QRhiResource()
1862{
1863 // destroy() cannot be called here, due to virtuals; it is up to the
1864 // subclasses to do that.
1865}
1866
1867/*!
1868 \fn void QRhiResource::destroy()
1869
1870 Releases (or requests deferred releasing of) the underlying native graphics
1871 resources. Safe to call multiple times, subsequent invocations will be a
1872 no-op then.
1873
1874 Once destroy() is called, the QRhiResource instance can be reused, by
1875 calling \c create() again. That will then result in creating new native
1876 graphics resources underneath.
1877
1878 \note Resources referenced by commands for the current frame should not be
1879 released until the frame is submitted by QRhi::endFrame().
1880
1881 The QRhiResource destructor also performs the same task, so calling this
1882 function is not necessary before destroying a QRhiResource.
1883
1884 \sa deleteLater()
1885 */
1886
1887/*!
1888 When called without a frame being recorded, this function is equivalent to
1889 deleting the object. Between a QRhi::beginFrame() and QRhi::endFrame()
1890 however the behavior is different: the QRhiResource will not be destroyed
1891 until the frame is submitted via QRhi::endFrame(), thus satisfying the QRhi
1892 requirement of not altering QRhiResource objects that are referenced by the
1893 frame being recorded.
1894
1895 \sa destroy()
1896 */
1897void QRhiResource::deleteLater()
1898{
1899 m_rhi->addDeleteLater(this);
1900}
1901
1902/*!
1903 \return the currently set object name. By default the name is empty.
1904 */
1905QByteArray QRhiResource::name() const
1906{
1907 return m_objectName;
1908}
1909
1910/*!
1911 Sets a \a name for the object.
1912
1913 This has two uses: to get descriptive names for the native graphics
1914 resources visible in graphics debugging tools, such as
1915 \l{https://renderdoc.org/}{RenderDoc} and
1916 \l{https://developer.apple.com/xcode/}{XCode}, and in the output stream of
1917 QRhiProfiler.
1918
1919 When it comes to naming native objects by relaying the name via the
1920 appropriate graphics API, note that the name is ignored when
1921 QRhi::DebugMarkers are not supported, and may, depending on the backend,
1922 also be ignored when QRhi::EnableDebugMarkers is not set.
1923
1924 \note The name may be ignored for objects other than buffers,
1925 renderbuffers, and textures, depending on the backend.
1926
1927 \note The name may be modified. For slotted resources, such as a QRhiBuffer
1928 backed by multiple native buffers, QRhi will append a suffix to make the
1929 underlying native buffers easily distinguishable from each other.
1930 */
1931void QRhiResource::setName(const QByteArray &name)
1932{
1933 m_objectName = name;
1934 m_objectName.replace(',', '_'); // cannot contain comma for QRhiProfiler
1935}
1936
1937/*!
1938 \return the global, unique identifier of this QRhiResource.
1939
1940 User code rarely needs to deal with the value directly. It is used
1941 internally for tracking and bookkeeping purposes.
1942 */
1943quint64 QRhiResource::globalResourceId() const
1944{
1945 return m_id;
1946}
1947
1948/*!
1949 \class QRhiBuffer
1950 \internal
1951 \inmodule QtGui
1952 \brief Vertex, index, or uniform (constant) buffer resource.
1953 */
1954
1955/*!
1956 \enum QRhiBuffer::Type
1957 Specifies storage type of buffer resource.
1958
1959 \value Immutable Indicates that the data is not expected to change ever
1960 after the initial upload. Under the hood such buffer resources are
1961 typically placed in device local (GPU) memory (on systems where
1962 applicable). Uploading new data is possible, but may be expensive. The
1963 upload typically happens by copying to a separate, host visible staging
1964 buffer from which a GPU buffer-to-buffer copy is issued into the actual
1965 GPU-only buffer.
1966
1967 \value Static Indicates that the data is expected to change only
1968 infrequently. Typically placed in device local (GPU) memory, where
1969 applicable. On backends where host visible staging buffers are used for
1970 uploading, the staging buffers are kept around for this type, unlike with
1971 Immutable, so subsequent uploads do not suffer in performance. Frequent
1972 updates, especially updates in consecutive frames, should be avoided.
1973
1974 \value Dynamic Indicates that the data is expected to change frequently.
1975 Not recommended for large buffers. Typically backed by host visible memory
1976 in 2 copies in order to allow for changing without stalling the graphics
1977 pipeline. The double buffering is managed transparently to the applications
1978 and is not exposed in the API here in any form. This is the recommended,
1979 and, with some backends, the only possible, type for buffers with
1980 UniformBuffer usage.
1981 */
1982
1983/*!
1984 \enum QRhiBuffer::UsageFlag
1985 Flag values to specify how the buffer is going to be used.
1986
1987 \value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in
1988 \l{setVertexInput()}{QRhiCommandBuffer::setVertexInput()}.
1989
1990 \value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in
1991 \l{setVertexInput()}{QRhiCommandBuffer::setVertexInput()}.
1992
1993 \value UniformBuffer Uniform buffer (also called constant buffer). This
1994 allows the QRhiBuffer to be used in combination with
1995 \l{UniformBuffer}{QRhiShaderResourceBinding::UniformBuffer}. When
1996 \l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as
1997 not supported, this usage can only be combined with the type Dynamic.
1998
1999 \value StorageBuffer Storage buffer. This allows the QRhiBuffer to be used
2000 in combination with \l{BufferLoad}{QRhiShaderResourceBinding::BufferLoad},
2001 \l{BufferStore}{QRhiShaderResourceBinding::BufferStore}, or
2002 \l{BufferLoadStore}{QRhiShaderResourceBinding::BufferLoadStore}. This usage
2003 can only be combined with the types Immutable or Static, and is only
2004 available when the \l{QRhi::Compute}{Compute feature} is reported as
2005 supported.
2006 */
2007
2008/*!
2009 \fn void QRhiBuffer::setSize(int sz)
2010
2011 Sets the size of the buffer in bytes. The size is normally specified in
2012 QRhi::newBuffer() so this function is only used when the size has to be
2013 changed. As with other setters, the size only takes effect when calling
2014 create(), and for already created buffers this involves releasing the previous
2015 native resource and creating new ones under the hood.
2016
2017 Backends may choose to allocate buffers bigger than \a sz in order to
2018 fulfill alignment requirements. This is hidden from the applications and
2019 size() will always report the size requested in \a sz.
2020 */
2021
2022/*!
2023 \class QRhiBuffer::NativeBuffer
2024 \brief Contains information about the underlying native resources of a buffer.
2025 */
2026
2027/*!
2028 \variable QRhiBuffer::NativeBuffer::objects
2029 \brief an array with pointers to the native object handles.
2030
2031 With OpenGL, the native handle is a GLuint value, so the elements in the \c
2032 objects array are pointers to a GLuint. With Vulkan, the native handle is a
2033 VkBuffer, so the elements of the array are pointers to a VkBuffer. With
2034 Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or
2035 MTLBuffer pointer, respectively.
2036
2037 \note Pay attention to the fact that the elements are always pointers to
2038 the native buffer handle type, even if the native type itself is a pointer.
2039 */
2040
2041/*!
2042 \variable QRhiBuffer::NativeBuffer::slotCount
2043 \brief Specifies the number of valid elements in the objects array.
2044
2045 The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer
2046 is not backed by any native buffer objects. This can happen with
2047 QRhiBuffers with the usage UniformBuffer when the underlying API does not
2048 support (or the backend chooses not to use) native uniform buffers. 1 is
2049 commonly used for Immutable and Static types (but some backends may
2050 differ). 2 or 3 is typical when the type is Dynamic (but some backends may
2051 differ).
2052
2053 \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight
2054 */
2055
2056/*!
2057 \internal
2058 */
2059QRhiBuffer::QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, int size_)
2060 : QRhiResource(rhi),
2061 m_type(type_), m_usage(usage_), m_size(size_)
2062{
2063}
2064
2065/*!
2066 \return the resource type.
2067 */
2068QRhiResource::Type QRhiBuffer::resourceType() const
2069{
2070 return Buffer;
2071}
2072
2073/*!
2074 \fn bool QRhiBuffer::create()
2075
2076 Creates the corresponding native graphics resources. If there are already
2077 resources present due to an earlier create() with no corresponding
2078 destroy(), then destroy() is called implicitly first.
2079
2080 \return \c true when successful, \c false when a graphics operation failed.
2081 Regardless of the return value, calling destroy() is always safe.
2082 */
2083
2084/*!
2085 \return the underlying native resources for this buffer. The returned value
2086 will be empty if exposing the underlying native resources is not supported by
2087 the backend.
2088
2089 A QRhiBuffer may be backed by multiple native buffer objects, depending on
2090 the type() and the QRhi backend in use. When this is the case, all of them
2091 are returned in the objects array in the returned struct, with slotCount
2092 specifying the number of native buffer objects. While
2093 \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be
2094 used to determine which of the native buffers QRhi is using for operations
2095 that read or write from this QRhiBuffer within the frame being recorded.
2096
2097 In some cases a QRhiBuffer will not be backed by a native buffer object at
2098 all. In this case slotCount will be set to 0 and no valid native objects
2099 are returned. This is not an error, and is perfectly valid when a given
2100 backend does not use native buffers for QRhiBuffers with certain types or
2101 usages.
2102
2103 \note Be aware that QRhi backends may employ various buffer update
2104 strategies. Unlike textures, where uploading image data always means
2105 recording a buffer-to-image (or similar) copy command on the command
2106 buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate
2107 in many different ways. For example, a QRhiBuffer with usage type
2108 UniformBuffer may not even be backed by a native buffer object at all if
2109 uniform buffers are not used or supported by a given backend and graphics
2110 API. There are also differences to how data is written to the buffer and
2111 the type of backing memory used. For buffers backed by host visible memory,
2112 calling this function guarantees that pending host writes are executed for
2113 all the returned native buffers.
2114
2115 \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight
2116 */
2117QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer()
2118{
2119 return {};
2120}
2121
2122/*!
2123 \return a pointer to a memory block with the host visible buffer data.
2124
2125 This is a shortcut for medium-to-large dynamic uniform buffers that have
2126 their \b entire contents (or at least all regions that are read by the
2127 shaders in the current frame) changed \b{in every frame} and the
2128 QRhiResourceUpdateBatch-based update mechanism is seen too heavy due to the
2129 amount of data copying involved.
2130
2131 The call to this function must be eventually followed by a call to
2132 endFullDynamicUniformBufferUpdateForCurrentFrame(), before recording any
2133 render or compute pass that relies on this buffer.
2134
2135 \warning Updating data via this method is not compatible with
2136 QRhiResourceUpdateBatch-based updates and readbacks. Unexpected behavior
2137 may occur when attempting to combine the two update models for the same
2138 buffer. Similarly, the data updated this direct way may not be visible to
2139 \l{QRhiResourceUpdateBatch::readBackBuffer()}{readBackBuffer operations},
2140 depending on the backend.
2141
2142 \warning When updating buffer data via this method, the update must be done
2143 in every frame, otherwise backends that perform double or tripple buffering
2144 of resources may end up in unexpected behavior.
2145
2146 \warning Partial updates are not possible with this approach since some
2147 backends may choose a strategy where the previous contents of the buffer is
2148 lost upon calling this function. Data must be written to all regions that
2149 are read by shaders in the frame currently being prepared.
2150
2151 \warning This function can only be called when recording a frame, so
2152 between QRhi::beginFrame() and QRhi::endFrame().
2153
2154 \warning This function can only be called on Dynamic buffers.
2155 */
2156char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame()
2157{
2158 return nullptr;
2159}
2160
2161/*!
2162 To be called when the entire contents of the buffer data has been updated
2163 in the memory block returned from
2164 beginFullDynamicBufferUpdateForCurrentFrame().
2165 */
2166void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()
2167{
2168}
2169
2170/*!
2171 \class QRhiRenderBuffer
2172 \internal
2173 \inmodule QtGui
2174 \brief Renderbuffer resource.
2175
2176 Renderbuffers cannot be sampled or read but have some benefits over
2177 textures in some cases:
2178
2179 A DepthStencil renderbuffer may be lazily allocated and be backed by
2180 transient memory with some APIs. On some platforms this may mean the
2181 depth/stencil buffer uses no physical backing at all.
2182
2183 Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be
2184 supported even when QRhi::MultisampleTexture is not.
2185
2186 How the renderbuffer is implemented by a backend is not exposed to the
2187 applications. In some cases it may be backed by ordinary textures, while in
2188 others there may be a different kind of native resource used.
2189
2190 Renderbuffers that are used as (and are only used as) depth-stencil buffers
2191 in combination with a QRhiSwapChain's color buffers should have the
2192 UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers,
2193 depending on the backend and the underlying APIs, be more efficient, and
2194 QRhi provides automatic sizing behavior to match the color buffers, which
2195 means calling setPixelSize() and create() are not necessary for such
2196 renderbuffers.
2197 */
2198
2199/*!
2200 \enum QRhiRenderBuffer::Type
2201 Specifies the type of the renderbuffer
2202
2203 \value DepthStencil Combined depth/stencil
2204 \value Color Color
2205 */
2206
2207/*!
2208 \enum QRhiRenderBuffer::Flag
2209 Flag values for flags() and setFlags()
2210
2211 \value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
2212 that the renderbuffer is only used in combination with a QRhiSwapChain, and
2213 never in any other way. This provides automatic sizing and resource
2214 rebuilding, so calling setPixelSize() or create() is not needed whenever
2215 this flag is set. This flag value may also trigger backend-specific
2216 behavior, for example with OpenGL, where a separate windowing system
2217 interface API is in use (EGL, GLX, etc.), the flag is especially important
2218 as it avoids creating any actual renderbuffer resource as there is already
2219 a windowing system provided depth/stencil buffer as requested by
2220 QSurfaceFormat.
2221 */
2222
2223/*!
2224 \internal
2225 */
2226QRhiRenderBuffer::QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_,
2227 int sampleCount_, Flags flags_,
2228 QRhiTexture::Format backingFormatHint_)
2229 : QRhiResource(rhi),
2230 m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_),
2231 m_backingFormatHint(backingFormatHint_)
2232{
2233}
2234
2235/*!
2236 \return the resource type.
2237 */
2238QRhiResource::Type QRhiRenderBuffer::resourceType() const
2239{
2240 return RenderBuffer;
2241}
2242
2243/*!
2244 \fn bool QRhiRenderBuffer::create()
2245
2246 Creates the corresponding native graphics resources. If there are already
2247 resources present due to an earlier create() with no corresponding
2248 destroy(), then destroy() is called implicitly first.
2249
2250 \return \c true when successful, \c false when a graphics operation failed.
2251 Regardless of the return value, calling destroy() is always safe.
2252 */
2253
2254/*!
2255 \fn QRhiTexture::Format QRhiRenderBuffer::backingFormat() const
2256
2257 \internal
2258 */
2259
2260/*!
2261 \class QRhiTexture
2262 \internal
2263 \inmodule QtGui
2264 \brief Texture resource.
2265 */
2266
2267/*!
2268 \enum QRhiTexture::Flag
2269
2270 Flag values to specify how the texture is going to be used. Not honoring
2271 the flags set before create() and attempting to use the texture in ways that
2272 was not declared upfront can lead to unspecified behavior or decreased
2273 performance depending on the backend and the underlying graphics API.
2274
2275 \value RenderTarget The texture going to be used in combination with
2276 QRhiTextureRenderTarget.
2277
2278 \value CubeMap The texture is a cubemap. Such textures have 6 layers, one
2279 for each face in the order of +X, -X, +Y, -Y, +Z, -Z. Cubemap textures
2280 cannot be multisample.
2281
2282 \value MipMapped The texture has mipmaps. The appropriate mip count is
2283 calculated automatically and can also be retrieved via
2284 QRhi::mipLevelsForSize(). The images for the mip levels have to be
2285 provided in the texture uploaded or generated via
2286 QRhiResourceUpdateBatch::generateMips(). Multisample textures cannot have
2287 mipmaps.
2288
2289 \value sRGB Use an sRGB format.
2290
2291 \value UsedAsTransferSource The texture is used as the source of a texture
2292 copy or readback, meaning the texture is given as the source in
2293 QRhiResourceUpdateBatch::copyTexture() or
2294 QRhiResourceUpdateBatch::readBackTexture().
2295
2296 \value UsedWithGenerateMips The texture is going to be used with
2297 QRhiResourceUpdateBatch::generateMips().
2298
2299 \value UsedWithLoadStore The texture is going to be used with image
2300 load/store operations, for example, in a compute shader.
2301
2302 \value UsedAsCompressedAtlas The texture has a compressed format and the
2303 dimensions of subresource uploads may not match the texture size.
2304 */
2305
2306/*!
2307 \enum QRhiTexture::Format
2308
2309 Specifies the texture format. See also QRhi::isTextureFormatSupported() and
2310 note that flags() can modify the format when QRhiTexture::sRGB is set.
2311
2312 \value UnknownFormat Not a valid format. This cannot be passed to setFormat().
2313
2314 \value RGBA8 Four component, unsigned normalized 8 bit per component. Always supported.
2315
2316 \value BGRA8 Four component, unsigned normalized 8 bit per component.
2317
2318 \value R8 One component, unsigned normalized 8 bit.
2319
2320 \value RG8 Two components, unsigned normalized 8 bit.
2321
2322 \value R16 One component, unsigned normalized 16 bit.
2323
2324 \value RED_OR_ALPHA8 Either same as R8, or is a similar format with the component swizzled to alpha,
2325 depending on \l{QRhi::RedOrAlpha8IsRed}{RedOrAlpha8IsRed}.
2326
2327 \value RGBA16F Four components, 16-bit float per component.
2328
2329 \value RGBA32F Four components, 32-bit float per component.
2330
2331 \value D16 16-bit depth (normalized unsigned integer)
2332
2333 \value D24 24-bit depth (normalized unsigned integer)
2334
2335 \value D24S8 24-bit depth (normalized unsigned integer), 8 bit stencil
2336
2337 \value D32F 32-bit depth (32-bit float)
2338
2339 \value BC1
2340 \value BC2
2341 \value BC3
2342 \value BC4
2343 \value BC5
2344 \value BC6H
2345 \value BC7
2346
2347 \value ETC2_RGB8
2348 \value ETC2_RGB8A1
2349 \value ETC2_RGBA8
2350
2351 \value ASTC_4x4
2352 \value ASTC_5x4
2353 \value ASTC_5x5
2354 \value ASTC_6x5
2355 \value ASTC_6x6
2356 \value ASTC_8x5
2357 \value ASTC_8x6
2358 \value ASTC_8x8
2359 \value ASTC_10x5
2360 \value ASTC_10x6
2361 \value ASTC_10x8
2362 \value ASTC_10x10
2363 \value ASTC_12x10
2364 \value ASTC_12x12
2365 */
2366
2367/*!
2368 \class QRhiTexture::NativeTexture
2369 \brief Contains information about the underlying native resources of a texture.
2370 */
2371
2372/*!
2373 \variable QRhiTexture::NativeTexture::object
2374 \brief 64-bit integer containing the native object handle.
2375
2376 With OpenGL, the native handle is a GLuint value, so \c object can then be
2377 cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c
2378 object can be cast to a VkImage. With Direct3D 11 and Metal \c
2379 object contains a ID3D11Texture2D or MTLTexture pointer, respectively.
2380 */
2381
2382/*!
2383 \variable QRhiTexture::NativeTexture::layout
2384 \brief Specifies the current image layout for APIs like Vulkan.
2385
2386 For Vulkan, \c layout contains a \c VkImageLayout value.
2387 */
2388
2389/*!
2390 \internal
2391 */
2392QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_,
2393 int sampleCount_, Flags flags_)
2394 : QRhiResource(rhi),
2395 m_format(format_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_)
2396{
2397}
2398
2399/*!
2400 \return the resource type.
2401 */
2402QRhiResource::Type QRhiTexture::resourceType() const
2403{
2404 return Texture;
2405}
2406
2407/*!
2408 \fn bool QRhiTexture::create()
2409
2410 Creates the corresponding native graphics resources. If there are already
2411 resources present due to an earlier create() with no corresponding
2412 destroy(), then destroy() is called implicitly first.
2413
2414 \return \c true when successful, \c false when a graphics operation failed.
2415 Regardless of the return value, calling destroy() is always safe.
2416 */
2417
2418/*!
2419 \return the underlying native resources for this texture. The returned value
2420 will be empty if exposing the underlying native resources is not supported by
2421 the backend.
2422
2423 \sa createFrom()
2424 */
2425QRhiTexture::NativeTexture QRhiTexture::nativeTexture()
2426{
2427 return {};
2428}
2429
2430/*!
2431 Similar to create() except that no new native textures are created. Instead,
2432 the native texture resources specified by \a src is used.
2433
2434 This allows importing an existing native texture object (which must belong
2435 to the same device or sharing context, depending on the graphics API) from
2436 an external graphics engine.
2437
2438 \note format(), pixelSize(), sampleCount(), and flags() must still be set
2439 correctly. Passing incorrect sizes and other values to QRhi::newTexture()
2440 and then following it with a createFrom() expecting that the native texture
2441 object alone is sufficient to deduce such values is \b wrong and will lead
2442 to problems.
2443
2444 \note QRhiTexture does not take ownership of the texture object. destroy()
2445 does not free the object or any associated memory.
2446
2447 The opposite of this operation, exposing a QRhiTexture-created native
2448 texture object to a foreign engine, is possible via nativeTexture().
2449
2450*/
2451bool QRhiTexture::createFrom(QRhiTexture::NativeTexture src)
2452{
2453 Q_UNUSED(src);
2454 return false;
2455}
2456
2457/*!
2458 With some graphics APIs, such as Vulkan, integrating custom rendering code
2459 that uses the graphics API directly needs special care when it comes to
2460 image layouts. This function allows communicating the expected layout the
2461 image backing the QRhiTexture is in after the native rendering commands.
2462
2463 For example, consider rendering into a QRhiTexture's VkImage directly with
2464 Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and
2465 QRhiCommandBuffer::endExternal(), followed by using the image for texture
2466 sampling in a QRhi-based render pass. To avoid potentially incorrect image
2467 layout transitions, this function can be used to indicate what the image
2468 layout will be once the commands recorded in said code block complete.
2469
2470 Calling this function makes sense only after
2471 QRhiCommandBuffer::endExternal() and before a subsequent
2472 QRhiCommandBuffer::beginPass().
2473
2474 This function has no effect with QRhi backends where the underlying
2475 graphics API does not expose a concept of image layouts.
2476 */
2477void QRhiTexture::setNativeLayout(int layout)
2478{
2479 Q_UNUSED(layout);
2480}
2481
2482/*!
2483 \class QRhiSampler
2484 \internal
2485 \inmodule QtGui
2486 \brief Sampler resource.
2487 */
2488
2489/*!
2490 \enum QRhiSampler::Filter
2491 Specifies the minification, magnification, or mipmap filtering
2492
2493 \value None Applicable only for mipmapMode(), indicates no mipmaps to be used
2494 \value Nearest
2495 \value Linear
2496 */
2497
2498/*!
2499 \enum QRhiSampler::AddressMode
2500 Specifies the addressing mode
2501
2502 \value Repeat
2503 \value ClampToEdge
2504 \value Mirror
2505 */
2506
2507/*!
2508 \enum QRhiSampler::CompareOp
2509 Specifies the texture comparison function.
2510
2511 \value Never (default)
2512 \value Less
2513 \value Equal
2514 \value LessOrEqual
2515 \value Greater
2516 \value NotEqual
2517 \value GreaterOrEqual
2518 \value Always
2519 */
2520
2521/*!
2522 \internal
2523 */
2524QRhiSampler::QRhiSampler(QRhiImplementation *rhi,
2525 Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
2526 AddressMode u_, AddressMode v_, AddressMode w_)
2527 : QRhiResource(rhi),
2528 m_magFilter(magFilter_), m_minFilter(minFilter_), m_mipmapMode(mipmapMode_),
2529 m_addressU(u_), m_addressV(v_), m_addressW(w_),
2530 m_compareOp(QRhiSampler::Never)
2531{
2532}
2533
2534/*!
2535 \return the resource type.
2536 */
2537QRhiResource::Type QRhiSampler::resourceType() const
2538{
2539 return Sampler;
2540}
2541
2542/*!
2543 \class QRhiRenderPassDescriptor
2544 \internal
2545 \inmodule QtGui
2546 \brief Render pass resource.
2547
2548 A render pass, if such a concept exists in the underlying graphics API, is
2549 a collection of attachments (color, depth, stencil) and describes how those
2550 attachments are used.
2551 */
2552
2553/*!
2554 \internal
2555 */
2556QRhiRenderPassDescriptor::QRhiRenderPassDescriptor(QRhiImplementation *rhi)
2557 : QRhiResource(rhi)
2558{
2559}
2560
2561/*!
2562 \return the resource type.
2563 */
2564QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
2565{
2566 return RenderPassDescriptor;
2567}
2568
2569/*!
2570 \fn bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const;
2571
2572 \return true if the \a other QRhiRenderPassDescriptor is compatible with
2573 this one, meaning \c this and \a other can be used interchangebly in
2574 QRhiGraphicsPipeline::setRenderPassDescriptor().
2575
2576 The concept of the compatibility of renderpass descriptors is similar to
2577 the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout
2578 compatibility} of QRhiShaderResourceBindings instances. They allow better
2579 reuse of QRhiGraphicsPipeline instances: for example, a
2580 QRhiGraphicsPipeline instance cache is expected to use these functions to
2581 look for a matching pipeline, instead of just comparing pointers, thus
2582 allowing a different QRhiRenderPassDescriptor and
2583 QRhiShaderResourceBindings to be used in combination with the pipeline, as
2584 long as they are compatible.
2585 */
2586
2587/*!
2588 \return a pointer to a backend-specific QRhiNativeHandles subclass, such as
2589 QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing
2590 the underlying native resources is not supported by the backend.
2591
2592 \sa QRhiVulkanRenderPassNativeHandles
2593 */
2594const QRhiNativeHandles *QRhiRenderPassDescriptor::nativeHandles()
2595{
2596 return nullptr;
2597}
2598
2599/*!
2600 \class QRhiRenderTarget
2601 \internal
2602 \inmodule QtGui
2603 \brief Represents an onscreen (swapchain) or offscreen (texture) render target.
2604 */
2605
2606/*!
2607 \internal
2608 */
2609QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi)
2610 : QRhiResource(rhi)
2611{
2612}
2613
2614/*!
2615 \return the resource type.
2616 */
2617QRhiResource::Type QRhiRenderTarget::resourceType() const
2618{
2619 return RenderTarget;
2620}
2621
2622/*!
2623 \fn QSize QRhiRenderTarget::pixelSize() const
2624
2625 \return the size in pixels.
2626 */
2627
2628/*!
2629 \fn float QRhiRenderTarget::devicePixelRatio() const
2630
2631 \return the device pixel ratio. For QRhiTextureRenderTarget this is always
2632 1. For targets retrieved from a QRhiSwapChain the value reflects the
2633 \l{QWindow::devicePixelRatio()}{device pixel ratio} of the targeted
2634 QWindow.
2635 */
2636
2637/*!
2638 \class QRhiTextureRenderTarget
2639 \internal
2640 \inmodule QtGui
2641 \brief Texture render target resource.
2642
2643 A texture render target allows rendering into one or more textures,
2644 optionally with a depth texture or depth/stencil renderbuffer.
2645
2646 \note Textures used in combination with QRhiTextureRenderTarget must be
2647 created with the QRhiTexture::RenderTarget flag.
2648
2649 The simplest example of creating a render target with a texture as its
2650 single color attachment:
2651
2652 \badcode
2653 texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget);
2654 texture->create();
2655 rt = rhi->newTextureRenderTarget({ texture });
2656 rp = rt->newCompatibleRenderPassDescriptor();
2657 rt->setRenderPassDescriptor(rt);
2658 rt->create();
2659 // rt can now be used with beginPass()
2660 \endcode
2661 */
2662
2663/*!
2664 \enum QRhiTextureRenderTarget::Flag
2665
2666 Flag values describing the load/store behavior for the render target. The
2667 load/store behavior may be baked into native resources under the hood,
2668 depending on the backend, and therefore it needs to be known upfront and
2669 cannot be changed without rebuilding (and so releasing and creating new
2670 native resources).
2671
2672 \value PreserveColorContents Indicates that the contents of the color
2673 attachments is to be loaded when starting a render pass, instead of
2674 clearing. This is potentially more expensive, especially on mobile (tiled)
2675 GPUs, but allows preserving the existing contents between passes.
2676
2677 \value PreserveDepthStencilContents Indicates that the contents of the
2678 depth texture is to be loaded when starting a render pass, instead
2679 clearing. Only applicable when a texture is used as the depth buffer
2680 (QRhiTextureRenderTargetDescription::depthTexture() is set) because
2681 depth/stencil renderbuffers may not have any physical backing and data may
2682 not be written out in the first place.
2683 */
2684
2685/*!
2686 \internal
2687 */
2688QRhiTextureRenderTarget::QRhiTextureRenderTarget(QRhiImplementation *rhi,
2689 const QRhiTextureRenderTargetDescription &desc_,
2690 Flags flags_)
2691 : QRhiRenderTarget(rhi),
2692 m_desc(desc_),
2693 m_flags(flags_)
2694{
2695}
2696
2697/*!
2698 \return the resource type.
2699 */
2700QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
2701{
2702 return TextureRenderTarget;
2703}
2704
2705/*!
2706 \fn QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()
2707
2708 \return a new QRhiRenderPassDescriptor that is compatible with this render
2709 target.
2710
2711 The returned value is used in two ways: it can be passed to
2712 setRenderPassDescriptor() and
2713 QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor
2714 describes the attachments (color, depth/stencil) and the load/store
2715 behavior that can be affected by flags(). A QRhiGraphicsPipeline can only
2716 be used in combination with a render target that has the same
2717 QRhiRenderPassDescriptor set.
2718
2719 Two QRhiTextureRenderTarget instances can share the same render pass
2720 descriptor as long as they have the same number and type of attachments.
2721 The associated QRhiTexture or QRhiRenderBuffer instances are not part of
2722 the render pass descriptor so those can differ in the two
2723 QRhiTextureRenderTarget intances.
2724
2725 \note resources, such as QRhiTexture instances, referenced in description()
2726 must already have create() called on them.
2727
2728 \sa create()
2729 */
2730
2731/*!
2732 \fn bool QRhiTextureRenderTarget::create()
2733
2734 Creates the corresponding native graphics resources. If there are already
2735 resources present due to an earlier create() with no corresponding
2736 destroy(), then destroy() is called implicitly first.
2737
2738 \note renderPassDescriptor() must be set before calling create(). To obtain
2739 a QRhiRenderPassDescriptor compatible with the render target, call
2740 newCompatibleRenderPassDescriptor() before create() but after setting all
2741 other parameters, such as description() and flags(). To save resources,
2742 reuse the same QRhiRenderPassDescriptor with multiple
2743 QRhiTextureRenderTarget instances, whenever possible. Sharing the same
2744 render pass descriptor is only possible when the render targets have the
2745 same number and type of attachments (the actual textures can differ) and
2746 the same flags.
2747
2748 \note resources, such as QRhiTexture instances, referenced in description()
2749 must already have create() called on them.
2750
2751 \return \c true when successful, \c false when a graphics operation failed.
2752 Regardless of the return value, calling destroy() is always safe.
2753 */
2754
2755/*!
2756 \class QRhiShaderResourceBindings
2757 \internal
2758 \inmodule QtGui
2759 \brief Encapsulates resources for making buffer, texture, sampler resources visible to shaders.
2760
2761 A QRhiShaderResourceBindings is a collection of QRhiShaderResourceBinding
2762 objects, each of which describe a single binding.
2763
2764 Take a fragment shader with the following interface:
2765
2766 \badcode
2767 layout(std140, binding = 0) uniform buf {
2768 mat4 mvp;
2769 int flip;
2770 } ubuf;
2771
2772 layout(binding = 1) uniform sampler2D tex;
2773 \endcode
2774
2775 To make resources visible to the shader, the following
2776 QRhiShaderResourceBindings could be created and then passed to
2777 QRhiGraphicsPipeline::setShaderResourceBindings():
2778
2779 \badcode
2780 srb = rhi->newShaderResourceBindings();
2781 srb->setBindings({
2782 QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf),
2783 QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler)
2784 });
2785 srb->create();
2786 ...
2787 ps = rhi->newGraphicsPipeline();
2788 ...
2789 ps->setShaderResourceBindings(srb);
2790 ps->create();
2791 ...
2792 cb->setGraphicsPipeline(ps);
2793 cb->setShaderResources(); // binds srb
2794 \endcode
2795
2796 This assumes that \c ubuf is a QRhiBuffer, \c texture is a QRhiTexture,
2797 while \a sampler is a QRhiSampler. The example also assumes that the
2798 uniform block is present in the vertex shader as well so the same buffer is
2799 made visible to the vertex stage too.
2800
2801 \section3 Advanced usage
2802
2803 Building on the above example, let's assume that a pass now needs to use
2804 the exact same pipeline and shaders with a different texture. Creating a
2805 whole separate QRhiGraphicsPipeline just for this would be an overkill.
2806 This is why QRhiCommandBuffer::setShaderResources() allows specifying a \a
2807 srb argument. As long as the layouts (so the number of bindings and the
2808 binding points) match between two QRhiShaderResourceBindings, they can both
2809 be used with the same pipeline, assuming the pipeline was created with one of
2810 them in the first place.
2811
2812 \badcode
2813 srb2 = rhi->newShaderResourceBindings();
2814 ...
2815 cb->setGraphicsPipeline(ps);
2816 cb->setShaderResources(srb2); // binds srb2
2817 \endcode
2818 */
2819
2820/*!
2821 \internal
2822 */
2823QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi)
2824 : QRhiResource(rhi)
2825{
2826}
2827
2828/*!
2829 \return the resource type.
2830 */
2831QRhiResource::Type QRhiShaderResourceBindings::resourceType() const
2832{
2833 return ShaderResourceBindings;
2834}
2835
2836/*!
2837 \return \c true if the layout is compatible with \a other. The layout does
2838 not include the actual resource (such as, buffer or texture) and related
2839 parameters (such as, offset or size). It does include the binding point,
2840 pipeline stage, and resource type, however. The number and order of the
2841 bindings must also match in order to be compatible.
2842
2843 When there is a QRhiGraphicsPipeline created with this
2844 QRhiShaderResourceBindings, and the function returns \c true, \a other can
2845 then safely be passed to QRhiCommandBuffer::setShaderResources(), and so
2846 be used with the pipeline in place of this QRhiShaderResourceBindings.
2847
2848 This function can be called before create() as well. The bindings must
2849 already be set via setBindings() however.
2850 */
2851bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBindings *other) const
2852{
2853 if (other == this)
2854 return true;
2855
2856 if (!other)
2857 return false;
2858
2859 // This can become a hot code path. Therefore we do not iterate and call
2860 // isLayoutCompatible() on m_bindings, but rather check a pre-calculated
2861 // hash code and then, if the hash matched, do a uint array comparison
2862 // (that's still more cache friendly).
2863
2864 return m_layoutDescHash == other->m_layoutDescHash
2865 && m_layoutDesc == other->m_layoutDesc;
2866}
2867
2868void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb)
2869{
2870 srb->m_layoutDescHash = 0;
2871 srb->m_layoutDesc.clear();
2872 for (const QRhiShaderResourceBinding &b : qAsConst(srb->m_bindings)) {
2873 const QRhiShaderResourceBinding::Data *d = b.data();
2874 // must match QRhiShaderResourceBinding::isLayoutCompatible()
2875 srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type);
2876 srb->m_layoutDesc << uint(d->binding) << uint(d->stage) << uint(d->type);
2877 }
2878}
2879
2880/*!
2881 \class QRhiShaderResourceBinding
2882 \internal
2883 \inmodule QtGui
2884 \brief Describes the shader resource for a single binding point.
2885
2886 A QRhiShaderResourceBinding cannot be constructed directly. Instead, use
2887 the static functions uniformBuffer(), sampledTexture() to get an instance.
2888 */
2889
2890/*!
2891 \enum QRhiShaderResourceBinding::Type
2892 Specifies type of the shader resource bound to a binding point
2893
2894 \value UniformBuffer Uniform buffer
2895
2896 \value SampledTexture Combined image sampler
2897
2898 \value ImageLoad Image load (with GLSL this maps to doing imageLoad() on a
2899 single level - and either one or all layers - of a texture exposed to the
2900 shader as an image object)
2901
2902 \value ImageStore Image store (with GLSL this maps to doing imageStore() or
2903 imageAtomic*() on a single level - and either one or all layers - of a
2904 texture exposed to the shader as an image object)
2905
2906 \value ImageLoadStore Image load and store
2907
2908 \value BufferLoad Storage buffer store (with GLSL this maps to reading from
2909 a shader storage buffer)
2910
2911 \value BufferStore Storage buffer store (with GLSL this maps to writing to
2912 a shader storage buffer)
2913
2914 \value BufferLoadStore Storage buffer load and store
2915 */
2916
2917/*!
2918 \enum QRhiShaderResourceBinding::StageFlag
2919 Flag values to indicate which stages the shader resource is visible in
2920
2921 \value VertexStage Vertex stage
2922 \value FragmentStage Fragment (pixel) stage
2923 \value ComputeStage Compute stage
2924 */
2925
2926/*!
2927 \return \c true if the layout is compatible with \a other. The layout does not
2928 include the actual resource (such as, buffer or texture) and related
2929 parameters (such as, offset or size).
2930
2931 For example, \c a and \c b below are not equal, but are compatible layout-wise:
2932
2933 \badcode
2934 auto a = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buffer);
2935 auto b = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, someOtherBuffer, 256);
2936 \endcode
2937 */
2938bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
2939{
2940 return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type;
2941}
2942
2943/*!
2944 \return a shader resource binding for the given binding number, pipeline
2945 stages, and buffer specified by \a binding, \a stage, and \a buf.
2946
2947 \note When \a buf is not null, it must have been created with
2948 QRhiBuffer::UniformBuffer.
2949
2950 \note \a buf can be null. It is valid to create a
2951 QRhiShaderResourceBindings with unspecified resources, but such an object
2952 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
2953 suitable for creating pipelines. Such a pipeline must then always be used
2954 together with another, layout compatible QRhiShaderResourceBindings with
2955 resources present passed to QRhiCommandBuffer::setShaderResources().
2956 */
2957QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
2958 int binding, StageFlags stage, QRhiBuffer *buf)
2959{
2960 QRhiShaderResourceBinding b;
2961 b.d.binding = binding;
2962 b.d.stage = stage;
2963 b.d.type = UniformBuffer;
2964 b.d.u.ubuf.buf = buf;
2965 b.d.u.ubuf.offset = 0;
2966 b.d.u.ubuf.maybeSize = 0; // entire buffer
2967 b.d.u.ubuf.hasDynamicOffset = false;
2968 return b;
2969}
2970
2971/*!
2972 \return a shader resource binding for the given binding number, pipeline
2973 stages, and buffer specified by \a binding, \a stage, and \a buf. This
2974 overload binds a region only, as specified by \a offset and \a size.
2975
2976 \note It is up to the user to ensure the offset is aligned to
2977 QRhi::ubufAlignment().
2978
2979 \note \a size must be greater than 0.
2980
2981 \note When \a buf is not null, it must have been created with
2982 QRhiBuffer::UniformBuffer.
2983
2984 \note \a buf can be null. It is valid to create a
2985 QRhiShaderResourceBindings with unspecified resources, but such an object
2986 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
2987 suitable for creating pipelines. Such a pipeline must then always be used
2988 together with another, layout compatible QRhiShaderResourceBindings with
2989 resources present passed to QRhiCommandBuffer::setShaderResources().
2990 */
2991QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
2992 int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
2993{
2994 Q_ASSERT(size > 0);
2995 QRhiShaderResourceBinding b;
2996 b.d.binding = binding;
2997 b.d.stage = stage;
2998 b.d.type = UniformBuffer;
2999 b.d.u.ubuf.buf = buf;
3000 b.d.u.ubuf.offset = offset;
3001 b.d.u.ubuf.maybeSize = size;
3002 b.d.u.ubuf.hasDynamicOffset = false;
3003 return b;
3004}
3005
3006/*!
3007 \return a shader resource binding for the given binding number, pipeline
3008 stages, and buffer specified by \a binding, \a stage, and \a buf. The
3009 uniform buffer is assumed to have dynamic offset. The dynamic offset can be
3010 specified in QRhiCommandBuffer::setShaderResources(), thus allowing using
3011 varying offset values without creating new bindings for the buffer. The
3012 size of the bound region is specified by \a size. Like with non-dynamic
3013 offsets, \c{offset + size} cannot exceed the size of \a buf.
3014
3015 \note When \a buf is not null, it must have been created with
3016 QRhiBuffer::UniformBuffer.
3017
3018 \note \a buf can be null. It is valid to create a
3019 QRhiShaderResourceBindings with unspecified resources, but such an object
3020 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3021 suitable for creating pipelines. Such a pipeline must then always be used
3022 together with another, layout compatible QRhiShaderResourceBindings with
3023 resources present passed to QRhiCommandBuffer::setShaderResources().
3024 */
3025QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(
3026 int binding, StageFlags stage, QRhiBuffer *buf, int size)
3027{
3028 Q_ASSERT(size > 0);
3029 QRhiShaderResourceBinding b;
3030 b.d.binding = binding;
3031 b.d.stage = stage;
3032 b.d.type = UniformBuffer;
3033 b.d.u.ubuf.buf = buf;
3034 b.d.u.ubuf.offset = 0;
3035 b.d.u.ubuf.maybeSize = size;
3036 b.d.u.ubuf.hasDynamicOffset = true;
3037 return b;
3038}
3039
3040/*!
3041 \return a shader resource binding for the given binding number, pipeline
3042 stages, texture, and sampler specified by \a binding, \a stage, \a tex,
3043 \a sampler.
3044
3045 \note This function is equivalent to calling sampledTextures() with a
3046 \c count of 1.
3047
3048 \note \a tex and \a sampler can be null. It is valid to create a
3049 QRhiShaderResourceBindings with unspecified resources, but such an object
3050 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3051 suitable for creating pipelines. Such a pipeline must then always be used
3052 together with another, layout compatible QRhiShaderResourceBindings with
3053 resources present passed to QRhiCommandBuffer::setShaderResources().
3054
3055 \sa sampledTextures()
3056 */
3057QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
3058 int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
3059{
3060 QRhiShaderResourceBinding b;
3061 b.d.binding = binding;
3062 b.d.stage = stage;
3063 b.d.type = SampledTexture;
3064 b.d.u.stex.count = 1;
3065 b.d.u.stex.texSamplers[0].tex = tex;
3066 b.d.u.stex.texSamplers[0].sampler = sampler;
3067 return b;
3068}
3069
3070/*!
3071 \return a shader resource binding for the given binding number, pipeline
3072 stages, and the array of texture-sampler pairs specified by \a binding, \a
3073 stage, \a count, and \a texSamplers.
3074
3075 \note \a count must be at least 1, and not larger than 16.
3076
3077 \note When \a count is 1, this function is equivalent to sampledTexture().
3078
3079 This function is relevant when arrays of combined image samplers are
3080 involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D
3081 shadowMaps[8];} declares an array of combined image samplers. The
3082 application is then expected provide a QRhiShaderResourceBinding for
3083 binding point 5, set up by calling this function with \a count set to 8 and
3084 a valid texture and sampler for each element of the array.
3085
3086 \warning All elements of the array must be specified. With the above
3087 example, the only valid, portable approach is calling this function with a
3088 \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must
3089 be valid, meaning nullptr is not an accepted value. This is due to some of
3090 the underlying APIs, such as, Vulkan, that require a valid image and
3091 sampler object for each element in descriptor arrays. Applications are
3092 advised to provide "dummy" samplers and textures if some array elements are
3093 not relevant (due to not being accessed in the shader).
3094
3095 \note \a texSamplers can be null. It is valid to create a
3096 QRhiShaderResourceBindings with unspecified resources, but such an object
3097 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3098 suitable for creating pipelines. Such a pipeline must then always be used
3099 together with another, layout compatible QRhiShaderResourceBindings with
3100 resources present passed to QRhiCommandBuffer::setShaderResources().
3101
3102 \sa sampledTexture()
3103 */
3104QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures(
3105 int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers)
3106{
3107 Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE);
3108 QRhiShaderResourceBinding b;
3109 b.d.binding = binding;
3110 b.d.stage = stage;
3111 b.d.type = SampledTexture;
3112 b.d.u.stex.count = count;
3113 for (int i = 0; i < count; ++i) {
3114 if (texSamplers)
3115 b.d.u.stex.texSamplers[i] = texSamplers[i];
3116 else
3117 b.d.u.stex.texSamplers[i] = {};
3118 }
3119 return b;
3120}
3121
3122/*!
3123 \return a shader resource binding for a read-only storage image with the
3124 given \a binding number and pipeline \a stage. The image load operations
3125 will have access to all layers of the specified \a level. (so if the texture
3126 is a cubemap, the shader must use imageCube instead of image2D)
3127
3128 \note When \a tex is not null, it must have been created with
3129 QRhiTexture::UsedWithLoadStore.
3130
3131 \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings
3132 with unspecified resources, but such an object cannot be used with
3133 QRhiCommandBuffer::setShaderResources(). It is however suitable for creating
3134 pipelines. Such a pipeline must then always be used together with another,
3135 layout compatible QRhiShaderResourceBindings with resources present passed
3136 to QRhiCommandBuffer::setShaderResources().
3137 */
3138QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
3139 int binding, StageFlags stage, QRhiTexture *tex, int level)
3140{
3141 QRhiShaderResourceBinding b;
3142 b.d.binding = binding;
3143 b.d.stage = stage;
3144 b.d.type = ImageLoad;
3145 b.d.u.simage.tex = tex;
3146 b.d.u.simage.level = level;
3147 return b;
3148}
3149
3150/*!
3151 \return a shader resource binding for a write-only storage image with the
3152 given \a binding number and pipeline \a stage. The image store operations
3153 will have access to all layers of the specified \a level. (so if the texture
3154 is a cubemap, the shader must use imageCube instead of image2D)
3155
3156 \note When \a tex is not null, it must have been created with
3157 QRhiTexture::UsedWithLoadStore.
3158
3159 \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings
3160 with unspecified resources, but such an object cannot be used with
3161 QRhiCommandBuffer::setShaderResources(). It is however suitable for creating
3162 pipelines. Such a pipeline must then always be used together with another,
3163 layout compatible QRhiShaderResourceBindings with resources present passed
3164 to QRhiCommandBuffer::setShaderResources().
3165 */
3166QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
3167 int binding, StageFlags stage, QRhiTexture *tex, int level)
3168{
3169 QRhiShaderResourceBinding b;
3170 b.d.binding = binding;
3171 b.d.stage = stage;
3172 b.d.type = ImageStore;
3173 b.d.u.simage.tex = tex;
3174 b.d.u.simage.level = level;
3175 return b;
3176}
3177
3178/*!
3179 \return a shader resource binding for a read/write storage image with the
3180 given \a binding number and pipeline \a stage. The image load/store operations
3181 will have access to all layers of the specified \a level. (so if the texture
3182 is a cubemap, the shader must use imageCube instead of image2D)
3183
3184 \note When \a tex is not null, it must have been created with
3185 QRhiTexture::UsedWithLoadStore.
3186
3187 \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings
3188 with unspecified resources, but such an object cannot be used with
3189 QRhiCommandBuffer::setShaderResources(). It is however suitable for creating
3190 pipelines. Such a pipeline must then always be used together with another,
3191 layout compatible QRhiShaderResourceBindings with resources present passed
3192 to QRhiCommandBuffer::setShaderResources().
3193 */
3194QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
3195 int binding, StageFlags stage, QRhiTexture *tex, int level)
3196{
3197 QRhiShaderResourceBinding b;
3198 b.d.binding = binding;
3199 b.d.stage = stage;
3200 b.d.type = ImageLoadStore;
3201 b.d.u.simage.tex = tex;
3202 b.d.u.simage.level = level;
3203 return b;
3204}
3205
3206/*!
3207 \return a shader resource binding for a read-only storage buffer with the
3208 given \a binding number and pipeline \a stage.
3209
3210 \note When \a buf is not null, must have been created with
3211 QRhiBuffer::StorageBuffer.
3212
3213 \note \a buf can be null. It is valid to create a
3214 QRhiShaderResourceBindings with unspecified resources, but such an object
3215 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3216 suitable for creating pipelines. Such a pipeline must then always be used
3217 together with another, layout compatible QRhiShaderResourceBindings with
3218 resources present passed to QRhiCommandBuffer::setShaderResources().
3219 */
3220QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
3221 int binding, StageFlags stage, QRhiBuffer *buf)
3222{
3223 QRhiShaderResourceBinding b;
3224 b.d.binding = binding;
3225 b.d.stage = stage;
3226 b.d.type = BufferLoad;
3227 b.d.u.sbuf.buf = buf;
3228 b.d.u.sbuf.offset = 0;
3229 b.d.u.sbuf.maybeSize = 0; // entire buffer
3230 return b;
3231}
3232
3233/*!
3234 \return a shader resource binding for a read-only storage buffer with the
3235 given \a binding number and pipeline \a stage. This overload binds a region
3236 only, as specified by \a offset and \a size.
3237
3238 \note When \a buf is not null, must have been created with
3239 QRhiBuffer::StorageBuffer.
3240
3241 \note \a buf can be null. It is valid to create a
3242 QRhiShaderResourceBindings with unspecified resources, but such an object
3243 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3244 suitable for creating pipelines. Such a pipeline must then always be used
3245 together with another, layout compatible QRhiShaderResourceBindings with
3246 resources present passed to QRhiCommandBuffer::setShaderResources().
3247 */
3248QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
3249 int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
3250{
3251 Q_ASSERT(size > 0);
3252 QRhiShaderResourceBinding b;
3253 b.d.binding = binding;
3254 b.d.stage = stage;
3255 b.d.type = BufferLoad;
3256 b.d.u.sbuf.buf = buf;
3257 b.d.u.sbuf.offset = offset;
3258 b.d.u.sbuf.maybeSize = size;
3259 return b;
3260}
3261
3262/*!
3263 \return a shader resource binding for a write-only storage buffer with the
3264 given \a binding number and pipeline \a stage.
3265
3266 \note When \a buf is not null, must have been created with
3267 QRhiBuffer::StorageBuffer.
3268
3269 \note \a buf can be null. It is valid to create a
3270 QRhiShaderResourceBindings with unspecified resources, but such an object
3271 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3272 suitable for creating pipelines. Such a pipeline must then always be used
3273 together with another, layout compatible QRhiShaderResourceBindings with
3274 resources present passed to QRhiCommandBuffer::setShaderResources().
3275 */
3276QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
3277 int binding, StageFlags stage, QRhiBuffer *buf)
3278{
3279 QRhiShaderResourceBinding b;
3280 b.d.binding = binding;
3281 b.d.stage = stage;
3282 b.d.type = BufferStore;
3283 b.d.u.sbuf.buf = buf;
3284 b.d.u.sbuf.offset = 0;
3285 b.d.u.sbuf.maybeSize = 0; // entire buffer
3286 return b;
3287}
3288
3289/*!
3290 \return a shader resource binding for a write-only storage buffer with the
3291 given \a binding number and pipeline \a stage. This overload binds a region
3292 only, as specified by \a offset and \a size.
3293
3294 \note When \a buf is not null, must have been created with
3295 QRhiBuffer::StorageBuffer.
3296
3297 \note \a buf can be null. It is valid to create a
3298 QRhiShaderResourceBindings with unspecified resources, but such an object
3299 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3300 suitable for creating pipelines. Such a pipeline must then always be used
3301 together with another, layout compatible QRhiShaderResourceBindings with
3302 resources present passed to QRhiCommandBuffer::setShaderResources().
3303 */
3304QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
3305 int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
3306{
3307 Q_ASSERT(size > 0);
3308 QRhiShaderResourceBinding b;
3309 b.d.binding = binding;
3310 b.d.stage = stage;
3311 b.d.type = BufferStore;
3312 b.d.u.sbuf.buf = buf;
3313 b.d.u.sbuf.offset = offset;
3314 b.d.u.sbuf.maybeSize = size;
3315 return b;
3316}
3317
3318/*!
3319 \return a shader resource binding for a read-write storage buffer with the
3320 given \a binding number and pipeline \a stage.
3321
3322 \note When \a buf is not null, must have been created with
3323 QRhiBuffer::StorageBuffer.
3324
3325 \note \a buf can be null. It is valid to create a
3326 QRhiShaderResourceBindings with unspecified resources, but such an object
3327 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3328 suitable for creating pipelines. Such a pipeline must then always be used
3329 together with another, layout compatible QRhiShaderResourceBindings with
3330 resources present passed to QRhiCommandBuffer::setShaderResources().
3331 */
3332QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
3333 int binding, StageFlags stage, QRhiBuffer *buf)
3334{
3335 QRhiShaderResourceBinding b;
3336 b.d.binding = binding;
3337 b.d.stage = stage;
3338 b.d.type = BufferLoadStore;
3339 b.d.u.sbuf.buf = buf;
3340 b.d.u.sbuf.offset = 0;
3341 b.d.u.sbuf.maybeSize = 0; // entire buffer
3342 return b;
3343}
3344
3345/*!
3346 \return a shader resource binding for a read-write storage buffer with the
3347 given \a binding number and pipeline \a stage. This overload binds a region
3348 only, as specified by \a offset and \a size.
3349
3350 \note When \a buf is not null, must have been created with
3351 QRhiBuffer::StorageBuffer.
3352
3353 \note \a buf can be null. It is valid to create a
3354 QRhiShaderResourceBindings with unspecified resources, but such an object
3355 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
3356 suitable for creating pipelines. Such a pipeline must then always be used
3357 together with another, layout compatible QRhiShaderResourceBindings with
3358 resources present passed to QRhiCommandBuffer::setShaderResources().
3359 */
3360QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
3361 int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
3362{
3363 Q_ASSERT(size > 0);
3364 QRhiShaderResourceBinding b;
3365 b.d.binding = binding;
3366 b.d.stage = stage;
3367 b.d.type = BufferLoadStore;
3368 b.d.u.sbuf.buf = buf;
3369 b.d.u.sbuf.offset = offset;
3370 b.d.u.sbuf.maybeSize = size;
3371 return b;
3372}
3373
3374/*!
3375 \return \c true if the contents of the two QRhiShaderResourceBinding
3376 objects \a a and \a b are equal. This includes the resources (buffer,
3377 texture) and related parameters (offset, size) as well. To only compare
3378 layouts (binding point, pipeline stage, resource type), use
3379 \l{QRhiShaderResourceBinding::isLayoutCompatible()}{isLayoutCompatible()}
3380 instead.
3381
3382 \relates QRhiShaderResourceBinding
3383 */
3384bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept
3385{
3386 const QRhiShaderResourceBinding::Data *da = a.data();
3387 const QRhiShaderResourceBinding::Data *db = b.data();
3388
3389 if (da == db)
3390 return true;
3391
3392
3393 if (da->binding != db->binding
3394 || da->stage != db->stage
3395 || da->type != db->type)
3396 {
3397 return false;
3398 }
3399
3400 switch (da->type) {
3401 case QRhiShaderResourceBinding::UniformBuffer:
3402 if (da->u.ubuf.buf != db->u.ubuf.buf
3403 || da->u.ubuf.offset != db->u.ubuf.offset
3404 || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
3405 {
3406 return false;
3407 }
3408 break;
3409 case QRhiShaderResourceBinding::SampledTexture:
3410 if (da->u.stex.count != db->u.stex.count)
3411 return false;
3412 for (int i = 0; i < da->u.stex.count; ++i) {
3413 if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex
3414 || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler)
3415 {
3416 return false;
3417 }
3418 }
3419 break;
3420 case QRhiShaderResourceBinding::ImageLoad:
3421 Q_FALLTHROUGH();
3422 case QRhiShaderResourceBinding::ImageStore:
3423 Q_FALLTHROUGH();
3424 case QRhiShaderResourceBinding::ImageLoadStore:
3425 if (da->u.simage.tex != db->u.simage.tex
3426 || da->u.simage.level != db->u.simage.level)
3427 {
3428 return false;
3429 }
3430 break;
3431 case QRhiShaderResourceBinding::BufferLoad:
3432 Q_FALLTHROUGH();
3433 case QRhiShaderResourceBinding::BufferStore:
3434 Q_FALLTHROUGH();
3435 case QRhiShaderResourceBinding::BufferLoadStore:
3436 if (da->u.sbuf.buf != db->u.sbuf.buf
3437 || da->u.sbuf.offset != db->u.sbuf.offset
3438 || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
3439 {
3440 return false;
3441 }
3442 break;
3443 default:
3444 Q_UNREACHABLE();
3445 return false;
3446 }
3447
3448 return true;
3449}
3450
3451/*!
3452 \return \c false if all the bindings in the two QRhiShaderResourceBinding
3453 objects \a a and \a b are equal; otherwise returns \c true.
3454
3455 \relates QRhiShaderResourceBinding
3456 */
3457bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept
3458{
3459 return !(a == b);
3460}
3461
3462/*!
3463 \return the hash value for \a b, using \a seed to seed the calculation.
3464
3465 \relates QRhiShaderResourceBinding
3466 */
3467size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept
3468{
3469 const QRhiShaderResourceBinding::Data *d = b.data();
3470 size_t h = uint(d->binding) ^ uint(d->stage) ^ uint(d->type) ^ seed;
3471 switch (d->type) {
3472 case QRhiShaderResourceBinding::UniformBuffer:
3473 h ^= qHash(reinterpret_cast<quintptr>(d->u.ubuf.buf));
3474 break;
3475 case QRhiShaderResourceBinding::SampledTexture:
3476 h ^= qHash(reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex));
3477 h ^= qHash(reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler));
3478 break;
3479 case QRhiShaderResourceBinding::ImageLoad:
3480 Q_FALLTHROUGH();
3481 case QRhiShaderResourceBinding::ImageStore:
3482 Q_FALLTHROUGH();
3483 case QRhiShaderResourceBinding::ImageLoadStore:
3484 h ^= qHash(reinterpret_cast<quintptr>(d->u.simage.tex));
3485 break;
3486 case QRhiShaderResourceBinding::BufferLoad:
3487 Q_FALLTHROUGH();
3488 case QRhiShaderResourceBinding::BufferStore:
3489 Q_FALLTHROUGH();
3490 case QRhiShaderResourceBinding::BufferLoadStore:
3491 h ^= qHash(reinterpret_cast<quintptr>(d->u.sbuf.buf));
3492 break;
3493 default:
3494 break;
3495 }
3496 return h;
3497}
3498
3499#ifndef QT_NO_DEBUG_STREAM
3500QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
3501{
3502 QDebugStateSaver saver(dbg);
3503 const QRhiShaderResourceBinding::Data *d = b.data();
3504 dbg.nospace() << "QRhiShaderResourceBinding("
3505 << "binding=" << d->binding
3506 << " stage=" << d->stage
3507 << " type=" << d->type;
3508 switch (d->type) {
3509 case QRhiShaderResourceBinding::UniformBuffer:
3510 dbg.nospace() << " UniformBuffer("
3511 << "buffer=" << d->u.ubuf.buf
3512 << " offset=" << d->u.ubuf.offset
3513 << " maybeSize=" << d->u.ubuf.maybeSize
3514 << ')';
3515 break;
3516 case QRhiShaderResourceBinding::SampledTexture:
3517 dbg.nospace() << " SampledTextures("
3518 << "count=" << d->u.stex.count;
3519 for (int i = 0; i < d->u.stex.count; ++i) {
3520 dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex
3521 << " sampler=" << d->u.stex.texSamplers[i].sampler;
3522 }
3523 dbg.nospace() << ')';
3524 break;
3525 case QRhiShaderResourceBinding::ImageLoad:
3526 dbg.nospace() << " ImageLoad("
3527 << "texture=" << d->u.simage.tex
3528 << " level=" << d->u.simage.level
3529 << ')';
3530 break;
3531 case QRhiShaderResourceBinding::ImageStore:
3532 dbg.nospace() << " ImageStore("
3533 << "texture=" << d->u.simage.tex
3534 << " level=" << d->u.simage.level
3535 << ')';
3536 break;
3537 case QRhiShaderResourceBinding::ImageLoadStore:
3538 dbg.nospace() << " ImageLoadStore("
3539 << "texture=" << d->u.simage.tex
3540 << " level=" << d->u.simage.level
3541 << ')';
3542 break;
3543 case QRhiShaderResourceBinding::BufferLoad:
3544 dbg.nospace() << " BufferLoad("
3545 << "buffer=" << d->u.sbuf.buf
3546 << " offset=" << d->u.sbuf.offset
3547 << " maybeSize=" << d->u.sbuf.maybeSize
3548 << ')';
3549 break;
3550 case QRhiShaderResourceBinding::BufferStore:
3551 dbg.nospace() << " BufferStore("
3552 << "buffer=" << d->u.sbuf.buf
3553 << " offset=" << d->u.sbuf.offset
3554 << " maybeSize=" << d->u.sbuf.maybeSize
3555 << ')';
3556 break;
3557 case QRhiShaderResourceBinding::BufferLoadStore:
3558 dbg.nospace() << " BufferLoadStore("
3559 << "buffer=" << d->u.sbuf.buf
3560 << " offset=" << d->u.sbuf.offset
3561 << " maybeSize=" << d->u.sbuf.maybeSize
3562 << ')';
3563 break;
3564 default:
3565 dbg.nospace() << " UNKNOWN()";
3566 break;
3567 }
3568 dbg.nospace() << ')';
3569 return dbg;
3570}
3571#endif
3572
3573#ifndef QT_NO_DEBUG_STREAM
3574QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
3575{
3576 QDebugStateSaver saver(dbg);
3577 dbg.nospace() << "QRhiShaderResourceBindings("
3578 << srb.m_bindings
3579 << ')';
3580 return dbg;
3581}
3582#endif
3583
3584/*!
3585 \class QRhiGraphicsPipeline
3586 \internal
3587 \inmodule QtGui
3588 \brief Graphics pipeline state resource.
3589
3590 \note Setting the shader stages is mandatory. There must be at least one
3591 stage, and there must be a vertex stage.
3592
3593 \note Setting the shader resource bindings is mandatory. The referenced
3594 QRhiShaderResourceBindings must already have create() called on it by the
3595 time create() is called. Associating with a QRhiShaderResourceBindings that
3596 has no bindings is also valid, as long as no shader in any stage expects
3597 any resources.
3598
3599 \note Setting the render pass descriptor is mandatory. To obtain a
3600 QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(),
3601 use either QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() or
3602 QRhiSwapChain::newCompatibleRenderPassDescriptor().
3603
3604 \note Setting the vertex input layout is mandatory.
3605
3606 \note sampleCount() defaults to 1 and must match the sample count of the
3607 render target's color and depth stencil attachments.
3608
3609 \note The depth test, depth write, and stencil test are disabled by
3610 default.
3611
3612 \note stencilReadMask() and stencilWriteMask() apply to both faces. They
3613 both default to 0xFF.
3614 */
3615
3616/*!
3617 \fn void QRhiGraphicsPipeline::setTargetBlends(const QList<TargetBlend> &blends)
3618
3619 Sets the blend specification for color attachments. Each element in \a
3620 blends corresponds to a color attachment of the render target.
3621
3622 By default no blends are set, which is a shortcut to disabling blending and
3623 enabling color write for all four channels.
3624 */
3625
3626/*!
3627 \enum QRhiGraphicsPipeline::Flag
3628
3629 Flag values for describing the dynamic state of the pipeline, and other
3630 options. The viewport is always dynamic.
3631
3632 \value UsesBlendConstants Indicates that a blend color constant will be set
3633 via QRhiCommandBuffer::setBlendConstants()
3634
3635 \value UsesStencilRef Indicates that a stencil reference value will be set
3636 via QRhiCommandBuffer::setStencilRef()
3637
3638 \value UsesScissor Indicates that a scissor rectangle will be set via
3639 QRhiCommandBuffer::setScissor()
3640
3641 \value CompileShadersWithDebugInfo Requests compiling shaders with debug
3642 information enabled. This is relevant only when runtime shader compilation
3643 from source code is involved, and only when the underlying infrastructure
3644 supports this. With concrete examples, this is not relevant with Vulkan and
3645 SPIR-V, because the GLSL-to-SPIR-V compilation does not happen at run
3646 time. On the other hand, consider Direct3D and HLSL, where there are
3647 multiple options: when the QShader packages ship with pre-compiled bytecode
3648 (\c DXBC), debug information is to be requested through the tool that
3649 generates the \c{.qsb} file, similarly to the case of Vulkan and
3650 SPIR-V. However, when having HLSL source code in the pre- or
3651 runtime-generated QShader packages, the first phase of compilation (HLSL
3652 source to intermediate format) happens at run time too, with this flag taken
3653 into account. Debug information is relevant in particular with tools like
3654 RenderDoc since it allows seeing the original source code when investigating
3655 the pipeline and when performing vertex or fragment shader debugging.
3656 */
3657
3658/*!
3659 \enum QRhiGraphicsPipeline::Topology
3660 Specifies the primitive topology
3661
3662 \value Triangles (default)
3663 \value TriangleStrip
3664 \value TriangleFan (only available if QRhi::TriangleFanTopology is supported)
3665 \value Lines
3666 \value LineStrip
3667 \value Points
3668 */
3669
3670/*!
3671 \enum QRhiGraphicsPipeline::CullMode
3672 Specifies the culling mode
3673
3674 \value None No culling (default)
3675 \value Front Cull front faces
3676 \value Back Cull back faces
3677 */
3678
3679/*!
3680 \enum QRhiGraphicsPipeline::FrontFace
3681 Specifies the front face winding order
3682
3683 \value CCW Counter clockwise (default)
3684 \value CW Clockwise
3685 */
3686
3687/*!
3688 \enum QRhiGraphicsPipeline::ColorMaskComponent
3689 Flag values for specifying the color write mask
3690
3691 \value R
3692 \value G
3693 \value B
3694 \value A
3695 */
3696
3697/*!
3698 \enum QRhiGraphicsPipeline::BlendFactor
3699 Specifies the blend factor
3700
3701 \value Zero
3702 \value One
3703 \value SrcColor
3704 \value OneMinusSrcColor
3705 \value DstColor
3706 \value OneMinusDstColor
3707 \value SrcAlpha
3708 \value OneMinusSrcAlpha
3709 \value DstAlpha
3710 \value OneMinusDstAlpha
3711 \value ConstantColor
3712 \value OneMinusConstantColor
3713 \value ConstantAlpha
3714 \value OneMinusConstantAlpha
3715 \value SrcAlphaSaturate
3716 \value Src1Color
3717 \value OneMinusSrc1Color
3718 \value Src1Alpha
3719 \value OneMinusSrc1Alpha
3720 */
3721
3722/*!
3723 \enum QRhiGraphicsPipeline::BlendOp
3724 Specifies the blend operation
3725
3726 \value Add
3727 \value Subtract
3728 \value ReverseSubtract
3729 \value Min
3730 \value Max
3731 */
3732
3733/*!
3734 \enum QRhiGraphicsPipeline::CompareOp
3735 Specifies the depth or stencil comparison function
3736
3737 \value Never
3738 \value Less (default for depth)
3739 \value Equal
3740 \value LessOrEqual
3741 \value Greater
3742 \value NotEqual
3743 \value GreaterOrEqual
3744 \value Always (default for stencil)
3745 */
3746
3747/*!
3748 \enum QRhiGraphicsPipeline::StencilOp
3749 Specifies the stencil operation
3750
3751 \value StencilZero
3752 \value Keep (default)
3753 \value Replace
3754 \value IncrementAndClamp
3755 \value DecrementAndClamp
3756 \value Invert
3757 \value IncrementAndWrap
3758 \value DecrementAndWrap
3759 */
3760
3761/*!
3762 \class QRhiGraphicsPipeline::TargetBlend
3763 \internal
3764 \inmodule QtGui
3765 \brief Describes the blend state for one color attachment.
3766
3767 Defaults to color write enabled, blending disabled. The blend values are
3768 set up for pre-multiplied alpha (One, OneMinusSrcAlpha, One,
3769 OneMinusSrcAlpha) by default.
3770 */
3771
3772/*!
3773 \class QRhiGraphicsPipeline::StencilOpState
3774 \internal
3775 \inmodule QtGui
3776 \brief Describes the stencil operation state.
3777 */
3778
3779/*!
3780 \internal
3781 */
3782QRhiGraphicsPipeline::QRhiGraphicsPipeline(QRhiImplementation *rhi)
3783 : QRhiResource(rhi)
3784{
3785}
3786
3787/*!
3788 \return the resource type.
3789 */
3790QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
3791{
3792 return GraphicsPipeline;
3793}
3794
3795/*!
3796 \fn bool QRhiGraphicsPipeline::create()
3797
3798 Creates the corresponding native graphics resources. If there are already
3799 resources present due to an earlier create() with no corresponding
3800 destroy(), then destroy() is called implicitly first.
3801
3802 \return \c true when successful, \c false when a graphics operation failed.
3803 Regardless of the return value, calling destroy() is always safe.
3804 */
3805
3806/*!
3807 \fn void QRhiGraphicsPipeline::setDepthTest(bool enable)
3808
3809 Enables or disables depth testing. Both depth test and the writing out of
3810 depth data are disabled by default.
3811
3812 \sa setDepthWrite()
3813 */
3814
3815/*!
3816 \fn void QRhiGraphicsPipeline::setDepthWrite(bool enable)
3817
3818 Controls the writing out of depth data into the depth buffer. By default
3819 this is disabled. Depth write is typically enabled together with the depth
3820 test.
3821
3822 \note Enabling depth write without having depth testing enabled may not
3823 lead to the desired result, and should be avoided.
3824
3825 \sa setDepthTest()
3826 */
3827
3828/*!
3829 \class QRhiSwapChain
3830 \internal
3831 \inmodule QtGui
3832 \brief Swapchain resource.
3833
3834 A swapchain enables presenting rendering results to a surface. A swapchain
3835 is typically backed by a set of color buffers. Of these, one is displayed
3836 at a time.
3837
3838 Below is a typical pattern for creating and managing a swapchain and some
3839 associated resources in order to render onto a QWindow:
3840
3841 \badcode
3842 void init()
3843 {
3844 sc = rhi->newSwapChain();
3845 ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
3846 QSize(), // no need to set the size here due to UsedWithSwapChainOnly
3847 1,
3848 QRhiRenderBuffer::UsedWithSwapChainOnly);
3849 sc->setWindow(window);
3850 sc->setDepthStencil(ds);
3851 rp = sc->newCompatibleRenderPassDescriptor();
3852 sc->setRenderPassDescriptor(rp);
3853 resizeSwapChain();
3854 }
3855
3856 void resizeSwapChain()
3857 {
3858 hasSwapChain = sc->createOrResize();
3859 }
3860
3861 void render()
3862 {
3863 if (!hasSwapChain || notExposed)
3864 return;
3865
3866 if (sc->currentPixelSize() != sc->surfacePixelSize() || newlyExposed) {
3867 resizeSwapChain();
3868 if (!hasSwapChain)
3869 return;
3870 newlyExposed = false;
3871 }
3872
3873 rhi->beginFrame(sc);
3874 // ...
3875 rhi->endFrame(sc);
3876 }
3877 \endcode
3878
3879 Avoid relying on QWindow resize events to resize swapchains, especially
3880 considering that surface sizes may not always fully match the QWindow
3881 reported dimensions. The safe, cross-platform approach is to do the check
3882 via surfacePixelSize() whenever starting a new frame.
3883
3884 Releasing the swapchain must happen while the QWindow and the underlying
3885 native window is fully up and running. Building on the previous example:
3886
3887 \badcode
3888 void releaseSwapChain()
3889 {
3890 if (hasSwapChain) {
3891 sc->destroy();
3892 hasSwapChain = false;
3893 }
3894 }
3895
3896 // assuming Window is our QWindow subclass
3897 bool Window::event(QEvent *e)
3898 {
3899 switch (e->type()) {
3900 case QEvent::UpdateRequest: // for QWindow::requestUpdate()
3901 render();
3902 break;
3903 case QEvent::PlatformSurface:
3904 if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
3905 releaseSwapChain();
3906 break;
3907 default:
3908 break;
3909 }
3910 return QWindow::event(e);
3911 }
3912 \endcode
3913
3914 Initializing the swapchain and starting to render the first frame cannot
3915 start at any time. The safe, cross-platform approach is to rely on expose
3916 events. QExposeEvent is a loosely specified event that is sent whenever a
3917 window gets mapped, obscured, and resized, depending on the platform.
3918
3919 \badcode
3920 void Window::exposeEvent(QExposeEvent *)
3921 {
3922 // initialize and start rendering when the window becomes usable for graphics purposes
3923 if (isExposed() && !running) {
3924 running = true;
3925 init();
3926 }
3927
3928 // stop pushing frames when not exposed or size becomes 0
3929 if ((!isExposed() || (hasSwapChain && sc->surfacePixelSize().isEmpty())) && running)
3930 notExposed = true;
3931
3932 // continue when exposed again and the surface has a valid size
3933 if (isExposed() && running && notExposed && !sc->surfacePixelSize().isEmpty()) {
3934 notExposed = false;
3935 newlyExposed = true;
3936 }
3937
3938 if (isExposed() && !sc->surfacePixelSize().isEmpty())
3939 render();
3940 }
3941 \endcode
3942
3943 Once the rendering has started, a simple way to request a new frame is
3944 QWindow::requestUpdate(). While on some platforms this is merely a small
3945 timer, on others it has a specific implementation: for instance on macOS or
3946 iOS it may be backed by
3947 \l{https://developer.apple.com/documentation/corevideo/cvdisplaylink?language=objc}{CVDisplayLink}.
3948 The example above is already prepared for update requests by handling
3949 QEvent::UpdateRequest.
3950
3951 While acting as a QRhiRenderTarget, QRhiSwapChain also manages a
3952 QRhiCommandBuffer. Calling QRhi::endFrame() submits the recorded commands
3953 and also enqueues a \c present request. The default behavior is to do this
3954 with a swap interval of 1, meaning synchronizing to the display's vertical
3955 refresh is enabled. Thus the rendering thread calling beginFrame() and
3956 endFrame() will get throttled to vsync. On some backends this can be
3957 disabled by passing QRhiSwapChain:NoVSync in flags().
3958
3959 Multisampling (MSAA) is handled transparently to the applications when
3960 requested via setSampleCount(). Where applicable, QRhiSwapChain will take
3961 care of creating additional color buffers and issuing a multisample resolve
3962 command at the end of a frame. For OpenGL, it is necessary to request the
3963 appropriate sample count also via QSurfaceFormat, by calling
3964 QSurfaceFormat::setDefaultFormat() before initializing the QRhi.
3965 */
3966
3967/*!
3968 \enum QRhiSwapChain::Flag
3969 Flag values to describe swapchain properties
3970
3971 \value SurfaceHasPreMulAlpha Indicates that the target surface has
3972 transparency with premultiplied alpha. For example, this is what Qt Quick
3973 uses when the alpha channel is enabled on the target QWindow, because the
3974 scenegraph rendrerer always outputs fragments with alpha multiplied into
3975 the red, green, and blue values. To ensure identical behavior across
3976 platforms, always set QSurfaceFormat::alphaBufferSize() to a non-zero value
3977 on the target QWindow whenever this flag is set on the swapchain.
3978
3979 \value SurfaceHasNonPreMulAlpha Indicates the target surface has
3980 transparency with non-premultiplied alpha. Be aware that this may not be
3981 supported on some systems, if the system compositor always expects content
3982 with premultiplied alpha. In that case the behavior with this flag set is
3983 expected to be equivalent to SurfaceHasPreMulAlpha.
3984
3985 \value sRGB Requests to pick an sRGB format for the swapchain and/or its
3986 render target views, where applicable. Note that this implies that sRGB
3987 framebuffer update and blending will get enabled for all content targeting
3988 this swapchain, and opting out is not possible. For OpenGL, set
3989 \l{QSurfaceFormat::sRGBColorSpace}{sRGBColorSpace} on the QSurfaceFormat of
3990 the QWindow in addition.
3991
3992 \value UsedAsTransferSource Indicates the swapchain will be used as the
3993 source of a readback in QRhiResourceUpdateBatch::readBackTexture().
3994
3995 \value NoVSync Requests disabling waiting for vertical sync, also avoiding
3996 throttling the rendering thread. The behavior is backend specific and
3997 applicable only where it is possible to control this. Some may ignore the
3998 request altogether. For OpenGL, try instead setting the swap interval to 0
3999 on the QWindow via QSurfaceFormat::setSwapInterval().
4000
4001 \value MinimalBufferCount Requests creating the swapchain with the minimum
4002 number of buffers, which is in practice 2, unless the graphics
4003 implementation has a higher minimum number than that. Only applicable with
4004 backends where such control is available via the graphics API, for example,
4005 Vulkan. By default it is up to the backend to decide what number of buffers
4006 it requests (in practice this is almost always either 2 or 3), and it is
4007 not the applications' concern. However, on Vulkan for instance the backend
4008 will likely prefer the higher number (3), for example to avoid odd
4009 performance issues with some Vulkan implementations on mobile devices. It
4010 could be that on some platforms it can prove to be beneficial to force the
4011 lower buffer count (2), so this flag allows forcing that. Note that all
4012 this has no effect on the number of frames kept in flight, so the CPU
4013 (QRhi) will still prepare frames at most \c{N - 1} frames ahead of the GPU,
4014 even when the swapchain image buffer count larger than \c N. (\c{N} =
4015 QRhi::FramesInFlight and typically 2).
4016 */
4017
4018/*!
4019 \internal
4020 */
4021QRhiSwapChain::QRhiSwapChain(QRhiImplementation *rhi)
4022 : QRhiResource(rhi)
4023{
4024}
4025
4026/*!
4027 \return the resource type.
4028 */
4029QRhiResource::Type QRhiSwapChain::resourceType() const
4030{
4031 return SwapChain;
4032}
4033
4034/*!
4035 \fn QSize QRhiSwapChain::currentPixelSize() const
4036
4037 \return the size with which the swapchain was last successfully built. Use
4038 this to decide if createOrResize() needs to be called again: if
4039 \c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be
4040 resized.
4041
4042 \note Typical rendering logic will call this function to get the output
4043 size when starting to prepare a new frame, and base dependent calculations
4044 (such as, the viewport) on the size returned from this function.
4045
4046 While in many cases the value is the same as \c{QWindow::size() *
4047 QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not
4048 guaranteed to be correct on all platforms and graphics API implementations.
4049 Using this function is therefore strongly recommended whenever there is a
4050 need to identify the dimensions, in pixels, of the output layer or surface.
4051
4052 This also has the added benefit of avoiding potential data races when QRhi
4053 is used on a dedicated rendering thread, because the need to call QWindow
4054 functions, that may then access data updated on the main thread, is
4055 avoided.
4056
4057 \sa surfacePixelSize()
4058 */
4059
4060/*!
4061 \fn QSize QRhiSwapChain::surfacePixelSize()
4062
4063 \return The size of the window's associated surface or layer.
4064
4065 \warning Do not assume this is the same as \c{QWindow::size() *
4066 QWindow::devicePixelRatio()}. With some graphics APIs and windowing system
4067 interfaces (for example, Vulkan) there is a theoretical possibility for a
4068 surface to assume a size different from the associated window. To support
4069 these cases, rendering logic must always base size-derived calculations
4070 (such as, viewports) on the size reported from QRhiSwapChain, and never on
4071 the size queried from QWindow.
4072
4073 \note Can also be called before createOrResize(), if at least window() is
4074 already set) This in combination with currentPixelSize() allows to detect
4075 when a swapchain needs to be resized. However, watch out for the fact that
4076 the size of the underlying native object (surface, layer, or similar) is
4077 "live", so whenever this function is called, it returns the latest value
4078 reported by the underlying implementation, without any atomicity guarantee.
4079 Therefore, using this function to determine pixel sizes for graphics
4080 resources that are used in a frame is strongly discouraged. Rely on
4081 currentPixelSize() instead which returns a size that is atomic and will not
4082 change between createOrResize() invocations.
4083
4084 \note For depth-stencil buffers used in combination with the swapchain's
4085 color buffers, it is strongly recommended to rely on the automatic sizing
4086 and rebuilding behavior provided by the
4087 QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface
4088 size via this function just to get a size that can be passed to
4089 QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of
4090 atomicity as described above.
4091
4092 \sa currentPixelSize()
4093 */
4094
4095/*!
4096 \fn QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer()
4097
4098 \return a command buffer on which rendering commands can be recorded. Only
4099 valid within a QRhi::beginFrame() - QRhi::endFrame() block where
4100 beginFrame() was called with this swapchain.
4101
4102 \note the value must not be cached and reused between frames
4103*/
4104
4105/*!
4106 \fn QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget()
4107
4108 \return a render target that can used with beginPass() in order to render
4109 the swapchain's current backbuffer. Only valid within a
4110 QRhi::beginFrame() - QRhi::endFrame() block where beginFrame() was called
4111 with this swapchain.
4112
4113 \note the value must not be cached and reused between frames
4114 */
4115
4116/*!
4117 \fn bool QRhiSwapChain::createOrResize()
4118
4119 Creates the swapchain if not already done and resizes the swapchain buffers
4120 to match the current size of the targeted surface. Call this whenever the
4121 size of the target surface is different than before.
4122
4123 \note call destroy() only when the swapchain needs to be released
4124 completely, typically upon
4125 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. To perform resizing, just
4126 call createOrResize().
4127
4128 \return \c true when successful, \c false when a graphics operation failed.
4129 Regardless of the return value, calling destroy() is always safe.
4130 */
4131
4132/*!
4133 \class QRhiComputePipeline
4134 \internal
4135 \inmodule QtGui
4136 \brief Compute pipeline state resource.
4137
4138 \note Setting the shader resource bindings is mandatory. The referenced
4139 QRhiShaderResourceBindings must already have created() called on it by the
4140 time create() is called.
4141
4142 \note Setting the shader is mandatory.
4143 */
4144
4145/*!
4146 \enum QRhiComputePipeline::Flag
4147
4148 Flag values for describing pipeline options.
4149
4150 \value CompileShadersWithDebugInfo Requests compiling shaders with debug
4151 information enabled, when applicable. See
4152 QRhiGraphicsPipeline::CompileShadersWithDebugInfo for more information.
4153 */
4154
4155/*!
4156 \return the resource type.
4157 */
4158QRhiResource::Type QRhiComputePipeline::resourceType() const
4159{
4160 return ComputePipeline;
4161}
4162
4163/*!
4164 \internal
4165 */
4166QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi)
4167 : QRhiResource(rhi)
4168{
4169}
4170
4171/*!
4172 \class QRhiCommandBuffer
4173 \internal
4174 \inmodule QtGui
4175 \brief Command buffer resource.
4176
4177 Not creatable by applications at the moment. The only ways to obtain a
4178 valid QRhiCommandBuffer are to get it from the targeted swapchain via
4179 QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering
4180 completely offscreen, initializing one via QRhi::beginOffscreenFrame().
4181 */
4182
4183/*!
4184 \enum QRhiCommandBuffer::IndexFormat
4185 Specifies the index data type
4186
4187 \value IndexUInt16 Unsigned 16-bit (quint16)
4188 \value IndexUInt32 Unsigned 32-bit (quint32)
4189 */
4190
4191/*!
4192 \enum QRhiCommandBuffer::BeginPassFlag
4193 Flag values for QRhi::beginPass()
4194
4195 \value ExternalContent Specifies that there will be a call to
4196 QRhiCommandBuffer::beginExternal() in this pass. Some backends, Vulkan in
4197 particular, will fail if this flag is not set and beginExternal() is still
4198 called.
4199
4200 \value DoNotTrackResourcesForCompute Specifies that there is no need to
4201 track resources used in this pass if the only purpose of such tracking is
4202 to generate barriers for compute. Implies that there are no compute passes
4203 in the frame. This is an optimization hint that may be taken into account
4204 by certain backends, OpenGL in particular, allowing them to skip certain
4205 operations. When this flag is set for a render pass in a frame, calling
4206 \l{QRhiCommandBuffer::beginComputePass()}{beginComputePass()} in that frame
4207 may lead to unexpected behavior, depending on the resource dependencies
4208 between the render and compute passes.
4209 */
4210
4211/*!
4212 \typedef QRhiCommandBuffer::DynamicOffset
4213
4214 Synonym for QPair<int, quint32>. The first entry is the binding, the second
4215 is the offset in the buffer.
4216*/
4217
4218/*!
4219 \typedef QRhiCommandBuffer::VertexInput
4220
4221 Synonym for QPair<QRhiBuffer *, quint32>. The second entry is an offset in
4222 the buffer specified by the first.
4223*/
4224
4225/*!
4226 \internal
4227 */
4228QRhiCommandBuffer::QRhiCommandBuffer(QRhiImplementation *rhi)
4229 : QRhiResource(rhi)
4230{
4231}
4232
4233/*!
4234 \return the resource type.
4235 */
4236QRhiResource::Type QRhiCommandBuffer::resourceType() const
4237{
4238 return CommandBuffer;
4239}
4240
4241#ifndef QT_NO_DEBUG
4242static const char *resourceTypeStr(QRhiResource *res)
4243{
4244 switch (res->resourceType()) {
4245 case QRhiResource::Buffer:
4246 return "Buffer";
4247 case QRhiResource::Texture:
4248 return "Texture";
4249 case QRhiResource::Sampler:
4250 return "Sampler";
4251 case QRhiResource::RenderBuffer:
4252 return "RenderBuffer";
4253 case QRhiResource::RenderPassDescriptor:
4254 return "RenderPassDescriptor";
4255 case QRhiResource::RenderTarget:
4256 return "RenderTarget";
4257 case QRhiResource::TextureRenderTarget:
4258 return "TextureRenderTarget";
4259 case QRhiResource::ShaderResourceBindings:
4260 return "ShaderResourceBindings";
4261 case QRhiResource::GraphicsPipeline:
4262 return "GraphicsPipeline";
4263 case QRhiResource::SwapChain:
4264 return "SwapChain";
4265 case QRhiResource::ComputePipeline:
4266 return "ComputePipeline";
4267 case QRhiResource::CommandBuffer:
4268 return "CommandBuffer";
4269 default:
4270 Q_UNREACHABLE();
4271 break;
4272 }
4273 return "";
4274}
4275#endif
4276
4277QRhiImplementation::~QRhiImplementation()
4278{
4279 qDeleteAll(resUpdPool);
4280
4281 // Be nice and show something about leaked stuff. Though we may not get
4282 // this far with some backends where the allocator or the api may check
4283 // and freak out for unfreed graphics objects in the derived dtor already.
4284#ifndef QT_NO_DEBUG
4285 if (!resources.isEmpty()) {
4286 qWarning("QRhi %p going down with %d unreleased resources that own native graphics objects. This is not nice.",
4287 q, int(resources.count()));
4288 for (QRhiResource *res : qAsConst(resources)) {
4289 qWarning(" %s resource %p (%s)", resourceTypeStr(res), res, res->m_objectName.constData());
4290 res->m_rhi = nullptr;
4291 }
4292 }
4293#endif
4294}
4295
4296bool QRhiImplementation::isCompressedFormat(QRhiTexture::Format format) const
4297{
4298 return (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7)
4299 || (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8)
4300 || (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12);
4301}
4302
4303void QRhiImplementation::compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
4304 quint32 *bpl, quint32 *byteSize,
4305 QSize *blockDim) const
4306{
4307 int xdim = 4;
4308 int ydim = 4;
4309 quint32 blockSize = 0;
4310
4311 switch (format) {
4312 case QRhiTexture::BC1:
4313 blockSize = 8;
4314 break;
4315 case QRhiTexture::BC2:
4316 blockSize = 16;
4317 break;
4318 case QRhiTexture::BC3:
4319 blockSize = 16;
4320 break;
4321 case QRhiTexture::BC4:
4322 blockSize = 8;
4323 break;
4324 case QRhiTexture::BC5:
4325 blockSize = 16;
4326 break;
4327 case QRhiTexture::BC6H:
4328 blockSize = 16;
4329 break;
4330 case QRhiTexture::BC7:
4331 blockSize = 16;
4332 break;
4333
4334 case QRhiTexture::ETC2_RGB8:
4335 blockSize = 8;
4336 break;
4337 case QRhiTexture::ETC2_RGB8A1:
4338 blockSize = 8;
4339 break;
4340 case QRhiTexture::ETC2_RGBA8:
4341 blockSize = 16;
4342 break;
4343
4344 case QRhiTexture::ASTC_4x4:
4345 blockSize = 16;
4346 break;
4347 case QRhiTexture::ASTC_5x4:
4348 blockSize = 16;
4349 xdim = 5;
4350 break;
4351 case QRhiTexture::ASTC_5x5:
4352 blockSize = 16;
4353 xdim = ydim = 5;
4354 break;
4355 case QRhiTexture::ASTC_6x5:
4356 blockSize = 16;
4357 xdim = 6;
4358 ydim = 5;
4359 break;
4360 case QRhiTexture::ASTC_6x6:
4361 blockSize = 16;
4362 xdim = ydim = 6;
4363 break;
4364 case QRhiTexture::ASTC_8x5:
4365 blockSize = 16;
4366 xdim = 8;
4367 ydim = 5;
4368 break;
4369 case QRhiTexture::ASTC_8x6:
4370 blockSize = 16;
4371 xdim = 8;
4372 ydim = 6;
4373 break;
4374 case QRhiTexture::ASTC_8x8:
4375 blockSize = 16;
4376 xdim = ydim = 8;
4377 break;
4378 case QRhiTexture::ASTC_10x5:
4379 blockSize = 16;
4380 xdim = 10;
4381 ydim = 5;
4382 break;
4383 case QRhiTexture::ASTC_10x6:
4384 blockSize = 16;
4385 xdim = 10;
4386 ydim = 6;
4387 break;
4388 case QRhiTexture::ASTC_10x8:
4389 blockSize = 16;
4390 xdim = 10;
4391 ydim = 8;
4392 break;
4393 case QRhiTexture::ASTC_10x10:
4394 blockSize = 16;
4395 xdim = ydim = 10;
4396 break;
4397 case QRhiTexture::ASTC_12x10:
4398 blockSize = 16;
4399 xdim = 12;
4400 ydim = 10;
4401 break;
4402 case QRhiTexture::ASTC_12x12:
4403 blockSize = 16;
4404 xdim = ydim = 12;
4405 break;
4406
4407 default:
4408 Q_UNREACHABLE();
4409 break;
4410 }
4411
4412 const quint32 wblocks = uint((size.width() + xdim - 1) / xdim);
4413 const quint32 hblocks = uint((size.height() + ydim - 1) / ydim);
4414
4415 if (bpl)
4416 *bpl = wblocks * blockSize;
4417 if (byteSize)
4418 *byteSize = wblocks * hblocks * blockSize;
4419 if (blockDim)
4420 *blockDim = QSize(xdim, ydim);
4421}
4422
4423void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSize &size,
4424 quint32 *bpl, quint32 *byteSize) const
4425{
4426 if (isCompressedFormat(format)) {
4427 compressedFormatInfo(format, size, bpl, byteSize, nullptr);
4428 return;
4429 }
4430
4431 quint32 bpc = 0;
4432 switch (format) {
4433 case QRhiTexture::RGBA8:
4434 bpc = 4;
4435 break;
4436 case QRhiTexture::BGRA8:
4437 bpc = 4;
4438 break;
4439 case QRhiTexture::R8:
4440 bpc = 1;
4441 break;
4442 case QRhiTexture::RG8:
4443 bpc = 2;
4444 break;
4445 case QRhiTexture::R16:
4446 bpc = 2;
4447 break;
4448 case QRhiTexture::RED_OR_ALPHA8:
4449 bpc = 1;
4450 break;
4451
4452 case QRhiTexture::RGBA16F:
4453 bpc = 8;
4454 break;
4455 case QRhiTexture::RGBA32F:
4456 bpc = 16;
4457 break;
4458 case QRhiTexture::R16F:
4459 bpc = 2;
4460 break;
4461 case QRhiTexture::R32F:
4462 bpc = 4;
4463 break;
4464
4465 case QRhiTexture::D16:
4466 bpc = 2;
4467 break;
4468 case QRhiTexture::D24:
4469 case QRhiTexture::D24S8:
4470 case QRhiTexture::D32F:
4471 bpc = 4;
4472 break;
4473
4474 default:
4475 Q_UNREACHABLE();
4476 break;
4477 }
4478
4479 if (bpl)
4480 *bpl = uint(size.width()) * bpc;
4481 if (byteSize)
4482 *byteSize = uint(size.width() * size.height()) * bpc;
4483}
4484
4485// Approximate because it excludes subresource alignment or multisampling.
4486quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format, const QSize &baseSize,
4487 int mipCount, int layerCount)
4488{
4489 quint32 approxSize = 0;
4490 for (int level = 0; level < mipCount; ++level) {
4491 quint32 byteSize = 0;
4492 const QSize size(qFloor(qreal(qMax(1, baseSize.width() >> level))),
4493 qFloor(qreal(qMax(1, baseSize.height() >> level))));
4494 textureFormatInfo(format, size, nullptr, &byteSize);
4495 approxSize += byteSize;
4496 }
4497 approxSize *= uint(layerCount);
4498 return approxSize;
4499}
4500
4501bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps)
4502{
4503 if (ps->cbeginShaderStages() == ps->cendShaderStages()) {
4504 qWarning("Cannot build a graphics pipeline without any stages");
4505 return false;
4506 }
4507
4508 bool hasVertexStage = false;
4509 for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) {
4510 if (!it->shader().isValid()) {
4511 qWarning("Empty shader passed to graphics pipeline");
4512 return false;
4513 }
4514 if (it->type() == QRhiShaderStage::Vertex)
4515 hasVertexStage = true;
4516 }
4517 if (!hasVertexStage) {
4518 qWarning("Cannot build a graphics pipeline without a vertex stage");
4519 return false;
4520 }
4521
4522 if (!ps->renderPassDescriptor()) {
4523 qWarning("Cannot build a graphics pipeline without a QRhiRenderPassDescriptor");
4524 return false;
4525 }
4526
4527 if (!ps->shaderResourceBindings()) {
4528 qWarning("Cannot build a graphics pipeline without QRhiShaderResourceBindings");
4529 return false;
4530 }
4531
4532 return true;
4533}
4534
4535bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb)
4536{
4537#ifndef QT_NO_DEBUG
4538 bool bindingsOk = true;
4539 const int CHECKED_BINDINGS_COUNT = 64;
4540 bool bindingSeen[CHECKED_BINDINGS_COUNT] = {};
4541 for (auto it = srb->cbeginBindings(), end = srb->cendBindings(); it != end; ++it) {
4542 const int binding = it->data()->binding;
4543 if (binding >= CHECKED_BINDINGS_COUNT)
4544 continue;
4545 if (binding < 0) {
4546 qWarning("Invalid binding number %d", binding);
4547 bindingsOk = false;
4548 continue;
4549 }
4550 switch (it->data()->type) {
4551 case QRhiShaderResourceBinding::UniformBuffer:
4552 if (!bindingSeen[binding]) {
4553 bindingSeen[binding] = true;
4554 } else {
4555 qWarning("Uniform buffer duplicates an existing binding number %d", binding);
4556 bindingsOk = false;
4557 }
4558 break;
4559 case QRhiShaderResourceBinding::SampledTexture:
4560 if (!bindingSeen[binding]) {
4561 bindingSeen[binding] = true;
4562 } else {
4563 qWarning("Combined image sampler duplicates an existing binding number %d", binding);
4564 bindingsOk = false;
4565 }
4566 break;
4567 case QRhiShaderResourceBinding::ImageLoad:
4568 Q_FALLTHROUGH();
4569 case QRhiShaderResourceBinding::ImageStore:
4570 Q_FALLTHROUGH();
4571 case QRhiShaderResourceBinding::ImageLoadStore:
4572 if (!bindingSeen[binding]) {
4573 bindingSeen[binding] = true;
4574 } else {
4575 qWarning("Image duplicates an existing binding number %d", binding);
4576 bindingsOk = false;
4577 }
4578 break;
4579 case QRhiShaderResourceBinding::BufferLoad:
4580 Q_FALLTHROUGH();
4581 case QRhiShaderResourceBinding::BufferStore:
4582 Q_FALLTHROUGH();
4583 case QRhiShaderResourceBinding::BufferLoadStore:
4584 if (!bindingSeen[binding]) {
4585 bindingSeen[binding] = true;
4586 } else {
4587 qWarning("Buffer duplicates an existing binding number %d", binding);
4588 bindingsOk = false;
4589 }
4590 break;
4591 default:
4592 qWarning("Unknown binding type %d", int(it->data()->type));
4593 bindingsOk = false;
4594 break;
4595 }
4596 }
4597
4598 if (!bindingsOk) {
4599 qWarning() << *srb;
4600 return false;
4601 }
4602#else
4603 Q_UNUSED(srb);
4604#endif
4605 return true;
4606}
4607
4608/*!
4609 \internal
4610 */
4611QRhi::QRhi()
4612{
4613}
4614
4615/*!
4616 Destructor. Destroys the backend and releases resources.
4617 */
4618QRhi::~QRhi()
4619{
4620 if (!d)
4621 return;
4622
4623 qDeleteAll(d->pendingDeleteResources);
4624 d->pendingDeleteResources.clear();
4625
4626 runCleanup();
4627
4628 d->destroy();
4629 delete d;
4630}
4631
4632/*!
4633 \return a new QRhi instance with a backend for the graphics API specified by \a impl.
4634
4635 \a params must point to an instance of one of the backend-specific
4636 subclasses of QRhiInitParams, such as, QRhiVulkanInitParams,
4637 QRhiMetalInitParams, QRhiD3D11InitParams, QRhiGles2InitParams. See these
4638 classes for examples on creating a QRhi.
4639
4640 \a flags is optional. It is used to enable profile and debug related
4641 features that are potentially expensive and should only be used during
4642 development.
4643 */
4644QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice)
4645{
4646 QScopedPointer<QRhi> r(new QRhi);
4647
4648 switch (impl) {
4649 case Null:
4650 r->d = new QRhiNull(static_cast<QRhiNullInitParams *>(params));
4651 break;
4652 case Vulkan:
4653#if QT_CONFIG(vulkan)
4654 r->d = new QRhiVulkan(static_cast<QRhiVulkanInitParams *>(params),
4655 static_cast<QRhiVulkanNativeHandles *>(importDevice));
4656 break;
4657#else
4658 Q_UNUSED(importDevice);
4659 qWarning("This build of Qt has no Vulkan support");
4660 break;
4661#endif
4662 case OpenGLES2:
4663#ifndef QT_NO_OPENGL
4664 r->d = new QRhiGles2(static_cast<QRhiGles2InitParams *>(params),
4665 static_cast<QRhiGles2NativeHandles *>(importDevice));
4666 break;
4667#else
4668 qWarning("This build of Qt has no OpenGL support");
4669 break;
4670#endif
4671 case D3D11:
4672#ifdef Q_OS_WIN
4673 r->d = new QRhiD3D11(static_cast<QRhiD3D11InitParams *>(params),
4674 static_cast<QRhiD3D11NativeHandles *>(importDevice));
4675 break;
4676#else
4677 qWarning("This platform has no Direct3D 11 support");
4678 break;
4679#endif
4680 case Metal:
4681#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
4682 r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params),
4683 static_cast<QRhiMetalNativeHandles *>(importDevice));
4684 break;
4685#else
4686 qWarning("This platform has no Metal support");
4687 break;
4688#endif
4689 default:
4690 break;
4691 }
4692
4693 if (r->d) {
4694 r->d->q = r.data();
4695
4696 if (flags.testFlag(EnableProfiling)) {
4697 QRhiProfilerPrivate *profD = QRhiProfilerPrivate::get(&r->d->profiler);
4698 profD->rhiDWhenEnabled = r->d;
4699 const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(QtDebugMsg, true);
4700 }
4701
4702 // Play nice with QSG_INFO since that is still the most commonly used
4703 // way to get graphics info printed from Qt Quick apps, and the Quick
4704 // scenegraph is our primary user.
4705 if (qEnvironmentVariableIsSet("QSG_INFO"))
4706 const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(QtDebugMsg, true);
4707
4708 r->d->debugMarkers = flags.testFlag(EnableDebugMarkers);
4709
4710 if (r->d->create(flags)) {
4711 r->d->implType = impl;
4712 r->d->implThread = QThread::currentThread();
4713 return r.take();
4714 }
4715 }
4716
4717 return nullptr;
4718}
4719
4720/*!
4721 \return the backend type for this QRhi.
4722 */
4723QRhi::Implementation QRhi::backend() const
4724{
4725 return d->implType;
4726}
4727
4728/*!
4729 \return the thread on which the QRhi was \l{QRhi::create()}{initialized}.
4730 */
4731QThread *QRhi::thread() const
4732{
4733 return d->implThread;
4734}
4735
4736/*!
4737 Registers a \a callback that is invoked either when the QRhi is destroyed,
4738 or when runCleanup() is called.
4739
4740 The callback will run with the graphics resource still available, so this
4741 provides an opportunity for the application to cleanly release QRhiResource
4742 instances belonging to the QRhi. This is particularly useful for managing
4743 the lifetime of resources stored in \c cache type of objects, where the
4744 cache holds QRhiResources or objects containing QRhiResources.
4745
4746 \sa runCleanup(), ~QRhi()
4747 */
4748void QRhi::addCleanupCallback(const CleanupCallback &callback)
4749{
4750 d->addCleanupCallback(callback);
4751}
4752
4753/*!
4754 Invokes all registered cleanup functions. The list of cleanup callbacks it
4755 then cleared. Normally destroying the QRhi does this automatically, but
4756 sometimes it can be useful to trigger cleanup in order to release all
4757 cached, non-essential resources.
4758
4759 \sa addCleanupCallback()
4760 */
4761void QRhi::runCleanup()
4762{
4763 for (const CleanupCallback &f : qAsConst(d->cleanupCallbacks))
4764 f(this);
4765
4766 d->cleanupCallbacks.clear();
4767}
4768
4769/*!
4770 \class QRhiResourceUpdateBatch
4771 \internal
4772 \inmodule QtGui
4773 \brief Records upload and copy type of operations.
4774
4775 With QRhi it is no longer possible to perform copy type of operations at
4776 arbitrary times. Instead, all such operations are recorded into batches
4777 that are then passed, most commonly, to QRhiCommandBuffer::beginPass().
4778 What then happens under the hood is hidden from the application: the
4779 underlying implementations can defer and implement these operations in
4780 various different ways.
4781
4782 A resource update batch owns no graphics resources and does not perform any
4783 actual operations on its own. It should rather be viewed as a command
4784 buffer for update, upload, and copy type of commands.
4785
4786 To get an available, empty batch from the pool, call
4787 QRhi::nextResourceUpdateBatch().
4788 */
4789
4790/*!
4791 \internal
4792 */
4793QRhiResourceUpdateBatch::QRhiResourceUpdateBatch(QRhiImplementation *rhi)
4794 : d(new QRhiResourceUpdateBatchPrivate)
4795{
4796 d->q = this;
4797 d->rhi = rhi;
4798}
4799
4800QRhiResourceUpdateBatch::~QRhiResourceUpdateBatch()
4801{
4802 delete d;
4803}
4804
4805/*!
4806 \return the batch to the pool. This should only be used when the batch is
4807 not passed to one of QRhiCommandBuffer::beginPass(),
4808 QRhiCommandBuffer::endPass(), or QRhiCommandBuffer::resourceUpdate()
4809 because these implicitly call destroy().
4810
4811 \note QRhiResourceUpdateBatch instances must never by \c deleted by
4812 applications.
4813 */
4814void QRhiResourceUpdateBatch::release()
4815{
4816 d->free();
4817}
4818
4819/*!
4820 Copies all queued operations from the \a other batch into this one.
4821
4822 \note \a other may no longer contain valid data after the merge operation,
4823 and must not be submitted, but it will still need to be released by calling
4824 release().
4825
4826 This allows for a convenient pattern where resource updates that are
4827 already known during the initialization step are collected into a batch
4828 that is then merged into another when starting to first render pass later
4829 on:
4830
4831 \badcode
4832 void init()
4833 {
4834 ...
4835 initialUpdates = rhi->nextResourceUpdateBatch();
4836 initialUpdates->uploadStaticBuffer(vbuf, vertexData);
4837 initialUpdates->uploadStaticBuffer(ibuf, indexData);
4838 ...
4839 }
4840
4841 void render()
4842 {
4843 ...
4844 QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
4845 if (initialUpdates) {
4846 resUpdates->merge(initialUpdates);
4847 initialUpdates->release();
4848 initialUpdates = nullptr;
4849 }
4850 resUpdates->updateDynamicBuffer(...);
4851 ...
4852 cb->beginPass(rt, clearCol, clearDs, resUpdates);
4853 }
4854 \endcode
4855 */
4856void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other)
4857{
4858 d->merge(other->d);
4859}
4860
4861/*!
4862 \return true until the number of buffer and texture operations enqueued
4863 onto this batch is below a reasonable limit.
4864
4865 The return value is false when the number of buffer and/or texture
4866 operations added to this batch have reached, or are about to reach, a
4867 certain limit. The batch is fully functional afterwards as well, but may
4868 need to allocate additional memory. Therefore, a renderer that collects
4869 lots of buffer and texture updates in a single batch when preparing a frame
4870 may want to consider \l{QRhiCommandBuffer::resourceUpdate()}{submitting the
4871 batch} and \l{QRhi::nextResourceUpdateBatch()}{starting a new one} when
4872 this function returns false.
4873 */
4874bool QRhiResourceUpdateBatch::hasOptimalCapacity() const
4875{
4876 return d->hasOptimalCapacity();
4877}
4878
4879/*!
4880 Enqueues updating a region of a QRhiBuffer \a buf created with the type
4881 QRhiBuffer::Dynamic.
4882
4883 The region is specified \a offset and \a size. The actual bytes to write
4884 are specified by \a data which must have at least \a size bytes available.
4885 \a data can safely be destroyed or changed once this function returns.
4886
4887 \note If host writes are involved, which is the case with
4888 updateDynamicBuffer() typically as such buffers are backed by host visible
4889 memory with most backends, they may accumulate within a frame. Thus pass 1
4890 reading a region changed by a batch passed to pass 2 may see the changes
4891 specified in pass 2's update batch.
4892
4893 \note QRhi transparently manages double buffering in order to prevent
4894 stalling the graphics pipeline. The fact that a QRhiBuffer may have
4895 multiple native underneath can be safely ignored when using the QRhi and
4896 QRhiResourceUpdateBatch.
4897 */
4898void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
4899{
4900 if (size > 0) {
4901 const int idx = d->activeBufferOpCount++;
4902 const int opListSize = d->bufferOps.size();
4903 if (idx < opListSize)
4904 QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(&d->bufferOps[idx], buf, offset, size, data);
4905 else
4906 d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data));
4907 }
4908}
4909
4910/*!
4911 Enqueues updating a region of a QRhiBuffer \a buf created with the type
4912 QRhiBuffer::Immutable or QRhiBuffer::Static.
4913
4914 The region is specified \a offset and \a size. The actual bytes to write
4915 are specified by \a data which must have at least \a size bytes available.
4916 \a data can safely be destroyed or changed once this function returns.
4917 */
4918void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
4919{
4920 if (size > 0) {
4921 const int idx = d->activeBufferOpCount++;
4922 if (idx < d->bufferOps.size())
4923 QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, offset, size, data);
4924 else
4925 d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data));
4926 }
4927}
4928
4929/*!
4930 Enqueues updating the entire QRhiBuffer \a buf created with the type
4931 QRhiBuffer::Immutable or QRhiBuffer::Static.
4932 */
4933void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
4934{
4935 if (buf->size() > 0) {
4936 const int idx = d->activeBufferOpCount++;
4937 if (idx < d->bufferOps.size())
4938 QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, 0, 0, data);
4939 else
4940 d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, 0, data));
4941 }
4942}
4943
4944/*!
4945 Enqueues reading back a region of the QRhiBuffer \a buf. The size of the
4946 region is specified by \a size in bytes, \a offset is the offset in bytes
4947 to start reading from.
4948
4949 A readback is asynchronous. \a result contains a callback that is invoked
4950 when the operation has completed. The data is provided in
4951 QRhiBufferReadbackResult::data. Upon successful completion that QByteArray
4952 will have a size equal to \a size. On failure the QByteArray will be empty.
4953
4954 \note Reading buffers with a usage different than QRhiBuffer::UniformBuffer
4955 is supported only when the QRhi::ReadBackNonUniformBuffer feature is
4956 reported as supported.
4957
4958 \note The asynchronous readback is guaranteed to have completed when one of
4959 the following conditions is met: \l{QRhi::finish()}{finish()} has been
4960 called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted},
4961 including the frame that issued the readback operation, and the
4962 \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c
4963 N is the \l{QRhi::resourceLimit()}{resource limit value} returned for
4964 QRhi::MaxAsyncReadbackFrames.
4965
4966 \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit()
4967 */
4968void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
4969{
4970 const int idx = d->activeBufferOpCount++;
4971 if (idx < d->bufferOps.size())
4972 d->bufferOps[idx] = QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result);
4973 else
4974 d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result));
4975}
4976
4977/*!
4978 Enqueues uploading the image data for one or more mip levels in one or more
4979 layers of the texture \a tex.
4980
4981 The details of the copy (source QImage or compressed texture data, regions,
4982 target layers and levels) are described in \a desc.
4983 */
4984void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
4985{
4986 if (desc.cbeginEntries() != desc.cendEntries()) {
4987 const int idx = d->activeTextureOpCount++;
4988 if (idx < d->textureOps.size())
4989 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc);
4990 else
4991 d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc));
4992 }
4993}
4994
4995/*!
4996 Enqueues uploading the image data for mip level 0 of layer 0 of the texture
4997 \a tex.
4998
4999 \a tex must have an uncompressed format. Its format must also be compatible
5000 with the QImage::format() of \a image. The source data is given in \a
5001 image.
5002 */
5003void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &image)
5004{
5005 uploadTexture(tex, QRhiTextureUploadEntry(0, 0, image));
5006}
5007
5008/*!
5009 Enqueues a texture-to-texture copy operation from \a src into \a dst as
5010 described by \a desc.
5011
5012 \note The source texture \a src must be created with
5013 QRhiTexture::UsedAsTransferSource.
5014 */
5015void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
5016{
5017 const int idx = d->activeTextureOpCount++;
5018 if (idx < d->textureOps.size())
5019 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc);
5020 else
5021 d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc));
5022}
5023
5024/*!
5025 Enqueues a texture-to-host copy operation as described by \a rb.
5026
5027 Normally \a rb will specify a QRhiTexture as the source. However, when the
5028 swapchain in the current frame was created with
5029 QRhiSwapChain::UsedAsTransferSource, it can also be the source of the
5030 readback. For this, leave the texture set to null in \a rb.
5031
5032 Unlike other operations, the results here need to be processed by the
5033 application. Therefore, \a result provides not just the data but also a
5034 callback as operations on the batch are asynchronous by nature:
5035
5036 \badcode
5037 beginFrame(sc);
5038 beginPass
5039 ...
5040 QRhiReadbackResult *rbResult = new QRhiReadbackResult;
5041 rbResult->completed = [rbResult] {
5042 {
5043 const QImage::Format fmt = QImage::Format_RGBA8888_Premultiplied; // fits QRhiTexture::RGBA8
5044 const uchar *p = reinterpret_cast<const uchar *>(rbResult->data.constData());
5045 QImage image(p, rbResult->pixelSize.width(), rbResult->pixelSize.height(), fmt);
5046 image.save("result.png");
5047 }
5048 delete rbResult;
5049 };
5050 u = nextResourceUpdateBatch();
5051 QRhiReadbackDescription rb; // no texture -> uses the current backbuffer of sc
5052 u->readBackTexture(rb, rbResult);
5053 endPass(u);
5054 endFrame(sc);
5055 \endcode
5056
5057 \note The texture must be created with QRhiTexture::UsedAsTransferSource.
5058
5059 \note Multisample textures cannot be read back.
5060
5061 \note The readback returns raw byte data, in order to allow the applications
5062 to interpret it in any way they see fit. Be aware of the blending settings
5063 of rendering code: if the blending is set up to rely on premultiplied alpha,
5064 the results of the readback must also be interpreted as Premultiplied.
5065
5066 \note When interpreting the resulting raw data, be aware that the readback
5067 happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture
5068 maps therefore to byte ordered QImage formats, such as,
5069 QImage::Format_RGBA8888.
5070
5071 \note The asynchronous readback is guaranteed to have completed when one of
5072 the following conditions is met: \l{QRhi::finish()}{finish()} has been
5073 called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted},
5074 including the frame that issued the readback operation, and the
5075 \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c
5076 N is the \l{QRhi::resourceLimit()}{resource limit value} returned for
5077 QRhi::MaxAsyncReadbackFrames.
5078
5079 \sa readBackBuffer(), QRhi::resourceLimit()
5080 */
5081void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
5082{
5083 const int idx = d->activeTextureOpCount++;
5084 if (idx < d->textureOps.size())
5085 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result);
5086 else
5087 d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result));
5088}
5089
5090/*!
5091 Enqueues a mipmap generation operation for the specified texture \a tex.
5092
5093 Both 2D and cube textures are supported.
5094
5095 \note The texture must be created with QRhiTexture::MipMapped and
5096 QRhiTexture::UsedWithGenerateMips.
5097
5098 \warning QRhi cannot guarantee that mipmaps can be generated for all
5099 supported texture formats. For example, QRhiTexture::RGBA32F is not a \c
5100 filterable format in OpenGL ES 3.0 and Metal on iOS, and therefore the
5101 mipmap generation request may fail. RGBA8 and RGBA16F are typically
5102 filterable, so it is recommended to use these formats when mipmap generation
5103 is desired.
5104 */
5105void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex)
5106{
5107 const int idx = d->activeTextureOpCount++;
5108 if (idx < d->textureOps.size())
5109 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex);
5110 else
5111 d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex));
5112}
5113
5114/*!
5115 \return an available, empty batch to which copy type of operations can be
5116 recorded.
5117
5118 \note the return value is not owned by the caller and must never be
5119 destroyed. Instead, the batch is returned the pool for reuse by passing
5120 it to QRhiCommandBuffer::beginPass(), QRhiCommandBuffer::endPass(), or
5121 QRhiCommandBuffer::resourceUpdate(), or by calling
5122 QRhiResourceUpdateBatch::destroy() on it.
5123
5124 \note Can be called outside beginFrame() - endFrame() as well since a batch
5125 instance just collects data on its own, it does not perform any operations.
5126
5127 \warning The maximum number of batches is 64. When this limit is reached,
5128 the function will return null until a batch is returned to the pool.
5129 */
5130QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch()
5131{
5132 auto nextFreeBatch = [this]() -> QRhiResourceUpdateBatch * {
5133 auto isFree = [this](int i) -> QRhiResourceUpdateBatch * {
5134 const quint64 mask = 1ULL << quint64(i);
5135 if (!(d->resUpdPoolMap & mask)) {
5136 d->resUpdPoolMap |= mask;
5137 QRhiResourceUpdateBatch *u = d->resUpdPool[i];
5138 QRhiResourceUpdateBatchPrivate::get(u)->poolIndex = i;
5139 d->lastResUpdIdx = i;
5140 return u;
5141 }
5142 return nullptr;
5143 };
5144 const int poolSize = d->resUpdPool.size();
5145 for (int i = d->lastResUpdIdx + 1; i < poolSize; ++i) {
5146 if (QRhiResourceUpdateBatch *u = isFree(i))
5147 return u;
5148 }
5149 for (int i = 0; i <= d->lastResUpdIdx; ++i) {
5150 if (QRhiResourceUpdateBatch *u = isFree(i))
5151 return u;
5152 }
5153 return nullptr;
5154 };
5155
5156 QRhiResourceUpdateBatch *u = nextFreeBatch();
5157 if (!u) {
5158 const int oldSize = d->resUpdPool.count();
5159 const int newSize = oldSize + qMin(4, qMax(0, 64 - oldSize));
5160 d->resUpdPool.resize(newSize);
5161 for (int i = oldSize; i < newSize; ++i)
5162 d->resUpdPool[i] = new QRhiResourceUpdateBatch(d);
5163 u = nextFreeBatch();
5164 if (!u)
5165 qWarning("Resource update batch pool exhausted (max is 64)");
5166 }
5167
5168 return u;
5169}
5170
5171void QRhiResourceUpdateBatchPrivate::free()
5172{
5173 Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q);
5174
5175 activeBufferOpCount = 0;
5176 activeTextureOpCount = 0;
5177
5178 const quint64 mask = 1ULL << quint64(poolIndex);
5179 rhi->resUpdPoolMap &= ~mask;
5180 poolIndex = -1;
5181}
5182
5183void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
5184{
5185 int combinedSize = activeBufferOpCount + other->activeBufferOpCount;
5186 if (bufferOps.size() < combinedSize)
5187 bufferOps.resize(combinedSize);
5188 for (int i = activeBufferOpCount; i < combinedSize; ++i)
5189 bufferOps[i] = std::move(other->bufferOps[i - activeBufferOpCount]);
5190 activeBufferOpCount += other->activeBufferOpCount;
5191
5192 combinedSize = activeTextureOpCount + other->activeTextureOpCount;
5193 if (textureOps.size() < combinedSize)
5194 textureOps.resize(combinedSize);
5195 for (int i = activeTextureOpCount; i < combinedSize; ++i)
5196 textureOps[i] = std::move(other->textureOps[i - activeTextureOpCount]);
5197 activeTextureOpCount += other->activeTextureOpCount;
5198}
5199
5200bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const
5201{
5202 return activeBufferOpCount < BUFFER_OPS_STATIC_ALLOC - 16
5203 && activeTextureOpCount < TEXTURE_OPS_STATIC_ALLOC - 16;
5204}
5205
5206void QRhiResourceUpdateBatchPrivate::trimOpLists()
5207{
5208 Q_ASSERT(poolIndex == -1); // must not be in use
5209
5210 activeBufferOpCount = 0;
5211 bufferOps.clear();
5212
5213 activeTextureOpCount = 0;
5214 textureOps.clear();
5215}
5216
5217/*!
5218 Sometimes committing resource updates is necessary without starting a
5219 render pass. Not often needed, updates should typically be passed to
5220 beginPass (or endPass, in case of readbacks) instead.
5221
5222 \note Cannot be called inside a pass.
5223 */
5224void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
5225{
5226 if (resourceUpdates)
5227 m_rhi->resourceUpdate(this, resourceUpdates);
5228}
5229
5230/*!
5231 Records starting a new render pass targeting the render target \a rt.
5232
5233 \a resourceUpdates, when not null, specifies a resource update batch that
5234 is to be committed and then released.
5235
5236 The color and depth/stencil buffers of the render target are normally
5237 cleared. The clear values are specified in \a colorClearValue and \a
5238 depthStencilClearValue. The exception is when the render target was created
5239 with QRhiTextureRenderTarget::PreserveColorContents and/or
5240 QRhiTextureRenderTarget::PreserveDepthStencilContents. The clear values are
5241 ignored then.
5242
5243 \note Enabling preserved color or depth contents leads to decreased
5244 performance depending on the underlying hardware. Mobile GPUs with tiled
5245 architecture benefit from not having to reload the previous contents into
5246 the tile buffer. Similarly, a QRhiTextureRenderTarget with a QRhiTexture as
5247 the depth buffer is less efficient than a QRhiRenderBuffer since using a
5248 depth texture triggers requiring writing the data out to it, while with
5249 renderbuffers this is not needed (as the API does not allow sampling or
5250 reading from a renderbuffer).
5251
5252 \note Do not assume that any state or resource bindings persist between
5253 passes.
5254
5255 \note The QRhiCommandBuffer's \c set and \c draw functions can only be
5256 called inside a pass. Also, with the exception of setGraphicsPipeline(),
5257 they expect to have a pipeline set already on the command buffer.
5258 Unspecified issues may arise otherwise, depending on the backend.
5259 */
5260void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt,
5261 const QColor &colorClearValue,
5262 const QRhiDepthStencilClearValue &depthStencilClearValue,
5263 QRhiResourceUpdateBatch *resourceUpdates,
5264 BeginPassFlags flags)
5265{
5266 m_rhi->beginPass(this, rt, colorClearValue, depthStencilClearValue, resourceUpdates, flags);
5267}
5268
5269/*!
5270 Records ending the current render pass.
5271
5272 \a resourceUpdates, when not null, specifies a resource update batch that
5273 is to be committed and then released.
5274 */
5275void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates)
5276{
5277 m_rhi->endPass(this, resourceUpdates);
5278}
5279
5280/*!
5281 Records setting a new graphics pipeline \a ps.
5282
5283 \note This function must be called before recording other \c set or \c draw
5284 commands on the command buffer.
5285
5286 \note QRhi will optimize out unnecessary invocations within a pass, so
5287 therefore overoptimizing to avoid calls to this function is not necessary
5288 on the applications' side.
5289
5290 \note This function can only be called inside a render pass, meaning
5291 between a beginPass() and endPass() call.
5292 */
5293void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
5294{
5295 m_rhi->setGraphicsPipeline(this, ps);
5296}
5297
5298/*!
5299 Records binding a set of shader resources, such as, uniform buffers or
5300 textures, that are made visible to one or more shader stages.
5301
5302 \a srb can be null in which case the current graphics or compute pipeline's
5303 associated QRhiShaderResourceBindings is used. When \a srb is non-null, it
5304 must be
5305 \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible},
5306 meaning the layout (number of bindings, the type and binding number of each
5307 binding) must fully match the QRhiShaderResourceBindings that was
5308 associated with the pipeline at the time of calling the pipeline's create().
5309
5310 There are cases when a seemingly unnecessary setShaderResources() call is
5311 mandatory: when rebuilding a resource referenced from \a srb, for example
5312 changing the size of a QRhiBuffer followed by a QRhiBuffer::create(), this
5313 is the place where associated native objects (such as descriptor sets in
5314 case of Vulkan) are updated to refer to the current native resources that
5315 back the QRhiBuffer, QRhiTexture, QRhiSampler objects referenced from \a
5316 srb. In this case setShaderResources() must be called even if \a srb is
5317 the same as in the last call.
5318
5319 \a dynamicOffsets allows specifying buffer offsets for uniform buffers that
5320 were associated with \a srb via
5321 QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(). This is
5322 different from providing the offset in the \a srb itself: dynamic offsets
5323 do not require building a new QRhiShaderResourceBindings for every
5324 different offset, can avoid writing the underlying descriptors (with
5325 backends where applicable), and so they may be more efficient. Each element
5326 of \a dynamicOffsets is a \c binding - \c offset pair.
5327 \a dynamicOffsetCount specifies the number of elements in \a dynamicOffsets.
5328
5329 \note All offsets in \a dynamicOffsets must be byte aligned to the value
5330 returned from QRhi::ubufAlignment().
5331
5332 \note Some backends may limit the number of supported dynamic offsets.
5333 Avoid using a \a dynamicOffsetCount larger than 8.
5334
5335 \note QRhi will optimize out unnecessary invocations within a pass (taking
5336 the conditions described above into account), so therefore overoptimizing
5337 to avoid calls to this function is not necessary on the applications' side.
5338
5339 \note This function can only be called inside a render or compute pass,
5340 meaning between a beginPass() and endPass(), or beginComputePass() and
5341 endComputePass().
5342 */
5343void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
5344 int dynamicOffsetCount,
5345 const DynamicOffset *dynamicOffsets)
5346{
5347 m_rhi->setShaderResources(this, srb, dynamicOffsetCount, dynamicOffsets);
5348}
5349
5350/*!
5351 Records vertex input bindings.
5352
5353 The index buffer used by subsequent drawIndexed() commands is specified by
5354 \a indexBuf, \a indexOffset, and \a indexFormat. \a indexBuf can be set to
5355 null when indexed drawing is not needed.
5356
5357 Vertex buffer bindings are batched. \a startBinding specifies the first
5358 binding number. The recorded command then binds each buffer from \a
5359 bindings to the binding point \c{startBinding + i} where \c i is the index
5360 in \a bindings. Each element in \a bindings specifies a QRhiBuffer and an
5361 offset.
5362
5363 \note Some backends may limit the number of vertex buffer bindings. Avoid
5364 using a \a bindingCount larger than 8.
5365
5366 Superfluous vertex input and index changes in the same pass are ignored
5367 automatically with most backends and therefore applications do not need to
5368 overoptimize to avoid calls to this function.
5369
5370 \note This function can only be called inside a render pass, meaning
5371 between a beginPass() and endPass() call.
5372
5373 As a simple example, take a vertex shader with two inputs:
5374
5375 \badcode
5376 layout(location = 0) in vec4 position;
5377 layout(location = 1) in vec3 color;
5378 \endcode
5379
5380 and assume we have the data available in interleaved format, using only 2
5381 floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for
5382 this shader can then be created using the input layout:
5383
5384 \badcode
5385 QRhiVertexInputLayout inputLayout;
5386 inputLayout.setBindings({
5387 { 5 * sizeof(float) }
5388 });
5389 inputLayout.setAttributes({
5390 { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
5391 { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
5392 });
5393 \endcode
5394
5395 Here there is one buffer binding (binding number 0), with two inputs
5396 referencing it. When recording the pass, once the pipeline is set, the
5397 vertex bindings can be specified simply like the following (using C++11
5398 initializer syntax), assuming vbuf is the QRhiBuffer with all the
5399 interleaved position+color data:
5400
5401 \badcode
5402 const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0);
5403 cb->setVertexInput(0, 1, &vbufBinding);
5404 \endcode
5405 */
5406void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings,
5407 QRhiBuffer *indexBuf, quint32 indexOffset,
5408 IndexFormat indexFormat)
5409{
5410 m_rhi->setVertexInput(this, startBinding, bindingCount, bindings, indexBuf, indexOffset, indexFormat);
5411}
5412
5413/*!
5414 Records setting the active viewport rectangle specified in \a viewport.
5415
5416 With backends where the underlying graphics API has scissoring always
5417 enabled, this function also sets the scissor to match the viewport whenever
5418 the active QRhiGraphicsPipeline does not have
5419 \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set.
5420
5421 \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
5422 bottom-left.
5423
5424 \note This function can only be called inside a render pass, meaning
5425 between a beginPass() and endPass() call.
5426 */
5427void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport)
5428{
5429 m_rhi->setViewport(this, viewport);
5430}
5431
5432/*!
5433 Records setting the active scissor rectangle specified in \a scissor.
5434
5435 This can only be called when the bound pipeline has
5436 \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. When the flag is
5437 set on the active pipeline, this function must be called because scissor
5438 testing will get enabled and so a scissor rectangle must be provided.
5439
5440 \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
5441 bottom-left.
5442
5443 \note This function can only be called inside a render pass, meaning
5444 between a beginPass() and endPass() call.
5445 */
5446void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor)
5447{
5448 m_rhi->setScissor(this, scissor);
5449}
5450
5451/*!
5452 Records setting the active blend constants to \a c.
5453
5454 This can only be called when the bound pipeline has
5455 QRhiGraphicsPipeline::UsesBlendConstants set.
5456
5457 \note This function can only be called inside a render pass, meaning
5458 between a beginPass() and endPass() call.
5459 */
5460void QRhiCommandBuffer::setBlendConstants(const QColor &c)
5461{
5462 m_rhi->setBlendConstants(this, c);
5463}
5464
5465/*!
5466 Records setting the active stencil reference value to \a refValue.
5467
5468 This can only be called when the bound pipeline has
5469 QRhiGraphicsPipeline::UsesStencilRef set.
5470
5471 \note This function can only be called inside a render pass, meaning between
5472 a beginPass() and endPass() call.
5473 */
5474void QRhiCommandBuffer::setStencilRef(quint32 refValue)
5475{
5476 m_rhi->setStencilRef(this, refValue);
5477}
5478
5479/*!
5480 Records a non-indexed draw.
5481
5482 The number of vertices is specified in \a vertexCount. For instanced
5483 drawing set \a instanceCount to a value other than 1. \a firstVertex is the
5484 index of the first vertex to draw. When drawing multiple instances, the
5485 first instance ID is specified by \a firstInstance.
5486
5487 \note \a firstInstance may not be supported, and is ignored when the
5488 QRhi::BaseInstance feature is reported as not supported. The first ID is
5489 always 0 in that case.
5490
5491 \note This function can only be called inside a render pass, meaning
5492 between a beginPass() and endPass() call.
5493 */
5494void QRhiCommandBuffer::draw(quint32 vertexCount,
5495 quint32 instanceCount,
5496 quint32 firstVertex,
5497 quint32 firstInstance)
5498{
5499 m_rhi->draw(this, vertexCount, instanceCount, firstVertex, firstInstance);
5500}
5501
5502/*!
5503 Records an indexed draw.
5504
5505 The number of vertices is specified in \a indexCount. \a firstIndex is the
5506 base index. The effective offset in the index buffer is given by
5507 \c{indexOffset + firstIndex * n} where \c n is 2 or 4 depending on the
5508 index element type. \c indexOffset is specified in setVertexInput().
5509
5510 \note The effective offset in the index buffer must be 4 byte aligned with
5511 some backends (for example, Metal). With these backends the
5512 \l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset}
5513 feature will be reported as not-supported.
5514
5515 For instanced drawing set \a instanceCount to a value other than 1. When
5516 drawing multiple instances, the first instance ID is specified by \a
5517 firstInstance.
5518
5519 \note \a firstInstance may not be supported, and is ignored when the
5520 QRhi::BaseInstance feature is reported as not supported. The first ID is
5521 always 0 in that case.
5522
5523 \a vertexOffset (also called \c{base vertex}) is a signed value that is
5524 added to the element index before indexing into the vertex buffer. Support
5525 for this is not always available, and the value is ignored when the feature
5526 QRhi::BaseVertex is reported as unsupported.
5527
5528 \note This function can only be called inside a render pass, meaning
5529 between a beginPass() and endPass() call.
5530 */
5531void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
5532 quint32 instanceCount,
5533 quint32 firstIndex,
5534 qint32 vertexOffset,
5535 quint32 firstInstance)
5536{
5537 m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
5538}
5539
5540/*!
5541 Records a named debug group on the command buffer. This is shown in
5542 graphics debugging tools such as \l{https://renderdoc.org/}{RenderDoc} and
5543 \l{https://developer.apple.com/xcode/}{XCode}. The end of the grouping is
5544 indicated by debugMarkEnd().
5545
5546 \note Ignored when QRhi::DebugMarkers are not supported or
5547 QRhi::EnableDebugMarkers is not set.
5548
5549 \note Can be called anywhere within the frame, both inside and outside of passes.
5550 */
5551void QRhiCommandBuffer::debugMarkBegin(const QByteArray &name)
5552{
5553 m_rhi->debugMarkBegin(this, name);
5554}
5555
5556/*!
5557 Records the end of a debug group.
5558
5559 \note Ignored when QRhi::DebugMarkers are not supported or
5560 QRhi::EnableDebugMarkers is not set.
5561
5562 \note Can be called anywhere within the frame, both inside and outside of passes.
5563 */
5564void QRhiCommandBuffer::debugMarkEnd()
5565{
5566 m_rhi->debugMarkEnd(this);
5567}
5568
5569/*!
5570 Inserts a debug message \a msg into the command stream.
5571
5572 \note Ignored when QRhi::DebugMarkers are not supported or
5573 QRhi::EnableDebugMarkers is not set.
5574
5575 \note With some backends debugMarkMsg() is only supported inside a pass and
5576 is ignored when called outside a pass. With others it is recorded anywhere
5577 within the frame.
5578 */
5579void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg)
5580{
5581 m_rhi->debugMarkMsg(this, msg);
5582}
5583
5584/*!
5585 Records starting a new compute pass.
5586
5587 \a resourceUpdates, when not null, specifies a resource update batch that
5588 is to be committed and then released.
5589
5590 \note Do not assume that any state or resource bindings persist between
5591 passes.
5592
5593 \note A compute pass can record setComputePipeline(), setShaderResources(),
5594 and dispatch() calls, not graphics ones. General functionality, such as,
5595 debug markers and beginExternal() is available both in render and compute
5596 passes.
5597
5598 \note Compute is only available when the \l{QRhi::Compute}{Compute} feature
5599 is reported as supported.
5600 */
5601void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates, BeginPassFlags flags)
5602{
5603 m_rhi->beginComputePass(this, resourceUpdates, flags);
5604}
5605
5606/*!
5607 Records ending the current compute pass.
5608
5609 \a resourceUpdates, when not null, specifies a resource update batch that
5610 is to be committed and then released.
5611 */
5612void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates)
5613{
5614 m_rhi->endComputePass(this, resourceUpdates);
5615}
5616
5617/*!
5618 Records setting a new compute pipeline \a ps.
5619
5620 \note This function must be called before recording setShaderResources() or
5621 dispatch() commands on the command buffer.
5622
5623 \note QRhi will optimize out unnecessary invocations within a pass, so
5624 therefore overoptimizing to avoid calls to this function is not necessary
5625 on the applications' side.
5626
5627 \note This function can only be called inside a compute pass, meaning
5628 between a beginComputePass() and endComputePass() call.
5629 */
5630void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps)
5631{
5632 m_rhi->setComputePipeline(this, ps);
5633}
5634
5635/*!
5636 Records dispatching compute work items, with \a x, \a y, and \a z
5637 specifying the number of local workgroups in the corresponding dimension.
5638
5639 \note This function can only be called inside a compute pass, meaning
5640 between a beginComputePass() and endComputePass() call.
5641
5642 \note \a x, \a y, and \a z must fit the limits from the underlying graphics
5643 API implementation at run time. The maximum values are typically 65535.
5644
5645 \note Watch out for possible limits on the local workgroup size as well.
5646 This is specified in the shader, for example: \c{layout(local_size_x = 16,
5647 local_size_y = 16) in;}. For example, with OpenGL the minimum value mandated
5648 by the specification for the number of invocations in a single local work
5649 group (the product of \c local_size_x, \c local_size_y, and \c local_size_z)
5650 is 1024, while with OpenGL ES (3.1) the value may be as low as 128. This
5651 means that the example given above may be rejected by some OpenGL ES
5652 implementations as the number of invocations is 256.
5653 */
5654void QRhiCommandBuffer::dispatch(int x, int y, int z)
5655{
5656 m_rhi->dispatch(this, x, y, z);
5657}
5658
5659/*!
5660 \return a pointer to a backend-specific QRhiNativeHandles subclass, such as
5661 QRhiVulkanCommandBufferNativeHandles. The returned value is \nullptr when
5662 exposing the underlying native resources is not supported by, or not
5663 applicable to, the backend.
5664
5665 \sa QRhiVulkanCommandBufferNativeHandles,
5666 QRhiMetalCommandBufferNativeHandles, beginExternal(), endExternal()
5667 */
5668const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles()
5669{
5670 return m_rhi->nativeHandles(this);
5671}
5672
5673/*!
5674 To be called when the application before the application is about to
5675 enqueue commands to the current pass' command buffer by calling graphics
5676 API functions directly.
5677
5678 \note This is only available when the intent was declared upfront in
5679 beginPass() or beginComputePass(). Therefore this function must only be
5680 called when the pass recording was started with specifying
5681 QRhiCommandBuffer::ExternalContent.
5682
5683 With Vulkan or Metal one can query the native command buffer or encoder
5684 objects via nativeHandles() and enqueue commands to them. With OpenGL or
5685 Direct3D 11 the (device) context can be retrieved from
5686 QRhi::nativeHandles(). However, this must never be done without ensuring
5687 the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for
5688 wrapping any externally added command recording between beginExternal() and
5689 endExternal(). Conceptually this is the same as QPainter's
5690 \l{QPainter::beginNativePainting()}{beginNativePainting()} and
5691 \l{QPainter::endNativePainting()}{endNativePainting()} functions.
5692
5693 For OpenGL in particular, this function has an additional task: it makes
5694 sure the context is made current on the current thread.
5695
5696 \note Once beginExternal() is called, no other render pass specific
5697 functions (\c set* or \c draw*) must be called on the
5698 QRhiCommandBuffer until endExternal().
5699
5700 \warning Some backends may return a native command buffer object from
5701 QRhiCommandBuffer::nativeHandles() that is different from the primary one
5702 when inside a beginExternal() - endExternal() block. Therefore it is
5703 important to (re)query the native command buffer object after calling
5704 beginExternal(). In practical terms this means that with Vulkan for example
5705 the externally recorded Vulkan commands are placed onto a secondary command
5706 buffer (with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT).
5707 nativeHandles() returns this secondary command buffer when called between
5708 begin/endExternal.
5709
5710 \sa endExternal(), nativeHandles()
5711 */
5712void QRhiCommandBuffer::beginExternal()
5713{
5714 m_rhi->beginExternal(this);
5715}
5716
5717/*!
5718 To be called once the externally added commands are recorded to the command
5719 buffer or context.
5720
5721 \note All QRhiCommandBuffer state must be assumed as invalid after calling
5722 this function. Pipelines, vertex and index buffers, and other state must be
5723 set again if more draw calls are recorded after the external commands.
5724
5725 \sa beginExternal(), nativeHandles()
5726 */
5727void QRhiCommandBuffer::endExternal()
5728{
5729 m_rhi->endExternal(this);
5730}
5731
5732/*!
5733 \return the value (typically an offset) \a v aligned to the uniform buffer
5734 alignment given by by ubufAlignment().
5735 */
5736int QRhi::ubufAligned(int v) const
5737{
5738 const int byteAlign = ubufAlignment();
5739 return (v + byteAlign - 1) & ~(byteAlign - 1);
5740}
5741
5742/*!
5743 \return the number of mip levels for a given \a size.
5744 */
5745int QRhi::mipLevelsForSize(const QSize &size) const
5746{
5747 return qFloor(std::log2(qMax(size.width(), size.height()))) + 1;
5748}
5749
5750/*!
5751 \return the texture image size for a given \a mipLevel, calculated based on
5752 the level 0 size given in \a baseLevelSize.
5753 */
5754QSize QRhi::sizeForMipLevel(int mipLevel, const QSize &baseLevelSize) const
5755{
5756 const int w = qMax(1, baseLevelSize.width() >> mipLevel);
5757 const int h = qMax(1, baseLevelSize.height() >> mipLevel);
5758 return QSize(w, h);
5759}
5760
5761/*!
5762 \return \c true if the underlying graphics API has the Y axis pointing up
5763 in framebuffers and images.
5764
5765 In practice this is \c true for OpenGL only.
5766 */
5767bool QRhi::isYUpInFramebuffer() const
5768{
5769 return d->isYUpInFramebuffer();
5770}
5771
5772/*!
5773 \return \c true if the underlying graphics API has the Y axis pointing up
5774 in its normalized device coordinate system.
5775
5776 In practice this is \c false for Vulkan only.
5777
5778 \note clipSpaceCorrMatrix() includes the corresponding adjustment (to make
5779 Y point up) in its returned matrix.
5780 */
5781bool QRhi::isYUpInNDC() const
5782{
5783 return d->isYUpInNDC();
5784}
5785
5786/*!
5787 \return \c true if the underlying graphics API uses depth range [0, 1] in
5788 clip space.
5789
5790 In practice this is \c false for OpenGL only, because OpenGL uses a
5791 post-projection depth range of [-1, 1]. (not to be confused with the
5792 NDC-to-window mapping controlled by glDepthRange(), which uses a range of
5793 [0, 1], unless overridden by the QRhiViewport) In some OpenGL versions
5794 glClipControl() could be used to change this, but the OpenGL backend of
5795 QRhi does not use that function as it is not available in OpenGL ES or
5796 OpenGL versions lower than 4.5.
5797
5798 \note clipSpaceCorrMatrix() includes the corresponding adjustment in its
5799 returned matrix. Therefore, many users of QRhi do not need to take any
5800 further measures apart from pre-multiplying their projection matrices with
5801 clipSpaceCorrMatrix(). However, some graphics techniques, such as, some
5802 types of shadow mapping, involve working with and outputting depth values
5803 in the shaders. These will need to query and take the value of this
5804 function into account as appropriate.
5805 */
5806bool QRhi::isClipDepthZeroToOne() const
5807{
5808 return d->isClipDepthZeroToOne();
5809}
5810
5811/*!
5812 \return a matrix that can be used to allow applications keep using
5813 OpenGL-targeted vertex data and perspective projection matrices (such as,
5814 the ones generated by QMatrix4x4::perspective()), regardless of the active
5815 QRhi backend.
5816
5817 In a typical renderer, once \c{this_matrix * mvp} is used instead of just
5818 \c mvp, vertex data with Y up and viewports with depth range 0 - 1 can be
5819 used without considering what backend (and so graphics API) is going to be
5820 used at run time. This way branching based on isYUpInNDC() and
5821 isClipDepthZeroToOne() can be avoided (although such logic may still become
5822 required when implementing certain advanced graphics techniques).
5823
5824 See
5825 \l{https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/}{this
5826 page} for a discussion of the topic from Vulkan perspective.
5827 */
5828QMatrix4x4 QRhi::clipSpaceCorrMatrix() const
5829{
5830 return d->clipSpaceCorrMatrix();
5831}
5832
5833/*!
5834 \return \c true if the specified texture \a format modified by \a flags is
5835 supported.
5836
5837 The query is supported both for uncompressed and compressed formats.
5838 */
5839bool QRhi::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
5840{
5841 return d->isTextureFormatSupported(format, flags);
5842}
5843
5844/*!
5845 \return \c true if the specified \a feature is supported
5846 */
5847bool QRhi::isFeatureSupported(QRhi::Feature feature) const
5848{
5849 return d->isFeatureSupported(feature);
5850}
5851
5852/*!
5853 \return the value for the specified resource \a limit.
5854
5855 The values are expected to be queried by the backends upon initialization,
5856 meaning calling this function is a light operation.
5857 */
5858int QRhi::resourceLimit(ResourceLimit limit) const
5859{
5860 return d->resourceLimit(limit);
5861}
5862
5863/*!
5864 \return a pointer to the backend-specific collection of native objects
5865 for the device, context, and similar concepts used by the backend.
5866
5867 Cast to QRhiVulkanNativeHandles, QRhiD3D11NativeHandles,
5868 QRhiGles2NativeHandles, QRhiMetalNativeHandles as appropriate.
5869
5870 \note No ownership is transferred, neither for the returned pointer nor for
5871 any native objects.
5872 */
5873const QRhiNativeHandles *QRhi::nativeHandles()
5874{
5875 return d->nativeHandles();
5876}
5877
5878/*!
5879 With OpenGL this makes the OpenGL context current on the current thread.
5880 The function has no effect with other backends.
5881
5882 Calling this function is relevant typically in Qt framework code, when one
5883 has to ensure external OpenGL code provided by the application can still
5884 run like it did before with direct usage of OpenGL, as long as the QRhi is
5885 using the OpenGL backend.
5886
5887 \return false when failed, similarly to QOpenGLContext::makeCurrent(). When
5888 the operation failed, isDeviceLost() can be called to determine if there
5889 was a loss of context situation. Such a check is equivalent to checking via
5890 QOpenGLContext::isValid().
5891
5892 \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid()
5893 */
5894bool QRhi::makeThreadLocalNativeContextCurrent()
5895{
5896 return d->makeThreadLocalNativeContextCurrent();
5897}
5898
5899/*!
5900 \return the associated QRhiProfiler instance.
5901
5902 An instance is always available for each QRhi, but it is not very useful
5903 without EnableProfiling because no data is collected without setting the
5904 flag upon creation.
5905 */
5906QRhiProfiler *QRhi::profiler()
5907{
5908 return &d->profiler;
5909}
5910
5911/*!
5912 Attempts to release resources in the backend's caches. This can include both
5913 CPU and GPU resources. Only memory and resources that can be recreated
5914 automatically are in scope. As an example, if the backend's
5915 QRhiGraphicsPipeline implementation maintains a cache of shader compilation
5916 results, calling this function leads to emptying that cache, thus
5917 potentially freeing up memory and graphics resources.
5918
5919 Calling this function makes sense in resource constrained environments,
5920 where at a certain point there is a need to ensure minimal resource usage,
5921 at the expense of performance.
5922 */
5923void QRhi::releaseCachedResources()
5924{
5925 d->releaseCachedResources();
5926
5927 for (QRhiResourceUpdateBatch *u : d->resUpdPool) {
5928 if (u->d->poolIndex < 0)
5929 u->d->trimOpLists();
5930 }
5931}
5932
5933/*!
5934 \return true if the graphics device was lost.
5935
5936 The loss of the device is typically detected in beginFrame(), endFrame() or
5937 QRhiSwapChain::createOrResize(), depending on the backend and the underlying
5938 native APIs. The most common is endFrame() because that is where presenting
5939 happens. With some backends QRhiSwapChain::createOrResize() can also fail
5940 due to a device loss. Therefore this function is provided as a generic way
5941 to check if a device loss was detected by a previous operation.
5942
5943 When the device is lost, no further operations should be done via the QRhi.
5944 Rather, all QRhi resources should be released, followed by destroying the
5945 QRhi. A new QRhi can then be attempted to be created. If successful, all
5946 graphics resources must be reinitialized. If not, try again later,
5947 repeatedly.
5948
5949 While simple applications may decide to not care about device loss,
5950 on the commonly used desktop platforms a device loss can happen
5951 due to a variety of reasons, including physically disconnecting the
5952 graphics adapter, disabling the device or driver, uninstalling or upgrading
5953 the graphics driver, or due to errors that lead to a graphics device reset.
5954 Some of these can happen under perfectly normal circumstances as well, for
5955 example the upgrade of the graphics driver to a newer version is a common
5956 task that can happen at any time while a Qt application is running. Users
5957 may very well expect applications to be able to survive this, even when the
5958 application is actively using an API like OpenGL or Direct3D.
5959
5960 Qt's own frameworks built on top of QRhi, such as, Qt Quick, can be
5961 expected to handle and take appropriate measures when a device loss occurs.
5962 If the data for graphics resources, such as textures and buffers, are still
5963 available on the CPU side, such an event may not be noticeable on the
5964 application level at all since graphics resources can seamlessly be
5965 reinitialized then. However, applications and libraries working directly
5966 with QRhi are expected to be prepared to check and handle device loss
5967 situations themselves.
5968
5969 \note With OpenGL, applications may need to opt-in to context reset
5970 notifications by setting QSurfaceFormat::ResetNotification on the
5971 QOpenGLContext. This is typically done by enabling the flag in
5972 QRhiGles2InitParams::format. Keep in mind however that some systems may
5973 generate context resets situations even when this flag is not set.
5974 */
5975bool QRhi::isDeviceLost() const
5976{
5977 return d->isDeviceLost();
5978}
5979
5980/*!
5981 \return a new graphics pipeline resource.
5982
5983 \sa QRhiResource::destroy()
5984 */
5985QRhiGraphicsPipeline *QRhi::newGraphicsPipeline()
5986{
5987 return d->createGraphicsPipeline();
5988}
5989
5990/*!
5991 \return a new compute pipeline resource.
5992
5993 \note Compute is only available when the \l{QRhi::Compute}{Compute} feature
5994 is reported as supported.
5995
5996 \sa QRhiResource::destroy()
5997 */
5998QRhiComputePipeline *QRhi::newComputePipeline()
5999{
6000 return d->createComputePipeline();
6001}
6002
6003/*!
6004 \return a new shader resource binding collection resource.
6005
6006 \sa QRhiResource::destroy()
6007 */
6008QRhiShaderResourceBindings *QRhi::newShaderResourceBindings()
6009{
6010 return d->createShaderResourceBindings();
6011}
6012
6013/*!
6014 \return a new buffer with the specified \a type, \a usage, and \a size.
6015
6016 \note Some \a usage and \a type combinations may not be supported by all
6017 backends. See \l{QRhiBuffer::UsageFlag}{UsageFlags} and
6018 \l{QRhi::NonDynamicUniformBuffers}{the feature flags}.
6019
6020 \note Backends may choose to allocate buffers bigger than \a size. This is
6021 done transparently to applications, so there are no special restrictions on
6022 the value of \a size. QRhiBuffer::size() will always report back the value
6023 that was requested in \a size.
6024
6025 \sa QRhiResource::destroy()
6026 */
6027QRhiBuffer *QRhi::newBuffer(QRhiBuffer::Type type,
6028 QRhiBuffer::UsageFlags usage,
6029 int size)
6030{
6031 return d->createBuffer(type, usage, size);
6032}
6033
6034/*!
6035 \return a new renderbuffer with the specified \a type, \a pixelSize, \a
6036 sampleCount, and \a flags.
6037
6038 When \a backingFormatHint is set to a texture format other than
6039 QRhiTexture::UnknownFormat, it may be used by the backend to decide what
6040 format to use for the storage backing the renderbuffer.
6041
6042 \note \a backingFormatHint becomes relevant typically when multisampling
6043 and floating point texture formats are involved: rendering into a
6044 multisample QRhiRenderBuffer and then resolving into a non-RGBA8
6045 QRhiTexture implies (with some graphics APIs) that the storage backing the
6046 QRhiRenderBuffer uses the matching non-RGBA8 format. That means that
6047 passing a format like QRhiTexture::RGBA32F is important, because backends
6048 will typically opt for QRhiTexture::RGBA8 by default, which would then
6049 break later on due to attempting to set up RGBA8->RGBA32F multisample
6050 resolve in the color attachment(s) of the QRhiTextureRenderTarget.
6051
6052 \sa QRhiResource::destroy()
6053 */
6054QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type,
6055 const QSize &pixelSize,
6056 int sampleCount,
6057 QRhiRenderBuffer::Flags flags,
6058 QRhiTexture::Format backingFormatHint)
6059{
6060 return d->createRenderBuffer(type, pixelSize, sampleCount, flags, backingFormatHint);
6061}
6062
6063/*!
6064 \return a new texture with the specified \a format, \a pixelSize, \a
6065 sampleCount, and \a flags.
6066
6067 \note \a format specifies the requested internal and external format,
6068 meaning the data to be uploaded to the texture will need to be in a
6069 compatible format, while the native texture may (but is not guaranteed to,
6070 in case of OpenGL at least) use this format internally.
6071
6072 \sa QRhiResource::destroy()
6073 */
6074QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
6075 const QSize &pixelSize,
6076 int sampleCount,
6077 QRhiTexture::Flags flags)
6078{
6079 return d->createTexture(format, pixelSize, sampleCount, flags);
6080}
6081
6082/*!
6083 \return a new sampler with the specified magnification filter \a magFilter,
6084 minification filter \a minFilter, mipmapping mode \a mipmapMode, and the
6085 addressing (wrap) modes \a addressU, \a addressV, and \a addressW.
6086
6087 \sa QRhiResource::destroy()
6088 */
6089QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter,
6090 QRhiSampler::Filter minFilter,
6091 QRhiSampler::Filter mipmapMode,
6092 QRhiSampler::AddressMode addressU,
6093 QRhiSampler::AddressMode addressV,
6094 QRhiSampler::AddressMode addressW)
6095{
6096 return d->createSampler(magFilter, minFilter, mipmapMode, addressU, addressV, addressW);
6097}
6098
6099/*!
6100 \return a new texture render target with color and depth/stencil
6101 attachments given in \a desc, and with the specified \a flags.
6102
6103 \sa QRhiResource::destroy()
6104 */
6105
6106QRhiTextureRenderTarget *QRhi::newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
6107 QRhiTextureRenderTarget::Flags flags)
6108{
6109 return d->createTextureRenderTarget(desc, flags);
6110}
6111
6112/*!
6113 \return a new swapchain.
6114
6115 \sa QRhiResource::destroy(), QRhiSwapChain::createOrResize()
6116 */
6117QRhiSwapChain *QRhi::newSwapChain()
6118{
6119 return d->createSwapChain();
6120}
6121
6122/*!
6123 Starts a new frame targeting the next available buffer of \a swapChain.
6124
6125 A frame consists of resource updates and one or more render and compute
6126 passes.
6127
6128 \a flags can indicate certain special cases.
6129
6130 The high level pattern of rendering into a QWindow using a swapchain:
6131
6132 \list
6133
6134 \li Create a swapchain.
6135
6136 \li Call QRhiSwapChain::createOrResize() whenever the surface size is
6137 different than before.
6138
6139 \li Call QRhiSwapChain::destroy() on
6140 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed.
6141
6142 \li Then on every frame:
6143 \badcode
6144 beginFrame(sc);
6145 updates = nextResourceUpdateBatch();
6146 updates->...
6147 QRhiCommandBuffer *cb = sc->currentFrameCommandBuffer();
6148 cb->beginPass(sc->currentFrameRenderTarget(), colorClear, dsClear, updates);
6149 ...
6150 cb->endPass();
6151 ... // more passes as necessary
6152 endFrame(sc);
6153 \endcode
6154
6155 \endlist
6156
6157 \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult
6158 value on failure. Some of these should be treated as soft, "try again
6159 later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned,
6160 the swapchain is to be resized or updated by calling
6161 QRhiSwapChain::createOrResize(). The application should then attempt to
6162 generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is
6163 lost but this may also be recoverable by releasing all resources, including
6164 the QRhi itself, and then recreating all resources. See isDeviceLost() for
6165 further discussion.
6166
6167 \sa endFrame(), beginOffscreenFrame(), isDeviceLost()
6168 */
6169QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags)
6170{
6171 if (d->inFrame)
6172 qWarning("Attempted to call beginFrame() within a still active frame; ignored");
6173
6174 QRhi::FrameOpResult r = !d->inFrame ? d->beginFrame(swapChain, flags) : FrameOpSuccess;
6175 if (r == FrameOpSuccess)
6176 d->inFrame = true;
6177
6178 return r;
6179}
6180
6181/*!
6182 Ends, commits, and presents a frame that was started in the last
6183 beginFrame() on \a swapChain.
6184
6185 Double (or triple) buffering is managed internally by the QRhiSwapChain and
6186 QRhi.
6187
6188 \a flags can optionally be used to change the behavior in certain ways.
6189 Passing QRhi::SkipPresent skips queuing the Present command or calling
6190 swapBuffers.
6191
6192 \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult
6193 value on failure. Some of these should be treated as soft, "try again
6194 later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned,
6195 the swapchain is to be resized or updated by calling
6196 QRhiSwapChain::createOrResize(). The application should then attempt to
6197 generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is
6198 lost but this may also be recoverable by releasing all resources, including
6199 the QRhi itself, and then recreating all resources. See isDeviceLost() for
6200 further discussion.
6201
6202 \sa beginFrame(), isDeviceLost()
6203 */
6204QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags)
6205{
6206 if (!d->inFrame)
6207 qWarning("Attempted to call endFrame() without an active frame; ignored");
6208
6209 QRhi::FrameOpResult r = d->inFrame ? d->endFrame(swapChain, flags) : FrameOpSuccess;
6210 d->inFrame = false;
6211 // deleteLater is a high level QRhi concept the backends know
6212 // nothing about - handle it here.
6213 qDeleteAll(d->pendingDeleteResources);
6214 d->pendingDeleteResources.clear();
6215
6216 return r;
6217}
6218
6219/*!
6220 \return true when there is an active frame, meaning there was a
6221 beginFrame() (or beginOffscreenFrame()) with no corresponding endFrame()
6222 (or endOffscreenFrame()) yet.
6223
6224 \sa currentFrameSlot(), beginFrame(), endFrame()
6225 */
6226bool QRhi::isRecordingFrame() const
6227{
6228 return d->inFrame;
6229}
6230
6231/*!
6232 \return the current frame slot index while recording a frame. Unspecified
6233 when called outside an active frame (that is, when isRecordingFrame() is \c
6234 false).
6235
6236 With backends like Vulkan or Metal, it is the responsibility of the QRhi
6237 backend to block whenever starting a new frame and finding the CPU is
6238 already \c{FramesInFlight - 1} frames ahead of the GPU (because the command
6239 buffer submitted in frame no. \c{current} - \c{FramesInFlight} has not yet
6240 completed).
6241
6242 Resources that tend to change between frames (such as, the native buffer
6243 object backing a QRhiBuffer with type QRhiBuffer::Dynamic) exist in
6244 multiple versions, so that each frame, that can be submitted while a
6245 previous one is still being processed, works with its own copy, thus
6246 avoiding the need to stall the pipeline when preparing the frame. (The
6247 contents of a resource that may still be in use in the GPU should not be
6248 touched, but simply always waiting for the previous frame to finish would
6249 reduce GPU utilization and ultimately, performance and efficiency.)
6250
6251 Conceptually this is somewhat similar to copy-on-write schemes used by some
6252 C++ containers and other types. It may also be similar to what an OpenGL or
6253 Direct 3D 11 implementation performs internally for certain type of objects.
6254
6255 In practice, such double (or tripple) buffering resources is realized in
6256 the Vulkan, Metal, and similar QRhi backends by having a fixed number of
6257 native resource (such as, VkBuffer) \c slots behind a QRhiResource. That
6258 can then be indexed by a frame slot index running 0, 1, ..,
6259 FramesInFlight-1, and then wrapping around.
6260
6261 All this is managed transparently to the users of QRhi. However,
6262 applications that integrate rendering done directly with the graphics API
6263 may want to perform a similar double or tripple buffering of their own
6264 graphics resources. That is then most easily achieved by knowing the values
6265 of the maximum number of in-flight frames (retrievable via resourceLimit())
6266 and the current frame (slot) index (returned by this function).
6267
6268 \sa isRecordingFrame(), beginFrame(), endFrame()
6269 */
6270int QRhi::currentFrameSlot() const
6271{
6272 return d->currentFrameSlot;
6273}
6274
6275/*!
6276 Starts a new offscreen frame. Provides a command buffer suitable for
6277 recording rendering commands in \a cb. \a flags is used to indicate
6278 certain special cases, just like with beginFrame().
6279
6280 \note The QRhiCommandBuffer stored to *cb is not owned by the caller.
6281
6282 Rendering without a swapchain is possible as well. The typical use case is
6283 to use it in completely offscreen applications, e.g. to generate image
6284 sequences by rendering and reading back without ever showing a window.
6285
6286 Usage in on-screen applications (so beginFrame, endFrame,
6287 beginOffscreenFrame, endOffscreenFrame, beginFrame, ...) is possible too
6288 but it does reduce parallelism so it should be done only infrequently.
6289
6290 Offscreen frames do not let the CPU - potentially - generate another frame
6291 while the GPU is still processing the previous one. This has the side
6292 effect that if readbacks are scheduled, the results are guaranteed to be
6293 available once endOffscreenFrame() returns. That is not the case with
6294 frames targeting a swapchain.
6295
6296 The skeleton of rendering a frame without a swapchain and then reading the
6297 frame contents back could look like the following:
6298
6299 \badcode
6300 QRhiReadbackResult rbResult;
6301 QRhiCommandBuffer *cb;
6302 beginOffscreenFrame(&cb);
6303 beginPass
6304 ...
6305 u = nextResourceUpdateBatch();
6306 u->readBackTexture(rb, &rbResult);
6307 endPass(u);
6308 endOffscreenFrame();
6309 // image data available in rbResult
6310 \endcode
6311
6312 \sa endOffscreenFrame(), beginFrame()
6313 */
6314QRhi::FrameOpResult QRhi::beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags)
6315{
6316 if (d->inFrame)
6317 qWarning("Attempted to call beginOffscreenFrame() within a still active frame; ignored");
6318
6319 QRhi::FrameOpResult r = !d->inFrame ? d->beginOffscreenFrame(cb, flags) : FrameOpSuccess;
6320 if (r == FrameOpSuccess)
6321 d->inFrame = true;
6322
6323 return r;
6324}
6325
6326/*!
6327 Ends and waits for the offscreen frame.
6328
6329 \sa beginOffscreenFrame()
6330 */
6331QRhi::FrameOpResult QRhi::endOffscreenFrame(EndFrameFlags flags)
6332{
6333 if (!d->inFrame)
6334 qWarning("Attempted to call endOffscreenFrame() without an active frame; ignored");
6335
6336 QRhi::FrameOpResult r = d->inFrame ? d->endOffscreenFrame(flags) : FrameOpSuccess;
6337 d->inFrame = false;
6338 qDeleteAll(d->pendingDeleteResources);
6339 d->pendingDeleteResources.clear();
6340
6341 return r;
6342}
6343
6344/*!
6345 Waits for any work on the graphics queue (where applicable) to complete,
6346 then executes all deferred operations, like completing readbacks and
6347 resource releases. Can be called inside and outside of a frame, but not
6348 inside a pass. Inside a frame it implies submitting any work on the
6349 command buffer.
6350
6351 \note Avoid this function. One case where it may be needed is when the
6352 results of an enqueued readback in a swapchain-based frame are needed at a
6353 fixed given point and so waiting for the results is desired.
6354 */
6355QRhi::FrameOpResult QRhi::finish()
6356{
6357 return d->finish();
6358}
6359
6360/*!
6361 \return the list of supported sample counts.
6362
6363 A typical example would be (1, 2, 4, 8).
6364
6365 With some backend this list of supported values is fixed in advance, while
6366 with some others the (physical) device properties indicate what is
6367 supported at run time.
6368 */
6369QList<int> QRhi::supportedSampleCounts() const
6370{
6371 return d->supportedSampleCounts();
6372}
6373
6374/*!
6375 \return the minimum uniform buffer offset alignment in bytes. This is
6376 typically 256.
6377
6378 Attempting to bind a uniform buffer region with an offset not aligned to
6379 this value will lead to failures depending on the backend and the
6380 underlying graphics API.
6381
6382 \sa ubufAligned()
6383 */
6384int QRhi::ubufAlignment() const
6385{
6386 return d->ubufAlignment();
6387}
6388
6389static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0);
6390
6391QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId()
6392{
6393 return counter.fetchAndAddRelaxed(1) + 1;
6394}
6395
6396bool QRhiPassResourceTracker::isEmpty() const
6397{
6398 return m_buffers.isEmpty() && m_textures.isEmpty();
6399}
6400
6401void QRhiPassResourceTracker::reset()
6402{
6403 m_buffers.clear();
6404 m_textures.clear();
6405}
6406
6407static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a,
6408 QRhiPassResourceTracker::BufferStage b)
6409{
6410 return QRhiPassResourceTracker::BufferStage(qMin(int(a), int(b)));
6411}
6412
6413void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
6414 const UsageState &state)
6415{
6416 auto it = m_buffers.find(buf);
6417 if (it != m_buffers.end()) {
6418 if (it->access != *access) {
6419 const QByteArray name = buf->name();
6420 qWarning("Buffer %p (%s) used with different accesses within the same pass, this is not allowed.",
6421 buf, name.constData());
6422 return;
6423 }
6424 if (it->stage != *stage) {
6425 it->stage = earlierStage(it->stage, *stage);
6426 *stage = it->stage;
6427 }
6428 return;
6429 }
6430
6431 Buffer b;
6432 b.slot = slot;
6433 b.access = *access;
6434 b.stage = *stage;
6435 b.stateAtPassBegin = state; // first use -> initial state
6436 m_buffers.insert(buf, b);
6437}
6438
6439static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
6440 QRhiPassResourceTracker::TextureStage b)
6441{
6442 return QRhiPassResourceTracker::TextureStage(qMin(int(a), int(b)));
6443}
6444
6445static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access)
6446{
6447 return access == QRhiPassResourceTracker::TexStorageLoad
6448 || access == QRhiPassResourceTracker::TexStorageStore
6449 || access == QRhiPassResourceTracker::TexStorageLoadStore;
6450}
6451
6452void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
6453 const UsageState &state)
6454{
6455 auto it = m_textures.find(tex);
6456 if (it != m_textures.end()) {
6457 if (it->access != *access) {
6458 // Different subresources of a texture may be used for both load
6459 // and store in the same pass. (think reading from one mip level
6460 // and writing to another one in a compute shader) This we can
6461 // handle by treating the entire resource as read-write.
6462 if (isImageLoadStore(it->access) && isImageLoadStore(*access)) {
6463 it->access = QRhiPassResourceTracker::TexStorageLoadStore;
6464 *access = it->access;
6465 } else {
6466 const QByteArray name = tex->name();
6467 qWarning("Texture %p (%s) used with different accesses within the same pass, this is not allowed.",
6468 tex, name.constData());
6469 }
6470 }
6471 if (it->stage != *stage) {
6472 it->stage = earlierStage(it->stage, *stage);
6473 *stage = it->stage;
6474 }
6475 return;
6476 }
6477
6478 Texture t;
6479 t.access = *access;
6480 t.stage = *stage;
6481 t.stateAtPassBegin = state; // first use -> initial state
6482 m_textures.insert(tex, t);
6483}
6484
6485QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
6486{
6487 // pick the earlier stage (as this is going to be dstAccessMask)
6488 if (stages.testFlag(QRhiShaderResourceBinding::VertexStage))
6489 return QRhiPassResourceTracker::BufVertexStage;
6490 if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage))
6491 return QRhiPassResourceTracker::BufFragmentStage;
6492 if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
6493 return QRhiPassResourceTracker::BufComputeStage;
6494
6495 Q_UNREACHABLE();
6496 return QRhiPassResourceTracker::BufVertexStage;
6497}
6498
6499QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
6500{
6501 // pick the earlier stage (as this is going to be dstAccessMask)
6502 if (stages.testFlag(QRhiShaderResourceBinding::VertexStage))
6503 return QRhiPassResourceTracker::TexVertexStage;
6504 if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage))
6505 return QRhiPassResourceTracker::TexFragmentStage;
6506 if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage))
6507 return QRhiPassResourceTracker::TexComputeStage;
6508
6509 Q_UNREACHABLE();
6510 return QRhiPassResourceTracker::TexVertexStage;
6511}
6512
6513QT_END_NAMESPACE
6514