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 quint64 key = cache.keys()[elem_to_remove];
108
109 // need to call glDeleteTextures on each removed cache entry:
110 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
111 do {
112 funcs->glDeleteTextures(1, &it.value().texId);
113 } while (++it != cache.constEnd() && it.key() == key);
114 cache.remove(key); // may remove more than 1, but OK
115 }
116
117 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
118 funcs->glGenTextures(1, &cache_entry.texId);
119 funcs->glBindTexture(GL_TEXTURE_2D, cache_entry.texId);
120 if (static_cast<QOpenGLExtensions *>(funcs)->hasOpenGLExtension(QOpenGLExtensions::Sized16Formats)) {
121 QRgba64 buffer[1024];
122 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
123 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, paletteSize(), 1,
124 0, GL_RGBA, GL_UNSIGNED_SHORT, buffer);
125 } else {
126 uint buffer[1024];
127 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
128 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1,
129 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
130 }
131 return cache.insert(hash_val, cache_entry).value().texId;
132}
133
134
135//TODO: Let GL generate the texture using an FBO
136void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, qreal opacity) const
137{
138 int pos = 0;
139 const QGradientStops s = gradient.stops();
140
141 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
142
143 uint alpha = qRound(opacity * 256);
144 QRgba64 current_color = combineAlpha256(s[0].second.rgba64(), alpha);
145 qreal incr = 1.0 / qreal(size);
146 qreal fpos = 1.5 * incr;
147 colorTable[pos++] = qPremultiply(current_color);
148
149 while (fpos <= s.first().first) {
150 colorTable[pos] = colorTable[pos - 1];
151 pos++;
152 fpos += incr;
153 }
154
155 if (colorInterpolation)
156 current_color = qPremultiply(current_color);
157
158 const int sLast = s.size() - 1;
159 for (int i = 0; i < sLast; ++i) {
160 qreal delta = 1/(s[i+1].first - s[i].first);
161 QRgba64 next_color = combineAlpha256(s[i + 1].second.rgba64(), alpha);
162 if (colorInterpolation)
163 next_color = qPremultiply(next_color);
164
165 while (fpos < s[i+1].first && pos < size) {
166 int dist = int(256 * ((fpos - s[i].first) * delta));
167 int idist = 256 - dist;
168 if (colorInterpolation)
169 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
170 else
171 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
172 ++pos;
173 fpos += incr;
174 }
175 current_color = next_color;
176 }
177
178 Q_ASSERT(s.size() > 0);
179
180 QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha));
181 for (;pos < size; ++pos)
182 colorTable[pos] = last_color;
183
184 // Make sure the last color stop is represented at the end of the table
185 colorTable[size-1] = last_color;
186}
187
188void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
189{
190 int pos = 0;
191 const QGradientStops s = gradient.stops();
192
193 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
194
195 uint alpha = qRound(opacity * 256);
196 // Qt LIES! It returns ARGB (on little-endian AND on big-endian)
197 uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha);
198 qreal incr = 1.0 / qreal(size);
199 qreal fpos = 1.5 * incr;
200 colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
201
202 while (fpos <= s.first().first) {
203 colorTable[pos] = colorTable[pos - 1];
204 pos++;
205 fpos += incr;
206 }
207
208 if (colorInterpolation)
209 current_color = qPremultiply(current_color);
210
211 const int sLast = s.size() - 1;
212 for (int i = 0; i < sLast; ++i) {
213 qreal delta = 1/(s[i+1].first - s[i].first);
214 uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha);
215 if (colorInterpolation)
216 next_color = qPremultiply(next_color);
217
218 while (fpos < s[i+1].first && pos < size) {
219 int dist = int(256 * ((fpos - s[i].first) * delta));
220 int idist = 256 - dist;
221 if (colorInterpolation)
222 colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
223 else
224 colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
225 ++pos;
226 fpos += incr;
227 }
228 current_color = next_color;
229 }
230
231 Q_ASSERT(s.size() > 0);
232
233 uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
234 for (;pos < size; ++pos)
235 colorTable[pos] = last_color;
236
237 // Make sure the last color stop is represented at the end of the table
238 colorTable[size-1] = last_color;
239}
240
241QT_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:191