From 4ba6cd2dcd936b4d5b5f69eb495236221d768e25 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 7 Aug 2024 14:21:28 +0200 Subject: [PATCH] Fix HDR colorspace transforms for non-SSE2/non-NEON Task-number: QTBUG-127646 Change-Id: Ie3eab7b7e07155a0e9f70455c8e33f308f7b84d1 Reviewed-by: Eirik Aavitsland (cherry picked from commit 8e942c9d704376232d8a5437f861174709a26600) Reviewed-by: Qt Cherry-pick Bot --- src/gui/painting/qcolortransform.cpp | 76 +++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp index 14200ccf9d5..2cbc19b9626 100644 --- a/src/gui/painting/qcolortransform.cpp +++ b/src/gui/painting/qcolortransform.cpp @@ -780,6 +780,9 @@ void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len template<> void loadPremultiplied(QColorVector *buffer, const QRgb *src, const qsizetype len, const QColorTransformPrivate *d_ptr) { + const int rangeMaxR = d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear; + const int rangeMaxG = d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear; + const int rangeMaxB = d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear; for (qsizetype i = 0; i < len; ++i) { const uint p = src[i]; const int a = qAlpha(p); @@ -788,9 +791,16 @@ void loadPremultiplied(QColorVector *buffer, const QRgb *src, const qsizet const int ridx = int(qRed(p) * ia + 0.5f); const int gidx = int(qGreen(p) * ia + 0.5f); const int bidx = int(qBlue(p) * ia + 0.5f); - buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); - buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); - buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + if (ridx <= rangeMaxR && gidx <= rangeMaxG && bidx <= rangeMaxB) { + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + } else { + constexpr float f = 1.f / QColorTrcLut::Resolution; + buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(ridx * f); + buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(gidx * f); + buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(bidx * f); + } } else { buffer[i].x = buffer[i].y = buffer[i].z = 0.0f; } @@ -800,6 +810,9 @@ void loadPremultiplied(QColorVector *buffer, const QRgb *src, const qsizet template<> void loadPremultiplied(QColorVector *buffer, const QRgba64 *src, const qsizetype len, const QColorTransformPrivate *d_ptr) { + const int rangeMaxR = d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear; + const int rangeMaxG = d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear; + const int rangeMaxB = d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear; for (qsizetype i = 0; i < len; ++i) { const QRgba64 &p = src[i]; const int a = p.alpha(); @@ -808,9 +821,16 @@ void loadPremultiplied(QColorVector *buffer, const QRgba64 *src, const const int ridx = int(p.red() * ia + 0.5f); const int gidx = int(p.green() * ia + 0.5f); const int bidx = int(p.blue() * ia + 0.5f); - buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); - buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); - buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + if (ridx <= rangeMaxR && gidx <= rangeMaxG && bidx <= rangeMaxB) { + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + } else { + constexpr float f = 1.f / QColorTrcLut::Resolution; + buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(ridx * f); + buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(gidx * f); + buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(bidx * f); + } } else { buffer[i].x = buffer[i].y = buffer[i].z = 0.0f; } @@ -820,22 +840,54 @@ void loadPremultiplied(QColorVector *buffer, const QRgba64 *src, const template<> void loadUnpremultiplied(QColorVector *buffer, const QRgb *src, const qsizetype len, const QColorTransformPrivate *d_ptr) { + const int rangeMaxR = d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear; + const int rangeMaxG = d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear; + const int rangeMaxB = d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear; for (qsizetype i = 0; i < len; ++i) { const uint p = src[i]; - buffer[i].x = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(qRed(p)); - buffer[i].y = d_ptr->colorSpaceIn->lut[1]->u8ToLinearF32(qGreen(p)); - buffer[i].z = d_ptr->colorSpaceIn->lut[2]->u8ToLinearF32(qBlue(p)); + const int ridx = qRed(p) << QColorTrcLut::ShiftUp; + const int gidx = qGreen(p) << QColorTrcLut::ShiftUp; + const int bidx = qBlue(p) << QColorTrcLut::ShiftUp; + if (ridx <= rangeMaxR && gidx <= rangeMaxG && bidx <= rangeMaxB) { + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + } else { + constexpr float f = 1.f / QColorTrcLut::Resolution; + buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(ridx * f); + buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(gidx * f); + buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(bidx * f); + } } } +static int u16toidx(int c) +{ + c -= c >> 8; + return c >> QColorTrcLut::ShiftDown; +} + template<> void loadUnpremultiplied(QColorVector *buffer, const QRgba64 *src, const qsizetype len, const QColorTransformPrivate *d_ptr) { + const int rangeMaxR = d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear; + const int rangeMaxG = d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear; + const int rangeMaxB = d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear; for (qsizetype i = 0; i < len; ++i) { const QRgba64 &p = src[i]; - buffer[i].x = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(p.red()); - buffer[i].y = d_ptr->colorSpaceIn->lut[1]->u16ToLinearF32(p.green()); - buffer[i].z = d_ptr->colorSpaceIn->lut[2]->u16ToLinearF32(p.blue()); + const int ridx = u16toidx(p.red()); + const int gidx = u16toidx(p.green()); + const int bidx = u16toidx(p.blue()); + if (ridx <= rangeMaxR && gidx <= rangeMaxG && bidx <= rangeMaxB) { + buffer[i].x = d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx] * (1.0f / (255 * 256)); + buffer[i].y = d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx] * (1.0f / (255 * 256)); + buffer[i].z = d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx] * (1.0f / (255 * 256)); + } else { + constexpr float f = 1.f / QColorTrcLut::Resolution; + buffer[i].x = d_ptr->colorSpaceIn->trc[0].applyExtended(ridx * f); + buffer[i].y = d_ptr->colorSpaceIn->trc[1].applyExtended(gidx * f); + buffer[i].z = d_ptr->colorSpaceIn->trc[2].applyExtended(bidx * f); + } } } #endif