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 quint64 key = cache.keys()[elem_to_remove];
110 QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key);
112 funcs->glDeleteTextures(1, &it.value().texId);
113 }
while (++it != cache.constEnd() && it.key() == key);
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)) {
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);
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);
131 return cache.insert(hash_val, cache_entry).value().texId;
139 const QGradientStops s = gradient.stops();
141 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
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;
149 while (fpos <= s.first().first) {
150 colorTable[pos] = colorTable[pos - 1];
155 if (colorInterpolation)
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)
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);
171 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
175 current_color = next_color;
178 Q_ASSERT(s.size() > 0);
180 QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha));
181 for (;pos < size; ++pos)
182 colorTable[pos] = last_color;
185 colorTable[size-1] = last_color;
188void QOpenGL2GradientCache::generateGradientColorTable(
const QGradient& gradient, uint *colorTable,
int size, qreal opacity)
const
191 const QGradientStops s = gradient.stops();
193 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
195 uint alpha = qRound(opacity * 256);
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));
202 while (fpos <= s.first().first) {
203 colorTable[pos] = colorTable[pos - 1];
208 if (colorInterpolation)
209 current_color = qPremultiply(current_color);
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);
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));
224 colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
228 current_color = next_color;
231 Q_ASSERT(s.size() > 0);
233 uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
234 for (;pos < size; ++pos)
235 colorTable[pos] = last_color;
238 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)