Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qopengltexturecache.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <private/qopengltextureuploader_p.h>
7#include <qmath.h>
8#include <qopenglfunctions.h>
9#include <private/qimagepixmapcleanuphooks_p.h>
10#include <qpa/qplatformpixmap.h>
11
12#include <qtopengl_tracepoints_p.h>
13
15
17{
18public:
20 {
21 QImagePixmapCleanupHooks::instance()->addPlatformPixmapModificationHook(cleanupTexturesForPixmapData);
22 QImagePixmapCleanupHooks::instance()->addPlatformPixmapDestructionHook(cleanupTexturesForPixmapData);
23 QImagePixmapCleanupHooks::instance()->addImageHook(cleanupTexturesForCacheKey);
24 }
25
27 {
28 QImagePixmapCleanupHooks::instance()->removePlatformPixmapModificationHook(cleanupTexturesForPixmapData);
29 QImagePixmapCleanupHooks::instance()->removePlatformPixmapDestructionHook(cleanupTexturesForPixmapData);
30 QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey);
31 }
32
33 QOpenGLTextureCache *cacheForContext(QOpenGLContext *context) {
34 QMutexLocker lock(&m_mutex);
35 return m_resource.value<QOpenGLTextureCache>(context);
36 }
37
38 static void cleanupTexturesForCacheKey(qint64 key);
39 static void cleanupTexturesForPixmapData(QPlatformPixmap *pmd);
40
41private:
42 QOpenGLMultiGroupSharedResource m_resource;
43 QMutex m_mutex;
44};
45
46Q_GLOBAL_STATIC(QOpenGLTextureCacheWrapper, qt_texture_caches)
47
48QOpenGLTextureCache *QOpenGLTextureCache::cacheForContext(QOpenGLContext *context)
49{
50 return qt_texture_caches()->cacheForContext(context);
51}
52
53void QOpenGLTextureCacheWrapper::cleanupTexturesForCacheKey(qint64 key)
54{
55 QList<QOpenGLSharedResource *> resources = qt_texture_caches()->m_resource.resources();
56 for (QList<QOpenGLSharedResource *>::iterator it = resources.begin(); it != resources.end(); ++it)
57 static_cast<QOpenGLTextureCache *>(*it)->invalidate(key);
58}
59
60void QOpenGLTextureCacheWrapper::cleanupTexturesForPixmapData(QPlatformPixmap *pmd)
61{
62 cleanupTexturesForCacheKey(pmd->cacheKey());
63}
64
65static quint64 cacheSize()
66{
67 bool ok = false;
68 const int envCacheSize = qEnvironmentVariableIntValue("QT_OPENGL_TEXTURE_CACHE_SIZE", &ok);
69 if (ok)
70 return envCacheSize;
71
72 return 1024 * 1024; // 1024 MB cache default
73}
74
75QOpenGLTextureCache::QOpenGLTextureCache(QOpenGLContext *ctx)
76 : QOpenGLSharedResource(ctx->shareGroup())
77 , m_cache(cacheSize())
78{
79}
80
81QOpenGLTextureCache::~QOpenGLTextureCache()
82{
83}
84
85QOpenGLTextureCache::BindResult QOpenGLTextureCache::bindTexture(QOpenGLContext *context,
86 const QPixmap &pixmap,
87 QOpenGLTextureUploader::BindOptions options)
88{
89 if (pixmap.isNull())
90 return { 0, {} };
91 QMutexLocker locker(&m_mutex);
92 qint64 key = pixmap.cacheKey();
93
94 // A QPainter is active on the image - take the safe route and replace the texture.
95 if (!pixmap.paintingActive()) {
96 QOpenGLCachedTexture *entry = m_cache.object(key);
97 if (entry && entry->options() == options) {
98 context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id());
99 return { entry->id(), {} };
100 }
101 }
102
103 BindResult result = bindTexture(context, key, pixmap.toImage(), options);
104 if (result.id > 0)
105 QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
106
107 return result;
108}
109
110QOpenGLTextureCache::BindResult QOpenGLTextureCache::bindTexture(QOpenGLContext *context,
111 const QImage &image,
112 QOpenGLTextureUploader::BindOptions options)
113{
114 if (image.isNull())
115 return { 0, {} };
116 QMutexLocker locker(&m_mutex);
117 qint64 key = image.cacheKey();
118
119 // A QPainter is active on the image - take the safe route and replace the texture.
120 if (!image.paintingActive()) {
121 QOpenGLCachedTexture *entry = m_cache.object(key);
122 if (entry && entry->options() == options) {
123 context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id());
124 return { entry->id(), {} };
125 }
126 }
127
128 QImage img = image;
129 if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures))
130 options |= QOpenGLTextureUploader::PowerOfTwoBindOption;
131
132 BindResult result = bindTexture(context, key, img, options);
133 if (result.id > 0)
134 QImagePixmapCleanupHooks::enableCleanupHooks(image);
135
136 return result;
137}
138
139Q_TRACE_POINT(qtopengl, QOpenGLTextureCache_bindTexture_entry, QOpenGLContext *context, qint64 key, const unsigned char *image, int options);
141
142QOpenGLTextureCache::BindResult QOpenGLTextureCache::bindTexture(QOpenGLContext *context,
143 qint64 key,
144 const QImage &image,
145 QOpenGLTextureUploader::BindOptions options)
146{
147 Q_TRACE_SCOPE(QOpenGLTextureCache_bindTexture, context, key, image.bits(), options);
148
149 GLuint id;
150 QOpenGLFunctions *funcs = context->functions();
151 funcs->glGenTextures(1, &id);
152 funcs->glBindTexture(GL_TEXTURE_2D, id);
153
154 int cost = QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, image, options);
155
156 m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost / 1024);
157
158 return { id, BindResultFlag::NewTexture };
159}
160
161void QOpenGLTextureCache::invalidate(qint64 key)
162{
163 QMutexLocker locker(&m_mutex);
164 m_cache.remove(key);
165}
166
167void QOpenGLTextureCache::invalidateResource()
168{
169 m_cache.clear();
170}
171
172void QOpenGLTextureCache::freeResource(QOpenGLContext *)
173{
174 Q_ASSERT(false); // the texture cache lives until the context group disappears
175}
176
177static void freeTexture(QOpenGLFunctions *funcs, GLuint id)
178{
179 funcs->glDeleteTextures(1, &id);
180}
181
182QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context) : m_options(options)
183{
184 m_resource = new QOpenGLSharedResourceGuard(context, id, freeTexture);
185}
186
187QT_END_NAMESPACE
static void cleanupTexturesForPixmapData(QPlatformPixmap *pmd)
QOpenGLTextureCache * cacheForContext(QOpenGLContext *context)
static void cleanupTexturesForCacheKey(qint64 key)
Combined button and popup list for selecting options.
Q_TRACE_POINT(qtcore, QCoreApplication_postEvent_exit)
static void freeTexture(QOpenGLFunctions *funcs, GLuint id)