Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickshadereffectsource.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
6#include "qquickitem_p.h"
7#include "qquickwindow_p.h"
8#include <private/qsgadaptationlayer_p.h>
9#include <QtQuick/private/qsgrenderer_p.h>
10#include <qsgsimplerectnode.h>
11
12#include "qmath.h"
13#include <QtQuick/private/qsgtexture_p.h>
14#include <QtCore/QRunnable>
15
17
46
61
145 : QQuickItem(parent)
146 , m_provider(nullptr)
147 , m_texture(nullptr)
148 , m_wrapMode(ClampToEdge)
149 , m_sourceItem(nullptr)
150 , m_textureSize(0, 0)
151 , m_format(RGBA8)
152 , m_samples(0)
153 , m_live(true)
154 , m_hideSource(false)
155 , m_mipmap(false)
156 , m_recursive(false)
157 , m_grab(true)
158 , m_textureMirroring(MirrorVertically)
159{
161}
162
164{
165 if (window()) {
166 window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
167 QQuickWindow::AfterSynchronizingStage);
168 } else {
169 // If we don't have a window, these should already have been
170 // released in invalidateSG or in releaseResrouces()
171 Q_ASSERT(!m_texture);
172 Q_ASSERT(!m_provider);
173 }
174
175 if (m_sourceItem) {
176 QQuickItemPrivate *sd = QQuickItemPrivate::get(m_sourceItem);
178 sd->derefFromEffectItem(m_hideSource);
179 if (window())
180 sd->derefWindow();
181 }
182}
183
184void QQuickShaderEffectSource::ensureTexture()
185{
186 if (m_texture)
187 return;
188
190 && QQuickItemPrivate::get(this)->sceneGraphRenderContext()
191 && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphRenderContext()->thread(),
192 "QQuickShaderEffectSource::ensureTexture",
193 "Cannot be used outside the rendering thread");
194
195 QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext();
196 m_texture = rc->sceneGraphContext()->createLayer(rc);
197 connect(QQuickItemPrivate::get(this)->window, SIGNAL(sceneGraphInvalidated()), m_texture, SLOT(invalidated()), Qt::DirectConnection);
198 connect(m_texture, SIGNAL(updateRequested()), this, SLOT(update()));
200}
201
203
205{
207 if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
208 qWarning("QQuickShaderEffectSource::textureProvider: can only be queried on the rendering thread of an exposed window");
209 return nullptr;
210 }
211
212 if (!m_provider) {
213 const_cast<QQuickShaderEffectSource *>(this)->m_provider = new QQuickShaderEffectSourceTextureProvider();
214 const_cast<QQuickShaderEffectSource *>(this)->ensureTexture();
215 connect(m_texture, SIGNAL(updateRequested()), m_provider, SIGNAL(textureChanged()));
216
217 get_wrap_mode(m_wrapMode, &m_provider->horizontalWrap, &m_provider->verticalWrap);
220 m_provider->sourceTexture = m_texture;
221 }
222 return m_provider;
223}
224
247
249{
250 if (mode == m_wrapMode)
251 return;
252 m_wrapMode = mode;
253 update();
255}
256
266{
267 return m_sourceItem;
268}
269
271{
272 Q_ASSERT(item == m_sourceItem);
273 Q_UNUSED(item);
274 if (change.sizeChange())
275 update();
276}
277
279{
280 if (item == m_sourceItem)
281 return;
282 if (m_sourceItem) {
284 d->derefFromEffectItem(m_hideSource);
285 d->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
286 disconnect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
287 if (window())
288 d->derefWindow();
289 }
290
291 m_sourceItem = item;
292
293 if (m_sourceItem) {
294 if (window() == m_sourceItem->window()
295 || (window() == nullptr && m_sourceItem->window())
296 || (m_sourceItem->window() == nullptr && window())) {
298 // 'item' needs a window to get a scene graph node. It usually gets one through its
299 // parent, but if the source item is "inline" rather than a reference -- i.e.
300 // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
301 // In those cases, 'item' should get the window from 'this'.
302 if (window())
303 d->refWindow(window());
304 else if (m_sourceItem->window())
305 d->refWindow(m_sourceItem->window());
306 d->refFromEffectItem(m_hideSource);
307 d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
308 connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
309 } else {
310 qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
311 m_sourceItem = nullptr;
312 }
313 }
314 update();
316}
317
318void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
319{
320 Q_ASSERT(item == m_sourceItem);
321 Q_UNUSED(item);
322 m_sourceItem = nullptr;
323 update();
325}
326
327
338{
339 return m_sourceRect;
340}
341
343{
344 if (rect == m_sourceRect)
345 return;
346 m_sourceRect = rect;
347 update();
349}
350
366{
367 return m_textureSize;
368}
369
371{
372 if (size == m_textureSize)
373 return;
374 m_textureSize = size;
375 update();
377}
378
398
400{
401 if (format == m_format)
402 return;
403 m_format = format;
404 update();
406}
407
417{
418 return m_live;
419}
420
422{
423 if (live == m_live)
424 return;
425 m_live = live;
426 update();
428}
429
442{
443 return m_hideSource;
444}
445
447{
448 if (hide == m_hideSource)
449 return;
450 if (m_sourceItem) {
451 QQuickItemPrivate::get(m_sourceItem)->refFromEffectItem(hide);
452 QQuickItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
453 }
454 m_hideSource = hide;
455 update();
457}
458
469{
470 return m_mipmap;
471}
472
474{
475 if (enabled == m_mipmap)
476 return;
477 m_mipmap = enabled;
478 update();
480}
481
501{
502 return m_recursive;
503}
504
506{
507 if (enabled == m_recursive)
508 return;
509 m_recursive = enabled;
511}
512
532
534{
535 if (mirroring == QQuickShaderEffectSource::TextureMirroring(m_textureMirroring))
536 return;
537 m_textureMirroring = mirroring;
538 update();
540}
541
567{
568 return m_samples;
569}
570
572{
573 if (count == m_samples)
574 return;
575 m_samples = count;
576 update();
578}
579
588{
589 if (m_grab)
590 return;
591 m_grab = true;
592 update();
593}
594
596{
597 switch (mode) {
599 *hWrap = QSGTexture::Repeat;
601 break;
603 *vWrap = QSGTexture::Repeat;
605 break;
607 *hWrap = *vWrap = QSGTexture::Repeat;
608 break;
609 default:
610 // QQuickShaderEffectSource::ClampToEdge
611 *hWrap = *vWrap = QSGTexture::ClampToEdge;
612 break;
613 }
614}
615
616
618{
619 if (m_texture || m_provider) {
620 window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
621 QQuickWindow::AfterSynchronizingStage);
622 m_texture = nullptr;
623 m_provider = nullptr;
624 }
625}
626
628{
630public:
632 QSGNode *pn = QSGNode::parent();
633 if (pn) {
634 Q_ASSERT(pn->type() == QSGNode::GeometryNodeType);
635 pn->markDirty(DirtyMaterial);
636 }
637 }
638};
639
653
655{
656 if (!m_sourceItem || m_sourceItem->width() <= 0 || m_sourceItem->height() <= 0) {
657 if (m_texture)
658 m_texture->setItem(nullptr);
659 delete oldNode;
660 return nullptr;
661 }
662
663 ensureTexture();
664
665 m_texture->setLive(m_live);
666 m_texture->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
667 QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0
668 ? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
669 : m_sourceRect;
670 m_texture->setRect(sourceRect);
672 const float dpr = d->window->effectiveDevicePixelRatio();
673 QSize textureSize = m_textureSize.isEmpty()
675 : m_textureSize;
677
678 const QSize minTextureSize = d->sceneGraphContext()->minimumFBOSize();
679 // Keep power-of-two by doubling the size.
680 while (textureSize.width() < minTextureSize.width())
681 textureSize.rwidth() *= 2;
682 while (textureSize.height() < minTextureSize.height())
683 textureSize.rheight() *= 2;
684
685 m_texture->setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
686 m_texture->setSize(textureSize);
687 m_texture->setRecursive(m_recursive);
688 m_texture->setFormat(toLayerFormat(m_format));
689 m_texture->setHasMipmaps(m_mipmap);
690 m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
691 m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
692 m_texture->setSamples(m_samples);
693
694 if (m_grab)
695 m_texture->scheduleUpdate();
696 m_grab = false;
697
698 QSGTexture::Filtering filtering = QQuickItemPrivate::get(this)->smooth
701 QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
702 QSGTexture::WrapMode hWrap, vWrap;
703 get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
704
705 if (m_provider) {
706 m_provider->mipmapFiltering = mmFiltering;
707 m_provider->filtering = filtering;
708 m_provider->horizontalWrap = hWrap;
709 m_provider->verticalWrap = vWrap;
710 }
711
712 // Don't create the paint node if we're not spanning any area
713 if (width() <= 0 || height() <= 0) {
714 delete oldNode;
715 return nullptr;
716 }
717
718 QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
719 if (!node) {
720 node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
722 node->setTexture(m_texture);
724 node->appendChildNode(attached);
725 connect(m_texture, SIGNAL(updateRequested()), attached, SLOT(markTextureDirty()));
726 }
727
728 // If live and recursive, update continuously.
729 if (m_live && m_recursive)
731
732 node->setMipmapFiltering(mmFiltering);
733 node->setFiltering(filtering);
734 node->setHorizontalWrapMode(hWrap);
735 node->setVerticalWrapMode(vWrap);
736 node->setTargetRect(QRectF(0, 0, width(), height()));
737 node->setInnerTargetRect(QRectF(0, 0, width(), height()));
738 node->update();
739
740 return node;
741}
742
743void QQuickShaderEffectSource::invalidateSceneGraph()
744{
745 if (m_texture)
746 delete m_texture;
747 if (m_provider)
748 delete m_provider;
749 m_texture = nullptr;
750 m_provider = nullptr;
751}
752
754{
755 if (change == QQuickItem::ItemSceneChange && m_sourceItem) {
756 // See comment in QQuickShaderEffectSource::setSourceItem().
757 if (value.window)
758 QQuickItemPrivate::get(m_sourceItem)->refWindow(value.window);
759 else
760 QQuickItemPrivate::get(m_sourceItem)->derefWindow();
761 }
763}
764
766
767#include "qquickshadereffectsource.moc"
768#include "moc_qquickshadereffectsource_p.cpp"
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types)
void derefFromEffectItem(bool unhide)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
QSizeF size() const
QQuickWindow * window() const
Returns the window in which this item is rendered.
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool smooth
\qmlproperty bool QtQuick::Item::smooth
Definition qquickitem.h:112
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
bool enabled
\qmlproperty bool QtQuick::Item::enabled
Definition qquickitem.h:79
void update()
Schedules a call to updatePaintNode() for this item.
QQuickShaderEffectSourceCleanup(QSGLayer *t, QQuickShaderEffectSourceTextureProvider *p)
QQuickShaderEffectSourceTextureProvider * provider
void run() override
Implement this pure virtual function in your subclass.
QSGTexture * texture() const override
Returns a pointer to the texture object.
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) override
QQuickShaderEffectSource(QQuickItem *parent=nullptr)
\qmltype ShaderEffectSource \instantiates QQuickShaderEffectSource \inqmlmodule QtQuick
QSGTextureProvider * textureProvider() const override
Returns the texture provider for an item.
void setTextureMirroring(TextureMirroring mirroring)
void setSourceRect(const QRectF &rect)
void setTextureSize(const QSize &size)
void releaseResources() override
This function is called when an item should release graphics resources which are not already managed ...
QSGNode * updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
Q_INVOKABLE void scheduleUpdate()
\qmlmethod QtQuick::ShaderEffectSource::scheduleUpdate()
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
\inmodule QtCore
Definition qrunnable.h:18
virtual QSGLayer * createLayer(QSGRenderContext *renderContext)=0
virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)=0
virtual void setTexture(QSGTexture *texture)=0
virtual void setTargetRect(const QRectF &rect)=0
virtual void setFiltering(QSGTexture::Filtering filtering)=0
virtual void update()=0
virtual void setInnerTargetRect(const QRectF &rect)=0
virtual void setMipmapFiltering(QSGTexture::Filtering filtering)=0
virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode)=0
virtual void scheduleUpdate()=0
virtual void setRecursive(bool recursive)=0
virtual void setMirrorVertical(bool mirror)=0
virtual void setSamples(int samples)=0
virtual void setDevicePixelRatio(qreal ratio)=0
virtual void setItem(QSGNode *item)=0
virtual void setMirrorHorizontal(bool mirror)=0
virtual void setLive(bool live)=0
virtual void setFormat(Format format)=0
virtual void setSize(const QSize &pixelSize)=0
virtual void setRect(const QRectF &logicalRect)=0
virtual void setHasMipmaps(bool mipmap)=0
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
@ DirtyMaterial
Definition qsgnode.h:75
@ UsePreprocess
Definition qsgnode.h:52
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
Definition qsgnode.cpp:398
@ GeometryNodeType
Definition qsgnode.h:41
QSGNode * parent() const
Returns the parent node of this node.
Definition qsgnode.h:93
void markDirty(DirtyState bits)
Notifies all connected renderers that the node has dirty bits.
Definition qsgnode.cpp:624
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:586
QSGContext * sceneGraphContext() const
The QSGTextureProvider class encapsulates texture based entities in QML.
\inmodule QtQuick
Definition qsgtexture.h:20
void setMipmapFiltering(Filtering filter)
Sets the mipmap sampling mode to filter.
Filtering
Specifies how sampling of texels should filter when texture coordinates are not pixel aligned.
Definition qsgtexture.h:34
WrapMode
Specifies how the sampler should treat texture coordinates.
Definition qsgtexture.h:28
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr int & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:157
constexpr int & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:154
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:124
static QThread * currentThread()
Definition qthread.cpp:1039
rect
[4]
Combined button and popup list for selecting options.
@ DirectConnection
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
@ None
Definition qhash.cpp:531
#define qWarning
Definition qlogging.h:166
int qCeil(T v)
Definition qmath.h:36
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLenum GLuint texture
GLuint sourceTexture
GLint GLsizei GLsizei GLenum format
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap)
static QSGLayer::Format toLayerFormat(QQuickShaderEffectSource::Format format)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
static const QSize minTextureSize
#define Q_OBJECT
#define emit
#define Q_SLOT
#define Q_UNUSED(x)
QObject::connect nullptr
myObject disconnect()
[26]
QGraphicsItem * item
edit hide()
\inmodule QtQuick
Definition qquickitem.h:159