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