1// Copyright (C) 2019 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
4#include "qsgtexture_p.h"
5#include "qsgtexture_platform.h"
6#include <private/qqmlglobal_p.h>
7#include <private/qsgmaterialshader_p.h>
8#include <private/qsgrenderer_p.h>
9#include <private/qquickitem_p.h> // qquickwindow_p.h cannot be included on its own due to template nonsense
10#include <private/qquickwindow_p.h>
11#include <QtCore/private/qnativeinterface_p.h>
12#include <rhi/qrhi.h>
13
14#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && defined(__GLIBC__)
15#define CAN_BACKTRACE_EXECINFO
16#endif
17
18#if defined(Q_OS_MAC)
19#define CAN_BACKTRACE_EXECINFO
20#endif
21
22#if defined(QT_NO_DEBUG)
23#undef CAN_BACKTRACE_EXECINFO
24#endif
25
26#if defined(CAN_BACKTRACE_EXECINFO)
27#include <execinfo.h>
28#include <QHash>
29#endif
30
31#ifndef QT_NO_DEBUG
32Q_GLOBAL_STATIC(QSet<QSGTexture *>, qsg_valid_texture_set)
33Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex)
34#endif
35
36QT_BEGIN_NAMESPACE
37
38bool operator==(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept
39{
40 return a.filtering == b.filtering
41 && a.mipmapFiltering == b.mipmapFiltering
42 && a.horizontalWrap == b.horizontalWrap
43 && a.verticalWrap == b.verticalWrap
44 && a.anisotropylevel == b.anisotropylevel;
45}
46
47bool operator!=(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept
48{
49 return !(a == b);
50}
51
52size_t qHash(const QSGSamplerDescription &s, size_t seed) noexcept
53{
54 const int f = s.filtering;
55 const int m = s.mipmapFiltering;
56 const int w = s.horizontalWrap;
57 const int a = s.anisotropylevel;
58 return (((f & 7) << 24) | ((m & 7) << 16) | ((w & 7) << 8) | (a & 7)) ^ seed;
59}
60
61QSGSamplerDescription QSGSamplerDescription::fromTexture(QSGTexture *t)
62{
63 QSGSamplerDescription s;
64 s.filtering = t->filtering();
65 s.mipmapFiltering = t->mipmapFiltering();
66 s.horizontalWrap = t->horizontalWrapMode();
67 s.verticalWrap = t->verticalWrapMode();
68 s.anisotropylevel = t->anisotropyLevel();
69 return s;
70}
71
72QSGTexturePrivate::QSGTexturePrivate(QSGTexture *t)
73 : wrapChanged(false)
74 , filteringChanged(false)
75 , anisotropyChanged(false)
76 , horizontalWrap(QSGTexture::ClampToEdge)
77 , verticalWrap(QSGTexture::ClampToEdge)
78 , mipmapMode(QSGTexture::None)
79 , filterMode(QSGTexture::Nearest)
80 , anisotropyLevel(QSGTexture::AnisotropyNone)
81#if QT_CONFIG(opengl)
82 , m_openglTextureAccessor(t)
83#endif
84#ifdef Q_OS_WIN
85 , m_d3d11TextureAccessor(t)
86 , m_d3d12TextureAccessor(t)
87#endif
88#if defined(__OBJC__)
89 , m_metalTextureAccessor(t)
90#endif
91#if QT_CONFIG(vulkan)
92 , m_vulkanTextureAccessor(t)
93#endif
94{
95#if !QT_CONFIG(opengl)
96 Q_UNUSED(t);
97#endif
98}
99
100#ifndef QT_NO_DEBUG
101
102static int qt_debug_texture_count = 0;
103
104#if (defined(Q_OS_LINUX) || defined (Q_OS_MAC)) && !defined(Q_OS_ANDROID)
105DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE)
106
107#define BACKTRACE_SIZE 20
108class SGTextureTraceItem
109{
110public:
111 void *backTrace[BACKTRACE_SIZE];
112 size_t backTraceSize;
113};
114
115static QHash<QSGTexture*, SGTextureTraceItem*> qt_debug_allocated_textures;
116#endif
117
118inline static void qt_debug_print_texture_count()
119{
120 qDebug(msg: "Number of leaked textures: %i", qt_debug_texture_count);
121 qt_debug_texture_count = -1;
122
123#if defined(CAN_BACKTRACE_EXECINFO)
124 if (qmlDebugLeakBacktrace()) {
125 while (!qt_debug_allocated_textures.isEmpty()) {
126 QHash<QSGTexture*, SGTextureTraceItem*>::Iterator it = qt_debug_allocated_textures.begin();
127 QSGTexture* texture = it.key();
128 SGTextureTraceItem* item = it.value();
129
130 qt_debug_allocated_textures.erase(it);
131
132 qDebug() << "------";
133 qDebug() << "Leaked" << texture << "backtrace:";
134
135 char** symbols = backtrace_symbols(array: item->backTrace, size: item->backTraceSize);
136
137 if (symbols) {
138 for (int i=0; i<(int) item->backTraceSize; i++)
139 qDebug(msg: "Backtrace <%02d>: %s", i, symbols[i]);
140 free(ptr: symbols);
141 }
142
143 qDebug() << "------";
144
145 delete item;
146 }
147 }
148#endif
149}
150
151inline static void qt_debug_add_texture(QSGTexture* texture)
152{
153#if defined(CAN_BACKTRACE_EXECINFO)
154 if (qmlDebugLeakBacktrace()) {
155 SGTextureTraceItem* item = new SGTextureTraceItem;
156 item->backTraceSize = backtrace(array: item->backTrace, BACKTRACE_SIZE);
157 qt_debug_allocated_textures.insert(key: texture, value: item);
158 }
159#else
160 Q_UNUSED(texture);
161#endif // Q_OS_LINUX
162
163 ++qt_debug_texture_count;
164
165 static bool atexit_registered = false;
166 if (!atexit_registered) {
167 atexit(func: qt_debug_print_texture_count);
168 atexit_registered = true;
169 }
170}
171
172static void qt_debug_remove_texture(QSGTexture* texture)
173{
174#if defined(CAN_BACKTRACE_EXECINFO)
175 if (qmlDebugLeakBacktrace()) {
176 SGTextureTraceItem* item = qt_debug_allocated_textures.value(key: texture, defaultValue: 0);
177 if (item) {
178 qt_debug_allocated_textures.remove(key: texture);
179 delete item;
180 }
181 }
182#else
183 Q_UNUSED(texture);
184#endif
185
186 --qt_debug_texture_count;
187
188 if (qt_debug_texture_count < 0)
189 qDebug(msg: "Texture destroyed after qt_debug_print_texture_count() was called.");
190}
191
192#endif // QT_NO_DEBUG
193
194/*!
195 \class QSGTexture
196
197 \inmodule QtQuick
198
199 \brief The QSGTexture class is the base class for textures used in
200 the scene graph.
201
202 Users can freely implement their own texture classes to support arbitrary
203 input textures, such as YUV video frames or 8 bit alpha masks. The scene
204 graph provides a default implementation for RGBA textures.The default
205 implementation is not instantiated directly, rather they are constructed
206 via factory functions, such as QQuickWindow::createTextureFromImage().
207
208 With the default implementation, each QSGTexture is backed by a
209 QRhiTexture, which in turn contains a native texture object, such as an
210 OpenGL texture or a Vulkan image.
211
212 The size in pixels is given by textureSize(). hasAlphaChannel() reports if
213 the texture contains opacity values and hasMipmaps() reports if the texture
214 contains mipmap levels.
215
216 \l{QSGMaterial}{Materials} that work with textures reimplement
217 \l{QSGMaterialShader::updateSampledImage()}{updateSampledImage()} to
218 provide logic that decides which QSGTexture's underlying native texture
219 should be exposed at a given shader resource binding point.
220
221 QSGTexture does not separate image (texture) and sampler objects. The
222 parameters for filtering and wrapping can be specified with
223 setMipmapFiltering(), setFiltering(), setHorizontalWrapMode() and
224 setVerticalWrapMode(). The scene graph and Qt's graphics abstraction takes
225 care of creating separate sampler objects, when applicable.
226
227 \section1 Texture Atlases
228
229 Some scene graph backends use texture atlasses, grouping multiple small
230 textures into one large texture. If this is the case, the function
231 isAtlasTexture() will return true. Atlases are used to aid the rendering
232 algorithm to do better sorting which increases performance. Atlases are
233 also essential for batching (merging together geometry to reduce the number
234 of draw calls), because two instances of the same material using two
235 different QSGTextures are not batchable, whereas if both QSGTextures refer
236 to the same atlas, batching can happen, assuming the materials are
237 otherwise compatible.
238
239 The location of the texture inside the atlas is given with the
240 normalizedTextureSubRect() function.
241
242 If the texture is used in such a way that atlas is not preferable, the
243 function removedFromAtlas() can be used to extract a non-atlased copy.
244
245 \note All classes with QSG prefix should be used solely on the scene graph's
246 rendering thread. See \l {Scene Graph and Rendering} for more information.
247 */
248
249/*!
250 \enum QSGTexture::WrapMode
251
252 Specifies how the sampler should treat texture coordinates.
253
254 \value Repeat Only the fractional part of the texture coordinate is
255 used, causing values above 1 and below 0 to repeat.
256
257 \value ClampToEdge Values above 1 are clamped to 1 and values
258 below 0 are clamped to 0.
259
260 \value MirroredRepeat When the texture coordinate is even, only the
261 fractional part is used. When odd, the texture coordinate is set to
262 \c{1 - fractional part}. This value has been introduced in Qt 5.10.
263 */
264
265/*!
266 \enum QSGTexture::Filtering
267
268 Specifies how sampling of texels should filter when texture
269 coordinates are not pixel aligned.
270
271 \value None No filtering should occur. This value is only used
272 together with setMipmapFiltering().
273
274 \value Nearest Sampling returns the nearest texel.
275
276 \value Linear Sampling returns a linear interpolation of the
277 neighboring texels.
278*/
279
280/*!
281 \enum QSGTexture::AnisotropyLevel
282
283 Specifies the anisotropic filtering level to be used when
284 the texture is not screen aligned.
285
286 \value AnisotropyNone No anisotropic filtering.
287
288 \value Anisotropy2x 2x anisotropic filtering.
289
290 \value Anisotropy4x 4x anisotropic filtering.
291
292 \value Anisotropy8x 8x anisotropic filtering.
293
294 \value Anisotropy16x 16x anisotropic filtering.
295
296 \since 5.9
297*/
298
299/*!
300 Constructs the QSGTexture base class.
301 */
302QSGTexture::QSGTexture()
303 : QObject(*(new QSGTexturePrivate(this)))
304{
305#ifndef QT_NO_DEBUG
306 if (_q_sg_leak_check)
307 qt_debug_add_texture(texture: this);
308
309 QMutexLocker locker(qsg_valid_texture_mutex());
310 qsg_valid_texture_set()->insert(value: this);
311#endif
312}
313
314/*!
315 \internal
316 */
317QSGTexture::QSGTexture(QSGTexturePrivate &dd)
318 : QObject(dd)
319{
320#ifndef QT_NO_DEBUG
321 if (_q_sg_leak_check)
322 qt_debug_add_texture(texture: this);
323
324 QMutexLocker locker(qsg_valid_texture_mutex());
325 qsg_valid_texture_set()->insert(value: this);
326#endif
327}
328
329/*!
330 Destroys the QSGTexture.
331 */
332QSGTexture::~QSGTexture()
333{
334#ifndef QT_NO_DEBUG
335 if (_q_sg_leak_check)
336 qt_debug_remove_texture(texture: this);
337
338 QMutexLocker locker(qsg_valid_texture_mutex());
339 qsg_valid_texture_set()->remove(value: this);
340#endif
341}
342
343/*!
344 \fn QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const
345
346 Returns \a rect converted to normalized coordinates.
347
348 \sa normalizedTextureSubRect()
349 */
350
351/*!
352 This function returns a copy of the current texture which is removed
353 from its atlas.
354
355 The current texture remains unchanged, so texture coordinates do not
356 need to be updated.
357
358 Removing a texture from an atlas is primarily useful when passing
359 it to a shader that operates on the texture coordinates 0-1 instead
360 of the texture subrect inside the atlas.
361
362 If the texture is not part of a texture atlas, this function returns 0.
363
364 Implementations of this function are recommended to return the same instance
365 for multiple calls to limit memory usage.
366
367 \a resourceUpdates is an optional resource update batch, on which texture
368 operations, if any, are enqueued. Materials can retrieve an instance from
369 QSGMaterialShader::RenderState. When null, the removedFromAtlas()
370 implementation creates its own batch and submit it right away. However,
371 when a valid instance is specified, this function will not submit the
372 update batch.
373
374 \warning This function can only be called from the rendering thread.
375 */
376
377QSGTexture *QSGTexture::removedFromAtlas(QRhiResourceUpdateBatch *resourceUpdates) const
378{
379 Q_UNUSED(resourceUpdates);
380 Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()", "Called on a non-atlas texture");
381 return nullptr;
382}
383
384/*!
385 Returns whether this texture is part of an atlas or not.
386
387 The default implementation returns false.
388 */
389bool QSGTexture::isAtlasTexture() const
390{
391 return false;
392}
393
394/*!
395 \fn qint64 QSGTexture::comparisonKey() const
396
397 Returns a key suitable for comparing textures. Typically used in
398 QSGMaterial::compare() implementations.
399
400 Just comparing QSGTexture pointers is not always sufficient because two
401 QSGTexture instances that refer to the same native texture object
402 underneath should also be considered equal. Hence the need for this function.
403
404 Implementations of this function are not expected to, and should not create
405 any graphics resources (native texture objects) in case there are none yet.
406
407 A QSGTexture that does not have a native texture object underneath is
408 typically \b not equal to any other QSGTexture, so the return value has to
409 be crafted accordingly. There are exceptions to this, in particular when
410 atlasing is used (where multiple textures share the same atlas texture
411 under the hood), that is then up to the subclass implementations to deal
412 with as appropriate.
413
414 \warning This function can only be called from the rendering thread.
415
416 \since 5.14
417 */
418
419/*!
420 \fn QSize QSGTexture::textureSize() const
421
422 Returns the size of the texture in pixels.
423 */
424
425/*!
426 Returns the rectangle inside textureSize() that this texture
427 represents in normalized coordinates.
428
429 The default implementation returns a rect at position (0, 0) with
430 width and height of 1.
431 */
432QRectF QSGTexture::normalizedTextureSubRect() const
433{
434 return QRectF(0, 0, 1, 1);
435}
436
437/*!
438 \fn bool QSGTexture::hasAlphaChannel() const
439
440 Returns true if the texture data contains an alpha channel.
441 */
442
443/*!
444 \fn bool QSGTexture::hasMipmaps() const
445
446 Returns true if the texture data contains mipmap levels.
447 */
448
449
450/*!
451 Sets the mipmap sampling mode to \a filter.
452
453 Setting the mipmap filtering has no effect it the texture does not have mipmaps.
454
455 \sa hasMipmaps()
456 */
457void QSGTexture::setMipmapFiltering(Filtering filter)
458{
459 Q_D(QSGTexture);
460 if (d->mipmapMode != (uint) filter) {
461 d->mipmapMode = filter;
462 d->filteringChanged = true;
463 }
464}
465
466/*!
467 Returns whether mipmapping should be used when sampling from this texture.
468 */
469QSGTexture::Filtering QSGTexture::mipmapFiltering() const
470{
471 return (QSGTexture::Filtering) d_func()->mipmapMode;
472}
473
474
475/*!
476 Sets the sampling mode to \a filter.
477 */
478void QSGTexture::setFiltering(QSGTexture::Filtering filter)
479{
480 Q_D(QSGTexture);
481 if (d->filterMode != (uint) filter) {
482 d->filterMode = filter;
483 d->filteringChanged = true;
484 }
485}
486
487/*!
488 Returns the sampling mode to be used for this texture.
489 */
490QSGTexture::Filtering QSGTexture::filtering() const
491{
492 return (QSGTexture::Filtering) d_func()->filterMode;
493}
494
495/*!
496 Sets the level of anisotropic filtering to \a level. The default value is
497 QSGTexture::AnisotropyNone, which means no anisotropic filtering is
498 enabled.
499
500 \note The request may be ignored depending on the graphics API in use.
501 There is no guarantee anisotropic filtering is supported at run time.
502
503 \since 5.9
504 */
505void QSGTexture::setAnisotropyLevel(AnisotropyLevel level)
506{
507 Q_D(QSGTexture);
508 if (d->anisotropyLevel != (uint) level) {
509 d->anisotropyLevel = level;
510 d->anisotropyChanged = true;
511 }
512}
513
514/*!
515 Returns the anisotropy level in use for filtering this texture.
516
517 \since 5.9
518 */
519QSGTexture::AnisotropyLevel QSGTexture::anisotropyLevel() const
520{
521 return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel;
522}
523
524
525
526/*!
527 Sets the horizontal wrap mode to \a hwrap
528 */
529
530void QSGTexture::setHorizontalWrapMode(WrapMode hwrap)
531{
532 Q_D(QSGTexture);
533 if ((uint) hwrap != d->horizontalWrap) {
534 d->horizontalWrap = hwrap;
535 d->wrapChanged = true;
536 }
537}
538
539/*!
540 Returns the horizontal wrap mode to be used for this texture.
541 */
542QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const
543{
544 return (QSGTexture::WrapMode) d_func()->horizontalWrap;
545}
546
547
548
549/*!
550 Sets the vertical wrap mode to \a vwrap
551 */
552void QSGTexture::setVerticalWrapMode(WrapMode vwrap)
553{
554 Q_D(QSGTexture);
555 if ((uint) vwrap != d->verticalWrap) {
556 d->verticalWrap = vwrap;
557 d->wrapChanged = true;
558 }
559}
560
561/*!
562 Returns the vertical wrap mode to be used for this texture.
563 */
564QSGTexture::WrapMode QSGTexture::verticalWrapMode() const
565{
566 return (QSGTexture::WrapMode) d_func()->verticalWrap;
567}
568
569/*!
570 \return the QRhiTexture for this QSGTexture or null if there is none (either
571 because a valid texture has not been created internally yet, or because the
572 concept is not applicable to the scenegraph backend in use).
573
574 This function is not expected to create a new QRhiTexture in case there is
575 none. It should return null in that case. The expectation towards the
576 renderer is that a null texture leads to using a transparent, dummy texture
577 instead.
578
579 \warning This function can only be called from the rendering thread.
580
581 \since 6.0
582 */
583QRhiTexture *QSGTexture::rhiTexture() const
584{
585 return nullptr;
586}
587
588/*!
589 Call this function to enqueue image upload operations to \a
590 resourceUpdates, in case there are any pending ones. When there is no new
591 data (for example, because there was no setImage() since the last call to
592 this function), the function does nothing.
593
594 Materials involving \a rhi textures are expected to call this function from
595 their \l{QSGMaterialShader::updateSampledImage()}{updateSampledImage()}
596 implementation, typically without any conditions, passing \c{state.rhi()}
597 and \c{state.resourceUpdateBatch()} from the QSGMaterialShader::RenderState.
598
599 \warning This function can only be called from the rendering thread.
600
601 \since 6.0
602 */
603void QSGTexture::commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
604{
605 Q_UNUSED(rhi);
606 Q_UNUSED(resourceUpdates);
607}
608
609bool QSGTexturePrivate::hasDirtySamplerOptions() const
610{
611 return wrapChanged || filteringChanged || anisotropyChanged;
612}
613
614void QSGTexturePrivate::resetDirtySamplerOptions()
615{
616 wrapChanged = filteringChanged = anisotropyChanged = false;
617}
618
619/*!
620 \class QSGDynamicTexture
621 \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures,
622 such as content that is rendered to FBO's.
623 \inmodule QtQuick
624
625 To update the content of the texture, call updateTexture() explicitly.
626
627 \note All classes with QSG prefix should be used solely on the scene graph's
628 rendering thread. See \l {Scene Graph and Rendering} for more information.
629 */
630
631
632/*!
633 \fn bool QSGDynamicTexture::updateTexture()
634
635 Call this function to explicitly update the dynamic texture.
636
637 The function returns true if the texture was changed as a resul of the update; otherwise
638 returns false.
639
640 \note This function is typically called from QQuickItem::updatePaintNode()
641 or QSGNode::preprocess(), meaning during the \c{synchronization} or the
642 \c{node preprocessing} phases of the scenegraph. Calling it at other times
643 is discouraged and can lead to unexpected behavior.
644 */
645
646/*!
647 \internal
648 */
649QSGDynamicTexture::QSGDynamicTexture(QSGTexturePrivate &dd)
650 : QSGTexture(dd)
651{
652}
653
654/*!
655 \internal
656 */
657QSGDynamicTexture::~QSGDynamicTexture()
658 = default;
659
660/*!
661 \fn template <typename QNativeInterface> NativeInterface *QSGTexture::nativeInterface() const
662
663 Returns a native interface of the given type for the texture.
664
665 This function provides access to platform specific functionality of
666 QSGTexture, as declared in the QNativeInterface namespace:
667
668 \annotatedlist native-interfaces-qsgtexture
669
670 This allows accessing the underlying native texture object, such as, the \c GLuint
671 texture ID with OpenGL, or the \c VkImage handle with Vulkan.
672
673 If the requested interface is not available a \nullptr is returned.
674 */
675
676
677#if QT_CONFIG(opengl) || defined(Q_QDOC)
678namespace QNativeInterface {
679/*!
680 \class QNativeInterface::QSGOpenGLTexture
681 \inmodule QtQuick
682 \ingroup native-interfaces
683 \ingroup native-interfaces-qsgtexture
684 \inheaderfile QSGTexture
685 \brief Provides access to and enables adopting OpenGL texture objects.
686 \since 6.0
687*/
688
689/*!
690 \fn VkImage QNativeInterface::QSGOpenGLTexture::nativeTexture() const
691 \return the OpenGL texture ID.
692 */
693
694QT_DEFINE_NATIVE_INTERFACE(QSGOpenGLTexture);
695
696/*!
697 Creates a new QSGTexture wrapping an existing OpenGL texture object for
698 \a window.
699
700 The native object specified in \a textureId is wrapped, but not owned, by
701 the resulting QSGTexture. The caller of the function is responsible for
702 deleting the returned QSGTexture, but that will not destroy the underlying
703 native object.
704
705 This function is currently suitable for 2D RGBA textures only.
706
707 \warning This function will return null if the scenegraph has not yet been
708 initialized.
709
710 Use \a options to customize the texture attributes. Only the
711 TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
712
713 \a size specifies the size in pixels.
714
715 \note This function must be called on the scenegraph rendering thread.
716
717 \sa QQuickWindow::sceneGraphInitialized(), QSGTexture,
718 {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import}
719
720 \since 6.0
721 */
722QSGTexture *QSGOpenGLTexture::fromNative(GLuint textureId,
723 QQuickWindow *window,
724 const QSize &size,
725 QQuickWindow::CreateTextureOptions options)
726{
727 return QQuickWindowPrivate::get(c: window)->createTextureFromNativeTexture(nativeObjectHandle: quint64(textureId), nativeLayoutOrState: 0, size, options);
728}
729
730/*!
731 Creates a new QSGTexture wrapping an existing OpenGL ES texture object for
732 \a window.
733
734 The native object specified in \a textureId is wrapped, but not owned, by
735 the resulting QSGTexture. The caller of the function is responsible for
736 deleting the returned QSGTexture, but that will not destroy the underlying
737 native object.
738
739 This function is suitable only for textures that are meant to be
740 used with the \c{GL_TEXTURE_EXTERNAL_OES} target: usually textures
741 to which another device (such as a camera) writes data.
742
743 \warning This function will return null if the scenegraph has not yet been
744 initialized.
745
746 Use \a options to customize the texture attributes. Only the
747 TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
748
749 \a size specifies the size in pixels.
750
751 \note This function must be called on the scenegraph rendering thread.
752
753 \since 6.1
754
755 \sa fromNative()
756 */
757QSGTexture *QSGOpenGLTexture::fromNativeExternalOES(GLuint textureId,
758 QQuickWindow *window,
759 const QSize &size,
760 QQuickWindow::CreateTextureOptions options)
761{
762 return QQuickWindowPrivate::get(c: window)->createTextureFromNativeTexture(nativeObjectHandle: quint64(textureId),
763 nativeLayoutOrState: 0,
764 size,
765 options,
766 flags: QQuickWindowPrivate::NativeTextureIsExternalOES);
767}
768} // QNativeInterface
769
770GLuint QSGTexturePlatformOpenGL::nativeTexture() const
771{
772 if (auto *tex = m_texture->rhiTexture())
773 return GLuint(tex->nativeTexture().object);
774 return 0;
775}
776#endif // opengl
777
778#if defined(Q_OS_WIN) || defined(Q_QDOC)
779namespace QNativeInterface {
780/*!
781 \class QNativeInterface::QSGD3D11Texture
782 \inmodule QtQuick
783 \ingroup native-interfaces
784 \ingroup native-interfaces-qsgtexture
785 \inheaderfile QSGTexture
786 \brief Provides access to and enables adopting Direct3D 11 texture objects.
787 \since 6.0
788*/
789
790/*!
791 \fn void *QNativeInterface::QSGD3D11Texture::nativeTexture() const
792 \return the ID3D11Texture2D object.
793 */
794
795QT_DEFINE_NATIVE_INTERFACE(QSGD3D11Texture);
796
797/*!
798 Creates a new QSGTexture wrapping an existing Direct 3D 11 \a texture object
799 for \a window.
800
801 The native object is wrapped, but not owned, by the resulting QSGTexture.
802 The caller of the function is responsible for deleting the returned
803 QSGTexture, but that will not destroy the underlying native object.
804
805 This function is currently suitable for 2D RGBA textures only.
806
807 \warning This function will return null if the scene graph has not yet been
808 initialized.
809
810 Use \a options to customize the texture attributes. Only the
811 TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
812
813 \a size specifies the size in pixels.
814
815 \note This function must be called on the scene graph rendering thread.
816
817 \sa QQuickWindow::sceneGraphInitialized(), QSGTexture,
818 {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import}
819
820 \since 6.0
821 */
822QSGTexture *QSGD3D11Texture::fromNative(void *texture,
823 QQuickWindow *window,
824 const QSize &size,
825 QQuickWindow::CreateTextureOptions options)
826{
827 return QQuickWindowPrivate::get(window)->createTextureFromNativeTexture(quint64(texture), 0, size, options);
828}
829} // QNativeInterface
830
831void *QSGTexturePlatformD3D11::nativeTexture() const
832{
833 if (auto *tex = m_texture->rhiTexture())
834 return reinterpret_cast<void *>(quintptr(tex->nativeTexture().object));
835 return 0;
836}
837
838namespace QNativeInterface {
839/*!
840 \class QNativeInterface::QSGD3D12Texture
841 \inmodule QtQuick
842 \ingroup native-interfaces
843 \ingroup native-interfaces-qsgtexture
844 \inheaderfile QSGTexture
845 \brief Provides access to and enables adopting Direct3D 12 texture objects.
846 \since 6.6
847*/
848
849/*!
850 \fn void *QNativeInterface::QSGD3D12Texture::nativeTexture() const
851 \return the ID3D12Texture object.
852 */
853
854QT_DEFINE_NATIVE_INTERFACE(QSGD3D12Texture);
855
856/*!
857 Creates a new QSGTexture wrapping an existing Direct 3D 12 \a texture object
858 for \a window.
859
860 The native object is wrapped, but not owned, by the resulting QSGTexture.
861 The caller of the function is responsible for deleting the returned
862 QSGTexture, but that will not destroy the underlying native object.
863
864 This function is currently suitable for 2D RGBA textures only.
865
866 \warning This function will return null if the scene graph has not yet been
867 initialized.
868
869 Use \a options to customize the texture attributes. Only the
870 TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
871
872 \a size specifies the size in pixels.
873
874 \a resourceState must specify the
875 \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_states}{current state}
876 of the texture resource.
877
878 \note This function must be called on the scene graph rendering thread.
879
880 \sa QQuickWindow::sceneGraphInitialized(), QSGTexture,
881 {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import}
882
883 \since 6.6
884 */
885QSGTexture *QSGD3D12Texture::fromNative(void *texture,
886 int resourceState,
887 QQuickWindow *window,
888 const QSize &size,
889 QQuickWindow::CreateTextureOptions options)
890{
891 return QQuickWindowPrivate::get(window)->createTextureFromNativeTexture(quint64(texture), resourceState, size, options);
892}
893} // QNativeInterface
894
895int QSGTexturePlatformD3D12::nativeResourceState() const
896{
897 if (auto *tex = m_texture->rhiTexture())
898 return tex->nativeTexture().layout;
899 return 0;
900}
901
902void *QSGTexturePlatformD3D12::nativeTexture() const
903{
904 if (auto *tex = m_texture->rhiTexture())
905 return reinterpret_cast<void *>(quintptr(tex->nativeTexture().object));
906 return 0;
907}
908
909#endif // win
910
911#if defined(__OBJC__) || defined(Q_QDOC)
912namespace QNativeInterface {
913/*!
914 \class QNativeInterface::QSGMetalTexture
915 \inmodule QtQuick
916 \ingroup native-interfaces
917 \ingroup native-interfaces-qsgtexture
918 \inheaderfile QSGTexture
919 \brief Provides access to and enables adopting Metal texture objects.
920 \since 6.0
921*/
922
923/*!
924 \fn id<MTLTexture> QNativeInterface::QSGMetalTexture::nativeTexture() const
925 \return the Metal texture object.
926 */
927
928/*!
929 \fn QSGTexture *QNativeInterface::QSGMetalTexture::fromNative(id<MTLTexture> texture, QQuickWindow *window, const QSize &size, QQuickWindow::CreateTextureOptions options)
930
931 Creates a new QSGTexture wrapping an existing Metal \a texture object for
932 \a window.
933
934 The native object is wrapped, but not owned, by the resulting QSGTexture.
935 The caller of the function is responsible for deleting the returned
936 QSGTexture, but that will not destroy the underlying native object.
937
938 This function is currently suitable for 2D RGBA textures only.
939
940 \warning This function will return null if the scene graph has not yet been
941 initialized.
942
943 Use \a options to customize the texture attributes. Only the
944 TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
945
946 \a size specifies the size in pixels.
947
948 \note This function must be called on the scene graph rendering thread.
949
950 \sa QQuickWindow::sceneGraphInitialized(), QSGTexture,
951 {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import}
952
953 \since 6.0
954 */
955
956} // QNativeInterface
957#endif // OBJC
958
959#if QT_CONFIG(vulkan) || defined(Q_QDOC)
960namespace QNativeInterface {
961/*!
962 \class QNativeInterface::QSGVulkanTexture
963 \inmodule QtQuick
964 \ingroup native-interfaces
965 \ingroup native-interfaces-qsgtexture
966 \inheaderfile QSGTexture
967 \brief Provides access to and enables adopting Vulkan image objects.
968 \since 6.0
969*/
970
971/*!
972 \fn VkImage QNativeInterface::QSGVulkanTexture::nativeImage() const
973 \return the VkImage handle.
974 */
975
976/*!
977 \fn VkImageLayout QNativeInterface::QSGVulkanTexture::nativeImageLayout() const
978 \return the image layout.
979 */
980
981QT_DEFINE_NATIVE_INTERFACE(QSGVulkanTexture);
982
983/*!
984 Creates a new QSGTexture wrapping an existing Vulkan \a image object for
985 \a window.
986
987 The native object is wrapped, but not owned, by the resulting QSGTexture.
988 The caller of the function is responsible for deleting the returned
989 QSGTexture, but that will not destroy the underlying native object.
990
991 This function is currently suitable for 2D RGBA textures only.
992
993 \warning This function will return null if the scene graph has not yet been
994 initialized.
995
996 \a layout must specify the current layout of the image.
997
998 Use \a options to customize the texture attributes. Only the
999 TextureHasAlphaChannel and TextureHasMipmaps are taken into account here.
1000
1001 \a size specifies the size in pixels.
1002
1003 \note This function must be called on the scene graph rendering thread.
1004
1005 \sa QQuickWindow::sceneGraphInitialized(), QSGTexture,
1006 {Scene Graph - Metal Texture Import}, {Scene Graph - Vulkan Texture Import}
1007
1008 \since 6.0
1009 */
1010QSGTexture *QSGVulkanTexture::fromNative(VkImage image,
1011 VkImageLayout layout,
1012 QQuickWindow *window,
1013 const QSize &size,
1014 QQuickWindow::CreateTextureOptions options)
1015{
1016 return QQuickWindowPrivate::get(c: window)->createTextureFromNativeTexture(nativeObjectHandle: quint64(image), nativeLayoutOrState: layout, size, options);
1017}
1018} // QNativeInterface
1019
1020VkImage QSGTexturePlatformVulkan::nativeImage() const
1021{
1022 if (auto *tex = m_texture->rhiTexture())
1023 return VkImage(tex->nativeTexture().object);
1024 return VK_NULL_HANDLE;
1025}
1026
1027VkImageLayout QSGTexturePlatformVulkan::nativeImageLayout() const
1028{
1029 if (auto *tex = m_texture->rhiTexture())
1030 return VkImageLayout(tex->nativeTexture().layout);
1031 return VK_IMAGE_LAYOUT_UNDEFINED;
1032}
1033#endif // vulkan
1034
1035void *QSGTexture::resolveInterface(const char *name, int revision) const
1036{
1037 using namespace QNativeInterface;
1038 Q_UNUSED(name);
1039 Q_UNUSED(revision);
1040
1041 Q_D(const QSGTexture);
1042 auto *dd = const_cast<QSGTexturePrivate *>(d);
1043 Q_UNUSED(dd);
1044
1045#if QT_CONFIG(vulkan)
1046 QT_NATIVE_INTERFACE_RETURN_IF(QSGVulkanTexture, &dd->m_vulkanTextureAccessor);
1047#endif
1048#if defined(__OBJC__)
1049 QT_NATIVE_INTERFACE_RETURN_IF(QSGMetalTexture, &dd->m_metalTextureAccessor);
1050#endif
1051#if defined(Q_OS_WIN)
1052 QT_NATIVE_INTERFACE_RETURN_IF(QSGD3D11Texture, &dd->m_d3d11TextureAccessor);
1053 QT_NATIVE_INTERFACE_RETURN_IF(QSGD3D12Texture, &dd->m_d3d12TextureAccessor);
1054#endif
1055#if QT_CONFIG(opengl)
1056 QT_NATIVE_INTERFACE_RETURN_IF(QSGOpenGLTexture, &dd->m_openglTextureAccessor);
1057#endif
1058
1059 return nullptr;
1060}
1061
1062QT_END_NAMESPACE
1063
1064#include "moc_qsgtexture.cpp"
1065

source code of qtdeclarative/src/quick/scenegraph/coreapi/qsgtexture.cpp