Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquickrendertarget.cpp
Go to the documentation of this file.
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
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
11
24 : ref(1)
25{
26}
27
29 : ref(1),
30 type(other->type),
31 pixelSize(other->pixelSize),
32 devicePixelRatio(other->devicePixelRatio),
33 sampleCount(other->sampleCount),
34 u(other->u),
35 mirrorVertically(other->mirrorVertically)
36{
37}
38
45{
46}
47
51void QQuickRenderTarget::detach()
52{
54}
55
60 : d(other.d)
61{
62 d->ref.ref();
63}
64
69{
70 qAtomicAssign(d, other.d);
71 return *this;
72}
73
78{
79 if (!d->ref.deref())
80 delete d;
81}
82
88{
89 return d->type == QQuickRenderTargetPrivate::Type::Null;
90}
91
103{
104 return d->devicePixelRatio;
105}
106
120{
121 if (d->devicePixelRatio == ratio)
122 return;
123
124 detach();
125 d->devicePixelRatio = ratio;
126}
127
138{
139 return d->mirrorVertically;
140}
141
142
155{
156 if (d->mirrorVertically == enable)
157 return;
158
159 detach();
161}
162
194#if QT_CONFIG(opengl) || defined(Q_QDOC)
195QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, uint format,
196 const QSize &pixelSize, int sampleCount)
197{
200
201 if (!textureId) {
202 qWarning("QQuickRenderTarget: textureId is invalid");
203 return rt;
204 }
205
206 if (pixelSize.isEmpty()) {
207 qWarning("QQuickRenderTarget: Cannot create with empty size");
208 return rt;
209 }
210
211 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
212 d->pixelSize = pixelSize;
213 d->sampleCount = qMax(1, sampleCount);
214
215 auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromGL(format);
216 d->u.nativeTexture = { textureId, 0, uint(rhiFormat), 0 };
217
218 return rt;
219}
220
249QQuickRenderTarget QQuickRenderTarget::fromOpenGLTexture(uint textureId, const QSize &pixelSize, int sampleCount)
250{
251 return fromOpenGLTexture(textureId, 0, pixelSize, sampleCount);
252}
253
280QQuickRenderTarget QQuickRenderTarget::fromOpenGLRenderBuffer(uint renderbufferId, const QSize &pixelSize, int sampleCount)
281{
284
285 if (!renderbufferId) {
286 qWarning("QQuickRenderTarget: renderbufferId is invalid");
287 return rt;
288 }
289
290 if (pixelSize.isEmpty()) {
291 qWarning("QQuickRenderTarget: Cannot create with empty size");
292 return rt;
293 }
294
295 d->type = QQuickRenderTargetPrivate::Type::NativeRenderbuffer;
296 d->pixelSize = pixelSize;
297 d->sampleCount = qMax(1, sampleCount);
298 d->u.nativeRenderbufferObject = renderbufferId;
299
300 return rt;
301}
302#endif
303
331#if defined(Q_OS_WIN) || defined(Q_QDOC)
332QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, uint format,
333 const QSize &pixelSize, int sampleCount)
334{
337
338 if (!texture) {
339 qWarning("QQuickRenderTarget: texture is null");
340 return rt;
341 }
342
343 if (pixelSize.isEmpty()) {
344 qWarning("QQuickRenderTarget: Cannot create with empty size");
345 return rt;
346 }
347
348 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
349 d->pixelSize = pixelSize;
350 d->sampleCount = qMax(1, sampleCount);
351
352 QRhiTexture::Flags flags;
353 auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &flags);
354 d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(flags) };
355
356 return rt;
357}
358
384QQuickRenderTarget QQuickRenderTarget::fromD3D11Texture(void *texture, const QSize &pixelSize, int sampleCount)
385{
386 return fromD3D11Texture(texture, 0 /* DXGI_FORMAT_UNKNOWN */, pixelSize, sampleCount);
387}
388
419QQuickRenderTarget QQuickRenderTarget::fromD3D12Texture(void *texture,
420 int resourceState,
421 uint format,
422 const QSize &pixelSize,
423 int sampleCount)
424{
427
428 if (!texture) {
429 qWarning("QQuickRenderTarget: texture is null");
430 return rt;
431 }
432
433 if (pixelSize.isEmpty()) {
434 qWarning("QQuickRenderTarget: Cannot create with empty size");
435 return rt;
436 }
437
438 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
439 d->pixelSize = pixelSize;
440 d->sampleCount = qMax(1, sampleCount);
441
442 QRhiTexture::Flags flags;
443 auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromDXGI(format, &flags);
444 d->u.nativeTexture = { quint64(texture), resourceState, uint(rhiFormat), uint(flags) };
445
446 return rt;
447}
448#endif
449
477#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_QDOC)
478QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, uint format,
479 const QSize &pixelSize, int sampleCount)
480{
483
484 if (!texture) {
485 qWarning("QQuickRenderTarget: texture is null");
486 return rt;
487 }
488
489 if (pixelSize.isEmpty()) {
490 qWarning("QQuickRenderTarget: Cannot create with empty size");
491 return rt;
492 }
493
494 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
495 d->pixelSize = pixelSize;
496 d->sampleCount = qMax(1, sampleCount);
497
498 QRhiTexture::Flags flags;
499 auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromMetal(format, &flags);
500 d->u.nativeTexture = { quint64(texture), 0, uint(rhiFormat), uint(flags) };
501
502 return rt;
503}
504
530QQuickRenderTarget QQuickRenderTarget::fromMetalTexture(MTLTexture *texture, const QSize &pixelSize, int sampleCount)
531{
532 return fromMetalTexture(texture, 0 /* MTLPixelFormatInvalid */, pixelSize, sampleCount);
533}
534#endif
535
564#if QT_CONFIG(vulkan) || defined(Q_QDOC)
565QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, VkFormat format,
566 const QSize &pixelSize, int sampleCount)
567{
570
571 if (image == VK_NULL_HANDLE) {
572 qWarning("QQuickRenderTarget: image is invalid");
573 return rt;
574 }
575
576 if (pixelSize.isEmpty()) {
577 qWarning("QQuickRenderTarget: Cannot create with empty size");
578 return rt;
579 }
580
581 d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
582 d->pixelSize = pixelSize;
583 d->sampleCount = qMax(1, sampleCount);
584
585 QRhiTexture::Flags flags;
586 auto rhiFormat = QSGRhiSupport::toRhiTextureFormatFromVulkan(format, &flags);
587 d->u.nativeTexture = { quint64(image), layout, uint(rhiFormat), uint(flags) };
588
589 return rt;
590}
591
617QQuickRenderTarget QQuickRenderTarget::fromVulkanImage(VkImage image, VkImageLayout layout, const QSize &pixelSize, int sampleCount)
618{
619 return fromVulkanImage(image, layout, VK_FORMAT_UNDEFINED, pixelSize, sampleCount);
620}
621#endif
622
640{
643
644 if (!renderTarget) {
645 qWarning("QQuickRenderTarget: Needs a valid QRhiRenderTarget");
646 return rt;
647 }
648
649 d->type = QQuickRenderTargetPrivate::Type::RhiRenderTarget;
650 d->pixelSize = renderTarget->pixelSize();
651 d->sampleCount = renderTarget->sampleCount();
652 d->u.rhiRt = renderTarget;
653
654 return rt;
655}
656
672{
675
676 d->type = QQuickRenderTargetPrivate::Type::PaintDevice;
677 d->pixelSize = QSize(device->width(), device->height());
678 d->u.paintDevice = device;
679
680 return rt;
681}
682
698bool QQuickRenderTarget::isEqual(const QQuickRenderTarget &other) const noexcept
699{
700 if (d->type != other.d->type
701 || d->pixelSize != other.d->pixelSize
702 || d->devicePixelRatio != other.d->devicePixelRatio
703 || d->sampleCount != other.d->sampleCount
704 || d->mirrorVertically != other.d->mirrorVertically)
705 {
706 return false;
707 }
708
709 switch (d->type) {
710 case QQuickRenderTargetPrivate::Type::Null:
711 break;
712 case QQuickRenderTargetPrivate::Type::NativeTexture:
713 if (d->u.nativeTexture.object != other.d->u.nativeTexture.object
714 || d->u.nativeTexture.layoutOrState != other.d->u.nativeTexture.layoutOrState
715 || d->u.nativeTexture.rhiFormat != other.d->u.nativeTexture.rhiFormat
716 || d->u.nativeTexture.rhiFlags != other.d->u.nativeTexture.rhiFlags)
717 return false;
718 break;
719 case QQuickRenderTargetPrivate::Type::NativeRenderbuffer:
720 if (d->u.nativeRenderbufferObject != other.d->u.nativeRenderbufferObject)
721 return false;
722 break;
723 case QQuickRenderTargetPrivate::Type::RhiRenderTarget:
724 if (d->u.rhiRt != other.d->u.rhiRt)
725 return false;
726 break;
727 case QQuickRenderTargetPrivate::Type::PaintDevice:
728 if (d->u.paintDevice != other.d->u.paintDevice)
729 return false;
730 break;
731 default:
732 break;
733 }
734
735 return true;
736}
737
738static bool createRhiRenderTarget(const QRhiColorAttachment &colorAttachment,
739 const QSize &pixelSize,
740 int sampleCount,
741 QRhi *rhi,
743{
744 std::unique_ptr<QRhiRenderBuffer> depthStencil(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount));
745 if (!depthStencil->create()) {
746 qWarning("Failed to build depth-stencil buffer for QQuickRenderTarget");
747 return false;
748 }
749
750 QRhiTextureRenderTargetDescription rtDesc(colorAttachment);
751 rtDesc.setDepthStencilBuffer(depthStencil.get());
752 std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
753 std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
754 rt->setRenderPassDescriptor(rp.get());
755
756 if (!rt->create()) {
757 qWarning("Failed to build texture render target for QQuickRenderTarget");
758 return false;
759 }
760
761 dst->renderTarget = rt.release();
762 dst->rpDesc = rp.release();
763 dst->depthStencil = depthStencil.release();
764 dst->owns = true; // ownership of the native resource itself is not transferred but the QRhi objects are on us now
765
766 return true;
767}
768
770{
771 switch (type) {
772 case Type::Null:
773 dst->renderTarget = nullptr;
774 dst->paintDevice = nullptr;
775 dst->owns = false;
776 return true;
777
778 case Type::NativeTexture:
779 {
780 const auto format = u.nativeTexture.rhiFormat == QRhiTexture::UnknownFormat ? QRhiTexture::RGBA8
781 : QRhiTexture::Format(u.nativeTexture.rhiFormat);
782 const auto flags = QRhiTexture::RenderTarget | QRhiTexture::Flags(u.nativeTexture.rhiFlags);
783 std::unique_ptr<QRhiTexture> texture(rhi->newTexture(format, pixelSize, sampleCount, flags));
784 if (!texture->createFrom({ u.nativeTexture.object, u.nativeTexture.layoutOrState })) {
785 qWarning("Failed to build wrapper texture for QQuickRenderTarget");
786 return false;
787 }
788 QRhiColorAttachment att(texture.get());
790 return false;
791 dst->texture = texture.release();
792 }
793 return true;
794
795 case Type::NativeRenderbuffer:
796 {
797 std::unique_ptr<QRhiRenderBuffer> renderbuffer(rhi->newRenderBuffer(QRhiRenderBuffer::Color, pixelSize, sampleCount));
798 if (!renderbuffer->createFrom({ u.nativeRenderbufferObject })) {
799 qWarning("Failed to build wrapper renderbuffer for QQuickRenderTarget");
800 return false;
801 }
804 return false;
805 dst->renderBuffer = renderbuffer.release();
806 }
807 return true;
808
809 case Type::RhiRenderTarget:
810 dst->renderTarget = u.rhiRt;
811 dst->rpDesc = u.rhiRt->renderPassDescriptor(); // just for QQuickWindowRenderTarget::reset()
812 dst->owns = false;
813 return true;
814 case Type::PaintDevice:
815 dst->paintDevice = u.paintDevice;
816 dst->owns = false;
817 return true;
818
819 default:
820 break;
821 }
822 return false;
823}
824
IOBluetoothDevice * device
bool ref() noexcept
bool deref() noexcept
static QQuickRenderTargetPrivate * get(QQuickRenderTarget *rt)
bool resolve(QRhi *rhi, QQuickWindowRenderTarget *dst)
union QQuickRenderTargetPrivate::@687 u
The QQuickRenderTarget class provides an opaque container for native graphics resources specifying a ...
static QQuickRenderTarget fromPaintDevice(QPaintDevice *device)
void setMirrorVertically(bool enable)
Sets the size of the render target contents should be mirrored vertically to enable when drawing.
~QQuickRenderTarget()
Destructor.
QQuickRenderTarget & operator=(const QQuickRenderTarget &other)
void setDevicePixelRatio(qreal ratio)
Sets the device pixel ratio for this render target to ratio.
QQuickRenderTarget()
Constructs a default QQuickRenderTarget that does not reference any native objects.
static QQuickRenderTarget fromRhiRenderTarget(QRhiRenderTarget *renderTarget)
\inmodule QtGui
Definition qrhi.h:568
\inmodule QtGui
Definition qrhi.h:1135
virtual QSize pixelSize() const =0
virtual int sampleCount() const =0
void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer)
Sets the renderBuffer for depth-stencil.
Definition qrhi.h:632
@ RenderTarget
Definition qrhi.h:886
Format
Specifies the texture format.
Definition qrhi.h:902
@ UnknownFormat
Definition qrhi.h:903
\inmodule QtGui
Definition qrhi.h:1767
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition qrhi.cpp:10106
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition qrhi.cpp:10245
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10133
\inmodule QtCore
Definition qsize.h:25
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
Combined button and popup list for selecting options.
Definition image.cpp:4
QT_WARNING_POP void qAtomicAssign(T *&d, T *x)
This is a helper for the assignment operators of implicitly shared classes.
Definition qatomic.h:180
void qAtomicDetach(T *&d)
This is a helper for the detach method of implicitly shared classes.
Definition qatomic.h:199
#define qWarning
Definition qlogging.h:162
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum type
GLenum GLenum dst
GLbitfield flags
GLboolean enable
GLenum GLuint texture
GLint ref
GLint GLsizei GLsizei GLenum format
GLuint renderbuffer
static bool createRhiRenderTarget(const QRhiColorAttachment &colorAttachment, const QSize &pixelSize, int sampleCount, QRhi *rhi, QQuickWindowRenderTarget *dst)
unsigned long long quint64
Definition qtypes.h:56
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
QVBoxLayout * layout
QSharedPointer< T > other(t)
[5]