Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
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// Qt-Security score:significant reason:default
4
6
7#include "qquickitem_p.h"
9#include <private/qsgadaptationlayer_p.h>
10#include <QtQuick/private/qsgrenderer_p.h>
11#include <qsgsimplerectnode.h>
12
13#include "qmath.h"
14#include <QtQuick/private/qsgtexture_p.h>
15#include <QtCore/QRunnable>
16
18
47
62
63/*!
64 \qmltype ShaderEffectSource
65 \nativetype QQuickShaderEffectSource
66 \inqmlmodule QtQuick
67 \since 5.0
68 \inherits Item
69 \ingroup qtquick-effects
70 \brief Renders a \l {Qt Quick} item into a texture and displays it.
71
72 The ShaderEffectSource type renders \l sourceItem into a texture and
73 displays it in the scene. \l sourceItem is drawn into the texture as though
74 it was a fully opaque root item. Thus \l sourceItem itself can be
75 invisible, but still appear in the texture.
76
77 You can use the ShaderEffectSource as:
78 \list
79 \li a texture source in a \l ShaderEffect.
80 This allows you to apply custom shader effects to any \l {Qt Quick} item.
81 \li a cache for a complex item.
82 The complex item can be rendered once into the texture, which can
83 then be animated freely without the need to render the complex item
84 again every frame.
85 \li an opacity layer.
86 ShaderEffectSource allows you to apply an opacity to items as a group
87 rather than each item individually.
88 \endlist
89
90 \table
91 \row
92 \li \image declarative-shadereffectsource.png
93 \li \qml
94 import QtQuick 2.0
95
96 Rectangle {
97 width: 200
98 height: 100
99 gradient: Gradient {
100 GradientStop { position: 0; color: "white" }
101 GradientStop { position: 1; color: "black" }
102 }
103 Row {
104 opacity: 0.5
105 Item {
106 id: foo
107 width: 100; height: 100
108 Rectangle { x: 5; y: 5; width: 60; height: 60; color: "red" }
109 Rectangle { x: 20; y: 20; width: 60; height: 60; color: "orange" }
110 Rectangle { x: 35; y: 35; width: 60; height: 60; color: "yellow" }
111 }
112 ShaderEffectSource {
113 width: 100; height: 100
114 sourceItem: foo
115 }
116 }
117 }
118 \endqml
119 \endtable
120
121 The ShaderEffectSource type does not redirect any mouse or keyboard
122 input to \l sourceItem. If you hide the \l sourceItem by setting
123 \l{Item::visible}{visible} to false or \l{Item::opacity}{opacity} to zero,
124 it will no longer react to input. In cases where the ShaderEffectSource is
125 meant to replace the \l sourceItem, you typically want to hide the
126 \l sourceItem while still handling input. For this, you can use
127 the \l hideSource property.
128
129 \include notes.qdocinc shadereffectsource and multieffect
130
131 \note The ShaderEffectSource relies on FBO multisampling support
132 to antialias edges. If the underlying hardware does not support this,
133 which is the case for most embedded graphics chips, edges rendered
134 inside a ShaderEffectSource will not be antialiased. One way to remedy
135 this is to double the size of the effect source and render it with
136 \c {smooth: true} (this is the default value of smooth).
137 This will be equivalent to 4x multisampling, at the cost of lower performance
138 and higher memory use.
139
140 \warning In most cases, using a ShaderEffectSource will decrease
141 performance, and in all cases, it will increase video memory usage.
142 Rendering through a ShaderEffectSource might also lead to lower quality
143 since some OpenGL implementations support multisampled backbuffer,
144 but not multisampled framebuffer objects.
145*/
146
147QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
148 : QQuickItem(parent)
149 , m_provider(nullptr)
150 , m_texture(nullptr)
151 , m_wrapMode(ClampToEdge)
152 , m_sourceItem(nullptr)
153 , m_textureSize(0, 0)
154 , m_format(RGBA8)
155 , m_samples(0)
156 , m_live(true)
157 , m_hideSource(false)
158 , m_mipmap(false)
159 , m_recursive(false)
160 , m_grab(true)
161 , m_textureMirroring(MirrorVertically)
162{
163 setFlag(ItemHasContents);
164}
165
166QQuickShaderEffectSource::~QQuickShaderEffectSource()
167{
168 if (window()) {
169 window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
170 QQuickWindow::AfterSynchronizingStage);
171 } else {
172 // If we don't have a window, these should already have been
173 // released in invalidateSG or in releaseResrouces()
174 Q_ASSERT(!m_texture);
175 Q_ASSERT(!m_provider);
176 }
177
178 if (m_sourceItem) {
179 QQuickItemPrivate *sd = QQuickItemPrivate::get(m_sourceItem);
180 sd->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
181 sd->derefFromEffectItem(m_hideSource);
182 if (window())
183 sd->derefWindow();
184 }
185}
186
187void QQuickShaderEffectSource::ensureTexture()
188{
189 if (m_texture)
190 return;
191
192 Q_ASSERT_X(QQuickItemPrivate::get(this)->window
193 && QQuickItemPrivate::get(this)->sceneGraphRenderContext()
194 && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphRenderContext()->thread(),
195 "QQuickShaderEffectSource::ensureTexture",
196 "Cannot be used outside the rendering thread");
197
198 QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext();
199 m_texture = rc->sceneGraphContext()->createLayer(rc);
200 connect(QQuickItemPrivate::get(this)->window, SIGNAL(sceneGraphInvalidated()), m_texture, SLOT(invalidated()), Qt::DirectConnection);
201 connect(m_texture, SIGNAL(updateRequested()), this, SLOT(update()));
202 connect(m_texture, SIGNAL(scheduledUpdateCompleted()), this, SIGNAL(scheduledUpdateCompleted()));
203}
204
205static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap);
206
207QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const
208{
209 const QQuickItemPrivate *d = QQuickItemPrivate::get(this);
210 if (!d->window || !d->sceneGraphRenderContext() || QThread::currentThread() != d->sceneGraphRenderContext()->thread()) {
211 qWarning("QQuickShaderEffectSource::textureProvider: can only be queried on the rendering thread of an exposed window");
212 return nullptr;
213 }
214
215 if (!m_provider) {
216 const_cast<QQuickShaderEffectSource *>(this)->m_provider = new QQuickShaderEffectSourceTextureProvider();
217 const_cast<QQuickShaderEffectSource *>(this)->ensureTexture();
218 connect(m_texture, SIGNAL(updateRequested()), m_provider, SIGNAL(textureChanged()));
219
220 get_wrap_mode(m_wrapMode, &m_provider->horizontalWrap, &m_provider->verticalWrap);
221 m_provider->mipmapFiltering = mipmap() ? QSGTexture::Linear : QSGTexture::None;
222 m_provider->filtering = smooth() ? QSGTexture::Linear : QSGTexture::Nearest;
223 m_provider->sourceTexture = m_texture;
224 }
225 return m_provider;
226}
227
228/*!
229 \qmlproperty enumeration QtQuick::ShaderEffectSource::wrapMode
230
231 This property defines the OpenGL wrap modes associated with the texture.
232 Modifying this property makes most sense when the item is used as a
233 source texture of a \l ShaderEffect.
234
235 The default value is \c{ShaderEffectSource.ClampToEdge}.
236
237 \value ShaderEffectSource.ClampToEdge GL_CLAMP_TO_EDGE both horizontally and vertically
238 \value ShaderEffectSource.RepeatHorizontally GL_REPEAT horizontally, GL_CLAMP_TO_EDGE vertically
239 \value ShaderEffectSource.RepeatVertically GL_CLAMP_TO_EDGE horizontally, GL_REPEAT vertically
240 \value ShaderEffectSource.Repeat GL_REPEAT both horizontally and vertically
241
242 \note Some OpenGL ES 2 implementations do not support the GL_REPEAT
243 wrap mode with non-power-of-two textures.
244*/
245
246QQuickShaderEffectSource::WrapMode QQuickShaderEffectSource::wrapMode() const
247{
248 return m_wrapMode;
249}
250
251void QQuickShaderEffectSource::setWrapMode(WrapMode mode)
252{
253 if (mode == m_wrapMode)
254 return;
255 m_wrapMode = mode;
256 update();
257 emit wrapModeChanged();
258}
259
260/*!
261 \qmlproperty Item QtQuick::ShaderEffectSource::sourceItem
262
263 This property holds the item to be rendered into the texture.
264 Setting this to null while \l live is true, will release the texture
265 resources.
266*/
267
268QQuickItem *QQuickShaderEffectSource::sourceItem() const
269{
270 return m_sourceItem;
271}
272
273void QQuickShaderEffectSource::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
274{
275 Q_ASSERT(item == m_sourceItem);
276 Q_UNUSED(item);
277 if (change.sizeChange())
278 update();
279}
280
281void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
282{
283 if (item == m_sourceItem)
284 return;
285 if (m_sourceItem) {
286 QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem);
287 d->derefFromEffectItem(m_hideSource);
288 d->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
289 disconnect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
290 if (window())
291 d->derefWindow();
292 }
293
294 m_sourceItem = item;
295
296 if (m_sourceItem) {
297 if (window() == m_sourceItem->window()
298 || (window() == nullptr && m_sourceItem->window())
299 || (m_sourceItem->window() == nullptr && window())) {
300 QQuickItemPrivate *d = QQuickItemPrivate::get(item);
301 // 'item' needs a window to get a scene graph node. It usually gets one through its
302 // parent, but if the source item is "inline" rather than a reference -- i.e.
303 // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
304 // In those cases, 'item' should get the window from 'this'.
305 if (window())
306 d->refWindow(window());
307 else if (m_sourceItem->window())
308 d->refWindow(m_sourceItem->window());
309 d->refFromEffectItem(m_hideSource);
310 d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
311 connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
312 } else {
313 qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
314 m_sourceItem = nullptr;
315 }
316 }
317 update();
318 emit sourceItemChanged();
319}
320
321void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
322{
323 Q_ASSERT(item == m_sourceItem);
324 Q_UNUSED(item);
325 m_sourceItem = nullptr;
326 update();
327 emit sourceItemChanged();
328}
329
330
331/*!
332 \qmlproperty rect QtQuick::ShaderEffectSource::sourceRect
333
334 This property defines which rectangular area of the \l sourceItem to
335 render into the texture. The source rectangle can be larger than
336 \l sourceItem itself. If the rectangle is null, which is the default,
337 the whole \l sourceItem is rendered to texture.
338*/
339
340QRectF QQuickShaderEffectSource::sourceRect() const
341{
342 return m_sourceRect;
343}
344
345void QQuickShaderEffectSource::setSourceRect(const QRectF &rect)
346{
347 if (rect == m_sourceRect)
348 return;
349 m_sourceRect = rect;
350 update();
351 emit sourceRectChanged();
352}
353
354/*!
355 \qmlproperty size QtQuick::ShaderEffectSource::textureSize
356
357 This property holds the requested pixel size of the texture. If it is
358 empty, which is the default, the size of the source rectangle is used.
359
360 \note This value is in pixels since it directly controls the size of a
361 texture object.
362
363 \note Some platforms have a limit on how small framebuffer objects can be,
364 which means the actual texture size might be larger than the requested
365 size.
366*/
367
368QSize QQuickShaderEffectSource::textureSize() const
369{
370 return m_textureSize;
371}
372
373void QQuickShaderEffectSource::setTextureSize(const QSize &size)
374{
375 if (size == m_textureSize)
376 return;
377 m_textureSize = size;
378 update();
379 emit textureSizeChanged();
380}
381
382/*!
383 \qmlproperty enumeration QtQuick::ShaderEffectSource::format
384
385 This property defines the format of the backing texture.
386 Modifying this property makes most sense when the item is used as a
387 source texture of a \l ShaderEffect.
388
389 \value ShaderEffectSource.RGBA8
390 \value ShaderEffectSource.RGBA16F
391 \value ShaderEffectSource.RGBA32F
392 \value ShaderEffectSource.Alpha Starting with Qt 6.0, this value is not in use and has the same effect as \c RGBA8 in practice.
393 \value ShaderEffectSource.RGB Starting with Qt 6.0, this value is not in use and has the same effect as \c RGBA8 in practice.
394 \value ShaderEffectSource.RGBA Starting with Qt 6.0, this value is not in use and has the same effect as \c RGBA8 in practice.
395*/
396
397QQuickShaderEffectSource::Format QQuickShaderEffectSource::format() const
398{
399 return m_format;
400}
401
402void QQuickShaderEffectSource::setFormat(QQuickShaderEffectSource::Format format)
403{
404 if (format == m_format)
405 return;
406 m_format = format;
407 update();
408 emit formatChanged();
409}
410
411/*!
412 \qmlproperty bool QtQuick::ShaderEffectSource::live
413
414 If this property is true, the texture is updated whenever the
415 \l sourceItem updates. Otherwise, it will be a frozen image, even if
416 \l sourceItem is assigned a new item. The property is true by default.
417*/
418
419bool QQuickShaderEffectSource::live() const
420{
421 return m_live;
422}
423
424void QQuickShaderEffectSource::setLive(bool live)
425{
426 if (live == m_live)
427 return;
428 m_live = live;
429 update();
430 emit liveChanged();
431}
432
433/*!
434 \qmlproperty bool QtQuick::ShaderEffectSource::hideSource
435
436 If this property is true, the \l sourceItem is hidden, though it will still
437 be rendered into the texture. As opposed to hiding the \l sourceItem by
438 setting \l{Item::visible}{visible} to false, setting this property to true
439 will not prevent mouse or keyboard input from reaching \l sourceItem.
440 The property is useful when the ShaderEffectSource is anchored on top of,
441 and meant to replace the \l sourceItem.
442*/
443
444bool QQuickShaderEffectSource::hideSource() const
445{
446 return m_hideSource;
447}
448
449void QQuickShaderEffectSource::setHideSource(bool hide)
450{
451 if (hide == m_hideSource)
452 return;
453 if (m_sourceItem) {
454 QQuickItemPrivate::get(m_sourceItem)->refFromEffectItem(hide);
455 QQuickItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
456 }
457 m_hideSource = hide;
458 update();
459 emit hideSourceChanged();
460}
461
462/*!
463 \qmlproperty bool QtQuick::ShaderEffectSource::mipmap
464
465 If this property is true, mipmaps are generated for the texture.
466
467 \note Some OpenGL ES 2 implementations do not support mipmapping of
468 non-power-of-two textures.
469*/
470
471bool QQuickShaderEffectSource::mipmap() const
472{
473 return m_mipmap;
474}
475
476void QQuickShaderEffectSource::setMipmap(bool enabled)
477{
478 if (enabled == m_mipmap)
479 return;
480 m_mipmap = enabled;
481 update();
482 emit mipmapChanged();
483}
484
485/*!
486 \qmlproperty bool QtQuick::ShaderEffectSource::recursive
487
488 Set this property to true if the ShaderEffectSource has a dependency on
489 itself. ShaderEffectSources form a dependency chain, where one
490 ShaderEffectSource can be part of the \l sourceItem of another.
491 If there is a loop in this chain, a ShaderEffectSource could end up trying
492 to render into the same texture it is using as source, which is not allowed
493 by OpenGL. When this property is set to true, an extra texture is allocated
494 so that ShaderEffectSource can keep a copy of the texture from the previous
495 frame. It can then render into one texture and use the texture from the
496 previous frame as source.
497
498 Setting both this property and \l live to true will cause the scene graph
499 to render continuously. Since the ShaderEffectSource depends on itself,
500 updating it means that it immediately becomes dirty again.
501*/
502
503bool QQuickShaderEffectSource::recursive() const
504{
505 return m_recursive;
506}
507
508void QQuickShaderEffectSource::setRecursive(bool enabled)
509{
510 if (enabled == m_recursive)
511 return;
512 m_recursive = enabled;
513 emit recursiveChanged();
514}
515
516/*!
517 \qmlproperty enumeration QtQuick::ShaderEffectSource::textureMirroring
518 \since 5.6
519
520 This property defines how the generated OpenGL texture should be mirrored.
521 The default value is \c{ShaderEffectSource.MirrorVertically}.
522 Custom mirroring can be useful if the generated texture is directly accessed by custom shaders,
523 such as those specified by ShaderEffect. Mirroring has no effect on the UI representation of
524 the ShaderEffectSource item itself.
525
526 \value ShaderEffectSource.NoMirroring No mirroring
527 \value ShaderEffectSource.MirrorHorizontally The generated texture is flipped along X-axis.
528 \value ShaderEffectSource.MirrorVertically The generated texture is flipped along Y-axis.
529*/
530
531QQuickShaderEffectSource::TextureMirroring QQuickShaderEffectSource::textureMirroring() const
532{
533 return QQuickShaderEffectSource::TextureMirroring(m_textureMirroring);
534}
535
536void QQuickShaderEffectSource::setTextureMirroring(TextureMirroring mirroring)
537{
538 if (mirroring == QQuickShaderEffectSource::TextureMirroring(m_textureMirroring))
539 return;
540 m_textureMirroring = mirroring;
541 update();
542 emit textureMirroringChanged();
543}
544
545/*!
546 \qmlproperty int QtQuick::ShaderEffectSource::samples
547 \since 5.10
548
549 This property allows requesting multisampled rendering.
550
551 By default multisampling is enabled whenever multisampling is enabled for
552 the entire window, assuming the scenegraph renderer in use and the
553 underlying graphics API supports this.
554
555 By setting the value to 2, 4, etc. multisampled rendering can be requested
556 for a part of the scene without enabling multisampling for the entire
557 scene. This way multisampling is applied only to a given subtree, which can
558 lead to significant performance gains since multisampling is not applied to
559 other parts of the scene.
560
561 \note Enabling multisampling can be potentially expensive regardless of the
562 layer's size, as it incurs a hardware and driver dependent performance and
563 memory cost.
564
565 \note This property is only functional when support for multisample
566 renderbuffers and framebuffer blits is available. Otherwise the value is
567 silently ignored.
568 */
569int QQuickShaderEffectSource::samples() const
570{
571 return m_samples;
572}
573
574void QQuickShaderEffectSource::setSamples(int count)
575{
576 if (count == m_samples)
577 return;
578 m_samples = count;
579 update();
580 emit samplesChanged();
581}
582
583/*!
584 \qmlmethod QtQuick::ShaderEffectSource::scheduleUpdate()
585
586 Schedules a re-rendering of the texture for the next frame.
587 Use this to update the texture when \l live is false.
588*/
589
590void QQuickShaderEffectSource::scheduleUpdate()
591{
592 if (m_grab)
593 return;
594 m_grab = true;
595 update();
596}
597
598static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap)
599{
600 switch (mode) {
601 case QQuickShaderEffectSource::RepeatHorizontally:
602 *hWrap = QSGTexture::Repeat;
603 *vWrap = QSGTexture::ClampToEdge;
604 break;
605 case QQuickShaderEffectSource::RepeatVertically:
606 *vWrap = QSGTexture::Repeat;
607 *hWrap = QSGTexture::ClampToEdge;
608 break;
609 case QQuickShaderEffectSource::Repeat:
610 *hWrap = *vWrap = QSGTexture::Repeat;
611 break;
612 default:
613 // QQuickShaderEffectSource::ClampToEdge
614 *hWrap = *vWrap = QSGTexture::ClampToEdge;
615 break;
616 }
617}
618
619
620void QQuickShaderEffectSource::releaseResources()
621{
622 if (m_texture || m_provider) {
623 window()->scheduleRenderJob(new QQuickShaderEffectSourceCleanup(m_texture, m_provider),
624 QQuickWindow::AfterSynchronizingStage);
625 m_texture = nullptr;
626 m_provider = nullptr;
627 }
628}
629
631{
633public:
635 QSGNode *pn = QSGNode::parent();
636 if (pn) {
639 }
640 }
641};
642
643static QSGLayer::Format toLayerFormat(QQuickShaderEffectSource::Format format)
644{
645 switch (format) {
646 case QQuickShaderEffectSource::RGBA8:
647 return QSGLayer::RGBA8;
648 case QQuickShaderEffectSource::RGBA16F:
649 return QSGLayer::RGBA16F;
650 case QQuickShaderEffectSource::RGBA32F:
651 return QSGLayer::RGBA32F;
652 default:
653 return QSGLayer::RGBA8;
654 }
655}
656
657QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
658{
659 if (!m_sourceItem || m_sourceItem->width() <= 0 || m_sourceItem->height() <= 0) {
660 if (m_texture)
661 m_texture->setItem(nullptr);
662 delete oldNode;
663 return nullptr;
664 }
665
666 ensureTexture();
667
668 m_texture->setLive(m_live);
669 m_texture->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
670 QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0
671 ? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
672 : m_sourceRect;
673 m_texture->setRect(sourceRect);
674 QQuickItemPrivate *d = static_cast<QQuickItemPrivate *>(QObjectPrivate::get(this));
675 const float dpr = d->effectiveDevicePixelRatio();
676 QSize textureSize = m_textureSize.isEmpty()
677 ? QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height()))) * dpr
678 : m_textureSize;
679 Q_ASSERT(!textureSize.isEmpty());
680
681 const QSize minTextureSize = d->sceneGraphContext()->minimumFBOSize();
682 // Keep power-of-two by doubling the size.
683 while (textureSize.width() < minTextureSize.width())
684 textureSize.rwidth() *= 2;
685 while (textureSize.height() < minTextureSize.height())
686 textureSize.rheight() *= 2;
687
688 m_texture->setDevicePixelRatio(d->effectiveDevicePixelRatio());
689 m_texture->setSize(textureSize);
690 m_texture->setRecursive(m_recursive);
691 m_texture->setFormat(toLayerFormat(m_format));
692 m_texture->setHasMipmaps(m_mipmap);
693 m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
694 m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
695 m_texture->setSamples(m_samples);
696
697 if (m_grab)
698 m_texture->scheduleUpdate();
699 m_grab = false;
700
701 QSGTexture::Filtering filtering = QQuickItemPrivate::get(this)->smooth
702 ? QSGTexture::Linear
703 : QSGTexture::Nearest;
704 QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
705 QSGTexture::WrapMode hWrap, vWrap;
706 get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
707
708 if (m_provider) {
709 m_provider->mipmapFiltering = mmFiltering;
710 m_provider->filtering = filtering;
711 m_provider->horizontalWrap = hWrap;
712 m_provider->verticalWrap = vWrap;
713 }
714
715 // Don't create the paint node if we're not spanning any area
716 if (width() <= 0 || height() <= 0) {
717 delete oldNode;
718 return nullptr;
719 }
720
721 QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode);
722 if (!node) {
723 node = d->sceneGraphContext()->createInternalImageNode(d->sceneGraphRenderContext());
724 node->setFlag(QSGNode::UsePreprocess);
725 node->setTexture(m_texture);
726 QQuickShaderSourceAttachedNode *attached = new QQuickShaderSourceAttachedNode;
727 node->appendChildNode(attached);
728 connect(m_texture, SIGNAL(updateRequested()), attached, SLOT(markTextureDirty()));
729 }
730
731 // If live and recursive, update continuously.
732 if (m_live && m_recursive)
733 node->markDirty(QSGNode::DirtyMaterial);
734
735 node->setMipmapFiltering(mmFiltering);
736 node->setFiltering(filtering);
737 node->setHorizontalWrapMode(hWrap);
738 node->setVerticalWrapMode(vWrap);
739 node->setTargetRect(QRectF(0, 0, width(), height()));
740 node->setInnerTargetRect(QRectF(0, 0, width(), height()));
741 node->update();
742
743 return node;
744}
745
746void QQuickShaderEffectSource::invalidateSceneGraph()
747{
748 if (m_texture)
749 delete m_texture;
750 if (m_provider)
751 delete m_provider;
752 m_texture = nullptr;
753 m_provider = nullptr;
754}
755
756void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeData &value)
757{
758 if (change == QQuickItem::ItemSceneChange && m_sourceItem) {
759 // See comment in QQuickShaderEffectSource::setSourceItem().
760 if (value.window)
761 QQuickItemPrivate::get(m_sourceItem)->refWindow(value.window);
762 else
763 QQuickItemPrivate::get(m_sourceItem)->derefWindow();
764 }
765 QQuickItem::itemChange(change, value);
766}
767
768QT_END_NAMESPACE
769
770#include "qquickshadereffectsource.moc"
771#include "moc_qquickshadereffectsource_p.cpp"
QQuickShaderEffectSourceCleanup(QSGLayer *t, QQuickShaderEffectSourceTextureProvider *p)
QQuickShaderEffectSourceTextureProvider * provider
void run() override
Implement this pure virtual function in your subclass.
static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap)
static QSGLayer::Format toLayerFormat(QQuickShaderEffectSource::Format format)