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
qopenglgradientcache.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/qdrawhelper_p.h>
7#include <private/qopenglcontext_p.h>
8#include <private/qrgba64_p.h>
9#include <QtCore/qmutex.h>
10#include <QtCore/qrandom.h>
12#include <private/qopenglextensions_p.h>
13
14#ifndef GL_RGBA16
15#define GL_RGBA16 0x805B
16#endif
17
19
21{
22public:
23 QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context) {
24 QMutexLocker lock(&m_mutex);
25 return m_resource.value<QOpenGL2GradientCache>(context);
26 }
27
28private:
29 QOpenGLMultiGroupSharedResource m_resource;
30 QMutex m_mutex;
31};
32
33Q_GLOBAL_STATIC(QOpenGL2GradientCacheWrapper, qt_gradient_caches)
34
39
41{
42 cache.clear();
43}
44
45QOpenGL2GradientCache *QOpenGL2GradientCache::cacheForContext(QOpenGLContext *context)
46{
47 return qt_gradient_caches()->cacheForContext(context);
48}
49
51{
52 QMutexLocker lock(&m_mutex);
53 cache.clear();
54}
55
56void QOpenGL2GradientCache::freeResource(QOpenGLContext *)
57{
58 cleanCache();
59}
60
61void QOpenGL2GradientCache::cleanCache()
62{
63 QMutexLocker lock(&m_mutex);
64 QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin();
65 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
66 for (; it != cache.constEnd(); ++it) {
67 const CacheInfo &cache_info = it.value();
68 funcs->glDeleteTextures(1, &cache_info.texId);
69 }
70 cache.clear();
71}
72
73GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
74{
75 quint64 hash_val = 0;
76
77 const QGradientStops stops = gradient.stops();
78 for (int i = 0; i < stops.size() && i <= 2; i++)
79 hash_val += stops[i].second.rgba();
80
81 const QMutexLocker lock(&m_mutex);
82 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
83
84 if (it == cache.constEnd())
85 return addCacheElement(hash_val, gradient, opacity);
86 else {
87 do {
88 const CacheInfo &cache_info = it.value();
89 if (cache_info.stops == stops && cache_info.opacity == opacity
90 && cache_info.interpolationMode == gradient.interpolationMode())
91 {
92 return cache_info.texId;
93 }
94 ++it;
95 } while (it != cache.constEnd() && it.key() == hash_val);
96 // an exact match for these stops and opacity was not found, create new cache
97 return addCacheElement(hash_val, gradient, opacity);
98 }
99}
100
101
102GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
103{
104 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
105 if (cache.size() == maxCacheSize()) {
106 int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
107 const QList<quint64> keys = cache.keys();
108 quint64 key = keys[elem_to_remove];
109
110 // need to call glDeleteTextures on each removed cache entry:
111 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
112 do {
113 funcs->glDeleteTextures(1, &it.value().texId);
114 } while (++it != cache.constEnd() && it.key() == key);
115 cache.remove(key); // may remove more than 1, but OK
116 }
117
118 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
119 funcs->glGenTextures(1, &cache_entry.texId);
120 funcs->glBindTexture(GL_TEXTURE_2D, cache_entry.texId);
121 if (static_cast<QOpenGLExtensions *>(funcs)->hasOpenGLExtension(QOpenGLExtensions::Sized16Formats)) {
122 QRgba64 buffer[1024];
123 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
124 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, paletteSize(), 1,
125 0, GL_RGBA, GL_UNSIGNED_SHORT, buffer);
126 } else {
127 uint buffer[1024];
128 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
129 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1,
130 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
131 }
132 return cache.insert(hash_val, cache_entry).value().texId;
133}
134
135
136//TODO: Let GL generate the texture using an FBO
137void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, qreal opacity) const
138{
139 int pos = 0;
140 const QGradientStops s = gradient.stops();
141
142 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
143
144 uint alpha = qRound(opacity * 256);
145 QRgba64 current_color = combineAlpha256(s[0].second.rgba64(), alpha);
146 qreal incr = 1.0 / qreal(size);
147 qreal fpos = 1.5 * incr;
148 colorTable[pos++] = qPremultiply(current_color);
149
150 while (fpos <= s.first().first) {
151 colorTable[pos] = colorTable[pos - 1];
152 pos++;
153 fpos += incr;
154 }
155
156 if (colorInterpolation)
157 current_color = qPremultiply(current_color);
158
159 const int sLast = s.size() - 1;
160 for (int i = 0; i < sLast; ++i) {
161 qreal delta = 1/(s[i+1].first - s[i].first);
162 QRgba64 next_color = combineAlpha256(s[i + 1].second.rgba64(), alpha);
163 if (colorInterpolation)
164 next_color = qPremultiply(next_color);
165
166 while (fpos < s[i+1].first && pos < size) {
167 int dist = int(256 * ((fpos - s[i].first) * delta));
168 int idist = 256 - dist;
169 if (colorInterpolation)
170 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
171 else
172 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
173 ++pos;
174 fpos += incr;
175 }
176 current_color = next_color;
177 }
178
179 Q_ASSERT(s.size() > 0);
180
181 QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha));
182 for (;pos < size; ++pos)
183 colorTable[pos] = last_color;
184
185 // Make sure the last color stop is represented at the end of the table
186 colorTable[size-1] = last_color;
187}
188
189void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
190{
191 int pos = 0;
192 const QGradientStops s = gradient.stops();
193
194 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
195
196 uint alpha = qRound(opacity * 256);
197 // Qt LIES! It returns ARGB (on little-endian AND on big-endian)
198 uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha);
199 qreal incr = 1.0 / qreal(size);
200 qreal fpos = 1.5 * incr;
201 colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
202
203 while (fpos <= s.first().first) {
204 colorTable[pos] = colorTable[pos - 1];
205 pos++;
206 fpos += incr;
207 }
208
209 if (colorInterpolation)
210 current_color = qPremultiply(current_color);
211
212 const int sLast = s.size() - 1;
213 for (int i = 0; i < sLast; ++i) {
214 qreal delta = 1/(s[i+1].first - s[i].first);
215 uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha);
216 if (colorInterpolation)
217 next_color = qPremultiply(next_color);
218
219 while (fpos < s[i+1].first && pos < size) {
220 int dist = int(256 * ((fpos - s[i].first) * delta));
221 int idist = 256 - dist;
222 if (colorInterpolation)
223 colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
224 else
225 colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
226 ++pos;
227 fpos += incr;
228 }
229 current_color = next_color;
230 }
231
232 Q_ASSERT(s.size() > 0);
233
234 uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
235 for (;pos < size; ++pos)
236 colorTable[pos] = last_color;
237
238 // Make sure the last color stop is represented at the end of the table
239 colorTable[size-1] = last_color;
240}
241
242QT_END_NAMESPACE
QOpenGL2GradientCache * cacheForContext(QOpenGLContext *context)
GLuint getBuffer(const QGradient &gradient, qreal opacity)
\inmodule QtGui
The QOpenGLSharedResource class is used to keep track of resources that are shared between OpenGL con...
Combined button and popup list for selecting options.
#define GL_RGBA16
constexpr QRgba64 qPremultiply(QRgba64 c)
Definition qrgba64.h:196