Fix HDR transfer function image conversions
Handle TRC LUTs that overflow the 0-1 range. Change-Id: I336ef9dd56d8cb8c0caa62bff468c9b536550f57 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io> (cherry picked from commit 60bb057990657ff285ef0d73fa774eea907a0cbb) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
da4c0de7fb
commit
19ca1284c8
@ -448,6 +448,12 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
|
|||||||
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
|
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
|
||||||
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
||||||
constexpr bool isARGB = isArgb<T>();
|
constexpr bool isARGB = isArgb<T>();
|
||||||
|
const __m128i vRangeMax = _mm_setr_epi32(isARGB ? d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear,
|
||||||
|
d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear,
|
||||||
|
isARGB ? d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear,
|
||||||
|
QColorTrcLut::Resolution);
|
||||||
for (qsizetype i = 0; i < len; ++i) {
|
for (qsizetype i = 0; i < len; ++i) {
|
||||||
__m128i v;
|
__m128i v;
|
||||||
loadP<T>(src[i], v);
|
loadP<T>(src[i], v);
|
||||||
@ -468,12 +474,19 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
|
|||||||
const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
|
const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
|
||||||
const int gidx = _mm_extract_epi16(v, 2);
|
const int gidx = _mm_extract_epi16(v, 2);
|
||||||
const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
|
const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
|
||||||
|
if (_mm_movemask_epi8(_mm_cmpgt_epi32(v, vRangeMax)) == 0) {
|
||||||
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
|
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
|
||||||
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
|
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
|
||||||
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
|
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
|
||||||
vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00);
|
vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00);
|
||||||
|
|
||||||
_mm_storeu_ps(&buffer[i].x, vf);
|
_mm_storeu_ps(&buffer[i].x, vf);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +496,11 @@ void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *s
|
|||||||
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
|
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
|
||||||
const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
||||||
const __m128 vZero = _mm_set1_ps(0.0f);
|
const __m128 vZero = _mm_set1_ps(0.0f);
|
||||||
const __m128 vOne = _mm_set1_ps(1.0f);
|
const float factor = 1.f / float(QColorTrcLut::Resolution);
|
||||||
|
const __m128 vRangeMax = _mm_setr_ps(d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear * factor,
|
||||||
|
d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear * factor,
|
||||||
|
d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear * factor,
|
||||||
|
INFINITY);
|
||||||
for (qsizetype i = 0; i < len; ++i) {
|
for (qsizetype i = 0; i < len; ++i) {
|
||||||
__m128 vf = _mm_loadu_ps(&src[i].r);
|
__m128 vf = _mm_loadu_ps(&src[i].r);
|
||||||
// Approximate 1/a:
|
// Approximate 1/a:
|
||||||
@ -499,7 +516,7 @@ void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *s
|
|||||||
|
|
||||||
// LUT
|
// LUT
|
||||||
const __m128 under = _mm_cmplt_ps(vf, vZero);
|
const __m128 under = _mm_cmplt_ps(vf, vZero);
|
||||||
const __m128 over = _mm_cmpgt_ps(vf, vOne);
|
const __m128 over = _mm_cmpgt_ps(vf, vRangeMax);
|
||||||
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
|
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
|
||||||
// Within gamut
|
// Within gamut
|
||||||
__m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
|
__m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
|
||||||
@ -556,17 +573,30 @@ void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len
|
|||||||
{
|
{
|
||||||
constexpr bool isARGB = isArgb<T>();
|
constexpr bool isARGB = isArgb<T>();
|
||||||
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
||||||
|
const __m128i vRangeMax = _mm_setr_epi32(isARGB ? d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear,
|
||||||
|
d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear,
|
||||||
|
isARGB ? d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear,
|
||||||
|
QColorTrcLut::Resolution);
|
||||||
for (qsizetype i = 0; i < len; ++i) {
|
for (qsizetype i = 0; i < len; ++i) {
|
||||||
__m128i v;
|
__m128i v;
|
||||||
loadPU<T>(src[i], v);
|
loadPU<T>(src[i], v);
|
||||||
const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
|
const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
|
||||||
const int gidx = _mm_extract_epi16(v, 2);
|
const int gidx = _mm_extract_epi16(v, 2);
|
||||||
const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
|
const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
|
||||||
|
if (_mm_movemask_epi8(_mm_cmpgt_epi32(v, vRangeMax)) == 0) {
|
||||||
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
|
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], 0);
|
||||||
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
|
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], 2);
|
||||||
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
|
v = _mm_insert_epi16(v, d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], 4);
|
||||||
__m128 vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00);
|
__m128 vf = _mm_mul_ps(_mm_cvtepi32_ps(v), iFF00);
|
||||||
_mm_storeu_ps(&buffer[i].x, vf);
|
_mm_storeu_ps(&buffer[i].x, vf);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,11 +606,15 @@ void loadUnpremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32
|
|||||||
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
|
const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
|
||||||
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
|
||||||
const __m128 vZero = _mm_set1_ps(0.0f);
|
const __m128 vZero = _mm_set1_ps(0.0f);
|
||||||
const __m128 vOne = _mm_set1_ps(1.0f);
|
const float factor = 1.f / float(QColorTrcLut::Resolution);
|
||||||
|
const __m128 vRangeMax = _mm_setr_ps(d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear * factor,
|
||||||
|
d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear * factor,
|
||||||
|
d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear * factor,
|
||||||
|
INFINITY);
|
||||||
for (qsizetype i = 0; i < len; ++i) {
|
for (qsizetype i = 0; i < len; ++i) {
|
||||||
__m128 vf = _mm_loadu_ps(&src[i].r);
|
__m128 vf = _mm_loadu_ps(&src[i].r);
|
||||||
const __m128 under = _mm_cmplt_ps(vf, vZero);
|
const __m128 under = _mm_cmplt_ps(vf, vZero);
|
||||||
const __m128 over = _mm_cmpgt_ps(vf, vOne);
|
const __m128 over = _mm_cmpgt_ps(vf, vRangeMax);
|
||||||
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
|
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
|
||||||
// Within gamut
|
// Within gamut
|
||||||
__m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
|
__m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
|
||||||
@ -618,11 +652,28 @@ inline void loadP<QRgba64>(const QRgba64 &p, uint32x4_t &v)
|
|||||||
v = vmovl_u16(vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&p))));
|
v = vmovl_u16(vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&p))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool test_all_zero(uint32x4_t p)
|
||||||
|
{
|
||||||
|
#if defined(Q_PROCESSOR_ARM_64)
|
||||||
|
return vaddvq_u32(p) == 0;
|
||||||
|
#else
|
||||||
|
const uint32x2_t tmp = vpadd_u32(vget_low_u32(p), vget_high_u32(p));
|
||||||
|
return vget_lane_u32(vpadd_u32(tmp, tmp), 0) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
|
static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
|
||||||
{
|
{
|
||||||
constexpr bool isARGB = isArgb<T>();
|
constexpr bool isARGB = isArgb<T>();
|
||||||
const float iFF00 = 1.0f / (255 * 256);
|
const float iFF00 = 1.0f / (255 * 256);
|
||||||
|
const uint32x4_t vRangeMax = {
|
||||||
|
isARGB ? d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear,
|
||||||
|
d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear,
|
||||||
|
isARGB ? d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear,
|
||||||
|
QColorTrcLut::Resolution };
|
||||||
for (qsizetype i = 0; i < len; ++i) {
|
for (qsizetype i = 0; i < len; ++i) {
|
||||||
uint32x4_t v;
|
uint32x4_t v;
|
||||||
loadP<T>(src[i], v);
|
loadP<T>(src[i], v);
|
||||||
@ -648,12 +699,19 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
|
|||||||
const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
|
const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
|
||||||
const int gidx = vgetq_lane_u32(v, 1);
|
const int gidx = vgetq_lane_u32(v, 1);
|
||||||
const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
|
const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
|
||||||
|
if (test_all_zero(vcgtq_u32(v, vRangeMax))) {
|
||||||
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], v, 0);
|
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], v, 0);
|
||||||
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], v, 1);
|
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], v, 1);
|
||||||
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], v, 2);
|
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], v, 2);
|
||||||
vf = vmulq_n_f32(vcvtq_f32_u32(v), iFF00);
|
vf = vmulq_n_f32(vcvtq_f32_u32(v), iFF00);
|
||||||
|
|
||||||
vst1q_f32(&buffer[i].x, vf);
|
vst1q_f32(&buffer[i].x, vf);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,17 +740,31 @@ void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len
|
|||||||
{
|
{
|
||||||
constexpr bool isARGB = isArgb<T>();
|
constexpr bool isARGB = isArgb<T>();
|
||||||
const float iFF00 = 1.0f / (255 * 256);
|
const float iFF00 = 1.0f / (255 * 256);
|
||||||
|
const uint32x4_t vRangeMax = {
|
||||||
|
isARGB ? d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear,
|
||||||
|
d_ptr->colorSpaceIn->lut[1]->m_unclampedToLinear,
|
||||||
|
isARGB ? d_ptr->colorSpaceIn->lut[0]->m_unclampedToLinear
|
||||||
|
: d_ptr->colorSpaceIn->lut[2]->m_unclampedToLinear,
|
||||||
|
QColorTrcLut::Resolution };
|
||||||
for (qsizetype i = 0; i < len; ++i) {
|
for (qsizetype i = 0; i < len; ++i) {
|
||||||
uint32x4_t v;
|
uint32x4_t v;
|
||||||
loadPU<T>(src[i], v);
|
loadPU<T>(src[i], v);
|
||||||
const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
|
const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
|
||||||
const int gidx = vgetq_lane_u32(v, 1);
|
const int gidx = vgetq_lane_u32(v, 1);
|
||||||
const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
|
const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
|
||||||
|
if (test_all_zero(vcgtq_u32(v, vRangeMax))) {
|
||||||
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], v, 0);
|
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[0]->m_toLinear[ridx], v, 0);
|
||||||
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], v, 1);
|
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[1]->m_toLinear[gidx], v, 1);
|
||||||
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], v, 2);
|
v = vsetq_lane_u32(d_ptr->colorSpaceIn->lut[2]->m_toLinear[bidx], v, 2);
|
||||||
float32x4_t vf = vmulq_n_f32(vcvtq_f32_u32(v), iFF00);
|
float32x4_t vf = vmulq_n_f32(vcvtq_f32_u32(v), iFF00);
|
||||||
vst1q_f32(&buffer[i].x, vf);
|
vst1q_f32(&buffer[i].x, vf);
|
||||||
|
} 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
|
#else
|
||||||
|
@ -37,8 +37,10 @@ void QColorTrcLut::setFromGamma(float gamma, Direction dir)
|
|||||||
if (dir & ToLinear) {
|
if (dir & ToLinear) {
|
||||||
if (!m_toLinear)
|
if (!m_toLinear)
|
||||||
m_toLinear.reset(new ushort[Resolution + 1]);
|
m_toLinear.reset(new ushort[Resolution + 1]);
|
||||||
for (int i = 0; i <= Resolution; ++i)
|
for (int i = 0; i <= Resolution; ++i) {
|
||||||
m_toLinear[i] = ushort(qRound(qBound(0.f, qPow(i * iRes, gamma), 1.f) * (255 * 256)));
|
const int val = qRound(qPow(i * iRes, gamma) * (255 * 256));
|
||||||
|
m_toLinear[i] = qBound(0, val, 65280);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir & FromLinear) {
|
if (dir & FromLinear) {
|
||||||
@ -56,8 +58,12 @@ void QColorTrcLut::setFromTransferFunction(const QColorTransferFunction &fun, Di
|
|||||||
if (dir & ToLinear) {
|
if (dir & ToLinear) {
|
||||||
if (!m_toLinear)
|
if (!m_toLinear)
|
||||||
m_toLinear.reset(new ushort[Resolution + 1]);
|
m_toLinear.reset(new ushort[Resolution + 1]);
|
||||||
for (int i = 0; i <= Resolution; ++i)
|
for (int i = 0; i <= Resolution; ++i) {
|
||||||
m_toLinear[i] = ushort(qRound(qBound(0.f, fun.apply(i * iRes), 1.f) * (255 * 256)));
|
const int val = qRound(fun.apply(i * iRes)* (255 * 256));
|
||||||
|
if (val > 65280 && i < m_unclampedToLinear)
|
||||||
|
m_unclampedToLinear = i;
|
||||||
|
m_toLinear[i] = qBound(0, val, 65280);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir & FromLinear) {
|
if (dir & FromLinear) {
|
||||||
@ -75,8 +81,12 @@ void QColorTrcLut::setFromTransferGenericFunction(const QColorTransferGenericFun
|
|||||||
if (dir & ToLinear) {
|
if (dir & ToLinear) {
|
||||||
if (!m_toLinear)
|
if (!m_toLinear)
|
||||||
m_toLinear.reset(new ushort[Resolution + 1]);
|
m_toLinear.reset(new ushort[Resolution + 1]);
|
||||||
for (int i = 0; i <= Resolution; ++i)
|
for (int i = 0; i <= Resolution; ++i) {
|
||||||
m_toLinear[i] = ushort(qRound(qBound(0.f, fun.apply(i * iRes), 1.f) * (255 * 256)));
|
const int val = qRound(fun.apply(i * iRes) * (255 * 256));
|
||||||
|
if (val > 65280 && i < m_unclampedToLinear)
|
||||||
|
m_unclampedToLinear = i;
|
||||||
|
m_toLinear[i] = qBound(0, val, 65280);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir & FromLinear) {
|
if (dir & FromLinear) {
|
||||||
|
@ -206,6 +206,7 @@ public:
|
|||||||
// and to keep the tables small enough to fit in most inner caches.
|
// and to keep the tables small enough to fit in most inner caches.
|
||||||
std::unique_ptr<ushort[]> m_toLinear; // [0->Resolution] -> [0-65280]
|
std::unique_ptr<ushort[]> m_toLinear; // [0->Resolution] -> [0-65280]
|
||||||
std::unique_ptr<ushort[]> m_fromLinear; // [0->Resolution] -> [0-65280]
|
std::unique_ptr<ushort[]> m_fromLinear; // [0->Resolution] -> [0-65280]
|
||||||
|
ushort m_unclampedToLinear = Resolution;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QColorTrcLut() = default;
|
QColorTrcLut() = default;
|
||||||
|
@ -1068,9 +1068,7 @@ void tst_QColorSpace::scaleAlphaValue()
|
|||||||
|
|
||||||
void tst_QColorSpace::hdrColorSpaces()
|
void tst_QColorSpace::hdrColorSpaces()
|
||||||
{
|
{
|
||||||
QColorSpace bt2020linear = QColorSpace::Bt2020;
|
QColorSpace bt2020linear(QColorSpace::Primaries::Bt2020, QColorSpace::TransferFunction::Linear);
|
||||||
bt2020linear.setTransferFunction(QColorSpace::TransferFunction::Linear);
|
|
||||||
|
|
||||||
QColorTransform pqToLinear = QColorSpace(QColorSpace::Bt2100Pq).transformationToColorSpace(bt2020linear);
|
QColorTransform pqToLinear = QColorSpace(QColorSpace::Bt2100Pq).transformationToColorSpace(bt2020linear);
|
||||||
QColorTransform hlgToLinear = QColorSpace(QColorSpace::Bt2100Hlg).transformationToColorSpace(bt2020linear);
|
QColorTransform hlgToLinear = QColorSpace(QColorSpace::Bt2100Hlg).transformationToColorSpace(bt2020linear);
|
||||||
|
|
||||||
@ -1085,6 +1083,47 @@ void tst_QColorSpace::hdrColorSpaces()
|
|||||||
QCOMPARE(pqToLinear.map(maxWhite).redF(), 64.f);
|
QCOMPARE(pqToLinear.map(maxWhite).redF(), 64.f);
|
||||||
QCOMPARE(pqToLinear.map(maxWhite).greenF(), 64.f);
|
QCOMPARE(pqToLinear.map(maxWhite).greenF(), 64.f);
|
||||||
QCOMPARE(pqToLinear.map(maxWhite).blueF(), 64.f);
|
QCOMPARE(pqToLinear.map(maxWhite).blueF(), 64.f);
|
||||||
|
|
||||||
|
{
|
||||||
|
QImage image(1, 1, QImage::Format_RGBA32FPx4);
|
||||||
|
image.setPixel(0, 0, qRgba(255, 255, 255, 255));
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Pq);
|
||||||
|
QImage image2 = image.convertedToColorSpace(bt2020linear);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 64.f);
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Hlg);
|
||||||
|
image2 = image.convertedToColorSpace(bt2020linear);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 12.f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QImage image(1, 1, QImage::Format_RGBA32FPx4_Premultiplied);
|
||||||
|
image.setPixel(0, 0, qRgba(255, 255, 255, 255));
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Pq);
|
||||||
|
QImage image2 = image.convertedToColorSpace(bt2020linear);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 64.f);
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Hlg);
|
||||||
|
image2 = image.convertedToColorSpace(bt2020linear);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 12.f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QImage image(1, 1, QImage::Format_ARGB32);
|
||||||
|
image.setPixel(0, 0, qRgba(255, 255, 255, 255));
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Pq);
|
||||||
|
QImage image2 = image.convertedToColorSpace(bt2020linear, QImage::Format_RGBA32FPx4);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 64.f);
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Hlg);
|
||||||
|
image2 = image.convertedToColorSpace(bt2020linear, QImage::Format_RGBA32FPx4);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 12.f);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
QImage image(1, 1, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
image.setPixel(0, 0, qRgba(255, 255, 255, 255));
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Pq);
|
||||||
|
QImage image2 = image.convertedToColorSpace(bt2020linear, QImage::Format_RGBA32FPx4);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 64.f);
|
||||||
|
image.setColorSpace(QColorSpace::Bt2100Hlg);
|
||||||
|
image2 = image.convertedToColorSpace(bt2020linear, QImage::Format_RGBA32FPx4);
|
||||||
|
QCOMPARE(image2.pixelColor(0, 0).redF(), 12.f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QColorSpace)
|
QTEST_MAIN(tst_QColorSpace)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user