QtGui: Avoid rgba64->rgba32 conversion on every pixel in gradient
Convert rgba64 color table to a new rgb32 color table only once. Use this cache when required. This patch can 2x speed up gradient painting using 32bit color format. Task-number: QTBUG-50930 Change-Id: I9212e01e397c2e0127cdf3070cc49880a2d8df88 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com>
This commit is contained in:
parent
2ee7541616
commit
8dc55367ca
@ -3433,13 +3433,13 @@ static SourceFetchProc64 sourceFetch64[NBlendTypes][QImage::NImageFormats] = {
|
|||||||
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
|
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
|
||||||
{
|
{
|
||||||
int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
|
int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
|
||||||
return data->colorTable[qt_gradient_clamp(data, ipos)].toArgb32();
|
return data->colorTable32[qt_gradient_clamp(data, ipos)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int fixed_pos)
|
static const QRgba64& qt_gradient_pixel64_fixed(const QGradientData *data, int fixed_pos)
|
||||||
{
|
{
|
||||||
int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
|
int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
|
||||||
return data->colorTable[qt_gradient_clamp(data, ipos)];
|
return data->colorTable64[qt_gradient_clamp(data, ipos)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
|
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
|
||||||
|
@ -268,7 +268,8 @@ struct QGradientData
|
|||||||
#define GRADIENT_STOPTABLE_SIZE 1024
|
#define GRADIENT_STOPTABLE_SIZE 1024
|
||||||
#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
|
#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
|
||||||
|
|
||||||
QRgba64* colorTable; //[GRADIENT_STOPTABLE_SIZE];
|
const QRgba64 *colorTable64; //[GRADIENT_STOPTABLE_SIZE];
|
||||||
|
const QRgb *colorTable32; //[GRADIENT_STOPTABLE_SIZE];
|
||||||
|
|
||||||
uint alphaColor : 1;
|
uint alphaColor : 1;
|
||||||
};
|
};
|
||||||
@ -376,13 +377,13 @@ static inline uint qt_gradient_clamp(const QGradientData *data, int ipos)
|
|||||||
static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
|
static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
|
||||||
{
|
{
|
||||||
int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
|
int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
|
||||||
return data->colorTable[qt_gradient_clamp(data, ipos)].toArgb32();
|
return data->colorTable32[qt_gradient_clamp(data, ipos)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const QRgba64& qt_gradient_pixel64(const QGradientData *data, qreal pos)
|
static inline const QRgba64& qt_gradient_pixel64(const QGradientData *data, qreal pos)
|
||||||
{
|
{
|
||||||
int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
|
int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
|
||||||
return data->colorTable[qt_gradient_clamp(data, ipos)];
|
return data->colorTable64[qt_gradient_clamp(data, ipos)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c)
|
static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c)
|
||||||
@ -550,7 +551,7 @@ public:
|
|||||||
delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \
|
delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \
|
||||||
b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \
|
b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \
|
||||||
for (int i = 0; i < 4; ++i) \
|
for (int i = 0; i < 4; ++i) \
|
||||||
*buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]].toArgb32(); \
|
*buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable32[index_vec.i[i]]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \
|
#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \
|
||||||
|
@ -4138,7 +4138,8 @@ class QGradientCache
|
|||||||
{
|
{
|
||||||
inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
|
inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
|
||||||
stops(qMove(s)), opacity(op), interpolationMode(mode) {}
|
stops(qMove(s)), opacity(op), interpolationMode(mode) {}
|
||||||
QRgba64 buffer[GRADIENT_STOPTABLE_SIZE];
|
QRgba64 buffer64[GRADIENT_STOPTABLE_SIZE];
|
||||||
|
QRgb buffer32[GRADIENT_STOPTABLE_SIZE];
|
||||||
QGradientStops stops;
|
QGradientStops stops;
|
||||||
int opacity;
|
int opacity;
|
||||||
QGradient::InterpolationMode interpolationMode;
|
QGradient::InterpolationMode interpolationMode;
|
||||||
@ -4147,7 +4148,9 @@ class QGradientCache
|
|||||||
typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
|
typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline const QRgba64 *getBuffer(const QGradient &gradient, int opacity) {
|
typedef QPair<const QRgb *, const QRgba64 *> ColorBufferPair;
|
||||||
|
|
||||||
|
inline ColorBufferPair getBuffer(const QGradient &gradient, int opacity) {
|
||||||
quint64 hash_val = 0;
|
quint64 hash_val = 0;
|
||||||
|
|
||||||
const QGradientStops stops = gradient.stops();
|
const QGradientStops stops = gradient.stops();
|
||||||
@ -4163,7 +4166,8 @@ public:
|
|||||||
do {
|
do {
|
||||||
const CacheInfo &cache_info = it.value();
|
const CacheInfo &cache_info = it.value();
|
||||||
if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
|
if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
|
||||||
return cache_info.buffer;
|
return qMakePair(reinterpret_cast<const QRgb *>(cache_info.buffer32),
|
||||||
|
reinterpret_cast<const QRgba64 *>(cache_info.buffer64));
|
||||||
++it;
|
++it;
|
||||||
} while (it != cache.constEnd() && it.key() == hash_val);
|
} while (it != cache.constEnd() && it.key() == hash_val);
|
||||||
// an exact match for these stops and opacity was not found, create new cache
|
// an exact match for these stops and opacity was not found, create new cache
|
||||||
@ -4177,14 +4181,18 @@ protected:
|
|||||||
inline void generateGradientColorTable(const QGradient& g,
|
inline void generateGradientColorTable(const QGradient& g,
|
||||||
QRgba64 *colorTable,
|
QRgba64 *colorTable,
|
||||||
int size, int opacity) const;
|
int size, int opacity) const;
|
||||||
QRgba64 *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
|
ColorBufferPair addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
|
||||||
if (cache.size() == maxCacheSize()) {
|
if (cache.size() == maxCacheSize()) {
|
||||||
// may remove more than 1, but OK
|
// may remove more than 1, but OK
|
||||||
cache.erase(cache.begin() + (qrand() % maxCacheSize()));
|
cache.erase(cache.begin() + (qrand() % maxCacheSize()));
|
||||||
}
|
}
|
||||||
CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
|
CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
|
||||||
generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
|
generateGradientColorTable(gradient, cache_entry.buffer64, paletteSize(), opacity);
|
||||||
return cache.insert(hash_val, cache_entry).value().buffer;
|
for (int i = 0; i < GRADIENT_STOPTABLE_SIZE; ++i)
|
||||||
|
cache_entry.buffer32[i] = cache_entry.buffer64[i].toArgb32();
|
||||||
|
CacheInfo &cache_value = cache.insert(hash_val, cache_entry).value();
|
||||||
|
return qMakePair(reinterpret_cast<const QRgb *>(cache_value.buffer32),
|
||||||
|
reinterpret_cast<const QRgba64 *>(cache_value.buffer64));
|
||||||
}
|
}
|
||||||
|
|
||||||
QGradientColorTableHash cache;
|
QGradientColorTableHash cache;
|
||||||
@ -4418,7 +4426,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
|
|||||||
type = LinearGradient;
|
type = LinearGradient;
|
||||||
const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
|
const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
|
||||||
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
|
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
|
||||||
gradient.colorTable = const_cast<QRgba64*>(qt_gradient_cache()->getBuffer(*g, alpha));
|
|
||||||
|
QGradientCache::ColorBufferPair colorBuffers = qt_gradient_cache()->getBuffer(*g, alpha);
|
||||||
|
gradient.colorTable64 = colorBuffers.second;
|
||||||
|
gradient.colorTable32 = colorBuffers.first;
|
||||||
|
|
||||||
gradient.spread = g->spread();
|
gradient.spread = g->spread();
|
||||||
|
|
||||||
QLinearGradientData &linearData = gradient.linear;
|
QLinearGradientData &linearData = gradient.linear;
|
||||||
@ -4435,7 +4447,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
|
|||||||
type = RadialGradient;
|
type = RadialGradient;
|
||||||
const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
|
const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
|
||||||
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
|
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
|
||||||
gradient.colorTable = const_cast<QRgba64*>(qt_gradient_cache()->getBuffer(*g, alpha));
|
|
||||||
|
QGradientCache::ColorBufferPair colorBuffers = qt_gradient_cache()->getBuffer(*g, alpha);
|
||||||
|
gradient.colorTable64 = colorBuffers.second;
|
||||||
|
gradient.colorTable32 = colorBuffers.first;
|
||||||
|
|
||||||
gradient.spread = g->spread();
|
gradient.spread = g->spread();
|
||||||
|
|
||||||
QRadialGradientData &radialData = gradient.radial;
|
QRadialGradientData &radialData = gradient.radial;
|
||||||
@ -4456,7 +4472,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
|
|||||||
type = ConicalGradient;
|
type = ConicalGradient;
|
||||||
const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
|
const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
|
||||||
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
|
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
|
||||||
gradient.colorTable = const_cast<QRgba64*>(qt_gradient_cache()->getBuffer(*g, alpha));
|
|
||||||
|
QGradientCache::ColorBufferPair colorBuffers = qt_gradient_cache()->getBuffer(*g, alpha);
|
||||||
|
gradient.colorTable64 = colorBuffers.second;
|
||||||
|
gradient.colorTable32 = colorBuffers.first;
|
||||||
|
|
||||||
gradient.spread = QGradient::RepeatSpread;
|
gradient.spread = QGradient::RepeatSpread;
|
||||||
|
|
||||||
QConicalGradientData &conicalData = gradient.conical;
|
QConicalGradientData &conicalData = gradient.conical;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user