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