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>
15#define GL_RGBA16 0x805B
24 QMutexLocker lock(&m_mutex);
25 return m_resource.value<QOpenGL2GradientCache>(context);
29 QOpenGLMultiGroupSharedResource m_resource;
47 return qt_gradient_caches()->cacheForContext(context);
52 QMutexLocker lock(&m_mutex);
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);
77 const QGradientStops stops = gradient.stops();
78 for (
int i = 0; i < stops.size() && i <= 2; i++)
79 hash_val += stops[i].second.rgba();
81 const QMutexLocker lock(&m_mutex);
82 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
84 if (it == cache.constEnd())
85 return addCacheElement(hash_val, gradient, opacity);
88 const CacheInfo &cache_info = it.value();
89 if (cache_info.stops == stops && cache_info.opacity == opacity
90 && cache_info.interpolationMode == gradient.interpolationMode())
92 return cache_info.texId;
95 }
while (it != cache.constEnd() && it.key() == hash_val);
97 return addCacheElement(hash_val, gradient, opacity);
102GLuint
QOpenGL2GradientCache::addCacheElement(quint64 hash_val,
const QGradient &gradient, qreal opacity)
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];
111 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
113 funcs->glDeleteTextures(1, &it.value().texId);
114 }
while (++it != cache.constEnd() && it.key() == key);
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)) {
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);
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);
132 return cache.insert(hash_val, cache_entry).value().texId;
140 const QGradientStops s = gradient.stops();
142 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
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;
150 while (fpos <= s.first().first) {
151 colorTable[pos] = colorTable[pos - 1];
156 if (colorInterpolation)
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)
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);
172 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
176 current_color = next_color;
179 Q_ASSERT(s.size() > 0);
181 QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha));
182 for (;pos < size; ++pos)
183 colorTable[pos] = last_color;
186 colorTable[size-1] = last_color;
189void QOpenGL2GradientCache::generateGradientColorTable(
const QGradient& gradient, uint *colorTable,
int size, qreal opacity)
const
192 const QGradientStops s = gradient.stops();
194 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
196 uint alpha = qRound(opacity * 256);
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));
203 while (fpos <= s.first().first) {
204 colorTable[pos] = colorTable[pos - 1];
209 if (colorInterpolation)
210 current_color = qPremultiply(current_color);
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);
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));
225 colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
229 current_color = next_color;
232 Q_ASSERT(s.size() > 0);
234 uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
235 for (;pos < size; ++pos)
236 colorTable[pos] = last_color;
239 colorTable[size-1] = last_color;
QOpenGL2GradientCache * cacheForContext(QOpenGLContext *context)
GLuint getBuffer(const QGradient &gradient, qreal opacity)
void invalidateResource() override
The QOpenGLSharedResource class is used to keep track of resources that are shared between OpenGL con...
Combined button and popup list for selecting options.
constexpr QRgba64 qPremultiply(QRgba64 c)