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...
constexpr QRgba64 qPremultiply(QRgba64 c)