Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsgtexture.cpp
Go to the documentation of this file.
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"
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
37
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
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
62{
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
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
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
119{
120 qDebug("Number of leaked textures: %i", qt_debug_texture_count);
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(item->backTrace, item->backTraceSize);
136
137 if (symbols) {
138 for (int i=0; i<(int) item->backTraceSize; i++)
139 qDebug("Backtrace <%02d>: %s", i, symbols[i]);
140 free(symbols);
141 }
142
143 qDebug() << "------";
144
145 delete item;
146 }
147 }
148#endif
149}
150
152{
153#if defined(CAN_BACKTRACE_EXECINFO)
154 if (qmlDebugLeakBacktrace()) {
155 SGTextureTraceItem* item = new SGTextureTraceItem;
156 item->backTraceSize = backtrace(item->backTrace, BACKTRACE_SIZE);
157 qt_debug_allocated_textures.insert(texture, item);
158 }
159#else
161#endif // Q_OS_LINUX
162
164
165 static bool atexit_registered = false;
166 if (!atexit_registered) {
168 atexit_registered = true;
169 }
170}
171
173{
174#if defined(CAN_BACKTRACE_EXECINFO)
175 if (qmlDebugLeakBacktrace()) {
176 SGTextureTraceItem* item = qt_debug_allocated_textures.value(texture, 0);
177 if (item) {
178 qt_debug_allocated_textures.remove(texture);
179 delete item;
180 }
181 }
182#else
184#endif
185
187
189 qDebug("Texture destroyed after qt_debug_print_texture_count() was called.");
190}
191
192#endif // QT_NO_DEBUG
193
304{
305#ifndef QT_NO_DEBUG
308
309 QMutexLocker locker(qsg_valid_texture_mutex());
310 qsg_valid_texture_set()->insert(this);
311#endif
312}
313
318 : QObject(dd)
319{
320#ifndef QT_NO_DEBUG
323
324 QMutexLocker locker(qsg_valid_texture_mutex());
325 qsg_valid_texture_set()->insert(this);
326#endif
327}
328
333{
334#ifndef QT_NO_DEBUG
337
338 QMutexLocker locker(qsg_valid_texture_mutex());
339 qsg_valid_texture_set()->remove(this);
340#endif
341}
342
378{
379 Q_UNUSED(resourceUpdates);
380 Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()", "Called on a non-atlas texture");
381 return nullptr;
382}
383
390{
391 return false;
392}
393
433{
434 return QRectF(0, 0, 1, 1);
435}
436
458{
459 Q_D(QSGTexture);
460 if (d->mipmapMode != (uint) filter) {
461 d->mipmapMode = filter;
462 d->filteringChanged = true;
463 }
464}
465
470{
471 return (QSGTexture::Filtering) d_func()->mipmapMode;
472}
473
474
479{
480 Q_D(QSGTexture);
481 if (d->filterMode != (uint) filter) {
482 d->filterMode = filter;
483 d->filteringChanged = true;
484 }
485}
486
491{
492 return (QSGTexture::Filtering) d_func()->filterMode;
493}
494
506{
507 Q_D(QSGTexture);
508 if (d->anisotropyLevel != (uint) level) {
509 d->anisotropyLevel = level;
510 d->anisotropyChanged = true;
511 }
512}
513
520{
521 return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel;
522}
523
524
525
531{
532 Q_D(QSGTexture);
533 if ((uint) hwrap != d->horizontalWrap) {
534 d->horizontalWrap = hwrap;
535 d->wrapChanged = true;
536 }
537}
538
543{
544 return (QSGTexture::WrapMode) d_func()->horizontalWrap;
545}
546
547
548
553{
554 Q_D(QSGTexture);
555 if ((uint) vwrap != d->verticalWrap) {
556 d->verticalWrap = vwrap;
557 d->wrapChanged = true;
558 }
559}
560
565{
566 return (QSGTexture::WrapMode) d_func()->verticalWrap;
567}
568
584{
585 return nullptr;
586}
587
604{
605 Q_UNUSED(rhi);
606 Q_UNUSED(resourceUpdates);
607}
608
610{
612}
613
615{
617}
618
650 : QSGTexture(dd)
651{
652}
653
658 = default;
659
677#if QT_CONFIG(opengl) || defined(Q_QDOC)
678namespace QNativeInterface {
694QT_DEFINE_NATIVE_INTERFACE(QSGOpenGLTexture);
695
722QSGTexture *QSGOpenGLTexture::fromNative(GLuint textureId,
724 const QSize &size,
725 QQuickWindow::CreateTextureOptions options)
726{
728}
729
757QSGTexture *QSGOpenGLTexture::fromNativeExternalOES(GLuint textureId,
759 const QSize &size,
760 QQuickWindow::CreateTextureOptions options)
761{
763 0,
764 size,
765 options,
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 {
795QT_DEFINE_NATIVE_INTERFACE(QSGD3D11Texture);
796
822QSGTexture *QSGD3D11Texture::fromNative(void *texture,
824 const QSize &size,
825 QQuickWindow::CreateTextureOptions options)
826{
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 {
854QT_DEFINE_NATIVE_INTERFACE(QSGD3D12Texture);
855
885QSGTexture *QSGD3D12Texture::fromNative(void *texture,
886 int resourceState,
888 const QSize &size,
889 QQuickWindow::CreateTextureOptions options)
890{
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 {
956} // QNativeInterface
957#endif // OBJC
958
959#if QT_CONFIG(vulkan) || defined(Q_QDOC)
960namespace QNativeInterface {
981QT_DEFINE_NATIVE_INTERFACE(QSGVulkanTexture);
982
1010QSGTexture *QSGVulkanTexture::fromNative(VkImage image,
1011 VkImageLayout layout,
1013 const QSize &size,
1014 QQuickWindow::CreateTextureOptions options)
1015{
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
1063
1064#include "moc_qsgtexture.cpp"
\inmodule QtCore
Definition qhash.h:1093
\inmodule QtCore
Definition qhash.h:818
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
iterator erase(const_iterator it)
Definition qhash.h:1223
T value(const Key &key) const noexcept
Definition qhash.h:1044
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
\inmodule QtCore
Definition qobject.h:90
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGTexture * createTextureFromNativeTexture(quint64 nativeObjectHandle, int nativeLayoutOrState, uint nativeFormat, const QSize &size, QQuickWindow::CreateTextureOptions options, TextureFromNativeTextureFlags flags={}) const
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:483
\inmodule QtGui
Definition qrhi.h:1694
\inmodule QtGui
Definition qrhi.h:883
\inmodule QtGui
Definition qrhi.h:1767
~QSGDynamicTexture() override
QSGDynamicTexture()=default
void resetDirtySamplerOptions()
bool hasDirtySamplerOptions() const
QSGTexturePrivate(QSGTexture *t)
\inmodule QtQuick
Definition qsgtexture.h:20
virtual void commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates)
Call this function to enqueue image upload operations to resourceUpdates, in case there are any pendi...
void setAnisotropyLevel(AnisotropyLevel level)
Sets the level of anisotropic filtering to level.
QSGTexture::Filtering mipmapFiltering() const
Returns whether mipmapping should be used when sampling from this texture.
virtual QRectF normalizedTextureSubRect() const
Returns the rectangle inside textureSize() that this texture represents in normalized coordinates.
void setHorizontalWrapMode(WrapMode hwrap)
Sets the horizontal wrap mode to hwrap.
virtual QSGTexture * removedFromAtlas(QRhiResourceUpdateBatch *resourceUpdates=nullptr) const
This function returns a copy of the current texture which is removed from its atlas.
void setFiltering(Filtering filter)
Sets the sampling mode to filter.
QSGTexture::WrapMode verticalWrapMode() const
Returns the vertical wrap mode to be used for this texture.
QSGTexture::Filtering filtering() const
Returns the sampling mode to be used for this texture.
QSGTexture::AnisotropyLevel anisotropyLevel() const
Returns the anisotropy level in use for filtering this texture.
void setMipmapFiltering(Filtering filter)
Sets the mipmap sampling mode to filter.
Filtering
Specifies how sampling of texels should filter when texture coordinates are not pixel aligned.
Definition qsgtexture.h:34
WrapMode
Specifies how the sampler should treat texture coordinates.
Definition qsgtexture.h:28
~QSGTexture() override
Destroys the QSGTexture.
QSGTexture()
Constructs the QSGTexture base class.
virtual bool isAtlasTexture() const
Returns whether this texture is part of an atlas or not.
AnisotropyLevel
Specifies the anisotropic filtering level to be used when the texture is not screen aligned.
Definition qsgtexture.h:40
QSGTexture::WrapMode horizontalWrapMode() const
Returns the horizontal wrap mode to be used for this texture.
virtual QRhiTexture * rhiTexture() const
void setVerticalWrapMode(WrapMode vwrap)
Sets the vertical wrap mode to vwrap.
Definition qset.h:18
\inmodule QtCore
Definition qsize.h:25
#define this
Definition dialogs.cpp:9
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Definition image.cpp:4
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qDebug
[1]
Definition qlogging.h:160
#define QT_NATIVE_INTERFACE_RETURN_IF(NativeInterface, baseType)
#define QT_DEFINE_NATIVE_INTERFACE(...)
GLboolean GLboolean GLboolean b
const GLfloat * m
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLfloat GLfloat f
GLenum GLuint texture
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint name
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble s
[6]
Definition qopenglext.h:235
#define DEFINE_BOOL_CONFIG_OPTION(name, var)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define GLuint
bool _q_sg_leak_check
QT_BEGIN_NAMESPACE bool operator==(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept
size_t qHash(const QSGSamplerDescription &s, size_t seed) noexcept
static void qt_debug_print_texture_count()
static void qt_debug_remove_texture(QSGTexture *texture)
static int qt_debug_texture_count
bool operator!=(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept
static void qt_debug_add_texture(QSGTexture *texture)
#define QT_CONFIG(feature)
#define Q_UNUSED(x)
size_t quintptr
Definition qtypes.h:72
unsigned long long quint64
Definition qtypes.h:56
unsigned int uint
Definition qtypes.h:29
if(qFloatDistance(a, b)<(1<< 7))
[0]
QVBoxLayout * layout
QGraphicsItem * item
aWidget window() -> setWindowTitle("New Window Title")
[2]
static QSGSamplerDescription fromTexture(QSGTexture *t)