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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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