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