1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickrendertarget_p.h"
5#include <rhi/qrhi.h>
6#include <QtQuick/private/qquickitem_p.h>
7#include <QtQuick/private/qquickwindow_p.h>
8#include <QtQuick/private/qsgrhisupport_p.h>
9
10QT_BEGIN_NAMESPACE
11
12/*!
13 \class QQuickRenderTarget
14 \since 6.0
15 \inmodule QtQuick
16
17 \brief The QQuickRenderTarget class provides an opaque container for native
18 graphics resources specifying a render target, and associated metadata.
19
20 \sa QQuickWindow::setRenderTarget(), QQuickGraphicsDevice
21*/
22
23QQuickRenderTargetPrivate::QQuickRenderTargetPrivate()
24 : ref(1)
25{
26}
27
28QQuickRenderTargetPrivate::QQuickRenderTargetPrivate(const QQuickRenderTargetPrivate &other)
29 : ref(1),
30 type(other.type),
31 pixelSize(other.pixelSize),
32 devicePixelRatio(other.devicePixelRatio),
33 sampleCount(other.sampleCount),
34 u(other.u),
35 customDepthTexture(other.customDepthTexture),
36 mirrorVertically(other.mirrorVertically),
37 multisampleResolve(other.multisampleResolve)
38{
39}
40
41/*!
42 Constructs a default QQuickRenderTarget that does not reference any native
43 objects.
44 */
45QQuickRenderTarget::QQuickRenderTarget()
46 : d(new QQuickRenderTargetPrivate)
47{
48}
49
50/*!
51 \internal
52 */
53void QQuickRenderTarget::detach()
54{
55 qAtomicDetach(d);
56}
57
58/*!
59 \internal
60 */
61QQuickRenderTarget::QQuickRenderTarget(const QQuickRenderTarget &other)
62 : d(other.d)
63{
64 d->ref.ref();
65}
66
67/*!
68 \internal
69 */
70QQuickRenderTarget &QQuickRenderTarget::operator=(const QQuickRenderTarget &other)
71{
72 qAtomicAssign(d, x: other.d);
73 return *this;
74}
75
76/*!
77 Destructor.
78 */
79QQuickRenderTarget::~QQuickRenderTarget()
80{
81 if (!d->ref.deref())
82 delete d;
83}
84
85/*!
86 \return true if this QQuickRenderTarget is default constructed, referencing
87 no native objects.
88 */
89bool QQuickRenderTarget::isNull() const
90{
91 return d->type == QQuickRenderTargetPrivate::Type::Null;
92}
93
94/*!
95 \return the device pixel ratio for the render target. This is the ratio
96 between \e{device pixels} and \e{device independent pixels}.
97
98 The default device pixel ratio is 1.0.
99
100 \since 6.3
101
102 \sa setDevicePixelRatio()
103*/
104qreal QQuickRenderTarget::devicePixelRatio() const
105{
106 return d->devicePixelRatio;
107}
108
109/*!
110 Sets the device pixel ratio for this render target to \a ratio. This is
111 the ratio between \e{device pixels} and \e{device independent pixels}.
112
113 Note that the specified device pixel ratio value will be ignored if
114 QQuickRenderControl::renderWindow() is re-implemented to return a valid
115 QWindow.
116
117 \since 6.3
118
119 \sa devicePixelRatio()
120*/
121void QQuickRenderTarget::setDevicePixelRatio(qreal ratio)
122{
123 if (d->devicePixelRatio == ratio)
124 return;
125
126 detach();
127 d->devicePixelRatio = ratio;
128}
129
130/*!
131 \return Returns whether the render target is mirrored vertically.
132
133 The default value is \c {false}.
134
135 \since 6.4
136
137 \sa setMirrorVertically()
138*/
139bool QQuickRenderTarget::mirrorVertically() const
140{
141 return d->mirrorVertically;
142}
143
144
145/*!
146 Sets the size of the render target contents should be mirrored vertically to
147 \a enable when drawing. This allows easy integration of third-party rendering
148 code that does not follow the standard expectations.
149
150 \note This function should not be used when using the \c software backend.
151
152 \since 6.4
153
154 \sa mirrorVertically()
155 */
156void QQuickRenderTarget::setMirrorVertically(bool enable)
157{
158 if (d->mirrorVertically == enable)
159 return;
160
161 detach();
162 d->mirrorVertically = enable;
163}
164
165/*!
166 \return the currently set depth texture or, in most cases, \nullptr.
167
168 The value is only non-null when setDepthTexture() was called.
169
170 \since 6.8
171 */
172QRhiTexture *QQuickRenderTarget::depthTexture() const
173{
174 return d->customDepthTexture;
175}
176
177/*!
178 Requests using the given \a texture as the depth or depth-stencil buffer.
179 Ownership of \a texture is not taken.
180
181 The request is only taken into account when relevant. For example, calling
182 this function has no effect with fromRhiRenderTarget(), fromPaintDevice(),
183 or fromOpenGLRenderBuffer().
184
185 Normally a depth-stencil buffer is created automatically, transparently to
186 the user of QQuickRenderTarget. Therefore, there is no need to call this
187 function in most cases when working with QQuickRenderTarget. In special
188 circumstances, it can however become essential to be able to provide a
189 texture to render depth (or depth and stencil) data into, instead of letting
190 Qt Quick create its own intermediate textures or buffers. An example of this
191 is \l{https://www.khronos.org/openxr/}{OpenXR} and its extensions such as
192 \l{https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_KHR_composition_layer_depth}{XR_KHR_composition_layer_depth}.
193 In order to "submit the depth buffer" to the XR compositor, one has to, in
194 practice, retrieve an already created depth (depth-stencil) texture from
195 OpenXR (from the XrSwapchain) and use that texture as the render target for
196 depth data. That would not be possible without this function.
197
198 \note The \a texture is always expected to be a non-multisample 2D texture
199 or texture array (for multiview). If MSAA is involved, the samples are
200 resolved into \a texture at the end of the render pass, regardless of having
201 the MultisampleResolve flag set or not. MSAA is only supported for depth
202 (depth-stencil) textures when the underlying 3D API supports this, and this
203 support is not universally available. See \l{QRhi::ResolveDepthStencil}{the
204 relevant QRhi feature flag} for details. When this is not supported and
205 multisampling is requested in combination with a custom depth texture, \a
206 texture is not going to be touched during rendering and a warning is
207 printed.
208
209 \since 6.8
210
211 \note When it comes to OpenGL and OpenGL ES, using depth textures is not
212 functional on OpenGL ES 2.0 and requires at least OpenGL ES 3.0. Multisample
213 (MSAA) support is not available without at least OpenGL ES 3.1, or OpenGL
214 3.0 on desktop.
215 */
216void QQuickRenderTarget::setDepthTexture(QRhiTexture *texture)
217{
218 if (d->customDepthTexture == texture)
219 return;
220
221 detach();
222 d->customDepthTexture = texture;
223}
224
225/*!
226 \enum QQuickRenderTarget::Flag
227 Flags for the static QQuickRenderTarget constructor functions.
228
229 \value MultisampleResolve Indicates that the \c sampleCount argument is not
230 the number of samples for the provided texture (and that the texture is
231 still a non-multisample texture), but rather the desired samples for
232 multisample antialiasing. Triggers automatically creating and managing an
233 intermediate multisample texture (or texture array) as the color buffer,
234 transparently to the application. The samples are resolved into the provided
235 texture at the end of the render pass automatically. When this flag is not
236 set, and the \c sampleCount argument is greater than 1, it implies the
237 provided texture is multisample. The flag has no effect is the
238 \c sampleCount is 1 (indicating that multisampling is not involved).
239
240 \since 6.8
241*/
242
243/*!
244 \return a new QQuickRenderTarget referencing an OpenGL texture object
245 specified by \a textureId.
246
247 \a format specifies the native internal format of the
248 texture. Only texture formats that are supported by Qt's rendering
249 infrastructure should be used.
250
251 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
252 textures are supported.
253
254 \a sampleCount specifies the number of samples. 0 or 1 means no
255 multisampling, while a value like 4 or 8 states that the native object is a
256 multisample texture.
257
258 The texture is used as the first color attachment of the render target used
259 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
260 created and used automatically.
261
262 The OpenGL object name \a textureId must be a valid name in the rendering
263 context used by the Qt Quick scenegraph.
264
265 \note the resulting QQuickRenderTarget does not own any native resources,
266 it merely contains references and the associated metadata of the size and
267 sample count. It is the caller's responsibility to ensure that the native
268 resource exists as long as necessary.
269
270 \since 6.4
271
272 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
273 */
274#if QT_CONFIG(opengl) || defined(Q_QDOC)
275QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint format,
276 const QSize &pixelSize, int sampleCount)
277{
278 QQuickRenderTarget rt;
279 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
280
281 if (!textureId) {
282 qWarning(msg: "QQuickRenderTarget: textureId is invalid");
283 return rt;
284 }
285
286 if (pixelSize.isEmpty()) {
287 qWarning(msg: "QQuickRenderTarget: Cannot create with empty size");
288 return rt;
289 }
290
291 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
292 d->pixelSize = pixelSize;
293 d->sampleCount = qMax(a: 1, b: sampleCount);
294
295 QRhiTexture::Flags formatFlags;
296 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format, flags: &formatFlags);
297 d->u.nativeTexture = { .object: textureId, .layoutOrState: 0, .rhiFormat: uint(rhiFormat), .rhiFormatFlags: uint(formatFlags), .rhiViewFormat: uint(rhiFormat), .rhiViewFormatFlags: uint(formatFlags) };
298
299 return rt;
300}
301
302/*!
303 \overload
304
305 \return a new QQuickRenderTarget referencing an OpenGL texture
306 object specified by \a textureId. The texture is assumed to have a
307 format of GL_RGBA (GL_RGBA8).
308
309 \a pixelSize specifies the size of the image, in pixels. Currently
310 only 2D textures are supported.
311
312 \a sampleCount specifies the number of samples. 0 or 1 means no
313 multisampling, while a value like 4 or 8 states that the native
314 object is a multisample texture.
315
316 The texture is used as the first color attachment of the render target used
317 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
318 created and used automatically.
319
320 The OpenGL object name \a textureId must be a valid name in the rendering
321 context used by the Qt Quick scenegraph.
322
323 \note the resulting QQuickRenderTarget does not own any native resources,
324 it merely contains references and the associated metadata of the size and
325 sample count. It is the caller's responsibility to ensure that the native
326 resource exists as long as necessary.
327
328 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
329*/
330QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, const QSize &pixelSize, int sampleCount)
331{
332 return fromOpenGLTexture(textureId, format: 0, pixelSize, sampleCount);
333}
334
335/*!
336 \overload
337
338 \return a new QQuickRenderTarget referencing an OpenGL 2D texture or texture
339 array object specified by \a textureId.
340
341 \a format specifies the native internal format of the texture. Only texture
342 formats that are supported by Qt's rendering infrastructure should be used.
343
344 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
345 textures and 2D texture arrays are supported.
346
347 \a sampleCount specifies the number of samples. 0 or 1 means no
348 multisampling, while a value like 4 or 8 states that the native object is a
349 multisample texture, except when \a flags contains \l MultisampleResolve. In
350 that case, \a textureId is assumed to be a non-multisample 2D texture or 2D
351 texture array, and \a sampleCount defines the number of samples desired. The
352 resulting QQuickRenderTarget will use an intermediate, automatically created
353 multisample texture (or texture array) as its color attachment, and will
354 resolve the samples into \a textureId. This is the recommended approach to
355 perform MSAA when the native OpenGL texture is not already multisample.
356
357 When \a arraySize is greater than 1, it implies multiview rendering
358 (\l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview},
359 \l QRhiColorAttachment::setMultiViewCount()), which can be relevant with
360 VR/AR especially. In this case \a arraySize is the number of views,
361 typically \c 2. See \l QSGMaterial::viewCount() for details on enabling
362 multiview rendering within the Qt Quick scenegraph.
363
364 A depth-stencil buffer, if applicable, is created and used automatically.
365 When the color buffer is multisample, the depth-stencil buffer will
366 automatically be multisample too. For multiview rendering, the depth-stencil
367 texture will automatically be made an array with a matching \a arraySize.
368
369 The OpenGL object name \a textureId must be a valid 2D texture name in the
370 rendering context used by the Qt Quick scenegraph. When \a arraySize is
371 greater than 1, \a textureId must be a valid 2D texture array name.
372
373 \note the resulting QQuickRenderTarget does not own any native resources, it
374 merely contains references and the associated metadata of the size and
375 sample count. It is the caller's responsibility to ensure that the native
376 resource exists as long as necessary.
377
378 \since 6.8
379
380 \note The implementation of this overload is not compatible with OpenGL ES
381 2.0 or 3.0, and requires OpenGL ES 3.1 at minimum. (or OpenGL 3.0 on
382 desktop)
383
384 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl, fromOpenGLTexture()
385 */
386QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint format, QSize pixelSize, int sampleCount, int arraySize, Flags flags)
387{
388 QQuickRenderTarget rt;
389 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
390
391 if (!textureId) {
392 qWarning(msg: "QQuickRenderTarget: textureId is invalid");
393 return rt;
394 }
395
396 if (pixelSize.isEmpty()) {
397 qWarning(msg: "QQuickRenderTarget: Cannot create with empty size");
398 return rt;
399 }
400
401 QRhiTexture::Flags formatFlags;
402 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format, flags: &formatFlags);
403
404 d->pixelSize = pixelSize;
405 d->sampleCount = qMax(a: 1, b: sampleCount);
406 d->multisampleResolve = flags.testFlag(flag: Flag::MultisampleResolve);
407
408 if (arraySize <= 1) {
409 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
410 d->u.nativeTexture = { .object: textureId, .layoutOrState: 0, .rhiFormat: uint(rhiFormat), .rhiFormatFlags: uint(formatFlags), .rhiViewFormat: uint(rhiFormat), .rhiViewFormatFlags: uint(formatFlags) };
411 } else {
412 d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
413 d->u.nativeTextureArray = { .object: textureId, .layoutOrState: 0, .arraySize: arraySize, .rhiFormat: uint(rhiFormat), .rhiFormatFlags: uint(formatFlags), .rhiViewFormat: uint(rhiFormat), .rhiViewFormatFlags: uint(formatFlags) };
414 }
415
416 return rt;
417}
418
419/*!
420 \return a new QQuickRenderTarget referencing an OpenGL renderbuffer object
421 specified by \a renderbufferId.
422
423 The renderbuffer will be used as the color attachment for the internal
424 framebuffer object. This function is provided to allow targeting
425 renderbuffers that are created by the application with some external buffer
426 underneath, such as an EGLImageKHR. Once the application has called
427 \l{https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image.txt}{glEGLImageTargetRenderbufferStorageOES},
428 the renderbuffer can be passed to this function.
429
430 \a pixelSize specifies the size of the image, in pixels.
431
432 \a sampleCount specifies the number of samples. 0 or 1 means no
433 multisampling, while a value like 4 or 8 states that the native object is a
434 multisample renderbuffer.
435
436 \note the resulting QQuickRenderTarget does not own any native resources,
437 it merely contains references and the associated metadata of the size and
438 sample count. It is the caller's responsibility to ensure that the native
439 resource exists as long as necessary.
440
441 \since 6.2
442
443 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
444 */
445QQuickRenderTarget QQuickRenderTarget::fromOpenGLRenderBuffer(uint renderbufferId, const QSize &pixelSize, int sampleCount)
446{
447 QQuickRenderTarget rt;
448 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
449
450 if (!renderbufferId) {
451 qWarning(msg: "QQuickRenderTarget: renderbufferId is invalid");
452 return rt;
453 }
454
455 if (pixelSize.isEmpty()) {
456 qWarning(msg: "QQuickRenderTarget: Cannot create with empty size");
457 return rt;
458 }
459
460 d->type = QQuickRenderTargetPrivate::Type::NativeRenderbuffer;
461 d->pixelSize = pixelSize;
462 d->sampleCount = qMax(a: 1, b: sampleCount);
463 d->u.nativeRenderbufferObject = renderbufferId;
464
465 return rt;
466}
467#endif
468
469/*!
470 \return a new QQuickRenderTarget referencing a D3D11 texture object
471 specified by \a texture.
472
473 \a format specifies the DXGI_FORMAT of the texture. Only texture formats
474 that are supported by Qt's rendering infrastructure should be used.
475
476 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
477 textures are supported.
478
479 \a sampleCount specifies the number of samples. 0 or 1 means no
480 multisampling, while a value like 4 or 8 states that the native object is a
481 multisample texture.
482
483 The texture is used as the first color attachment of the render target used
484 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
485 created and used automatically.
486
487 \note the resulting QQuickRenderTarget does not own any native resources,
488 it merely contains references and the associated metadata of the size and
489 sample count. It is the caller's responsibility to ensure that the native
490 resource exists as long as necessary.
491
492 \since 6.4
493
494 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
495 */
496#if defined(Q_OS_WIN) || defined(Q_QDOC)
497QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, uint format,
498 const QSize &pixelSize, int sampleCount)
499{
500 QQuickRenderTarget rt;
501 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
502
503 if (!texture) {
504 qWarning("QQuickRenderTarget: texture is null");
505 return rt;
506 }
507
508 if (pixelSize.isEmpty()) {
509 qWarning("QQuickRenderTarget: Cannot create with empty size");
510 return rt;
511 }
512
513 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
514 d->pixelSize = pixelSize;
515 d->sampleCount = qMax(1, sampleCount);
516
517 QRhiTexture::Flags formatFlags;
518 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &formatFlags);
519 d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
520
521 return rt;
522}
523
524/*!
525 \overload
526
527 \return a new QQuickRenderTarget referencing a D3D11 texture
528 object specified by \a texture. The texture is assumed to have a
529 format of DXGI_FORMAT_R8G8B8A8_UNORM.
530
531 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
532 textures are supported.
533
534 \a sampleCount specifies the number of samples. 0 or 1 means no
535 multisampling, while a value like 4 or 8 states that the native object is a
536 multisample texture.
537
538 The texture is used as the first color attachment of the render target used
539 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
540 created and used automatically.
541
542 \note the resulting QQuickRenderTarget does not own any native resources,
543 it merely contains references and the associated metadata of the size and
544 sample count. It is the caller's responsibility to ensure that the native
545 resource exists as long as necessary.
546
547 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
548*/
549QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, const QSize &pixelSize, int sampleCount)
550{
551 return fromD3D11Texture(texture, 0 /* DXGI_FORMAT_UNKNOWN */, pixelSize, sampleCount);
552}
553
554/*!
555 \overload
556
557 \return a new QQuickRenderTarget referencing a D3D11 texture object
558 specified by \a texture.
559
560 \a format specifies the DXGI_FORMAT of the texture. Only texture formats
561 that are supported by Qt's rendering infrastructure should be used.
562
563 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
564 textures are supported.
565
566 \a sampleCount specifies the number of samples. 0 or 1 means no
567 multisampling, while a value like 4 or 8 states that the native object is a
568 multisample texture, except when \a flags contains \l MultisampleResolve. In
569 that case, \a texture is assumed to be a non-multisample 2D texture and \a
570 sampleCount defines the number of samples desired. The resulting
571 QQuickRenderTarget will use an intermediate, automatically created
572 multisample texture as its color attachment, and will resolve the samples
573 into \a texture. This is the recommended approach to perform MSAA when the
574 native texture is not already multisample.
575
576 The texture is used as the first color attachment of the render target used
577 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
578 created and used automatically. When the color buffer is multisample, the
579 depth-stencil buffer will automatically be multisample too.
580
581 \note the resulting QQuickRenderTarget does not own any native resources, it
582 merely contains references and the associated metadata of the size and
583 sample count. It is the caller's responsibility to ensure that the native
584 resource exists as long as necessary.
585
586 \since 6.8
587
588 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl, fromD3D11Texture()
589 */
590QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, uint format, QSize pixelSize, int sampleCount, Flags flags)
591{
592 QQuickRenderTarget rt = fromD3D11Texture(texture, format, pixelSize, sampleCount);
593 QQuickRenderTargetPrivate::get(&rt)->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
594 return rt;
595}
596
597/*!
598 \return a new QQuickRenderTarget referencing a D3D12 texture object
599 specified by \a texture.
600
601 \a resourceState must a valid bitmask with bits from D3D12_RESOURCE_STATES,
602 specifying the resource's current state.
603
604 \a format specifies the DXGI_FORMAT of the texture. Only texture formats
605 that are supported by Qt's rendering infrastructure should be used.
606
607 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
608 textures are supported.
609
610 \a sampleCount specifies the number of samples. 0 or 1 means no
611 multisampling, while a value like 4 or 8 states that the native object is a
612 multisample texture.
613
614 The texture is used as the first color attachment of the render target used
615 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
616 created and used automatically.
617
618 \note the resulting QQuickRenderTarget does not own any native resources,
619 it merely contains references and the associated metadata of the size and
620 sample count. It is the caller's responsibility to ensure that the native
621 resource exists as long as necessary.
622
623 \since 6.6
624
625 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
626 */
627QQuickRenderTarget QQuickRenderTarget::fromD3D12Texture(void *texture,
628 int resourceState,
629 uint format,
630 const QSize &pixelSize,
631 int sampleCount)
632{
633 QQuickRenderTarget rt;
634 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
635
636 if (!texture) {
637 qWarning("QQuickRenderTarget: texture is null");
638 return rt;
639 }
640
641 if (pixelSize.isEmpty()) {
642 qWarning("QQuickRenderTarget: Cannot create with empty size");
643 return rt;
644 }
645
646 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
647 d->pixelSize = pixelSize;
648 d->sampleCount = qMax(1, sampleCount);
649
650 QRhiTexture::Flags formatFlags;
651 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &formatFlags);
652 d->u.nativeTexture = { quint64(texture), resourceState, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
653
654 return rt;
655}
656
657/*!
658 \overload
659
660 \return a new QQuickRenderTarget referencing a D3D12 2D texture or 2D
661 texture array object specified by \a texture.
662
663 \a resourceState must a valid bitmask with bits from D3D12_RESOURCE_STATES,
664 specifying the resource's current state.
665
666 \a format specifies the DXGI_FORMAT of the texture. Only texture formats
667 that are supported by Qt's rendering infrastructure should be used.
668
669 \a viewFormat is the DXGI_FORMAT used for the render target view (RTV).
670 Often the same as \a format. Functional only when
671 \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html}{relaxed
672 format casting} is supported by the driver, the argument is ignored otherwise.
673 In practice support is expected to be always available on Windows 10 1703
674 and newer.
675
676 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
677 textures and 2D texture arrays are supported.
678
679 \a sampleCount specifies the number of samples. 0 or 1 means no
680 multisampling, while a value like 4 or 8 states that the native object is a
681 multisample texture, except when \a flags contains \l MultisampleResolve. In
682 that case, \a texture is assumed to be a non-multisample 2D texture or 2D
683 texture array, and \a sampleCount defines the number of samples desired. The
684 resulting QQuickRenderTarget will use an intermediate, automatically created
685 multisample texture (or texture array) as its color attachment, and will
686 resolve the samples into \a texture. This is the recommended approach to
687 perform MSAA when the native D3D12 texture is not already multisample.
688
689 The number of array elements (layers) is given in \a arraySize. When greater
690 than 1, it implies multiview rendering
691 (\l{https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html}{view
692 instancing}), which can be relevant with VR/AR especially. \a arraySize is
693 the number of views, typically \c 2. See \l QSGMaterial::viewCount() for
694 details on enabling multiview rendering within the Qt Quick scenegraph.
695
696 The texture is used as the first color attachment of the render target used
697 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
698 created and used automatically. When the color buffer is multisample, the
699 depth-stencil buffer will automatically be multisample too. For multiview
700 rendering, the depth-stencil texture will automatically be made an array
701 with a matching \a arraySize.
702
703 \note the resulting QQuickRenderTarget does not own any native resources, it
704 merely contains references and the associated metadata of the size and
705 sample count. It is the caller's responsibility to ensure that the native
706 resource exists as long as necessary.
707
708 \since 6.8
709
710 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
711 */
712QQuickRenderTarget QQuickRenderTarget::fromD3D12Texture(void *texture,
713 int resourceState,
714 uint format,
715 uint viewFormat,
716 QSize pixelSize,
717 int sampleCount,
718 int arraySize,
719 Flags flags)
720{
721 QQuickRenderTarget rt;
722 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
723
724 if (!texture) {
725 qWarning("QQuickRenderTarget: texture is null");
726 return rt;
727 }
728
729 if (pixelSize.isEmpty()) {
730 qWarning("QQuickRenderTarget: Cannot create with empty size");
731 return rt;
732 }
733
734 QRhiTexture::Flags formatFlags;
735 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &formatFlags);
736 QRhiTexture::Flags viewFormatFlags;
737 QRhiTexture::Format rhiViewFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(viewFormat, &viewFormatFlags);
738
739 d->pixelSize = pixelSize;
740 d->sampleCount = qMax(1, sampleCount);
741 d->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
742
743 if (arraySize <= 1) {
744 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
745 d->u.nativeTexture = { quint64(texture), resourceState, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
746 } else {
747 d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
748 d->u.nativeTextureArray = { quint64(texture), resourceState, arraySize, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
749 }
750
751 return rt;
752}
753
754#endif // Q_OS_WIN
755
756/*!
757 \return a new QQuickRenderTarget referencing a Metal texture object
758 specified by \a texture.
759
760 \a format specifies the MTLPixelFormat of the texture. Only texture formats
761 that are supported by Qt's rendering infrastructure should be used.
762
763 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
764 textures are supported.
765
766 \a sampleCount specifies the number of samples. 0 or 1 means no
767 multisampling, while a value like 4 or 8 states that the native object is a
768 multisample texture.
769
770 The texture is used as the first color attachment of the render target used
771 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
772 created and used automatically.
773
774 \note the resulting QQuickRenderTarget does not own any native resources,
775 it merely contains references and the associated metadata of the size and
776 sample count. It is the caller's responsibility to ensure that the native
777 resource exists as long as necessary.
778
779 \since 6.4
780
781 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
782 */
783#if QT_CONFIG(metal) || defined(Q_QDOC)
784QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, uint format,
785 const QSize &pixelSize, int sampleCount)
786{
787 QQuickRenderTarget rt;
788 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
789
790 if (!texture) {
791 qWarning("QQuickRenderTarget: texture is null");
792 return rt;
793 }
794
795 if (pixelSize.isEmpty()) {
796 qWarning("QQuickRenderTarget: Cannot create with empty size");
797 return rt;
798 }
799
800 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
801 d->pixelSize = pixelSize;
802 d->sampleCount = qMax(1, sampleCount);
803
804 QRhiTexture::Flags formatFlags;
805 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &formatFlags);
806 d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(formatFlags), uint(rhiFormat), uint(formatFlags) };
807
808 return rt;
809}
810
811/*!
812 \overload
813
814 \return a new QQuickRenderTarget referencing a Metal texture object
815 specified by \a texture. The texture is assumed to have a format of
816 MTLPixelFormatRGBA8Unorm.
817
818 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
819 textures are supported.
820
821 \a sampleCount specifies the number of samples. 0 or 1 means no
822 multisampling, while a value like 4 or 8 states that the native object is a
823 multisample texture.
824
825 The texture is used as the first color attachment of the render target used
826 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
827 created and used automatically.
828
829 \note the resulting QQuickRenderTarget does not own any native resources,
830 it merely contains references and the associated metadata of the size and
831 sample count. It is the caller's responsibility to ensure that the native
832 resource exists as long as necessary.
833
834 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
835*/
836QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, const QSize &pixelSize, int sampleCount)
837{
838 return fromMetalTexture(texture, 0 /* MTLPixelFormatInvalid */, pixelSize, sampleCount);
839}
840
841/*!
842 \overload
843
844 \return a new QQuickRenderTarget referencing a Metal 2D texture or 2D
845 texture array given in \a texture.
846
847 \a format specifies the MTLPixelFormat of the texture. Only texture formats
848 that are supported by Qt's rendering infrastructure should be used.
849
850 \a viewFormat is usually set to the same value as \a format. In some cases,
851 such as when rendering into a texture with a \c{_SRGB} format and the
852 implicit linear->sRGB conversion on shader writes is not wanted, the value
853 can be different. Note however that the value may be ignored by Qt, when at
854 run time QRhi reports that the \l{QRhi::TextureViewFormat} feature is
855 unsupported.
856
857 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
858 textures and 2D texture arrays are supported.
859
860 \a sampleCount specifies the number of samples. 0 or 1 means no
861 multisampling, while a value like 4 or 8 states that the native object is a
862 multisample texture, except when \a flags contains \l MultisampleResolve. In
863 that case, \a texture is assumed to be a non-multisample 2D texture or 2D
864 texture array, and \a sampleCount defines the number of samples desired. The
865 resulting QQuickRenderTarget will use an intermediate, automatically created
866 multisample texture (or texture array) as its color attachment, and will
867 resolve the samples into \a texture. This is the recommended approach to
868 perform MSAA when the native Metal texture is not already multisample.
869
870 The number of array elements (layers) is given in \a arraySize. When greater
871 than 1, it implies multiview rendering, which can be relevant with VR/AR
872 especially. \a arraySize is the number of views, typically \c 2. See
873 \l QSGMaterial::viewCount() for details on enabling multiview rendering within
874 the Qt Quick scenegraph.
875
876 The texture is used as the first color attachment of the render target used
877 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
878 created and used automatically. When the color buffer is multisample, the
879 depth-stencil buffer will automatically be multisample too. For multiview
880 rendering, the depth-stencil texture will automatically be made an array
881 with a matching \a arraySize.
882
883 \note the resulting QQuickRenderTarget does not own any native resources, it
884 merely contains references and the associated metadata of the size and
885 sample count. It is the caller's responsibility to ensure that the native
886 resource exists as long as necessary.
887
888 \since 6.8
889
890 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
891 */
892QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, uint format, uint viewFormat,
893 QSize pixelSize, int sampleCount, int arraySize, Flags flags)
894{
895 QQuickRenderTarget rt;
896 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
897
898 if (!texture) {
899 qWarning("QQuickRenderTarget: texture is null");
900 return rt;
901 }
902
903 if (pixelSize.isEmpty()) {
904 qWarning("QQuickRenderTarget: Cannot create with empty size");
905 return rt;
906 }
907
908 QRhiTexture::Flags formatFlags;
909 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &formatFlags);
910 QRhiTexture::Flags viewFormatFlags;
911 QRhiTexture::Format rhiViewFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(viewFormat, &viewFormatFlags);
912
913 d->pixelSize = pixelSize;
914 d->sampleCount = qMax(1, sampleCount);
915 d->multisampleResolve = flags.testFlag(Flag::MultisampleResolve);
916
917 if (arraySize <= 1) {
918 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
919 d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
920 } else {
921 d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
922 d->u.nativeTextureArray = { quint64(texture), 0, arraySize, uint(rhiFormat), uint(formatFlags), uint(rhiViewFormat), uint(viewFormatFlags) };
923 }
924
925 return rt;
926}
927
928#endif
929
930/*!
931 \return a new QQuickRenderTarget referencing a Vulkan image object
932 specified by \a image. The current \a layout of the image must be provided
933 as well.
934
935 \a format specifies the VkFormat of the image. Only image formats that are
936 supported by Qt's rendering infrastructure should be used.
937
938 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
939 textures are supported.
940
941 \a sampleCount specifies the number of samples. 0 or 1 means no
942 multisampling, while a value like 4 or 8 states that the native object is a
943 multisample texture.
944
945 The image is used as the first color attachment of the render target used
946 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
947 created and used automatically.
948
949 \note the resulting QQuickRenderTarget does not own any native resources,
950 it merely contains references and the associated metadata of the size and
951 sample count. It is the caller's responsibility to ensure that the native
952 resource exists as long as necessary.
953
954 \since 6.4
955
956 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
957 */
958#if QT_CONFIG(vulkan) || defined(Q_QDOC)
959QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format, const QSize &pixelSize, int sampleCount)
960{
961 QQuickRenderTarget rt;
962 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
963
964 if (image == VK_NULL_HANDLE) {
965 qWarning(msg: "QQuickRenderTarget: image is invalid");
966 return rt;
967 }
968
969 if (pixelSize.isEmpty()) {
970 qWarning(msg: "QQuickRenderTarget: Cannot create with empty size");
971 return rt;
972 }
973
974 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
975 d->pixelSize = pixelSize;
976 d->sampleCount = qMax(a: 1, b: sampleCount);
977
978 QRhiTexture::Flags formatFlags;
979 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, flags: &formatFlags);
980 d->u.nativeTexture = { .object: quint64(image), .layoutOrState: layout, .rhiFormat: uint(rhiFormat), .rhiFormatFlags: uint(formatFlags), .rhiViewFormat: uint(rhiFormat), .rhiViewFormatFlags: uint(formatFlags) };
981
982 return rt;
983}
984
985/*!
986 \overload
987
988 \return a new QQuickRenderTarget referencing a Vulkan image object specified
989 by \a image. The image is assumed to have a format of
990 VK_FORMAT_R8G8B8A8_UNORM.
991
992 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
993 textures are supported.
994
995 \a sampleCount specifies the number of samples. 0 or 1 means no
996 multisampling, while a value like 4 or 8 states that the native object is a
997 multisample texture.
998
999 The texture is used as the first color attachment of the render target used
1000 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
1001 created and used automatically.
1002
1003 \note the resulting QQuickRenderTarget does not own any native resources,
1004 it merely contains references and the associated metadata of the size and
1005 sample count. It is the caller's responsibility to ensure that the native
1006 resource exists as long as necessary.
1007
1008 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
1009*/
1010QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, const QSize &pixelSize, int sampleCount)
1011{
1012 return fromVulkanImage(image, layout, format: VK_FORMAT_UNDEFINED, pixelSize, sampleCount);
1013}
1014
1015/*!
1016 \overload
1017
1018 \return a new QQuickRenderTarget referencing a Vulkan image object
1019 specified by \a image. The current \a layout of the image must be provided
1020 as well. The image must be either a 2D texture or 2D texture array.
1021
1022 \a format specifies the VkFormat of the image. Only image formats that are
1023 supported by Qt's rendering infrastructure should be used.
1024
1025 \a viewFormat is usually set to the same value as \a format. In some cases,
1026 such as when rendering into a texture with a \c{_SRGB} format and the
1027 implicit linear->sRGB conversion on shader writes is not wanted, the value
1028 can be different. (for example, a \a format of \c VK_FORMAT_R8G8B8A8_SRGB
1029 and \a viewFormat of \c VK_FORMAT_R8G8B8A8_UNORM).
1030
1031 \a pixelSize specifies the size of the image, in pixels. Currently only 2D
1032 textures are supported.
1033
1034 \a sampleCount specifies the number of samples. 0 or 1 means no
1035 multisampling, while a value like 4 or 8 states that the native object is a
1036 multisample texture, except when \a flags contains \l MultisampleResolve. In
1037 that case, \a image is assumed to be a non-multisample 2D texture or 2D
1038 texture array, and \a sampleCount defines the number of samples desired. The
1039 resulting QQuickRenderTarget will use an intermediate, automatically created
1040 multisample texture (or texture array) as its color attachment, and will
1041 resolve the samples into \a image. This is the recommended approach to
1042 perform MSAA when the native Vulkan image is not already multisample.
1043
1044 The number of array elements (layers) is given in \a arraySize. When greater
1045 than 1, it implies multiview rendering
1046 (\l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html}{VK_KHR_multiview}),
1047 which can be relevant with VR/AR especially. \a arraySize is the number of
1048 views, typically \c 2. See \l QSGMaterial::viewCount() for details on
1049 enabling multiview rendering within the Qt Quick scenegraph.
1050
1051 The texture is used as the first color attachment of the render target used
1052 by the Qt Quick scenegraph. A depth-stencil buffer, if applicable, is
1053 created and used automatically. When the color buffer is multisample, the
1054 depth-stencil buffer will automatically be multisample too. For multiview
1055 rendering, the depth-stencil texture will automatically be made an array
1056 with a matching \a arraySize.
1057
1058 \note the resulting QQuickRenderTarget does not own any native resources, it
1059 merely contains references and the associated metadata of the size and
1060 sample count. It is the caller's responsibility to ensure that the native
1061 resource exists as long as necessary.
1062
1063 \since 6.8
1064
1065 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
1066 */
1067QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format, VkFormat viewFormat,
1068 QSize pixelSize, int sampleCount, int arraySize, Flags flags)
1069{
1070 QQuickRenderTarget rt;
1071 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
1072
1073 if (image == VK_NULL_HANDLE) {
1074 qWarning(msg: "QQuickRenderTarget: image is invalid");
1075 return rt;
1076 }
1077
1078 if (pixelSize.isEmpty()) {
1079 qWarning(msg: "QQuickRenderTarget: Cannot create with empty size");
1080 return rt;
1081 }
1082
1083 QRhiTexture::Flags formatFlags;
1084 QRhiTexture::Format rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, flags: &formatFlags);
1085 QRhiTexture::Flags viewFormatFlags;
1086 QRhiTexture::Format rhiViewFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format: viewFormat, flags: &viewFormatFlags);
1087
1088 d->pixelSize = pixelSize;
1089 d->sampleCount = qMax(a: 1, b: sampleCount);
1090 d->multisampleResolve = flags.testFlag(flag: Flag::MultisampleResolve);
1091
1092 if (arraySize <= 1) {
1093 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
1094 d->u.nativeTexture = { .object: quint64(image), .layoutOrState: layout, .rhiFormat: uint(rhiFormat), .rhiFormatFlags: uint(formatFlags), .rhiViewFormat: uint(rhiViewFormat), .rhiViewFormatFlags: uint(viewFormatFlags) };
1095 } else {
1096 d->type = QQuickRenderTargetPrivate::Type::NativeTextureArray;
1097 d->u.nativeTextureArray = { .object: quint64(image), .layoutOrState: layout, .arraySize: arraySize, .rhiFormat: uint(rhiFormat), .rhiFormatFlags: uint(formatFlags), .rhiViewFormat: uint(rhiViewFormat), .rhiViewFormatFlags: uint(viewFormatFlags) };
1098 }
1099
1100 return rt;
1101}
1102
1103#endif // Vulkan
1104
1105/*!
1106 \return a new QQuickRenderTarget referencing an existing \a renderTarget.
1107
1108 \a renderTarget will in most cases be a QRhiTextureRenderTarget, which
1109 allows directing the Qt Quick scene's rendering into a QRhiTexture.
1110
1111 \note the resulting QQuickRenderTarget does not own \a renderTarget and any
1112 underlying native resources, it merely contains references and the
1113 associated metadata of the size and sample count. It is the caller's
1114 responsibility to ensure that the referenced resources exists as long as
1115 necessary.
1116
1117 \since 6.6
1118
1119 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
1120*/
1121QQuickRenderTarget QQuickRenderTarget::fromRhiRenderTarget(QRhiRenderTarget *renderTarget)
1122{
1123 QQuickRenderTarget rt;
1124 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
1125
1126 if (!renderTarget) {
1127 qWarning(msg: "QQuickRenderTarget: Needs a valid QRhiRenderTarget");
1128 return rt;
1129 }
1130
1131 d->type = QQuickRenderTargetPrivate::Type::RhiRenderTarget;
1132 d->pixelSize = renderTarget->pixelSize();
1133 d->sampleCount = renderTarget->sampleCount();
1134 d->u.rhiRt = renderTarget;
1135
1136 return rt;
1137}
1138
1139/*!
1140 \return a new QQuickRenderTarget referencing a paint device object
1141 specified by \a device.
1142
1143 This option of redirecting rendering to a QPaintDevice is available only
1144 when running with the \c software backend of Qt Quick.
1145
1146 \note The QQuickRenderTarget does not take ownship of \a device, it is the
1147 caller's responsibility to ensure the object exists as long as necessary.
1148
1149 \since 6.4
1150
1151 \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
1152 */
1153QQuickRenderTarget QQuickRenderTarget::fromPaintDevice(QPaintDevice *device)
1154{
1155 QQuickRenderTarget rt;
1156 QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(rt: &rt);
1157
1158 d->type = QQuickRenderTargetPrivate::Type::PaintDevice;
1159 d->pixelSize = QSize(device->width(), device->height());
1160 d->u.paintDevice = device;
1161
1162 return rt;
1163}
1164
1165/*!
1166 \fn bool QQuickRenderTarget::operator==(const QQuickRenderTarget &a, const QQuickRenderTarget &b) noexcept
1167 \return true if \a a and \a b refer to the same set of native objects and
1168 have matching associated data (size, sample count).
1169*/
1170/*!
1171 \fn bool QQuickRenderTarget::operator!=(const QQuickRenderTarget &a, const QQuickRenderTarget &b) noexcept
1172
1173 \return true if \a a and \a b refer to a different set of native objects,
1174 or the associated data (size, sample count) does not match.
1175*/
1176
1177/*!
1178 \internal
1179*/
1180bool QQuickRenderTarget::isEqual(const QQuickRenderTarget &other) const noexcept
1181{
1182 if (d->type != other.d->type
1183 || d->pixelSize != other.d->pixelSize
1184 || d->devicePixelRatio != other.d->devicePixelRatio
1185 || d->sampleCount != other.d->sampleCount
1186 || d->mirrorVertically != other.d->mirrorVertically
1187 || d->multisampleResolve != other.d->multisampleResolve)
1188 {
1189 return false;
1190 }
1191
1192 switch (d->type) {
1193 case QQuickRenderTargetPrivate::Type::Null:
1194 break;
1195 case QQuickRenderTargetPrivate::Type::NativeTexture:
1196 if (d->u.nativeTexture.object != other.d->u.nativeTexture.object
1197 || d->u.nativeTexture.layoutOrState != other.d->u.nativeTexture.layoutOrState
1198 || d->u.nativeTexture.rhiFormat != other.d->u.nativeTexture.rhiFormat
1199 || d->u.nativeTexture.rhiFormatFlags != other.d->u.nativeTexture.rhiFormatFlags
1200 || d->u.nativeTexture.rhiViewFormat != other.d->u.nativeTexture.rhiViewFormat
1201 || d->u.nativeTexture.rhiViewFormatFlags != other.d->u.nativeTexture.rhiViewFormatFlags)
1202 return false;
1203 break;
1204 case QQuickRenderTargetPrivate::Type::NativeTextureArray:
1205 if (d->u.nativeTextureArray.object != other.d->u.nativeTextureArray.object
1206 || d->u.nativeTextureArray.layoutOrState != other.d->u.nativeTextureArray.layoutOrState
1207 || d->u.nativeTextureArray.arraySize != other.d->u.nativeTextureArray.arraySize
1208 || d->u.nativeTextureArray.rhiFormat != other.d->u.nativeTextureArray.rhiFormat
1209 || d->u.nativeTextureArray.rhiFormatFlags != other.d->u.nativeTextureArray.rhiFormatFlags
1210 || d->u.nativeTextureArray.rhiViewFormat != other.d->u.nativeTextureArray.rhiViewFormat
1211 || d->u.nativeTextureArray.rhiViewFormatFlags != other.d->u.nativeTextureArray.rhiViewFormatFlags)
1212 return false;
1213 break;
1214 case QQuickRenderTargetPrivate::Type::NativeRenderbuffer:
1215 if (d->u.nativeRenderbufferObject != other.d->u.nativeRenderbufferObject)
1216 return false;
1217 break;
1218 case QQuickRenderTargetPrivate::Type::RhiRenderTarget:
1219 if (d->u.rhiRt != other.d->u.rhiRt)
1220 return false;
1221 break;
1222 case QQuickRenderTargetPrivate::Type::PaintDevice:
1223 if (d->u.paintDevice != other.d->u.paintDevice)
1224 return false;
1225 break;
1226 default:
1227 break;
1228 }
1229
1230 return true;
1231}
1232
1233static bool createRhiRenderTargetWithRenderBuffer(QRhiRenderBuffer *renderBuffer,
1234 const QSize &pixelSize,
1235 int sampleCount,
1236 QRhi *rhi,
1237 QQuickWindowRenderTarget *dst)
1238{
1239 sampleCount = QSGRhiSupport::chooseSampleCount(samples: sampleCount, rhi);
1240
1241 std::unique_ptr<QRhiRenderBuffer> depthStencil;
1242 if (dst->implicitBuffers.depthStencil) {
1243 if (dst->implicitBuffers.depthStencil->pixelSize() == pixelSize
1244 && dst->implicitBuffers.depthStencil->sampleCount() == sampleCount)
1245 {
1246 depthStencil.reset(p: dst->implicitBuffers.depthStencil);
1247 dst->implicitBuffers.depthStencil = nullptr;
1248 }
1249 }
1250 dst->implicitBuffers.reset(rhi);
1251
1252 if (!depthStencil) {
1253 depthStencil.reset(p: rhi->newRenderBuffer(type: QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount));
1254 depthStencil->setName(QByteArrayLiteral("Depth-stencil buffer for QQuickRenderTarget"));
1255 if (!depthStencil->create()) {
1256 qWarning(msg: "Failed to build depth-stencil buffer for QQuickRenderTarget");
1257 return false;
1258 }
1259 }
1260
1261 QRhiColorAttachment colorAttachment(renderBuffer);
1262 QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
1263 rtDesc.setDepthStencilBuffer(depthStencil.get());
1264 std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(desc: rtDesc));
1265 rt->setName(QByteArrayLiteral("RT for QQuickRenderTarget with renderbuffer"));
1266 std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
1267 rt->setRenderPassDescriptor(rp.get());
1268
1269 if (!rt->create()) {
1270 qWarning(msg: "Failed to build renderbuffer-based render target for QQuickRenderTarget");
1271 return false;
1272 }
1273
1274 dst->rt.renderTarget = rt.release();
1275 dst->rt.owns = true;
1276 dst->res.rpDesc = rp.release();
1277 dst->implicitBuffers.depthStencil = depthStencil.release();
1278
1279 return true;
1280}
1281
1282static bool createRhiRenderTarget(QRhiTexture *texture,
1283 const QSize &pixelSize,
1284 int sampleCount,
1285 bool multisampleResolve,
1286 QRhi *rhi,
1287 QQuickWindowRenderTarget *dst)
1288{
1289 // Simple path: no user-supplied depth texture. So create our own
1290 // depth-stencil buffer, using renderbuffers (so this is still GLES 2.0
1291 // compatible), with MSAA support being GLES 3.0 compatible.
1292
1293 sampleCount = QSGRhiSupport::chooseSampleCount(samples: sampleCount, rhi);
1294 if (sampleCount <= 1)
1295 multisampleResolve = false;
1296
1297 std::unique_ptr<QRhiRenderBuffer> depthStencil;
1298 if (dst->implicitBuffers.depthStencil) {
1299 if (dst->implicitBuffers.depthStencil->pixelSize() == pixelSize
1300 && dst->implicitBuffers.depthStencil->sampleCount() == sampleCount)
1301 {
1302 depthStencil.reset(p: dst->implicitBuffers.depthStencil);
1303 dst->implicitBuffers.depthStencil = nullptr;
1304 }
1305 }
1306
1307 std::unique_ptr<QRhiTexture> colorBuffer;
1308 QRhiTexture::Flags multisampleTextureFlags;
1309 QRhiTexture::Format multisampleTextureFormat = texture->format();
1310 if (multisampleResolve) {
1311 multisampleTextureFlags = QRhiTexture::RenderTarget;
1312 if (texture->flags().testFlag(flag: QRhiTexture::sRGB))
1313 multisampleTextureFlags |= QRhiTexture::sRGB;
1314
1315 if (dst->implicitBuffers.multisampleTexture) {
1316 if (dst->implicitBuffers.multisampleTexture->pixelSize() == pixelSize
1317 && dst->implicitBuffers.multisampleTexture->format() == multisampleTextureFormat
1318 && dst->implicitBuffers.multisampleTexture->sampleCount() == sampleCount
1319 && dst->implicitBuffers.multisampleTexture->flags().testFlags(flags: multisampleTextureFlags))
1320 {
1321 colorBuffer.reset(p: dst->implicitBuffers.multisampleTexture);
1322 dst->implicitBuffers.multisampleTexture = nullptr;
1323 }
1324 }
1325 }
1326
1327 dst->implicitBuffers.reset(rhi);
1328
1329 if (!depthStencil) {
1330 depthStencil.reset(p: rhi->newRenderBuffer(type: QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount));
1331 depthStencil->setName(QByteArrayLiteral("Depth-stencil buffer for QQuickRenderTarget"));
1332 if (!depthStencil->create()) {
1333 qWarning(msg: "Failed to build depth-stencil buffer for QQuickRenderTarget");
1334 return false;
1335 }
1336 }
1337
1338 if (multisampleResolve && !colorBuffer) {
1339 colorBuffer.reset(p: rhi->newTexture(format: multisampleTextureFormat, pixelSize, sampleCount, flags: multisampleTextureFlags));
1340 colorBuffer->setName(QByteArrayLiteral("Multisample color buffer for QQuickRenderTarget"));
1341 colorBuffer->setWriteViewFormat(texture->writeViewFormat());
1342 if (!colorBuffer->create()) {
1343 qWarning(msg: "Failed to build multisample color buffer for QQuickRenderTarget");
1344 return false;
1345 }
1346 }
1347
1348 QRhiColorAttachment colorAttachment;
1349 if (multisampleResolve) {
1350 colorAttachment.setTexture(colorBuffer.get());
1351 colorAttachment.setResolveTexture(texture);
1352 } else {
1353 colorAttachment.setTexture(texture);
1354 }
1355 QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
1356 rtDesc.setDepthStencilBuffer(depthStencil.get());
1357 std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(desc: rtDesc));
1358 rt->setName(QByteArrayLiteral("RT for QQuickRenderTarget"));
1359 std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
1360 rt->setRenderPassDescriptor(rp.get());
1361
1362 if (!rt->create()) {
1363 qWarning(msg: "Failed to build texture render target for QQuickRenderTarget");
1364 return false;
1365 }
1366
1367 dst->rt.renderTarget = rt.release();
1368 dst->rt.owns = true;
1369 dst->res.rpDesc = rp.release();
1370 dst->implicitBuffers.depthStencil = depthStencil.release();
1371 if (multisampleResolve)
1372 dst->implicitBuffers.multisampleTexture = colorBuffer.release();
1373
1374 return true;
1375}
1376
1377static bool createRhiRenderTargetWithDepthTexture(QRhiTexture *texture,
1378 QRhiTexture *depthTexture,
1379 const QSize &pixelSize,
1380 int sampleCount,
1381 bool multisampleResolve,
1382 QRhi *rhi,
1383 QQuickWindowRenderTarget *dst)
1384{
1385 // This version takes a user-supplied depthTexture. That texture is always
1386 // non-multisample. If sample count is > 1, we still need our own
1387 // multisample depth-stencil buffer, and the depth(stencil) data is expected
1388 // to be resolved (and written out) to depthTexture, _if_ the underlying API
1389 // supports it (see QRhi's ResolveDepthStencil feature). The intermediate,
1390 // multisample depth-stencil buffer must be a texture here (not
1391 // renderbuffer), specifically for OpenGL ES and its related multisample
1392 // extensions.
1393
1394 sampleCount = QSGRhiSupport::chooseSampleCount(samples: sampleCount, rhi);
1395 if (sampleCount <= 1)
1396 multisampleResolve = false;
1397
1398 std::unique_ptr<QRhiTexture> depthStencil;
1399 if (dst->implicitBuffers.depthStencilTexture) {
1400 if (dst->implicitBuffers.depthStencilTexture->pixelSize() == pixelSize
1401 && dst->implicitBuffers.depthStencilTexture->sampleCount() == sampleCount)
1402 {
1403 depthStencil.reset(p: dst->implicitBuffers.depthStencilTexture);
1404 dst->implicitBuffers.depthStencilTexture = nullptr;
1405 }
1406 }
1407
1408 std::unique_ptr<QRhiTexture> colorBuffer;
1409 QRhiTexture::Flags multisampleTextureFlags;
1410 QRhiTexture::Format multisampleTextureFormat = texture->format();
1411 if (multisampleResolve) {
1412 multisampleTextureFlags = QRhiTexture::RenderTarget;
1413 if (texture->flags().testFlag(flag: QRhiTexture::sRGB))
1414 multisampleTextureFlags |= QRhiTexture::sRGB;
1415
1416 if (dst->implicitBuffers.multisampleTexture) {
1417 if (dst->implicitBuffers.multisampleTexture->pixelSize() == pixelSize
1418 && dst->implicitBuffers.multisampleTexture->format() == multisampleTextureFormat
1419 && dst->implicitBuffers.multisampleTexture->sampleCount() == sampleCount
1420 && dst->implicitBuffers.multisampleTexture->flags().testFlags(flags: multisampleTextureFlags))
1421 {
1422 colorBuffer.reset(p: dst->implicitBuffers.multisampleTexture);
1423 dst->implicitBuffers.multisampleTexture = nullptr;
1424 }
1425 }
1426 }
1427
1428 dst->implicitBuffers.reset(rhi);
1429
1430 bool needsDepthStencilBuffer = true;
1431 if (sampleCount <= 1) {
1432 depthStencil.reset();
1433 needsDepthStencilBuffer = false;
1434 }
1435 if (depthTexture->pixelSize() != pixelSize) {
1436 qWarning(msg: "Custom depth texture size (%dx%d) does not match the QQuickRenderTarget (%dx%d)",
1437 depthTexture->pixelSize().width(),
1438 depthTexture->pixelSize().height(),
1439 pixelSize.width(),
1440 pixelSize.height());
1441 return false;
1442 }
1443 if (depthTexture->sampleCount() > 1) {
1444 qWarning(msg: "Custom depth texture cannot be multisample");
1445 return false;
1446 }
1447 if (needsDepthStencilBuffer && !depthStencil) {
1448 QRhiTexture::Format multisampleDepthTextureFormat = depthTexture->format();
1449 depthStencil.reset(p: rhi->newTexture(format: multisampleDepthTextureFormat, pixelSize, sampleCount, flags: QRhiTexture::RenderTarget));
1450 depthStencil->setName(QByteArrayLiteral("Depth-stencil texture for QQuickRenderTarget"));
1451 if (!depthStencil->create()) {
1452 qWarning(msg: "Failed to build depth-stencil buffer for QQuickRenderTarget");
1453 return false;
1454 }
1455 }
1456
1457 if (multisampleResolve && !colorBuffer) {
1458 colorBuffer.reset(p: rhi->newTexture(format: multisampleTextureFormat, pixelSize, sampleCount, flags: multisampleTextureFlags));
1459 colorBuffer->setName(QByteArrayLiteral("Multisample color buffer for QQuickRenderTarget"));
1460 colorBuffer->setWriteViewFormat(texture->writeViewFormat());
1461 if (!colorBuffer->create()) {
1462 qWarning(msg: "Failed to build multisample color buffer for QQuickRenderTarget");
1463 return false;
1464 }
1465 }
1466
1467 QRhiColorAttachment colorAttachment;
1468 if (multisampleResolve) {
1469 colorAttachment.setTexture(colorBuffer.get());
1470 colorAttachment.setResolveTexture(texture);
1471 } else {
1472 colorAttachment.setTexture(texture);
1473 }
1474
1475 QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
1476 if (sampleCount > 1) {
1477 rtDesc.setDepthTexture(depthStencil.get());
1478 if (rhi->isFeatureSupported(feature: QRhi::ResolveDepthStencil))
1479 rtDesc.setDepthResolveTexture(depthTexture);
1480 else
1481 qWarning(msg: "Depth-stencil resolve is not supported by the underlying 3D API, depth contents will not be resolved");
1482 } else {
1483 rtDesc.setDepthTexture(depthTexture);
1484 }
1485
1486 std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(desc: rtDesc));
1487 rt->setName(QByteArrayLiteral("RT for QQuickRenderTarget"));
1488 std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
1489 rt->setRenderPassDescriptor(rp.get());
1490
1491 if (!rt->create()) {
1492 qWarning(msg: "Failed to build texture render target for QQuickRenderTarget");
1493 return false;
1494 }
1495
1496 dst->rt.renderTarget = rt.release();
1497 dst->rt.owns = true;
1498 dst->res.rpDesc = rp.release();
1499 if (depthStencil)
1500 dst->implicitBuffers.depthStencilTexture = depthStencil.release();
1501 if (multisampleResolve)
1502 dst->implicitBuffers.multisampleTexture = colorBuffer.release();
1503
1504 return true;
1505}
1506
1507static bool createRhiRenderTargetMultiView(QRhiTexture *texture,
1508 QRhiTexture *maybeCustomDepthTexture,
1509 const QSize &pixelSize,
1510 int arraySize,
1511 int sampleCount,
1512 bool multisampleResolve,
1513 QRhi *rhi,
1514 QQuickWindowRenderTarget *dst)
1515{
1516 // Multiview path, working with texture arrays. Optionally with a
1517 // user-supplied, non-multisample depth texture (array). (same semantics
1518 // then as with createRhiRenderTargetWithDepthTexture, but everything is a
1519 // 2D texture array here)
1520
1521 sampleCount = QSGRhiSupport::chooseSampleCount(samples: sampleCount, rhi);
1522 if (sampleCount <= 1)
1523 multisampleResolve = false;
1524
1525 std::unique_ptr<QRhiTexture> depthStencil;
1526 if (dst->implicitBuffers.depthStencilTexture) {
1527 if (dst->implicitBuffers.depthStencilTexture->pixelSize() == pixelSize
1528 && dst->implicitBuffers.depthStencilTexture->sampleCount() == sampleCount
1529 && dst->implicitBuffers.depthStencilTexture->arraySize() == arraySize)
1530 {
1531 depthStencil.reset(p: dst->implicitBuffers.depthStencilTexture);
1532 dst->implicitBuffers.depthStencilTexture = nullptr;
1533 }
1534 }
1535
1536 std::unique_ptr<QRhiTexture> colorBuffer;
1537 QRhiTexture::Flags multisampleTextureFlags;
1538 QRhiTexture::Format multisampleTextureFormat = texture->format();
1539 if (multisampleResolve) {
1540 multisampleTextureFlags = QRhiTexture::RenderTarget;
1541 if (texture->flags().testFlag(flag: QRhiTexture::sRGB))
1542 multisampleTextureFlags |= QRhiTexture::sRGB;
1543
1544 if (dst->implicitBuffers.multisampleTexture) {
1545 if (dst->implicitBuffers.multisampleTexture->pixelSize() == pixelSize
1546 && dst->implicitBuffers.multisampleTexture->format() == multisampleTextureFormat
1547 && dst->implicitBuffers.multisampleTexture->sampleCount() == sampleCount
1548 && dst->implicitBuffers.multisampleTexture->arraySize() == arraySize
1549 && dst->implicitBuffers.multisampleTexture->flags().testFlags(flags: multisampleTextureFlags))
1550 {
1551 colorBuffer.reset(p: dst->implicitBuffers.multisampleTexture);
1552 dst->implicitBuffers.multisampleTexture = nullptr;
1553 }
1554 }
1555 }
1556
1557 dst->implicitBuffers.reset(rhi);
1558
1559 bool needsDepthStencilBuffer = true;
1560 if (maybeCustomDepthTexture) {
1561 if (sampleCount <= 1) {
1562 depthStencil.reset();
1563 needsDepthStencilBuffer = false;
1564 }
1565 if (maybeCustomDepthTexture->arraySize() != arraySize) {
1566 qWarning(msg: "Custom depth texture array size (%d) does not match QQuickRenderTarget (%d)",
1567 maybeCustomDepthTexture->arraySize(), arraySize);
1568 return false;
1569 }
1570 if (maybeCustomDepthTexture->pixelSize() != pixelSize) {
1571 qWarning(msg: "Custom depth texture size (%dx%d) does not match the QQuickRenderTarget (%dx%d)",
1572 maybeCustomDepthTexture->pixelSize().width(),
1573 maybeCustomDepthTexture->pixelSize().height(),
1574 pixelSize.width(),
1575 pixelSize.height());
1576 return false;
1577 }
1578 if (maybeCustomDepthTexture->sampleCount() > 1) {
1579 qWarning(msg: "Custom depth texture cannot be multisample");
1580 return false;
1581 }
1582 }
1583 if (needsDepthStencilBuffer && !depthStencil) {
1584 QRhiTexture::Format format;
1585 if (maybeCustomDepthTexture)
1586 format = maybeCustomDepthTexture->format();
1587 else
1588 format = rhi->isTextureFormatSupported(format: QRhiTexture::D24S8) ? QRhiTexture::D24S8 : QRhiTexture::D32F;
1589 depthStencil.reset(p: rhi->newTextureArray(format, arraySize, pixelSize, sampleCount, flags: QRhiTexture::RenderTarget));
1590 depthStencil->setName(QByteArrayLiteral("Depth-stencil buffer (multiview) for QQuickRenderTarget"));
1591 if (!depthStencil->create()) {
1592 qWarning(msg: "Failed to build depth-stencil texture array for QQuickRenderTarget");
1593 return false;
1594 }
1595 }
1596
1597 if (multisampleResolve && !colorBuffer) {
1598 colorBuffer.reset(p: rhi->newTextureArray(format: multisampleTextureFormat, arraySize, pixelSize, sampleCount, flags: multisampleTextureFlags));
1599 colorBuffer->setName(QByteArrayLiteral("Multisample color buffer (multiview) for QQuickRenderTarget"));
1600 colorBuffer->setWriteViewFormat(texture->writeViewFormat());
1601 if (!colorBuffer->create()) {
1602 qWarning(msg: "Failed to build multisample texture array for QQuickRenderTarget");
1603 return false;
1604 }
1605 }
1606
1607 QRhiColorAttachment colorAttachment;
1608 colorAttachment.setMultiViewCount(arraySize);
1609 if (multisampleResolve) {
1610 colorAttachment.setTexture(colorBuffer.get());
1611 colorAttachment.setResolveTexture(texture);
1612 } else {
1613 colorAttachment.setTexture(texture);
1614 }
1615
1616 QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
1617 if (sampleCount > 1) {
1618 rtDesc.setDepthTexture(depthStencil.get());
1619 if (maybeCustomDepthTexture) {
1620 if (rhi->isFeatureSupported(feature: QRhi::ResolveDepthStencil))
1621 rtDesc.setDepthResolveTexture(maybeCustomDepthTexture);
1622 else
1623 qWarning(msg: "Depth-stencil resolve is not supported by the underlying 3D API, depth contents will not be resolved");
1624 }
1625 } else {
1626 if (depthStencil)
1627 rtDesc.setDepthTexture(depthStencil.get());
1628 else if (maybeCustomDepthTexture)
1629 rtDesc.setDepthTexture(maybeCustomDepthTexture);
1630 }
1631
1632 QRhiTextureRenderTarget::Flags rtFlags;
1633 if (!maybeCustomDepthTexture)
1634 rtFlags |= QRhiTextureRenderTarget::DoNotStoreDepthStencilContents;
1635
1636 std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(desc: rtDesc, flags: rtFlags));
1637 rt->setName(QByteArrayLiteral("RT for multiview QQuickRenderTarget"));
1638 std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
1639 rt->setRenderPassDescriptor(rp.get());
1640
1641 if (!rt->create()) {
1642 qWarning(msg: "Failed to build multiview texture render target for QQuickRenderTarget");
1643 return false;
1644 }
1645
1646 dst->rt.renderTarget = rt.release();
1647 dst->rt.owns = true;
1648 dst->res.rpDesc = rp.release();
1649 if (depthStencil)
1650 dst->implicitBuffers.depthStencilTexture = depthStencil.release();
1651 if (multisampleResolve)
1652 dst->implicitBuffers.multisampleTexture = colorBuffer.release();
1653
1654 dst->rt.multiViewCount = arraySize;
1655
1656 return true;
1657}
1658
1659bool QQuickRenderTargetPrivate::resolve(QRhi *rhi, QQuickWindowRenderTarget *dst)
1660{
1661 // dst->implicitBuffers may contain valid objects. If so, and their
1662 // properties are suitable, they are expected to be reused. Once taken what
1663 // we can reuse, it needs to be reset().
1664
1665 switch (type) {
1666 case Type::Null:
1667 dst->implicitBuffers.reset(rhi);
1668 return true;
1669
1670 case Type::NativeTexture:
1671 {
1672 QRhiTexture::Format format = u.nativeTexture.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
1673 : QRhiTexture::Format(u.nativeTexture.rhiFormat);
1674 QRhiTexture::Format viewFormat = u.nativeTexture.rhiViewFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
1675 : QRhiTexture::Format(u.nativeTexture.rhiViewFormat);
1676 const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTexture.rhiFormatFlags);
1677 std::unique_ptr<QRhiTexture> texture(rhi->newTexture(format, pixelSize, sampleCount: multisampleResolve ? 1 : sampleCount, flags));
1678 const bool textureIsSrgb = flags.testFlag(flag: QRhiTexture::sRGB);
1679 const bool viewIsSrgb = QRhiTexture::Flags(u.nativeTexture.rhiViewFormatFlags).testFlag(flag: QRhiTexture::sRGB);
1680 if (viewFormat != format || viewIsSrgb != textureIsSrgb)
1681 texture->setWriteViewFormat({ .format: viewFormat, .srgb: viewIsSrgb });
1682 if (!texture->createFrom(src: { .object: u.nativeTexture.object, .layout: u.nativeTexture.layoutOrState })) {
1683 qWarning(msg: "Failed to build wrapper texture for QQuickRenderTarget");
1684 return false;
1685 }
1686 if (customDepthTexture) {
1687 if (!createRhiRenderTargetWithDepthTexture(texture: texture.get(), depthTexture: customDepthTexture, pixelSize, sampleCount, multisampleResolve, rhi, dst))
1688 return false;
1689 } else {
1690 if (!createRhiRenderTarget(texture: texture.get(), pixelSize, sampleCount, multisampleResolve, rhi, dst))
1691 return false;
1692 }
1693 dst->res.texture = texture.release();
1694 }
1695 return true;
1696
1697 case Type::NativeTextureArray:
1698 {
1699 QRhiTexture::Format format = u.nativeTextureArray.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
1700 : QRhiTexture::Format(u.nativeTextureArray.rhiFormat);
1701 QRhiTexture::Format viewFormat = u.nativeTextureArray.rhiViewFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
1702 : QRhiTexture::Format(u.nativeTextureArray.rhiViewFormat);
1703 const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTextureArray.rhiFormatFlags);
1704 const int arraySize = u.nativeTextureArray.arraySize;
1705 std::unique_ptr<QRhiTexture> texture(rhi->newTextureArray(format, arraySize, pixelSize, sampleCount: multisampleResolve ? 1 : sampleCount, flags));
1706 const bool textureIsSrgb = flags.testFlag(flag: QRhiTexture::sRGB);
1707 const bool viewIsSrgb = QRhiTexture::Flags(u.nativeTextureArray.rhiViewFormatFlags).testFlag(flag: QRhiTexture::sRGB);
1708 if (viewFormat != format || viewIsSrgb != textureIsSrgb)
1709 texture->setWriteViewFormat({ .format: viewFormat, .srgb: viewIsSrgb });
1710 if (!texture->createFrom(src: { .object: u.nativeTextureArray.object, .layout: u.nativeTextureArray.layoutOrState })) {
1711 qWarning(msg: "Failed to build wrapper texture array for QQuickRenderTarget");
1712 return false;
1713 }
1714 if (!createRhiRenderTargetMultiView(texture: texture.get(), maybeCustomDepthTexture: customDepthTexture, pixelSize, arraySize, sampleCount, multisampleResolve, rhi, dst))
1715 return false;
1716 dst->res.texture = texture.release();
1717 }
1718 return true;
1719
1720 case Type::NativeRenderbuffer:
1721 {
1722 std::unique_ptr<QRhiRenderBuffer> renderbuffer(rhi->newRenderBuffer(type: QRhiRenderBuffer::Color, pixelSize, sampleCount));
1723 if (!renderbuffer->createFrom(src: { .object: u.nativeRenderbufferObject })) {
1724 qWarning(msg: "Failed to build wrapper renderbuffer for QQuickRenderTarget");
1725 return false;
1726 }
1727 if (customDepthTexture)
1728 qWarning(msg: "Custom depth texture is not supported with renderbuffers in QQuickRenderTarget");
1729 if (!createRhiRenderTargetWithRenderBuffer(renderBuffer: renderbuffer.get(), pixelSize, sampleCount, rhi, dst))
1730 return false;
1731 dst->res.renderBuffer = renderbuffer.release();
1732 }
1733 return true;
1734
1735 case Type::RhiRenderTarget:
1736 dst->implicitBuffers.reset(rhi);
1737 dst->rt.renderTarget = u.rhiRt;
1738 dst->rt.owns = false;
1739 if (dst->rt.renderTarget->resourceType() == QRhiResource::TextureRenderTarget) {
1740 auto texRt = static_cast<QRhiTextureRenderTarget *>(dst->rt.renderTarget);
1741 const QRhiTextureRenderTargetDescription desc = texRt->description();
1742 bool first = true;
1743 for (auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1744 if (it->multiViewCount() <= 1)
1745 continue;
1746 if (first || dst->rt.multiViewCount == it->multiViewCount()) {
1747 first = false;
1748 if (it->texture() && it->texture()->flags().testFlag(flag: QRhiTexture::TextureArray)) {
1749 if (it->texture()->arraySize() >= it->layer() + it->multiViewCount()) {
1750 dst->rt.multiViewCount = it->multiViewCount();
1751 } else {
1752 qWarning(msg: "Invalid QQuickRenderTarget; needs at least %d elements in texture array, got %d",
1753 it->layer() + it->multiViewCount(),
1754 it->texture()->arraySize());
1755 return false;
1756 }
1757 } else {
1758 qWarning(msg: "Invalid QQuickRenderTarget; multiview requires a texture array");
1759 return false;
1760 }
1761 } else {
1762 qWarning(msg: "Inconsistent multiViewCount in QQuickRenderTarget (was %d, now found an attachment with %d)",
1763 dst->rt.multiViewCount, it->multiViewCount());
1764 return false;
1765 }
1766 }
1767 }
1768 if (customDepthTexture)
1769 qWarning(msg: "Custom depth texture is not supported with QRhiRenderTarget in QQuickRenderTarget");
1770 return true;
1771
1772 case Type::PaintDevice:
1773 dst->implicitBuffers.reset(rhi);
1774 dst->sw.paintDevice = u.paintDevice;
1775 dst->sw.owns = false;
1776 return true;
1777 }
1778
1779 Q_UNREACHABLE_RETURN(false);
1780}
1781
1782QT_END_NAMESPACE
1783

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/quick/items/qquickrendertarget.cpp