1 /*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef ULTRAHDR_GAINMAPMATH_H
18 #define ULTRAHDR_GAINMAPMATH_H
19
20 #include <array>
21 #include <cmath>
22 #include <cstring>
23 #include <functional>
24
25 #include "ultrahdr_api.h"
26 #include "ultrahdr/ultrahdrcommon.h"
27 #include "ultrahdr/jpegr.h"
28
29 #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
30 #include <arm_neon.h>
31 #endif
32
33 #define USE_SRGB_INVOETF_LUT 1
34 #define USE_HLG_OETF_LUT 1
35 #define USE_PQ_OETF_LUT 1
36 #define USE_HLG_INVOETF_LUT 1
37 #define USE_PQ_INVOETF_LUT 1
38 #define USE_APPLY_GAIN_LUT 1
39
40 #define CLIP3(x, min, max) ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x)
41
42 namespace ultrahdr {
43
44 ////////////////////////////////////////////////////////////////////////////////
45 // Framework
46
47 // nominal {SDR, HLG, PQ} peak display luminance
48 // This aligns with the suggested default reference diffuse white from ISO/TS 22028-5
49 // sdr white
50 static const float kSdrWhiteNits = 203.0f;
51 // hlg peak white. 75% of hlg peak white maps to reference diffuse white
52 static const float kHlgMaxNits = 1000.0f;
53 // pq peak white. 58% of pq peak white maps to reference diffuse white
54 static const float kPqMaxNits = 10000.0f;
55
56 float getReferenceDisplayPeakLuminanceInNits(uhdr_color_transfer_t transfer);
57
58 // Image pixel descriptor
59 struct Color {
60 union {
61 struct {
62 float r;
63 float g;
64 float b;
65 };
66 struct {
67 float y;
68 float u;
69 float v;
70 };
71 };
72 };
73
74 typedef Color (*ColorTransformFn)(Color);
75 typedef float (*LuminanceFn)(Color);
76 typedef Color (*SceneToDisplayLuminanceFn)(Color, LuminanceFn);
77 typedef Color (*GetPixelFn)(uhdr_raw_image_t*, size_t, size_t);
78 typedef Color (*SamplePixelFn)(uhdr_raw_image_t*, size_t, size_t, size_t);
79 typedef void (*PutPixelFn)(uhdr_raw_image_t*, size_t, size_t, Color&);
80
81 inline Color operator+=(Color& lhs, const Color& rhs) {
82 lhs.r += rhs.r;
83 lhs.g += rhs.g;
84 lhs.b += rhs.b;
85 return lhs;
86 }
87
88 inline Color operator-=(Color& lhs, const Color& rhs) {
89 lhs.r -= rhs.r;
90 lhs.g -= rhs.g;
91 lhs.b -= rhs.b;
92 return lhs;
93 }
94
95 inline Color operator+(const Color& lhs, const Color& rhs) {
96 Color temp = lhs;
97 return temp += rhs;
98 }
99
100 inline Color operator-(const Color& lhs, const Color& rhs) {
101 Color temp = lhs;
102 return temp -= rhs;
103 }
104
105 inline Color operator+=(Color& lhs, const float rhs) {
106 lhs.r += rhs;
107 lhs.g += rhs;
108 lhs.b += rhs;
109 return lhs;
110 }
111
112 inline Color operator-=(Color& lhs, const float rhs) {
113 lhs.r -= rhs;
114 lhs.g -= rhs;
115 lhs.b -= rhs;
116 return lhs;
117 }
118
119 inline Color operator*=(Color& lhs, const float rhs) {
120 lhs.r *= rhs;
121 lhs.g *= rhs;
122 lhs.b *= rhs;
123 return lhs;
124 }
125
126 inline Color operator/=(Color& lhs, const float rhs) {
127 lhs.r /= rhs;
128 lhs.g /= rhs;
129 lhs.b /= rhs;
130 return lhs;
131 }
132
133 inline Color operator+(const Color& lhs, const float rhs) {
134 Color temp = lhs;
135 return temp += rhs;
136 }
137
138 inline Color operator-(const Color& lhs, const float rhs) {
139 Color temp = lhs;
140 return temp -= rhs;
141 }
142
143 inline Color operator*(const Color& lhs, const float rhs) {
144 Color temp = lhs;
145 return temp *= rhs;
146 }
147
148 inline Color operator/(const Color& lhs, const float rhs) {
149 Color temp = lhs;
150 return temp /= rhs;
151 }
152
153 ////////////////////////////////////////////////////////////////////////////////
154 // Float to Half and Half to Float conversions
155 union FloatUIntUnion {
156 uint32_t mUInt;
157 float mFloat;
158 };
159
160 // FIXME: The shift operations in this function are causing UBSAN (Undefined-shift) errors
161 // Precisely,
162 // runtime error: left shift of negative value -112
163 // runtime error : shift exponent 125 is too large for 32 - bit type 'uint32_t'(aka 'unsigned int')
164 // These need to be addressed. Until then, disable ubsan analysis for this function
165 UHDR_NO_SANITIZE_UNDEFINED
floatToHalf(float f)166 inline uint16_t floatToHalf(float f) {
167 FloatUIntUnion floatUnion;
168 floatUnion.mFloat = f;
169 // round-to-nearest-even: add last bit after truncated mantissa
170 const uint32_t b = floatUnion.mUInt + 0x00001000;
171
172 const int32_t e = (b & 0x7F800000) >> 23; // exponent
173 const uint32_t m = b & 0x007FFFFF; // mantissa
174
175 // sign : normalized : denormalized : saturate
176 return (b & 0x80000000) >> 16 | (e > 112) * ((((e - 112) << 10) & 0x7C00) | m >> 13) |
177 ((e < 113) & (e > 101)) * ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) |
178 (e > 143) * 0x7FFF;
179 }
180
181 // Taken from frameworks/base/libs/hwui/jni/android_graphics_ColorSpace.cpp
182
183 #if defined(__ANDROID__) // __fp16 is not defined on non-Android builds
halfToFloat(uint16_t bits)184 inline float halfToFloat(uint16_t bits) {
185 __fp16 h;
186 memcpy(&h, &bits, 2);
187 return (float)h;
188 }
189 #else
190 // This is Skia's implementation of SkHalfToFloat, which is
191 // based on Fabien Giesen's half_to_float_fast2()
192 // see https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
halfMantissa(uint16_t h)193 inline uint16_t halfMantissa(uint16_t h) { return h & 0x03ff; }
194
halfExponent(uint16_t h)195 inline uint16_t halfExponent(uint16_t h) { return (h >> 10) & 0x001f; }
196
halfSign(uint16_t h)197 inline uint16_t halfSign(uint16_t h) { return h >> 15; }
198
halfToFloat(uint16_t bits)199 inline float halfToFloat(uint16_t bits) {
200 static const FloatUIntUnion magic = {126 << 23};
201 FloatUIntUnion o;
202
203 if (halfExponent(bits) == 0) {
204 // Zero / Denormal
205 o.mUInt = magic.mUInt + halfMantissa(bits);
206 o.mFloat -= magic.mFloat;
207 } else {
208 // Set mantissa
209 o.mUInt = halfMantissa(bits) << 13;
210 // Set exponent
211 if (halfExponent(bits) == 0x1f) {
212 // Inf/NaN
213 o.mUInt |= (255 << 23);
214 } else {
215 o.mUInt |= ((127 - 15 + halfExponent(bits)) << 23);
216 }
217 }
218
219 // Set sign
220 o.mUInt |= (halfSign(bits) << 31);
221 return o.mFloat;
222 }
223 #endif // defined(__ANDROID__)
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // Use Shepard's method for inverse distance weighting. For more information:
227 // en.wikipedia.org/wiki/Inverse_distance_weighting#Shepard's_method
228 struct ShepardsIDW {
ShepardsIDWShepardsIDW229 ShepardsIDW(int mapScaleFactor) : mMapScaleFactor{mapScaleFactor} {
230 const int size = mMapScaleFactor * mMapScaleFactor * 4;
231 mWeights = new float[size];
232 mWeightsNR = new float[size];
233 mWeightsNB = new float[size];
234 mWeightsC = new float[size];
235 fillShepardsIDW(mWeights, 1, 1);
236 fillShepardsIDW(mWeightsNR, 0, 1);
237 fillShepardsIDW(mWeightsNB, 1, 0);
238 fillShepardsIDW(mWeightsC, 0, 0);
239 }
240
~ShepardsIDWShepardsIDW241 ~ShepardsIDW() {
242 delete[] mWeights;
243 delete[] mWeightsNR;
244 delete[] mWeightsNB;
245 delete[] mWeightsC;
246 }
247
248 int mMapScaleFactor;
249 // curr, right, bottom, bottom-right are used during interpolation. hence table weight size is 4.
250 float* mWeights; // default
251 float* mWeightsNR; // no right
252 float* mWeightsNB; // no bottom
253 float* mWeightsC; // no right & bottom
254
255 float euclideanDistance(float x1, float x2, float y1, float y2);
256 void fillShepardsIDW(float* weights, int incR, int incB);
257 };
258
259 ////////////////////////////////////////////////////////////////////////////////
260 // sRGB transformations.
261 // for all functions range in and out [0.0, 1.0]
262
263 // sRGB luminance
264 float srgbLuminance(Color e);
265
266 // sRGB rgb <-> yuv conversion
267 Color srgbRgbToYuv(Color e_gamma);
268 Color srgbYuvToRgb(Color e_gamma);
269
270 // sRGB eotf
271 float srgbInvOetf(float e_gamma);
272 Color srgbInvOetf(Color e_gamma);
273 float srgbInvOetfLUT(float e_gamma);
274 Color srgbInvOetfLUT(Color e_gamma);
275
276 // sRGB oetf
277 float srgbOetf(float e);
278 Color srgbOetf(Color e);
279
280 constexpr int32_t kSrgbInvOETFPrecision = 10;
281 constexpr int32_t kSrgbInvOETFNumEntries = 1 << kSrgbInvOETFPrecision;
282
283 ////////////////////////////////////////////////////////////////////////////////
284 // Display-P3 transformations
285 // for all functions range in and out [0.0, 1.0]
286
287 // DispP3 luminance
288 float p3Luminance(Color e);
289
290 // DispP3 rgb <-> yuv conversion
291 Color p3RgbToYuv(Color e_gamma);
292 Color p3YuvToRgb(Color e_gamma);
293
294 ////////////////////////////////////////////////////////////////////////////////
295 // BT.2100 transformations
296 // for all functions range in and out [0.0, 1.0]
297
298 // bt2100 luminance
299 float bt2100Luminance(Color e);
300
301 // bt2100 rgb <-> yuv conversion
302 Color bt2100RgbToYuv(Color e_gamma);
303 Color bt2100YuvToRgb(Color e_gamma);
304
305 // hlg oetf (normalized)
306 float hlgOetf(float e);
307 Color hlgOetf(Color e);
308 float hlgOetfLUT(float e);
309 Color hlgOetfLUT(Color e);
310
311 constexpr int32_t kHlgOETFPrecision = 16;
312 constexpr int32_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
313
314 // hlg inverse oetf (normalized)
315 float hlgInvOetf(float e_gamma);
316 Color hlgInvOetf(Color e_gamma);
317 float hlgInvOetfLUT(float e_gamma);
318 Color hlgInvOetfLUT(Color e_gamma);
319
320 constexpr int32_t kHlgInvOETFPrecision = 12;
321 constexpr int32_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
322
323 // hlg ootf (normalized)
324 Color hlgOotf(Color e, LuminanceFn luminance);
325 Color hlgOotfApprox(Color e, [[maybe_unused]] LuminanceFn luminance);
identityOotf(Color e,LuminanceFn)326 inline Color identityOotf(Color e, [[maybe_unused]] LuminanceFn) { return e; }
327
328 // hlg inverse ootf (normalized)
329 Color hlgInverseOotf(Color e, LuminanceFn luminance);
330 Color hlgInverseOotfApprox(Color e);
331
332 // pq oetf
333 float pqOetf(float e);
334 Color pqOetf(Color e);
335 float pqOetfLUT(float e);
336 Color pqOetfLUT(Color e);
337
338 constexpr int32_t kPqOETFPrecision = 16;
339 constexpr int32_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
340
341 // pq inverse oetf
342 float pqInvOetf(float e_gamma);
343 Color pqInvOetf(Color e_gamma);
344 float pqInvOetfLUT(float e_gamma);
345 Color pqInvOetfLUT(Color e_gamma);
346
347 constexpr int32_t kPqInvOETFPrecision = 12;
348 constexpr int32_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
349
350 // util class to prepare look up tables for oetf/eotf functions
351 class LookUpTable {
352 public:
LookUpTable(size_t numEntries,std::function<float (float)> computeFunc)353 LookUpTable(size_t numEntries, std::function<float(float)> computeFunc) {
354 for (size_t idx = 0; idx < numEntries; idx++) {
355 float value = static_cast<float>(idx) / static_cast<float>(numEntries - 1);
356 table.push_back(computeFunc(value));
357 }
358 }
getTable()359 const std::vector<float>& getTable() const { return table; }
360
361 private:
362 std::vector<float> table;
363 };
364
365 ////////////////////////////////////////////////////////////////////////////////
366 // Color access functions
367
368 // Get pixel from the image at the provided location.
369 Color getYuv444Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
370 Color getYuv422Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
371 Color getYuv420Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
372 Color getYuv400Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
373 Color getP010Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
374 Color getYuv444Pixel10bit(uhdr_raw_image_t* image, size_t x, size_t y);
375 Color getRgb888Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
376 Color getRgba8888Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
377 Color getRgba1010102Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
378 Color getRgbaF16Pixel(uhdr_raw_image_t* image, size_t x, size_t y);
379
380 // Sample the image at the provided location, with a weighting based on nearby pixels and the map
381 // scale factor.
382 Color sampleYuv444(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
383 Color sampleYuv422(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
384 Color sampleYuv420(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
385 Color sampleP010(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y);
386 Color sampleYuv44410bit(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
387 Color sampleRgba8888(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
388 Color sampleRgba1010102(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
389 Color sampleRgbaF16(uhdr_raw_image_t* image, size_t map_scale_factor, size_t x, size_t y);
390
391 // Put pixel in the image at the provided location.
392 void putRgba8888Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
393 void putRgb888Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
394 void putYuv400Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
395 void putYuv444Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel);
396
397 ////////////////////////////////////////////////////////////////////////////////
398 // Color space conversions
399
400 // color gamut conversion (rgb) functions
401 extern const std::array<float, 9> kBt709ToP3;
402 extern const std::array<float, 9> kBt709ToBt2100;
403 extern const std::array<float, 9> kP3ToBt709;
404 extern const std::array<float, 9> kP3ToBt2100;
405 extern const std::array<float, 9> kBt2100ToBt709;
406 extern const std::array<float, 9> kBt2100ToP3;
407
identityConversion(Color e)408 inline Color identityConversion(Color e) { return e; }
409 Color bt709ToP3(Color e);
410 Color bt709ToBt2100(Color e);
411 Color p3ToBt709(Color e);
412 Color p3ToBt2100(Color e);
413 Color bt2100ToBt709(Color e);
414 Color bt2100ToP3(Color e);
415
416 // convert between yuv encodings
417 extern const std::array<float, 9> kYuvBt709ToBt601;
418 extern const std::array<float, 9> kYuvBt709ToBt2100;
419 extern const std::array<float, 9> kYuvBt601ToBt709;
420 extern const std::array<float, 9> kYuvBt601ToBt2100;
421 extern const std::array<float, 9> kYuvBt2100ToBt709;
422 extern const std::array<float, 9> kYuvBt2100ToBt601;
423
424 #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
425
426 extern const int16_t kYuv709To601_coeffs_neon[8];
427 extern const int16_t kYuv709To2100_coeffs_neon[8];
428 extern const int16_t kYuv601To709_coeffs_neon[8];
429 extern const int16_t kYuv601To2100_coeffs_neon[8];
430 extern const int16_t kYuv2100To709_coeffs_neon[8];
431 extern const int16_t kYuv2100To601_coeffs_neon[8];
432
433 /*
434 * The Y values are provided at half the width of U & V values to allow use of the widening
435 * arithmetic instructions.
436 */
437 int16x8x3_t yuvConversion_neon(uint8x8_t y, int16x8_t u, int16x8_t v, int16x8_t coeffs);
438
439 void transformYuv420_neon(uhdr_raw_image_t* image, const int16_t* coeffs_ptr);
440
441 void transformYuv444_neon(uhdr_raw_image_t* image, const int16_t* coeffs_ptr);
442
443 uhdr_error_info_t convertYuv_neon(uhdr_raw_image_t* image, uhdr_color_gamut_t src_encoding,
444 uhdr_color_gamut_t dst_encoding);
445 #endif
446
447 // Performs a color gamut transformation on an yuv image.
448 Color yuvColorGamutConversion(Color e_gamma, const std::array<float, 9>& coeffs);
449 void transformYuv420(uhdr_raw_image_t* image, const std::array<float, 9>& coeffs);
450 void transformYuv444(uhdr_raw_image_t* image, const std::array<float, 9>& coeffs);
451
452 ////////////////////////////////////////////////////////////////////////////////
453 // Gain map calculations
454
455 constexpr int32_t kGainFactorPrecision = 10;
456 constexpr int32_t kGainFactorNumEntries = 1 << kGainFactorPrecision;
457
458 struct GainLUT {
GainLUTGainLUT459 GainLUT(uhdr_gainmap_metadata_ext_t* metadata, float gainmapWeight) {
460 bool isSingleChannel = metadata->are_all_channels_identical();
461 for (int i = 0; i < (isSingleChannel ? 1 : 3); i++) {
462 mGainTable[i] = memory[i] = new float[kGainFactorNumEntries];
463 this->mGammaInv[i] = 1.0f / metadata->gamma[i];
464 for (int32_t idx = 0; idx < kGainFactorNumEntries; idx++) {
465 float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
466 float logBoost = log2(metadata->min_content_boost[i]) * (1.0f - value) +
467 log2(metadata->max_content_boost[i]) * value;
468 mGainTable[i][idx] = exp2(logBoost * gainmapWeight);
469 }
470 }
471 if (isSingleChannel) {
472 memory[1] = memory[2] = nullptr;
473 mGammaInv[1] = mGammaInv[2] = mGammaInv[0];
474 mGainTable[1] = mGainTable[2] = mGainTable[0];
475 }
476 }
477
GainLUTGainLUT478 GainLUT(uhdr_gainmap_metadata_ext_t* metadata) : GainLUT(metadata, 1.0f) {}
479
~GainLUTGainLUT480 ~GainLUT() {
481 for (int i = 0; i < 3; i++) {
482 if (memory[i]) {
483 delete[] memory[i];
484 memory[i] = nullptr;
485 }
486 }
487 }
488
getGainFactorGainLUT489 float getGainFactor(float gain, int index) {
490 if (mGammaInv[index] != 1.0f) gain = pow(gain, mGammaInv[index]);
491 int32_t idx = static_cast<int32_t>(gain * (kGainFactorNumEntries - 1) + 0.5);
492 // TODO() : Remove once conversion modules have appropriate clamping in place
493 idx = CLIP3(idx, 0, kGainFactorNumEntries - 1);
494 return mGainTable[index][idx];
495 }
496
497 private:
498 float* memory[3]{};
499 float* mGainTable[3]{};
500 float mGammaInv[3]{};
501 };
502
503 /*
504 * Calculate the 8-bit unsigned integer gain value for the given SDR and HDR
505 * luminances in linear space and gainmap metadata fields.
506 */
507 uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metadata, int index);
508 uint8_t encodeGain(float y_sdr, float y_hdr, uhdr_gainmap_metadata_ext_t* metadata,
509 float log2MinContentBoost, float log2MaxContentBoost, int index);
510 float computeGain(float sdr, float hdr);
511 uint8_t affineMapGain(float gainlog2, float mingainlog2, float maxgainlog2, float gamma);
512
513 /*
514 * Calculates the linear luminance in nits after applying the given gain
515 * value, with the given hdr ratio, to the given sdr input in the range [0, 1].
516 */
517 Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata);
518 Color applyGain(Color e, float gain, uhdr_gainmap_metadata_ext_t* metadata, float gainmapWeight);
519 Color applyGainLUT(Color e, float gain, GainLUT& gainLUT, uhdr_gainmap_metadata_ext_t* metadata);
520
521 /*
522 * Apply gain in R, G and B channels, with the given hdr ratio, to the given sdr input
523 * in the range [0, 1].
524 */
525 Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata);
526 Color applyGain(Color e, Color gain, uhdr_gainmap_metadata_ext_t* metadata, float gainmapWeight);
527 Color applyGainLUT(Color e, Color gain, GainLUT& gainLUT, uhdr_gainmap_metadata_ext_t* metadata);
528
529 /*
530 * Sample the gain value for the map from a given x,y coordinate on a scale
531 * that is map scale factor larger than the map size.
532 */
533 float sampleMap(uhdr_raw_image_t* map, float map_scale_factor, size_t x, size_t y);
534 float sampleMap(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y,
535 ShepardsIDW& weightTables);
536 Color sampleMap3Channel(uhdr_raw_image_t* map, float map_scale_factor, size_t x, size_t y,
537 bool has_alpha);
538 Color sampleMap3Channel(uhdr_raw_image_t* map, size_t map_scale_factor, size_t x, size_t y,
539 ShepardsIDW& weightTables, bool has_alpha);
540
541 ////////////////////////////////////////////////////////////////////////////////
542 // function selectors
543
544 ColorTransformFn getGamutConversionFn(uhdr_color_gamut_t dst_gamut, uhdr_color_gamut_t src_gamut);
545 ColorTransformFn getYuvToRgbFn(uhdr_color_gamut_t gamut);
546 LuminanceFn getLuminanceFn(uhdr_color_gamut_t gamut);
547 ColorTransformFn getInverseOetfFn(uhdr_color_transfer_t transfer);
548 SceneToDisplayLuminanceFn getOotfFn(uhdr_color_transfer_t transfer);
549 GetPixelFn getPixelFn(uhdr_img_fmt_t format);
550 SamplePixelFn getSamplePixelFn(uhdr_img_fmt_t format);
551 PutPixelFn putPixelFn(uhdr_img_fmt_t format);
552
553 ////////////////////////////////////////////////////////////////////////////////
554 // common utils
555 static const float kHdrOffset = 1e-7f;
556 static const float kSdrOffset = 1e-7f;
557
clipNegatives(float value)558 static inline float clipNegatives(float value) { return (value < 0.0f) ? 0.0f : value; }
559
clipNegatives(Color e)560 static inline Color clipNegatives(Color e) {
561 return {{{clipNegatives(e.r), clipNegatives(e.g), clipNegatives(e.b)}}};
562 }
563
564 // maximum limit of normalized pixel value in float representation
565 static const float kMaxPixelFloat = 1.0f;
566
clampPixelFloat(float value)567 static inline float clampPixelFloat(float value) {
568 return (value < 0.0f) ? 0.0f : (value > kMaxPixelFloat) ? kMaxPixelFloat : value;
569 }
570
clampPixelFloat(Color e)571 static inline Color clampPixelFloat(Color e) {
572 return {{{clampPixelFloat(e.r), clampPixelFloat(e.g), clampPixelFloat(e.b)}}};
573 }
574
575 // maximum limit of pixel value for linear hdr intent raw resource
576 static const float kMaxPixelFloatHdrLinear = 10000.0f / 203.0f;
577
clampPixelFloatLinear(float value)578 static inline float clampPixelFloatLinear(float value) {
579 return CLIP3(value, 0.0f, kMaxPixelFloatHdrLinear);
580 }
581
clampPixelFloatLinear(Color e)582 static inline Color clampPixelFloatLinear(Color e) {
583 return {{{clampPixelFloatLinear(e.r), clampPixelFloatLinear(e.g), clampPixelFloatLinear(e.b)}}};
584 }
585
mapNonFiniteFloats(float val)586 static float mapNonFiniteFloats(float val) {
587 if (std::isinf(val)) {
588 return val > 0 ? kMaxPixelFloatHdrLinear : 0.0f;
589 }
590 // nan
591 return 0.0f;
592 }
593
sanitizePixel(Color e)594 static inline Color sanitizePixel(Color e) {
595 float r = std::isfinite(e.r) ? clampPixelFloatLinear(e.r) : mapNonFiniteFloats(e.r);
596 float g = std::isfinite(e.g) ? clampPixelFloatLinear(e.g) : mapNonFiniteFloats(e.g);
597 float b = std::isfinite(e.b) ? clampPixelFloatLinear(e.b) : mapNonFiniteFloats(e.b);
598 return {{{r, g, b}}};
599 }
600
601 bool isPixelFormatRgb(uhdr_img_fmt_t format);
602
603 uint32_t colorToRgba1010102(Color e_gamma);
604 uint64_t colorToRgbaF16(Color e_gamma);
605
606 std::unique_ptr<uhdr_raw_image_ext_t> copy_raw_image(uhdr_raw_image_t* src);
607
608 uhdr_error_info_t copy_raw_image(uhdr_raw_image_t* src, uhdr_raw_image_t* dst);
609
610 std::unique_ptr<uhdr_raw_image_ext_t> convert_raw_input_to_ycbcr(
611 uhdr_raw_image_t* src, bool chroma_sampling_enabled = false);
612
613 #if (defined(UHDR_ENABLE_INTRINSICS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)))
614 std::unique_ptr<uhdr_raw_image_ext_t> convert_raw_input_to_ycbcr_neon(uhdr_raw_image_t* src);
615 #endif
616
617 bool floatToSignedFraction(float v, int32_t* numerator, uint32_t* denominator);
618 bool floatToUnsignedFraction(float v, uint32_t* numerator, uint32_t* denominator);
619
620 } // namespace ultrahdr
621
622 #endif // ULTRAHDR_GAINMAPMATH_H
623