Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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>
10#include "qopenglfunctions.h"
11#include <private/qopenglextensions_p.h>
12
13#ifndef GL_RGBA16
14#define GL_RGBA16 0x805B
15#endif
16
18
20{
21public:
26
27private:
29 QMutex m_mutex;
30};
31
33
38
43
45{
46 return qt_gradient_caches()->cacheForContext(context);
47}
48
50{
51 QMutexLocker lock(&m_mutex);
52 cache.clear();
53}
54
56{
57 cleanCache();
58}
59
60void QOpenGL2GradientCache::cleanCache()
61{
62 QMutexLocker lock(&m_mutex);
65 for (; it != cache.constEnd(); ++it) {
66 const CacheInfo &cache_info = it.value();
67 funcs->glDeleteTextures(1, &cache_info.texId);
68 }
69 cache.clear();
70}
71
73{
74 quint64 hash_val = 0;
75
76 const QGradientStops stops = gradient.stops();
77 for (int i = 0; i < stops.size() && i <= 2; i++)
78 hash_val += stops[i].second.rgba();
79
80 const QMutexLocker lock(&m_mutex);
82
83 if (it == cache.constEnd())
84 return addCacheElement(hash_val, gradient, opacity);
85 else {
86 do {
87 const CacheInfo &cache_info = it.value();
88 if (cache_info.stops == stops && cache_info.opacity == opacity
89 && cache_info.interpolationMode == gradient.interpolationMode())
90 {
91 return cache_info.texId;
92 }
93 ++it;
94 } while (it != cache.constEnd() && it.key() == hash_val);
95 // an exact match for these stops and opacity was not found, create new cache
96 return addCacheElement(hash_val, gradient, opacity);
97 }
98}
99
100
101GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity)
102{
104 if (cache.size() == maxCacheSize()) {
105 int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
106 quint64 key = cache.keys()[elem_to_remove];
107
108 // need to call glDeleteTextures on each removed cache entry:
110 do {
111 funcs->glDeleteTextures(1, &it.value().texId);
112 } while (++it != cache.constEnd() && it.key() == key);
113 cache.remove(key); // may remove more than 1, but OK
114 }
115
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)) {
120 QRgba64 buffer[1024];
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);
124 } else {
125 uint buffer[1024];
126 generateGradientColorTable(gradient, buffer, paletteSize(), opacity);
127 funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1,
129 }
130 return cache.insert(hash_val, cache_entry).value().texId;
131}
132
133
134//TODO: Let GL generate the texture using an FBO
135void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, qreal opacity) const
136{
137 int pos = 0;
138 const QGradientStops s = gradient.stops();
139
140 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
141
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;
146 colorTable[pos++] = qPremultiply(current_color);
147
148 while (fpos <= s.first().first) {
149 colorTable[pos] = colorTable[pos - 1];
150 pos++;
151 fpos += incr;
152 }
153
154 if (colorInterpolation)
155 current_color = qPremultiply(current_color);
156
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)
162 next_color = qPremultiply(next_color);
163
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);
169 else
170 colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist));
171 ++pos;
172 fpos += incr;
173 }
174 current_color = next_color;
175 }
176
177 Q_ASSERT(s.size() > 0);
178
179 QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha));
180 for (;pos < size; ++pos)
181 colorTable[pos] = last_color;
182
183 // Make sure the last color stop is represented at the end of the table
184 colorTable[size-1] = last_color;
185}
186
187void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const
188{
189 int pos = 0;
190 const QGradientStops s = gradient.stops();
191
192 bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
193
194 uint alpha = qRound(opacity * 256);
195 // Qt LIES! It returns ARGB (on little-endian AND on big-endian)
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));
200
201 while (fpos <= s.first().first) {
202 colorTable[pos] = colorTable[pos - 1];
203 pos++;
204 fpos += incr;
205 }
206
207 if (colorInterpolation)
208 current_color = qPremultiply(current_color);
209
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);
216
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));
222 else
223 colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
224 ++pos;
225 fpos += incr;
226 }
227 current_color = next_color;
228 }
229
230 Q_ASSERT(s.size() > 0);
231
232 uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
233 for (;pos < size; ++pos)
234 colorTable[pos] = last_color;
235
236 // Make sure the last color stop is represented at the end of the table
237 colorTable[size-1] = last_color;
238}
239
\inmodule QtGui
Definition qbrush.h:135
@ ColorInterpolation
Definition qbrush.h:162
InterpolationMode interpolationMode() const
Definition qbrush.cpp:1706
QGradientStops stops() const
Returns the stop points for this gradient.
Definition qbrush.cpp:1631
qsizetype size() const noexcept
Definition qlist.h:397
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1921
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1925
qsizetype remove(const Key &key)
Definition qhash.h:1596
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:2034
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition qhash.h:1749
qsizetype size() const noexcept
Definition qhash.h:1567
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Definition qhash.h:1588
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:2025
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
QOpenGL2GradientCache * cacheForContext(QOpenGLContext *context)
static QOpenGL2GradientCache * cacheForContext(QOpenGLContext *context)
GLuint getBuffer(const QGradient &gradient, qreal opacity)
void freeResource(QOpenGLContext *ctx) override
\inmodule QtGui
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
The QOpenGLMultiGroupSharedResource keeps track of a shared resource that might be needed from multip...
QOpenGLSharedResource * value(QOpenGLContext *context)
The QOpenGLSharedResource class is used to keep track of resources that are shared between OpenGL con...
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
Definition qrandom.h:275
EGLContext ctx
static VulkanServerBufferGlFunctions * funcs
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static void * context
#define ARGB_COMBINE_ALPHA(argb, alpha)
static uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b)
static QRgba64 interpolate256(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2)
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint buffer
GLint first
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
#define GL_RGBA16
static quint32 ARGB2RGBA(quint32 x)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
constexpr QRgb qPremultiply(QRgb x)
Definition qrgb.h:45
QT_BEGIN_NAMESPACE QRgba64 combineAlpha256(QRgba64 rgba64, uint alpha256)
Definition qrgba64_p.h:26
#define GLuint
#define GL_UNSIGNED_BYTE
#define GL_RGBA
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
std::uniform_real_distribution dist(1, 2.5)
[2]
QReadWriteLock lock
[0]