File indexing completed on 2024-06-16 04:16:56
0001 /** 0002 * SPDX-FileCopyrightText: 2020-2021 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com> 0003 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <kis_heif_import_tools.h> 0009 0010 #if XSIMD_UNIVERSAL_BUILD_PASS 0011 0012 namespace Planar 0013 { 0014 #if defined HAVE_XSIMD && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0015 template<typename Arch, 0016 LinearizePolicy linearizePolicy, 0017 bool applyOOTF, 0018 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0019 int> = 0> 0020 inline void linearize(float *pixelValues, 0021 const double *lCoef, 0022 float displayGamma, 0023 float displayNits) 0024 { 0025 using float_v = typename KoColorTransferFunctions<Arch>::float_v; 0026 if (linearizePolicy == LinearizePolicy::LinearFromPQ) { 0027 auto v = float_v::load_unaligned(pixelValues); 0028 KoColorTransferFunctions<Arch>::removeSmpte2048Curve(v); 0029 v.store_unaligned(pixelValues); 0030 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG) { 0031 auto v = float_v::load_unaligned(pixelValues); 0032 KoColorTransferFunctions<Arch>::removeHLGCurve(v); 0033 v.store_unaligned(pixelValues); 0034 } else if (linearizePolicy == LinearizePolicy::LinearFromSMPTE428) { 0035 auto v = float_v::load_unaligned(pixelValues); 0036 KoColorTransferFunctions<Arch>::removeSMPTE_ST_428Curve(v); 0037 v.store_unaligned(pixelValues); 0038 } 0039 0040 if (linearizePolicy == LinearizePolicy::KeepTheSame) { 0041 qSwap(pixelValues[0], pixelValues[2]); 0042 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG && applyOOTF) { 0043 applyHLGOOTF(pixelValues, lCoef, displayGamma, displayNits); 0044 } 0045 } 0046 #endif 0047 0048 template<typename Arch, 0049 LinearizePolicy linearizePolicy, 0050 bool applyOOTF, 0051 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0052 int> = 0> 0053 inline void linearize(float *pixelValues, 0054 const double *lCoef, 0055 float displayGamma, 0056 float displayNits) 0057 { 0058 if (linearizePolicy == LinearizePolicy::KeepTheSame) { 0059 qSwap(pixelValues[0], pixelValues[2]); 0060 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG && applyOOTF) { 0061 applyHLGOOTF(pixelValues, lCoef, displayGamma, displayNits); 0062 } 0063 } 0064 0065 template<typename Arch, 0066 int luma, 0067 LinearizePolicy linearizePolicy, 0068 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0069 int> = 0> 0070 inline float value(const uint8_t *img, int stride, int x, int y) 0071 { 0072 if (luma == 8) { 0073 return float(img[y * (stride) + x]) / 255.0f; 0074 } else { 0075 uint16_t source = 0076 reinterpret_cast<const uint16_t *>(img)[y * (stride / 2) + x]; 0077 if (luma == 10) { 0078 return float(0x03ff & (source)) * multiplier10bit; 0079 } else if (luma == 12) { 0080 return float(0x0fff & (source)) * multiplier12bit; 0081 } else { 0082 return float(source) * multiplier16bit; 0083 } 0084 } 0085 } 0086 0087 template<LinearizePolicy policy> 0088 inline float linearizeValueAsNeeded(float value) 0089 { 0090 if (policy == LinearizePolicy::LinearFromPQ) { 0091 return removeSmpte2048Curve(value); 0092 } else if (policy == LinearizePolicy::LinearFromHLG) { 0093 return removeHLGCurve(value); 0094 } else if (policy == LinearizePolicy::LinearFromSMPTE428) { 0095 return removeSMPTE_ST_428Curve(value); 0096 } 0097 return value; 0098 } 0099 0100 template<typename Arch, 0101 int luma, 0102 LinearizePolicy linearizePolicy, 0103 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0104 int> = 0> 0105 inline float value(const uint8_t *img, int stride, int x, int y) 0106 { 0107 if (luma == 8) { 0108 return linearizeValueAsNeeded<linearizePolicy>( 0109 float(img[y * (stride) + x]) / 255.0f); 0110 } else { 0111 uint16_t source = 0112 reinterpret_cast<const uint16_t *>(img)[y * (stride / 2) + x]; 0113 if (luma == 10) { 0114 return linearizeValueAsNeeded<linearizePolicy>( 0115 float(0x03ff & (source)) * multiplier10bit); 0116 } else if (luma == 12) { 0117 return linearizeValueAsNeeded<linearizePolicy>( 0118 float(0x0fff & (source)) * multiplier12bit); 0119 } else { 0120 return linearizeValueAsNeeded<linearizePolicy>(float(source) 0121 * multiplier16bit); 0122 } 0123 } 0124 } 0125 0126 template<typename Arch, 0127 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0128 int> = 0> 0129 constexpr int bufferSize() 0130 { 0131 return 4; 0132 } 0133 0134 #if defined HAVE_XSIMD && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0135 template<typename Arch, 0136 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0137 int> = 0> 0138 constexpr int bufferSize() 0139 { 0140 return qMax<int>(4, KoStreamedMath<Arch>::float_v::size); 0141 } 0142 #endif 0143 0144 template<typename Arch, 0145 int luma, 0146 LinearizePolicy linearizePolicy, 0147 bool applyOOTF, 0148 bool hasAlpha> 0149 inline void readLayer(const int width, 0150 const int height, 0151 const uint8_t *imgR, 0152 const int strideR, 0153 const uint8_t *imgG, 0154 const int strideG, 0155 const uint8_t *imgB, 0156 const int strideB, 0157 const uint8_t *imgA, 0158 const int strideA, 0159 KisHLineIteratorSP it, 0160 float displayGamma, 0161 float displayNits, 0162 const KoColorSpace *colorSpace) 0163 { 0164 const QVector<qreal> lCoef{colorSpace->lumaCoefficients()}; 0165 QVector<float> pixelValues(bufferSize<Arch>()); 0166 float *data = pixelValues.data(); 0167 0168 for (int y = 0; y < height; y++) { 0169 for (int x = 0; x < width; x++) { 0170 for (int i = 0; i < bufferSize<Arch>(); i++) { 0171 data[i] = 1.0f; 0172 } 0173 0174 data[0] = value<Arch, luma, linearizePolicy>(imgR, strideR, x, y); 0175 data[1] = value<Arch, luma, linearizePolicy>(imgG, strideG, x, y); 0176 data[2] = value<Arch, luma, linearizePolicy>(imgB, strideB, x, y); 0177 0178 linearize<Arch, linearizePolicy, applyOOTF>(data, 0179 lCoef.constData(), 0180 displayGamma, 0181 displayNits); 0182 0183 if (hasAlpha) { 0184 data[3] = 0185 value<Arch, luma, LinearizePolicy::KeepTheSame>(imgA, 0186 strideA, 0187 x, 0188 y); 0189 } 0190 0191 if (luma == 8) { 0192 KoBgrU8Traits::fromNormalisedChannelsValue(it->rawData(), 0193 pixelValues); 0194 } else if (luma > 8 && linearizePolicy != LinearizePolicy::KeepTheSame) { 0195 KoBgrF32Traits::fromNormalisedChannelsValue(it->rawData(), 0196 pixelValues); 0197 } else { 0198 KoBgrU16Traits::fromNormalisedChannelsValue(it->rawData(), 0199 pixelValues); 0200 } 0201 0202 it->nextPixel(); 0203 } 0204 0205 it->nextRow(); 0206 } 0207 } 0208 0209 template<typename Arch, 0210 int luma, 0211 LinearizePolicy linearizePolicy, 0212 bool applyOOTF, 0213 typename... Args> 0214 inline auto readPlanarLayerWithAlpha(bool hasAlpha, Args &&...args) 0215 { 0216 if (hasAlpha) { 0217 return Planar::readLayer<Arch, luma, linearizePolicy, applyOOTF, true>( 0218 std::forward<Args>(args)...); 0219 } else { 0220 return Planar::readLayer<Arch, luma, linearizePolicy, applyOOTF, false>( 0221 std::forward<Args>(args)...); 0222 } 0223 } 0224 0225 template<typename Arch, 0226 int luma, 0227 LinearizePolicy linearizePolicy, 0228 typename... Args> 0229 inline auto readPlanarLayerWithPolicy(bool applyOOTF, Args &&...args) 0230 { 0231 if (applyOOTF) { 0232 return readPlanarLayerWithAlpha<Arch, luma, linearizePolicy, true>( 0233 std::forward<Args>(args)...); 0234 } else { 0235 return readPlanarLayerWithAlpha<Arch, luma, linearizePolicy, false>( 0236 std::forward<Args>(args)...); 0237 } 0238 } 0239 0240 template<typename Arch, int luma, typename... Args> 0241 inline auto readPlanarLayerWithLuma(LinearizePolicy linearizePolicy, 0242 Args &&...args) 0243 { 0244 if (linearizePolicy == LinearizePolicy::LinearFromHLG) { 0245 return readPlanarLayerWithPolicy<Arch, luma, LinearizePolicy::LinearFromHLG>(std::forward<Args>(args)...); 0246 } else if (linearizePolicy == LinearizePolicy::LinearFromPQ) { 0247 return readPlanarLayerWithPolicy<Arch, luma, LinearizePolicy::LinearFromPQ>(std::forward<Args>(args)...); 0248 } else if (linearizePolicy == LinearizePolicy::LinearFromSMPTE428) { 0249 return readPlanarLayerWithPolicy<Arch, luma, LinearizePolicy::LinearFromSMPTE428>(std::forward<Args>(args)...); 0250 } else { 0251 return readPlanarLayerWithPolicy<Arch, luma, LinearizePolicy::KeepTheSame>(std::forward<Args>(args)...); 0252 } 0253 } 0254 0255 template<typename Arch> 0256 void readLayerImpl::create(const int luma, 0257 LinearizePolicy policy, 0258 bool applyOOTF, 0259 bool hasAlpha, 0260 const int width, 0261 const int height, 0262 const uint8_t *imgR, 0263 const int strideR, 0264 const uint8_t *imgG, 0265 const int strideG, 0266 const uint8_t *imgB, 0267 const int strideB, 0268 const uint8_t *imgA, 0269 const int strideA, 0270 KisHLineIteratorSP it, 0271 float displayGamma, 0272 float displayNits, 0273 const KoColorSpace *colorSpace) 0274 { 0275 if (luma == 8) { 0276 return readPlanarLayerWithLuma<xsimd::current_arch, 8>(policy, 0277 applyOOTF, 0278 hasAlpha, 0279 width, 0280 height, 0281 imgR, 0282 strideR, 0283 imgG, 0284 strideG, 0285 imgB, 0286 strideB, 0287 imgA, 0288 strideA, 0289 it, 0290 displayGamma, 0291 displayNits, 0292 colorSpace); 0293 } else if (luma == 10) { 0294 return readPlanarLayerWithLuma<xsimd::current_arch, 10>(policy, 0295 applyOOTF, 0296 hasAlpha, 0297 width, 0298 height, 0299 imgR, 0300 strideR, 0301 imgG, 0302 strideG, 0303 imgB, 0304 strideB, 0305 imgA, 0306 strideA, 0307 it, 0308 displayGamma, 0309 displayNits, 0310 colorSpace); 0311 } else if (luma == 12) { 0312 return readPlanarLayerWithLuma<xsimd::current_arch, 12>(policy, 0313 applyOOTF, 0314 hasAlpha, 0315 width, 0316 height, 0317 imgR, 0318 strideR, 0319 imgG, 0320 strideG, 0321 imgB, 0322 strideB, 0323 imgA, 0324 strideA, 0325 it, 0326 displayGamma, 0327 displayNits, 0328 colorSpace); 0329 } else { 0330 return readPlanarLayerWithLuma<xsimd::current_arch, 16>(policy, 0331 applyOOTF, 0332 hasAlpha, 0333 width, 0334 height, 0335 imgR, 0336 strideR, 0337 imgG, 0338 strideG, 0339 imgB, 0340 strideB, 0341 imgA, 0342 strideA, 0343 it, 0344 displayGamma, 0345 displayNits, 0346 colorSpace); 0347 } 0348 } 0349 0350 template void 0351 readLayerImpl::create<xsimd::current_arch>(const int luma, 0352 LinearizePolicy policy, 0353 bool applyOOTF, 0354 bool hasAlpha, 0355 const int width, 0356 const int height, 0357 const uint8_t *imgR, 0358 const int strideR, 0359 const uint8_t *imgG, 0360 const int strideG, 0361 const uint8_t *imgB, 0362 const int strideB, 0363 const uint8_t *imgA, 0364 const int strideA, 0365 KisHLineIteratorSP it, 0366 float displayGamma, 0367 float displayNits, 0368 const KoColorSpace *colorSpace); 0369 0370 } // namespace Planar 0371 0372 namespace HDR 0373 { 0374 #if defined HAVE_XSIMD && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0375 template<typename Arch, 0376 LinearizePolicy linearizePolicy, 0377 bool applyOOTF, 0378 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0379 int> = 0> 0380 inline void linearize(float *pixelValues, 0381 const double *lCoef, 0382 float displayGamma, 0383 float displayNits) 0384 { 0385 using float_v = typename KoColorTransferFunctions<Arch>::float_v; 0386 if (linearizePolicy == LinearizePolicy::LinearFromPQ) { 0387 auto v = float_v::load_unaligned(pixelValues); 0388 KoColorTransferFunctions<Arch>::removeSmpte2048Curve(v); 0389 v.store_unaligned(pixelValues); 0390 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG) { 0391 auto v = float_v::load_unaligned(pixelValues); 0392 KoColorTransferFunctions<Arch>::removeHLGCurve(v); 0393 v.store_unaligned(pixelValues); 0394 } else if (linearizePolicy == LinearizePolicy::LinearFromSMPTE428) { 0395 auto v = float_v::load_unaligned(pixelValues); 0396 KoColorTransferFunctions<Arch>::removeSMPTE_ST_428Curve(v); 0397 v.store_unaligned(pixelValues); 0398 } 0399 0400 if (linearizePolicy == LinearizePolicy::KeepTheSame) { 0401 qSwap(pixelValues[0], pixelValues[2]); 0402 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG && applyOOTF) { 0403 applyHLGOOTF(pixelValues, lCoef, displayGamma, displayNits); 0404 } 0405 } 0406 #endif 0407 0408 template<typename Arch, 0409 LinearizePolicy linearizePolicy, 0410 bool applyOOTF, 0411 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0412 int> = 0> 0413 inline void linearize(float *pixelValues, 0414 const double *lCoef, 0415 float displayGamma, 0416 float displayNits) 0417 { 0418 if (linearizePolicy == LinearizePolicy::KeepTheSame) { 0419 qSwap(pixelValues[0], pixelValues[2]); 0420 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG && applyOOTF) { 0421 applyHLGOOTF(pixelValues, lCoef, displayGamma, displayNits); 0422 } 0423 } 0424 0425 template<typename Arch, 0426 int luma, 0427 LinearizePolicy linearizePolicy, 0428 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0429 int> = 0> 0430 inline float valueInterleaved(const uint8_t *img, 0431 int stride, 0432 int x, 0433 int y, 0434 int channels, 0435 int ch) 0436 { 0437 uint16_t source = reinterpret_cast<const uint16_t *>( 0438 img)[y * (stride / 2) + (x * channels) + ch]; 0439 if (luma == 10) { 0440 return float(0x03ff & (source)) * multiplier10bit; 0441 } else if (luma == 12) { 0442 return float(0x0fff & (source)) * multiplier12bit; 0443 } else { 0444 return float(source) * multiplier16bit; 0445 } 0446 } 0447 0448 template<LinearizePolicy policy> 0449 inline float linearizeValueAsNeeded(float value) 0450 { 0451 if (policy == LinearizePolicy::LinearFromPQ) { 0452 return removeSmpte2048Curve(value); 0453 } else if (policy == LinearizePolicy::LinearFromHLG) { 0454 return removeHLGCurve(value); 0455 } else if (policy == LinearizePolicy::LinearFromSMPTE428) { 0456 return removeSMPTE_ST_428Curve(value); 0457 } 0458 return value; 0459 } 0460 0461 template<typename Arch, 0462 int luma, 0463 LinearizePolicy linearizePolicy, 0464 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0465 int> = 0> 0466 inline float valueInterleaved(const uint8_t *img, 0467 int stride, 0468 int x, 0469 int y, 0470 int channels, 0471 int ch) 0472 { 0473 uint16_t source = reinterpret_cast<const uint16_t *>( 0474 img)[y * (stride / 2) + (x * channels) + ch]; 0475 if (luma == 10) { 0476 return linearizeValueAsNeeded<linearizePolicy>(float(0x03ff & (source)) 0477 * multiplier10bit); 0478 } else if (luma == 12) { 0479 return linearizeValueAsNeeded<linearizePolicy>(float(0x0fff & (source)) 0480 * multiplier12bit); 0481 } else { 0482 return linearizeValueAsNeeded<linearizePolicy>(float(source) 0483 * multiplier16bit); 0484 } 0485 } 0486 0487 template<typename Arch, 0488 int channels, 0489 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0490 int> = 0> 0491 constexpr int bufferSize() 0492 { 0493 return channels; 0494 } 0495 0496 #if defined HAVE_XSIMD && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0497 template<typename Arch, 0498 int channels, 0499 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0500 int> = 0> 0501 constexpr int bufferSize() 0502 { 0503 return qMax<int>(channels, KoStreamedMath<Arch>::float_v::size); 0504 } 0505 #endif 0506 0507 template<typename Arch, 0508 int luma, 0509 LinearizePolicy linearizePolicy, 0510 bool applyOOTF, 0511 int channels> 0512 inline void readLayer(const int width, 0513 const int height, 0514 const uint8_t *img, 0515 const int stride, 0516 KisHLineIteratorSP it, 0517 float displayGamma, 0518 float displayNits, 0519 const KoColorSpace *colorSpace) 0520 { 0521 const QVector<qreal> lCoef{colorSpace->lumaCoefficients()}; 0522 QVector<float> pixelValues(bufferSize<Arch, channels>()); 0523 float *data = pixelValues.data(); 0524 0525 for (int y = 0; y < height; y++) { 0526 for (int x = 0; x < width; x++) { 0527 for (int i = 0; i < bufferSize<Arch, channels>(); i++) { 0528 data[i] = 1.0f; 0529 } 0530 0531 const int alphaPos = [&]() { 0532 if (luma == 8) { 0533 return KoBgrU8Traits::alpha_pos; 0534 } else if (luma > 8 0535 && linearizePolicy != LinearizePolicy::KeepTheSame) { 0536 return KoBgrF32Traits::alpha_pos; 0537 } else { 0538 return KoBgrU16Traits::alpha_pos; 0539 } 0540 }(); 0541 0542 for (int ch = 0; ch < channels; ch++) { 0543 if (ch == alphaPos) { 0544 data[ch] = 0545 valueInterleaved<Arch, 0546 luma, 0547 LinearizePolicy::KeepTheSame>(img, 0548 stride, 0549 x, 0550 y, 0551 channels, 0552 ch); 0553 } else { 0554 data[ch] = 0555 valueInterleaved<Arch, luma, linearizePolicy>(img, 0556 stride, 0557 x, 0558 y, 0559 channels, 0560 ch); 0561 } 0562 } 0563 0564 linearize<Arch, linearizePolicy, applyOOTF>(data, 0565 lCoef.constData(), 0566 displayGamma, 0567 displayNits); 0568 0569 if (luma == 8) { 0570 KoBgrU8Traits::fromNormalisedChannelsValue(it->rawData(), 0571 pixelValues); 0572 } else if (luma > 8 && linearizePolicy != LinearizePolicy::KeepTheSame) { 0573 KoBgrF32Traits::fromNormalisedChannelsValue(it->rawData(), 0574 pixelValues); 0575 } else { 0576 KoBgrU16Traits::fromNormalisedChannelsValue(it->rawData(), 0577 pixelValues); 0578 } 0579 0580 it->nextPixel(); 0581 } 0582 0583 it->nextRow(); 0584 } 0585 } 0586 0587 template<typename Arch, 0588 int luma, 0589 LinearizePolicy linearizePolicy, 0590 bool applyOOTF, 0591 typename... Args> 0592 inline auto readInterleavedWithAlpha(bool hasAlpha, Args &&...args) 0593 { 0594 if (hasAlpha) { 0595 return HDR::readLayer<Arch, luma, linearizePolicy, applyOOTF, 4>( 0596 std::forward<Args>(args)...); 0597 } else { 0598 return HDR::readLayer<Arch, luma, linearizePolicy, applyOOTF, 3>( 0599 std::forward<Args>(args)...); 0600 } 0601 } 0602 0603 template<typename Arch, 0604 int luma, 0605 LinearizePolicy linearizePolicy, 0606 typename... Args> 0607 inline auto readInterleavedWithPolicy(bool applyOOTF, Args &&...args) 0608 { 0609 if (applyOOTF) { 0610 return readInterleavedWithAlpha<Arch, luma, linearizePolicy, true>( 0611 std::forward<Args>(args)...); 0612 } else { 0613 return readInterleavedWithAlpha<Arch, luma, linearizePolicy, false>( 0614 std::forward<Args>(args)...); 0615 } 0616 } 0617 0618 template<typename Arch, int luma, typename... Args> 0619 inline auto readInterleavedWithLuma(LinearizePolicy linearizePolicy, 0620 Args &&...args) 0621 { 0622 if (linearizePolicy == LinearizePolicy::LinearFromHLG) { 0623 return readInterleavedWithPolicy<Arch, luma, LinearizePolicy::LinearFromHLG>(std::forward<Args>(args)...); 0624 } else if (linearizePolicy == LinearizePolicy::LinearFromPQ) { 0625 return readInterleavedWithPolicy<Arch, luma, LinearizePolicy::LinearFromPQ>(std::forward<Args>(args)...); 0626 } else if (linearizePolicy == LinearizePolicy::LinearFromSMPTE428) { 0627 return readInterleavedWithPolicy<Arch, luma, LinearizePolicy::LinearFromSMPTE428>(std::forward<Args>(args)...); 0628 } else { 0629 return readInterleavedWithPolicy<Arch, luma, LinearizePolicy::KeepTheSame>(std::forward<Args>(args)...); 0630 } 0631 } 0632 0633 template<typename Arch> 0634 void readLayerImpl::create(const int luma, 0635 LinearizePolicy linearizePolicy, 0636 bool applyOOTF, 0637 const int channels, 0638 const int width, 0639 const int height, 0640 const uint8_t *img, 0641 const int stride, 0642 KisHLineIteratorSP it, 0643 float displayGamma, 0644 float displayNits, 0645 const KoColorSpace *colorSpace) 0646 { 0647 if (luma == 10) { 0648 return readInterleavedWithLuma<Arch, 10>(linearizePolicy, 0649 applyOOTF, 0650 channels, 0651 width, 0652 height, 0653 img, 0654 stride, 0655 it, 0656 displayGamma, 0657 displayNits, 0658 colorSpace); 0659 } else if (luma == 12) { 0660 return readInterleavedWithLuma<Arch, 12>(linearizePolicy, 0661 applyOOTF, 0662 channels, 0663 width, 0664 height, 0665 img, 0666 stride, 0667 it, 0668 displayGamma, 0669 displayNits, 0670 colorSpace); 0671 } else { 0672 return readInterleavedWithLuma<Arch, 16>(linearizePolicy, 0673 applyOOTF, 0674 channels, 0675 width, 0676 height, 0677 img, 0678 stride, 0679 it, 0680 displayGamma, 0681 displayNits, 0682 colorSpace); 0683 } 0684 } 0685 0686 template void 0687 readLayerImpl::create<xsimd::current_arch>(const int luma, 0688 LinearizePolicy linearizePolicy, 0689 bool applyOOTF, 0690 const int channels, 0691 const int width, 0692 const int height, 0693 const uint8_t *img, 0694 const int stride, 0695 KisHLineIteratorSP it, 0696 float displayGamma, 0697 float displayNits, 0698 const KoColorSpace *colorSpace); 0699 } // namespace HDR 0700 0701 namespace SDR 0702 { 0703 #if defined HAVE_XSIMD && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0704 template<typename Arch, 0705 LinearizePolicy linearizePolicy, 0706 bool applyOOTF, 0707 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0708 int> = 0> 0709 inline void linearize(float *pixelValues, 0710 const double *lCoef, 0711 float displayGamma, 0712 float displayNits) 0713 { 0714 using float_v = typename KoColorTransferFunctions<Arch>::float_v; 0715 if (linearizePolicy == LinearizePolicy::LinearFromPQ) { 0716 auto v = float_v::load_unaligned(pixelValues); 0717 KoColorTransferFunctions<Arch>::removeSmpte2048Curve(v); 0718 v.store_unaligned(pixelValues); 0719 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG) { 0720 auto v = float_v::load_unaligned(pixelValues); 0721 KoColorTransferFunctions<Arch>::removeHLGCurve(v); 0722 v.store_unaligned(pixelValues); 0723 } else if (linearizePolicy == LinearizePolicy::LinearFromSMPTE428) { 0724 auto v = float_v::load_unaligned(pixelValues); 0725 KoColorTransferFunctions<Arch>::removeSMPTE_ST_428Curve(v); 0726 v.store_unaligned(pixelValues); 0727 } 0728 0729 if (linearizePolicy == LinearizePolicy::KeepTheSame) { 0730 qSwap(pixelValues[0], pixelValues[2]); 0731 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG && applyOOTF) { 0732 applyHLGOOTF(pixelValues, lCoef, displayGamma, displayNits); 0733 } 0734 } 0735 #endif 0736 0737 template<typename Arch, 0738 LinearizePolicy linearizePolicy, 0739 bool applyOOTF, 0740 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0741 int> = 0> 0742 inline void linearize(float *pixelValues, 0743 const double *lCoef, 0744 float displayGamma, 0745 float displayNits) 0746 { 0747 if (linearizePolicy == LinearizePolicy::KeepTheSame) { 0748 qSwap(pixelValues[0], pixelValues[2]); 0749 } else if (linearizePolicy == LinearizePolicy::LinearFromHLG && applyOOTF) { 0750 applyHLGOOTF(pixelValues, lCoef, displayGamma, displayNits); 0751 } 0752 } 0753 0754 template<typename Arch, 0755 LinearizePolicy linearizePolicy, 0756 int channels, 0757 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0758 int> = 0> 0759 inline float value(const uint8_t *img, int stride, int x, int y, int ch) 0760 { 0761 uint8_t source = img[(y * stride) + (x * channels) + ch]; 0762 return float(source) / 255.0f; 0763 } 0764 0765 template<LinearizePolicy policy> 0766 inline float linearizeValueAsNeeded(float value) 0767 { 0768 if (policy == LinearizePolicy::LinearFromPQ) { 0769 return removeSmpte2048Curve(value); 0770 } else if (policy == LinearizePolicy::LinearFromHLG) { 0771 return removeHLGCurve(value); 0772 } else if (policy == LinearizePolicy::LinearFromSMPTE428) { 0773 return removeSMPTE_ST_428Curve(value); 0774 } 0775 return value; 0776 } 0777 0778 template<typename Arch, 0779 LinearizePolicy linearizePolicy, 0780 int channels, 0781 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0782 int> = 0> 0783 inline float value(const uint8_t *img, int stride, int x, int y, int ch) 0784 { 0785 uint8_t source = img[(y * stride) + (x * channels) + ch]; 0786 return linearizeValueAsNeeded<linearizePolicy>(float(source) / 255.0f); 0787 } 0788 0789 template<typename Arch, 0790 int channels, 0791 typename std::enable_if_t<std::is_same<Arch, xsimd::generic>::value, 0792 int> = 0> 0793 constexpr int bufferSize() 0794 { 0795 return channels; 0796 } 0797 0798 #if defined HAVE_XSIMD && !defined(XSIMD_NO_SUPPORTED_ARCHITECTURE) 0799 template<typename Arch, 0800 int channels, 0801 typename std::enable_if_t<!std::is_same<Arch, xsimd::generic>::value, 0802 int> = 0> 0803 constexpr int bufferSize() 0804 { 0805 return qMax<int>(channels, KoStreamedMath<Arch>::float_v::size); 0806 } 0807 #endif 0808 0809 template<typename Arch, 0810 LinearizePolicy linearizePolicy, 0811 bool applyOOTF, 0812 int channels> 0813 inline void readLayer(const int width, 0814 const int height, 0815 const uint8_t *img, 0816 const int stride, 0817 KisHLineIteratorSP it, 0818 float displayGamma, 0819 float displayNits, 0820 const KoColorSpace *colorSpace) 0821 { 0822 const QVector<qreal> lCoef{colorSpace->lumaCoefficients()}; 0823 QVector<float> pixelValues(bufferSize<Arch, channels>()); 0824 float *data = pixelValues.data(); 0825 0826 for (int y = 0; y < height; y++) { 0827 for (int x = 0; x < width; x++) { 0828 for (int i = 0; i < bufferSize<Arch, channels>(); i++) { 0829 data[i] = 0; 0830 } 0831 0832 for (int ch = 0; ch < channels; ch++) { 0833 if (ch == KoBgrU8Traits::alpha_pos) { 0834 data[ch] = 0835 value<Arch, LinearizePolicy::KeepTheSame, channels>( 0836 img, 0837 stride, 0838 x, 0839 y, 0840 ch); 0841 } else { 0842 data[ch] = value<Arch, linearizePolicy, channels>(img, 0843 stride, 0844 x, 0845 y, 0846 ch); 0847 } 0848 } 0849 0850 linearize<Arch, linearizePolicy, applyOOTF>(data, 0851 lCoef.constData(), 0852 displayGamma, 0853 displayNits); 0854 0855 KoBgrU8Traits::fromNormalisedChannelsValue(it->rawData(), 0856 pixelValues); 0857 0858 it->nextPixel(); 0859 } 0860 0861 it->nextRow(); 0862 } 0863 } 0864 0865 template<typename Arch, 0866 LinearizePolicy linearizePolicy, 0867 bool applyOOTF, 0868 typename... Args> 0869 inline auto readInterleavedWithAlpha(bool hasAlpha, Args &&...args) 0870 { 0871 if (hasAlpha) { 0872 return SDR::readLayer<Arch, linearizePolicy, applyOOTF, 4>( 0873 std::forward<Args>(args)...); 0874 } else { 0875 return SDR::readLayer<Arch, linearizePolicy, applyOOTF, 3>( 0876 std::forward<Args>(args)...); 0877 } 0878 } 0879 0880 template<typename Arch, LinearizePolicy linearizePolicy, typename... Args> 0881 inline auto readInterleavedWithPolicy(bool applyOOTF, Args &&...args) 0882 { 0883 if (applyOOTF) { 0884 return readInterleavedWithAlpha<Arch, linearizePolicy, true>( 0885 std::forward<Args>(args)...); 0886 } else { 0887 return readInterleavedWithAlpha<Arch, linearizePolicy, false>( 0888 std::forward<Args>(args)...); 0889 } 0890 } 0891 0892 template<typename Arch> 0893 void readLayerImpl::create(LinearizePolicy linearizePolicy, 0894 bool applyOOTF, 0895 bool hasAlpha, 0896 const int width, 0897 const int height, 0898 const uint8_t *img, 0899 const int stride, 0900 KisHLineIteratorSP it, 0901 float displayGamma, 0902 float displayNits, 0903 const KoColorSpace *colorSpace) 0904 { 0905 if (linearizePolicy == LinearizePolicy::LinearFromHLG) { 0906 return readInterleavedWithPolicy<Arch, LinearizePolicy::LinearFromHLG>(applyOOTF, 0907 hasAlpha, 0908 width, 0909 height, 0910 img, 0911 stride, 0912 it, 0913 displayGamma, 0914 displayNits, 0915 colorSpace); 0916 } else if (linearizePolicy == LinearizePolicy::LinearFromPQ) { 0917 return readInterleavedWithPolicy<Arch, LinearizePolicy::LinearFromPQ>(applyOOTF, 0918 hasAlpha, 0919 width, 0920 height, 0921 img, 0922 stride, 0923 it, 0924 displayGamma, 0925 displayNits, 0926 colorSpace); 0927 } else if (linearizePolicy == LinearizePolicy::LinearFromSMPTE428) { 0928 return readInterleavedWithPolicy<Arch, LinearizePolicy::LinearFromSMPTE428>(applyOOTF, 0929 hasAlpha, 0930 width, 0931 height, 0932 img, 0933 stride, 0934 it, 0935 displayGamma, 0936 displayNits, 0937 colorSpace); 0938 } else { 0939 return readInterleavedWithPolicy<Arch, LinearizePolicy::KeepTheSame>(applyOOTF, 0940 hasAlpha, 0941 width, 0942 height, 0943 img, 0944 stride, 0945 it, 0946 displayGamma, 0947 displayNits, 0948 colorSpace); 0949 } 0950 } 0951 0952 template void 0953 readLayerImpl::create<xsimd::current_arch>(LinearizePolicy linearizePolicy, 0954 bool applyOOTF, 0955 bool hasAlpha, 0956 const int width, 0957 const int height, 0958 const uint8_t *img, 0959 const int stride, 0960 KisHLineIteratorSP it, 0961 float displayGamma, 0962 float displayNits, 0963 const KoColorSpace *colorSpace); 0964 } // namespace SDR 0965 0966 #endif // XSIMD_UNIVERSAL_BUILD_PASS