1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsgtexture_p.h"
41#if QT_CONFIG(opengl)
42# include <QtGui/qopenglcontext.h>
43# include <QtGui/qopenglfunctions.h>
44#endif
45#include <private/qqmlglobal_p.h>
46#include <private/qsgmaterialshader_p.h>
47#include <QtGui/private/qrhi_p.h>
48
49#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && defined(__GLIBC__)
50#define CAN_BACKTRACE_EXECINFO
51#endif
52
53#if defined(Q_OS_MAC)
54#define CAN_BACKTRACE_EXECINFO
55#endif
56
57#if defined(QT_NO_DEBUG)
58#undef CAN_BACKTRACE_EXECINFO
59#endif
60
61#if defined(CAN_BACKTRACE_EXECINFO)
62#include <execinfo.h>
63#include <QHash>
64#endif
65
66#ifndef QT_NO_DEBUG
67static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
68#endif
69
70QT_BEGIN_NAMESPACE
71
72bool operator==(const QSGSamplerDescription &a, const QSGSamplerDescription &b) Q_DECL_NOTHROW
73{
74 return a.filtering == b.filtering
75 && a.mipmapFiltering == b.mipmapFiltering
76 && a.horizontalWrap == b.horizontalWrap
77 && a.verticalWrap == b.verticalWrap
78 && a.anisotropylevel == b.anisotropylevel;
79}
80
81bool operator!=(const QSGSamplerDescription &a, const QSGSamplerDescription &b) Q_DECL_NOTHROW
82{
83 return !(a == b);
84}
85
86uint qHash(const QSGSamplerDescription &s, uint seed) Q_DECL_NOTHROW
87{
88 const int f = s.filtering;
89 const int m = s.mipmapFiltering;
90 const int w = s.horizontalWrap;
91 const int a = s.anisotropylevel;
92 return (((f & 7) << 24) | ((m & 7) << 16) | ((w & 7) << 8) | (a & 7)) ^ seed;
93}
94
95QSGSamplerDescription QSGSamplerDescription::fromTexture(QSGTexture *t)
96{
97 QSGSamplerDescription s;
98 s.filtering = t->filtering();
99 s.mipmapFiltering = t->mipmapFiltering();
100 s.horizontalWrap = t->horizontalWrapMode();
101 s.verticalWrap = t->verticalWrapMode();
102 s.anisotropylevel = t->anisotropyLevel();
103 return s;
104}
105
106#if QT_CONFIG(opengl)
107#ifndef QT_NO_DEBUG
108inline static bool isPowerOfTwo(int x)
109{
110 // Assumption: x >= 1
111 return x == (x & -x);
112}
113#endif
114#endif
115
116QSGTexturePrivate::QSGTexturePrivate()
117 : wrapChanged(false)
118 , filteringChanged(false)
119 , anisotropyChanged(false)
120 , horizontalWrap(QSGTexture::ClampToEdge)
121 , verticalWrap(QSGTexture::ClampToEdge)
122 , mipmapMode(QSGTexture::None)
123 , filterMode(QSGTexture::Nearest)
124 , anisotropyLevel(QSGTexture::AnisotropyNone)
125{
126}
127
128#ifndef QT_NO_DEBUG
129
130static int qt_debug_texture_count = 0;
131
132#if (defined(Q_OS_LINUX) || defined (Q_OS_MAC)) && !defined(Q_OS_ANDROID)
133DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE)
134
135#define BACKTRACE_SIZE 20
136class SGTextureTraceItem
137{
138public:
139 void *backTrace[BACKTRACE_SIZE];
140 size_t backTraceSize;
141};
142
143static QHash<QSGTexture*, SGTextureTraceItem*> qt_debug_allocated_textures;
144#endif
145
146inline static void qt_debug_print_texture_count()
147{
148 qDebug("Number of leaked textures: %i", qt_debug_texture_count);
149 qt_debug_texture_count = -1;
150
151#if defined(CAN_BACKTRACE_EXECINFO)
152 if (qmlDebugLeakBacktrace()) {
153 while (!qt_debug_allocated_textures.isEmpty()) {
154 QHash<QSGTexture*, SGTextureTraceItem*>::Iterator it = qt_debug_allocated_textures.begin();
155 QSGTexture* texture = it.key();
156 SGTextureTraceItem* item = it.value();
157
158 qt_debug_allocated_textures.erase(it);
159
160 qDebug() << "------";
161 qDebug() << "Leaked" << texture << "backtrace:";
162
163 char** symbols = backtrace_symbols(item->backTrace, item->backTraceSize);
164
165 if (symbols) {
166 for (int i=0; i<(int) item->backTraceSize; i++)
167 qDebug("Backtrace <%02d>: %s", i, symbols[i]);
168 free(symbols);
169 }
170
171 qDebug() << "------";
172
173 delete item;
174 }
175 }
176#endif
177}
178
179inline static void qt_debug_add_texture(QSGTexture* texture)
180{
181#if defined(CAN_BACKTRACE_EXECINFO)
182 if (qmlDebugLeakBacktrace()) {
183 SGTextureTraceItem* item = new SGTextureTraceItem;
184 item->backTraceSize = backtrace(item->backTrace, BACKTRACE_SIZE);
185 qt_debug_allocated_textures.insert(texture, item);
186 }
187#else
188 Q_UNUSED(texture);
189#endif // Q_OS_LINUX
190
191 ++qt_debug_texture_count;
192
193 static bool atexit_registered = false;
194 if (!atexit_registered) {
195 atexit(qt_debug_print_texture_count);
196 atexit_registered = true;
197 }
198}
199
200static void qt_debug_remove_texture(QSGTexture* texture)
201{
202#if defined(CAN_BACKTRACE_EXECINFO)
203 if (qmlDebugLeakBacktrace()) {
204 SGTextureTraceItem* item = qt_debug_allocated_textures.value(texture, 0);
205 if (item) {
206 qt_debug_allocated_textures.remove(texture);
207 delete item;
208 }
209 }
210#else
211 Q_UNUSED(texture)
212#endif
213
214 --qt_debug_texture_count;
215
216 if (qt_debug_texture_count < 0)
217 qDebug("Texture destroyed after qt_debug_print_texture_count() was called.");
218}
219
220#endif // QT_NO_DEBUG
221
222/*!
223 \class QSGTexture
224
225 \inmodule QtQuick
226
227 \brief The QSGTexture class is a baseclass for textures used in
228 the scene graph.
229
230
231 Users can freely implement their own texture classes to support
232 arbitrary input textures, such as YUV video frames or 8 bit alpha
233 masks. The scene graph backend provides a default implementation
234 of normal color textures. As the implementation of these may be
235 hardware specific, they are constructed via the factory
236 function QQuickWindow::createTextureFromImage().
237
238 The texture is a wrapper around an OpenGL texture, which texture
239 id is given by textureId() and which size in pixels is given by
240 textureSize(). hasAlphaChannel() reports if the texture contains
241 opacity values and hasMipmaps() reports if the texture contains
242 mipmap levels.
243
244 To use a texture, call the bind() function. The texture parameters
245 specifying how the texture is bound, can be specified with
246 setMipmapFiltering(), setFiltering(), setHorizontalWrapMode() and
247 setVerticalWrapMode(). The texture will internally try to store
248 these values to minimize the OpenGL state changes when the texture
249 is bound.
250
251 \section1 Texture Atlasses
252
253 Some scene graph backends use texture atlasses, grouping multiple
254 small textures into one large texture. If this is the case, the
255 function isAtlasTexture() will return true. Atlasses are used to
256 aid the rendering algorithm to do better sorting which increases
257 performance. The location of the texture inside the atlas is
258 given with the normalizedTextureSubRect() function.
259
260 If the texture is used in such a way that atlas is not preferable,
261 the function removedFromAtlas() can be used to extract a
262 non-atlassed copy.
263
264 \note All classes with QSG prefix should be used solely on the scene graph's
265 rendering thread. See \l {Scene Graph and Rendering} for more information.
266
267 \sa {Scene Graph - Rendering FBOs}, {Scene Graph - Rendering FBOs in a thread}
268 */
269
270/*!
271 \enum QSGTexture::WrapMode
272
273 Specifies how the texture should treat texture coordinates.
274
275 \value Repeat Only the fractional part of the texture coordinate is
276 used, causing values above 1 and below 0 to repeat.
277
278 \value ClampToEdge Values above 1 are clamped to 1 and values
279 below 0 are clamped to 0.
280
281 \value MirroredRepeat When the texture coordinate is even, only the
282 fractional part is used. When odd, the texture coordinate is set to
283 \c{1 - fractional part}. This value has been introduced in Qt 5.10.
284 */
285
286/*!
287 \enum QSGTexture::Filtering
288
289 Specifies how sampling of texels should filter when texture
290 coordinates are not pixel aligned.
291
292 \value None No filtering should occur. This value is only used
293 together with setMipmapFiltering().
294
295 \value Nearest Sampling returns the nearest texel.
296
297 \value Linear Sampling returns a linear interpolation of the
298 neighboring texels.
299*/
300
301/*!
302 \enum QSGTexture::AnisotropyLevel
303
304 Specifies the anisotropic filtering level to be used when
305 the texture is not screen aligned.
306
307 \value AnisotropyNone No anisotropic filtering.
308
309 \value Anisotropy2x 2x anisotropic filtering.
310
311 \value Anisotropy4x 4x anisotropic filtering.
312
313 \value Anisotropy8x 8x anisotropic filtering.
314
315 \value Anisotropy16x 16x anisotropic filtering.
316
317 \since 5.9
318*/
319
320#ifndef QT_NO_DEBUG
321Q_QUICK_PRIVATE_EXPORT void qsg_set_material_failure();
322#endif
323
324#ifndef QT_NO_DEBUG
325Q_GLOBAL_STATIC(QSet<QSGTexture *>, qsg_valid_texture_set)
326Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex)
327
328bool qsg_safeguard_texture(QSGTexture *texture)
329{
330#if QT_CONFIG(opengl)
331 QMutexLocker locker(qsg_valid_texture_mutex());
332 if (!qsg_valid_texture_set()->contains(texture)) {
333 qWarning() << "Invalid texture accessed:" << (void *) texture;
334 qsg_set_material_failure();
335 QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, 0);
336 return false;
337 }
338#else
339 Q_UNUSED(texture)
340#endif
341 return true;
342}
343#endif
344
345/*!
346 Constructs the QSGTexture base class.
347 */
348QSGTexture::QSGTexture()
349 : QObject(*(new QSGTexturePrivate))
350{
351#ifndef QT_NO_DEBUG
352 if (qsg_leak_check)
353 qt_debug_add_texture(this);
354
355 QMutexLocker locker(qsg_valid_texture_mutex());
356 qsg_valid_texture_set()->insert(this);
357#endif
358}
359
360/*!
361 \internal
362 */
363QSGTexture::QSGTexture(QSGTexturePrivate &dd)
364 : QObject(dd)
365{
366#ifndef QT_NO_DEBUG
367 if (qsg_leak_check)
368 qt_debug_add_texture(this);
369
370 QMutexLocker locker(qsg_valid_texture_mutex());
371 qsg_valid_texture_set()->insert(this);
372#endif
373}
374
375/*!
376 Destroys the QSGTexture.
377 */
378QSGTexture::~QSGTexture()
379{
380#ifndef QT_NO_DEBUG
381 if (qsg_leak_check)
382 qt_debug_remove_texture(this);
383
384 QMutexLocker locker(qsg_valid_texture_mutex());
385 qsg_valid_texture_set()->remove(this);
386#endif
387}
388
389/*!
390 \fn void QSGTexture::bind()
391
392 Call this function to bind this texture to the current texture
393 target.
394
395 Binding a texture may also include uploading the texture data from
396 a previously set QImage.
397
398 \warning This function can only be called from the rendering thread.
399 */
400
401/*!
402 \fn QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const
403
404 Returns \a rect converted to normalized coordinates.
405
406 \sa normalizedTextureSubRect()
407 */
408
409/*!
410 This function returns a copy of the current texture which is removed
411 from its atlas.
412
413 The current texture remains unchanged, so texture coordinates do not
414 need to be updated.
415
416 Removing a texture from an atlas is primarily useful when passing
417 it to a shader that operates on the texture coordinates 0-1 instead
418 of the texture subrect inside the atlas.
419
420 If the texture is not part of a texture atlas, this function returns 0.
421
422 Implementations of this function are recommended to return the same instance
423 for multiple calls to limit memory usage.
424
425 \warning This function can only be called from the rendering thread.
426 */
427
428QSGTexture *QSGTexture::removedFromAtlas() const
429{
430 Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()", "Called on a non-atlas texture");
431 return nullptr;
432}
433
434/*!
435 Returns weither this texture is part of an atlas or not.
436
437 The default implementation returns false.
438 */
439bool QSGTexture::isAtlasTexture() const
440{
441 return false;
442}
443
444/*!
445 \fn int QSGTexture::textureId() const
446
447 Returns the OpenGL texture id for this texture.
448
449 The default value is 0, indicating that it is an invalid texture id.
450
451 The function should at all times return the correct texture id.
452
453 \warning This function can only be called from the rendering thread.
454 */
455
456/*!
457 Returns a key suitable for comparing textures. Typically used in
458 QSGMaterial::compare() implementations.
459
460 Just comparing QSGTexture pointers is not always sufficient because two
461 QSGTexture instances that refer to the same native texture object
462 underneath should also be considered equal. Hence this function.
463
464 \note Unlike textureId(), implementations of this function are not expected
465 to and should not create any graphics resources (so texture objects) in
466 case there is none yet.
467
468 A QSGTexture that does not have a native texture object underneath is
469 typically not equal to any other QSGTexture. There are exceptions to this,
470 in particular when atlasing is used (where multiple textures share the same
471 atlas texture under the hood), that is then up to the subclass
472 implementations to deal with as appropriate.
473
474 \warning This function can only be called from the rendering thread.
475
476 \since 5.14
477 */
478int QSGTexture::comparisonKey() const
479{
480 Q_D(const QSGTexture);
481 return d->comparisonKey();
482}
483
484/*!
485 \fn QSize QSGTexture::textureSize() const
486
487 Returns the size of the texture.
488 */
489
490/*!
491 Returns the rectangle inside textureSize() that this texture
492 represents in normalized coordinates.
493
494 The default implementation returns a rect at position (0, 0) with
495 width and height of 1.
496 */
497QRectF QSGTexture::normalizedTextureSubRect() const
498{
499 return QRectF(0, 0, 1, 1);
500}
501
502/*!
503 \fn bool QSGTexture::hasAlphaChannel() const
504
505 Returns true if the texture data contains an alpha channel.
506 */
507
508/*!
509 \fn bool QSGTexture::hasMipmaps() const
510
511 Returns true if the texture data contains mipmap levels.
512 */
513
514
515/*!
516 Sets the mipmap sampling mode to be used for the upcoming bind() call to \a filter.
517
518 Setting the mipmap filtering has no effect it the texture does not have mipmaps.
519
520 \sa hasMipmaps()
521 */
522void QSGTexture::setMipmapFiltering(Filtering filter)
523{
524 Q_D(QSGTexture);
525 if (d->mipmapMode != (uint) filter) {
526 d->mipmapMode = filter;
527 d->filteringChanged = true;
528 }
529}
530
531/*!
532 Returns whether mipmapping should be used when sampling from this texture.
533 */
534QSGTexture::Filtering QSGTexture::mipmapFiltering() const
535{
536 return (QSGTexture::Filtering) d_func()->mipmapMode;
537}
538
539
540/*!
541 Sets the sampling mode to be used for the upcoming bind() call to \a filter.
542 */
543void QSGTexture::setFiltering(QSGTexture::Filtering filter)
544{
545 Q_D(QSGTexture);
546 if (d->filterMode != (uint) filter) {
547 d->filterMode = filter;
548 d->filteringChanged = true;
549 }
550}
551
552/*!
553 Returns the sampling mode to be used for this texture.
554 */
555QSGTexture::Filtering QSGTexture::filtering() const
556{
557 return (QSGTexture::Filtering) d_func()->filterMode;
558}
559
560/*!
561 Sets the level of anisotropic filtering to be used for the upcoming bind() call to \a level.
562 The default value is QSGTexture::AnisotropyNone, which means no anisotropic filtering is enabled.
563
564 \since 5.9
565 */
566void QSGTexture::setAnisotropyLevel(AnisotropyLevel level)
567{
568 Q_D(QSGTexture);
569 if (d->anisotropyLevel != (uint) level) {
570 d->anisotropyLevel = level;
571 d->anisotropyChanged = true;
572 }
573}
574
575/*!
576 Returns the anisotropy level in use for filtering this texture.
577
578 \since 5.9
579 */
580QSGTexture::AnisotropyLevel QSGTexture::anisotropyLevel() const
581{
582 return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel;
583}
584
585
586
587/*!
588 Sets the horizontal wrap mode to be used for the upcoming bind() call to \a hwrap
589 */
590
591void QSGTexture::setHorizontalWrapMode(WrapMode hwrap)
592{
593 Q_D(QSGTexture);
594 if ((uint) hwrap != d->horizontalWrap) {
595 d->horizontalWrap = hwrap;
596 d->wrapChanged = true;
597 }
598}
599
600/*!
601 Returns the horizontal wrap mode to be used for this texture.
602 */
603QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const
604{
605 return (QSGTexture::WrapMode) d_func()->horizontalWrap;
606}
607
608
609
610/*!
611 Sets the vertical wrap mode to be used for the upcoming bind() call to \a vwrap
612 */
613void QSGTexture::setVerticalWrapMode(WrapMode vwrap)
614{
615 Q_D(QSGTexture);
616 if ((uint) vwrap != d->verticalWrap) {
617 d->verticalWrap = vwrap;
618 d->wrapChanged = true;
619 }
620}
621
622/*!
623 Returns the vertical wrap mode to be used for this texture.
624 */
625QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
626{
627 return (QSGTexture::WrapMode) d_func()->verticalWrap;
628}
629
630
631/*!
632 Update the texture state to match the filtering, mipmap and wrap options
633 currently set.
634
635 If \a force is true, all properties will be updated regardless of weither
636 they have changed or not.
637 */
638void QSGTexture::updateBindOptions(bool force) // legacy (GL-only)
639{
640#if QT_CONFIG(opengl)
641 Q_D(QSGTexture);
642 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
643 force |= isAtlasTexture();
644
645 if (force || d->filteringChanged) {
646 bool linear = d->filterMode == Linear;
647 GLint minFilter = linear ? GL_LINEAR : GL_NEAREST;
648 GLint magFilter = linear ? GL_LINEAR : GL_NEAREST;
649
650 if (hasMipmaps()) {
651 if (d->mipmapMode == Nearest)
652 minFilter = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST;
653 else if (d->mipmapMode == Linear)
654 minFilter = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR;
655 }
656 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
657 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
658 d->filteringChanged = false;
659 }
660
661 if (force || d->anisotropyChanged) {
662 d->anisotropyChanged = false;
663 if (QOpenGLContext::currentContext()->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")))
664 funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, float(1 << (d->anisotropyLevel)));
665 }
666
667 if (force || d->wrapChanged) {
668#ifndef QT_NO_DEBUG
669 if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat
670 || d->horizontalWrap == MirroredRepeat || d->verticalWrap == MirroredRepeat)
671 {
672 bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
673 QSize size = textureSize();
674 bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
675 if (!npotSupported && isNpot)
676 qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
677 }
678#endif
679 GLenum wrapS = GL_CLAMP_TO_EDGE;
680 if (d->horizontalWrap == Repeat)
681 wrapS = GL_REPEAT;
682 else if (d->horizontalWrap == MirroredRepeat)
683 wrapS = GL_MIRRORED_REPEAT;
684 GLenum wrapT = GL_CLAMP_TO_EDGE;
685 if (d->verticalWrap == Repeat)
686 wrapT = GL_REPEAT;
687 else if (d->verticalWrap == MirroredRepeat)
688 wrapT = GL_MIRRORED_REPEAT;
689 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
690 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
691 d->wrapChanged = false;
692 }
693#else
694 Q_UNUSED(force)
695#endif
696}
697
698/*!
699 \return the QRhiTexture for this QSGTexture or null if there is none.
700
701 Unlike textureId(), this function is not expected to create a new
702 QRhiTexture in case there is none. Just return null in that case. The
703 expectation towards the renderer is that a null texture leads to using a
704 transparent, dummy texture instead.
705
706 \note This function is only used when running the graphics API independent
707 rendering path of the scene graph.
708
709 \warning This function can only be called from the rendering thread.
710
711 \since 5.14
712 */
713QRhiTexture *QSGTexture::rhiTexture() const
714{
715 Q_D(const QSGTexture);
716 return d->rhiTexture();
717}
718
719/*!
720 Call this function to enqueue image upload operations to \a
721 resourceUpdates, in case there are any pending ones. When there is no new
722 data (for example, because there was no setImage() since the last call to
723 this function), the function does nothing.
724
725 Materials involving textures are expected to call this function from their
726 updateSampledImage() implementation, typically without any conditions.
727
728 \note This function is only used when running the graphics API independent
729 rendering path of the scene graph.
730
731 \warning This function can only be called from the rendering thread.
732
733 \since 5.14
734 */
735void QSGTexture::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
736{
737 Q_D(QSGTexture);
738 d->updateRhiTexture(rhi, resourceUpdates);
739}
740
741void QSGTexture::setWorkResourceUpdateBatch(QRhiResourceUpdateBatch *resourceUpdates)
742{
743 Q_D(QSGTexture);
744 d->workResourceUpdateBatch = resourceUpdates;
745}
746
747bool QSGTexturePrivate::hasDirtySamplerOptions() const
748{
749 return wrapChanged || filteringChanged || anisotropyChanged;
750}
751
752void QSGTexturePrivate::resetDirtySamplerOptions()
753{
754 wrapChanged = filteringChanged = anisotropyChanged = false;
755}
756
757int QSGTexturePrivate::comparisonKey() const
758{
759 // Must be overridden in subclasses but we cannot make this pure virtual
760 // before Qt 6 because the simple QSGTexture ctor must be kept working.
761 Q_Q(const QSGTexture);
762 return q->textureId(); // this is semantically wrong but at least compatible with existing, non-RHI-aware subclasses
763}
764
765QRhiTexture *QSGTexturePrivate::rhiTexture() const
766{
767 return nullptr;
768}
769
770void QSGTexturePrivate::updateRhiTexture(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
771{
772 Q_UNUSED(rhi);
773 Q_UNUSED(resourceUpdates);
774}
775
776/*!
777 \class QSGDynamicTexture
778 \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures,
779 such as content that is rendered to FBO's.
780 \inmodule QtQuick
781
782 To update the content of the texture, call updateTexture() explicitly. Simply calling bind()
783 will not update the texture.
784
785 \note All classes with QSG prefix should be used solely on the scene graph's
786 rendering thread. See \l {Scene Graph and Rendering} for more information.
787 */
788
789
790/*!
791 \fn bool QSGDynamicTexture::updateTexture()
792
793 Call this function to explicitly update the dynamic texture. Calling bind() will bind
794 the content that was previously updated.
795
796 The function returns true if the texture was changed as a resul of the update; otherwise
797 returns false.
798 */
799
800/*!
801 \internal
802 */
803QSGDynamicTexture::QSGDynamicTexture(QSGTexturePrivate &dd)
804 : QSGTexture(dd)
805{
806}
807
808QT_END_NAMESPACE
809
810#include "moc_qsgtexture.cpp"
811