5#include <private/qdrawhelper_p.h>
6#include <private/qopenglcontext_p.h>
7#include <private/qrgba64_p.h>
8#include <QtCore/qmutex.h>
9#include <QtCore/qrandom.h>
11#include <private/qopenglextensions_p.h>
14#define GL_RGBA16 0x805B
23 QMutexLocker lock(&m_mutex);
24 return m_resource.value<QOpenGL2GradientCache>(context);
28 QOpenGLMultiGroupSharedResource m_resource;
46 return qt_gradient_caches()->cacheForContext(context);
51 QMutexLocker lock(&m_mutex);
62 QMutexLocker lock(&m_mutex);
63 QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin();
64 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
65 for (; it != cache.constEnd(); ++it) {
66 const CacheInfo &cache_info = it.value();
67 funcs->glDeleteTextures(1, &cache_info.texId);
76 const QGradientStops stops = gradient.stops();
77 for (
int i = 0; i < stops.size() && i <= 2; i++)
78 hash_val += stops[i].second.rgba();
80 const QMutexLocker lock(&m_mutex);
81 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
83 if (it == cache.constEnd())
84 return addCacheElement(hash_val, gradient, opacity);
87 const CacheInfo &cache_info = it.value();
88 if (cache_info.stops == stops && cache_info.opacity == opacity
89 && cache_info.interpolationMode == gradient.interpolationMode())
91 return cache_info.texId;
94 }
while (it != cache.constEnd() && it.key() == hash_val);
96 return addCacheElement(hash_val, gradient, opacity);
101GLuint
QOpenGL2GradientCache::addCacheElement(quint64 hash_val,
const QGradient &gradient, qreal opacity)
103 QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
104 if (cache.size() == maxCacheSize()) {
105 int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
106 quint64 key = cache.keys()[elem_to_remove];
109 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
111 funcs->glDeleteTextures(1, &it.value().texId);
112 }
while (++it != cache.constEnd() && it.key() == key);
116 CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
117 funcs->glGenTextures(1, &cache_entry.texId);
118 funcs->glBindTexture(GL_TEXTURE_2D, cache_entry.texId);
119 if (
static_cast<QOpenGLExtensions *>(funcs)->hasOpenGLExtension(QOpenGLExtensions::Sized16Formats)) {
121 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
122 funcs->glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA16, paletteSize(), 1,
123 0, GL_RGBA, GL_UNSIGNED_SHORT, buffer);
126 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
127 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1,
128 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
130 return cache.insert(hash_val, cache_entry).value().texId;
138 const QGradientStops s = gradient.stops();
140 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
142 uint alpha = qRound(opacity * 256);
143 QRgba64 current_color = combineAlpha256(s[0].second.rgba64(), alpha);
144 qreal incr = 1.0 / qreal(size);
145 qreal fpos = 1.5 * incr;
148 while (fpos <= s.first().first) {
149 colorTable[pos] = colorTable[pos - 1];
154 if (colorInterpolation)
157 const int sLast = s.size() - 1;
158 for (
int i = 0; i < sLast; ++i) {
159 qreal delta = 1/(s[i+1].first - s[i].first);
160 QRgba64 next_color = combineAlpha256(s[i + 1].second.rgba64(), alpha);
161 if (colorInterpolation)
164 while (fpos < s[i+1].first && pos < size) {
165 int dist =
int(256 * ((fpos - s[i].first) * delta));
166 int idist = 256 - dist;
167 if (colorInterpolation)
168 colorTable[pos] = interpolate256(current_color, idist, next_color, dist);
170 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
174 current_color = next_color;
177 Q_ASSERT(s.size() > 0);
179 QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha));
180 for (;pos < size; ++pos)
181 colorTable[pos] = last_color;
184 colorTable[size-1] = last_color;
187void QOpenGL2GradientCache::generateGradientColorTable(
const QGradient& gradient, uint *colorTable,
int size, qreal opacity)
const
190 const QGradientStops s = gradient.stops();
192 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
194 uint alpha = qRound(opacity * 256);
196 uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha);
197 qreal incr = 1.0 / qreal(size);
198 qreal fpos = 1.5 * incr;
199 colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
201 while (fpos <= s.first().first) {
202 colorTable[pos] = colorTable[pos - 1];
207 if (colorInterpolation)
208 current_color = qPremultiply(current_color);
210 const int sLast = s.size() - 1;
211 for (
int i = 0; i < sLast; ++i) {
212 qreal delta = 1/(s[i+1].first - s[i].first);
213 uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha);
214 if (colorInterpolation)
215 next_color = qPremultiply(next_color);
217 while (fpos < s[i+1].first && pos < size) {
218 int dist =
int(256 * ((fpos - s[i].first) * delta));
219 int idist = 256 - dist;
220 if (colorInterpolation)
221 colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
223 colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
227 current_color = next_color;
230 Q_ASSERT(s.size() > 0);
232 uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
233 for (;pos < size; ++pos)
234 colorTable[pos] = last_color;
237 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)