xref: /aosp_15_r20/frameworks/base/native/android/display_luts.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "DisplayLuts"
17*d57664e9SAndroid Build Coastguard Worker 
18*d57664e9SAndroid Build Coastguard Worker #include <android/display_luts.h>
19*d57664e9SAndroid Build Coastguard Worker #include <display_luts_private.h>
20*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
21*d57664e9SAndroid Build Coastguard Worker 
22*d57664e9SAndroid Build Coastguard Worker #include <cmath>
23*d57664e9SAndroid Build Coastguard Worker 
24*d57664e9SAndroid Build Coastguard Worker #define ADISPLAYLUTS_BUFFER_LENGTH_LIMIT (100000)
25*d57664e9SAndroid Build Coastguard Worker 
26*d57664e9SAndroid Build Coastguard Worker #define CHECK_NOT_NULL(name) \
27*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
28*d57664e9SAndroid Build Coastguard Worker 
ADisplayLutsEntry_createEntry(float * buffer,int32_t length,ADisplayLuts_Dimension dimension,ADisplayLuts_SamplingKey key)29*d57664e9SAndroid Build Coastguard Worker ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length,
30*d57664e9SAndroid Build Coastguard Worker                                                  ADisplayLuts_Dimension dimension,
31*d57664e9SAndroid Build Coastguard Worker                                                  ADisplayLuts_SamplingKey key) {
32*d57664e9SAndroid Build Coastguard Worker     CHECK_NOT_NULL(buffer);
33*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(length >= ADISPLAYLUTS_BUFFER_LENGTH_LIMIT,
34*d57664e9SAndroid Build Coastguard Worker                         "the lut raw buffer length is too big to handle");
35*d57664e9SAndroid Build Coastguard Worker     if (dimension != ADISPLAYLUTS_ONE_DIMENSION && dimension != ADISPLAYLUTS_THREE_DIMENSION) {
36*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("the lut dimension is be either 1 or 3");
37*d57664e9SAndroid Build Coastguard Worker     }
38*d57664e9SAndroid Build Coastguard Worker     int32_t size = 0;
39*d57664e9SAndroid Build Coastguard Worker     if (dimension == ADISPLAYLUTS_THREE_DIMENSION) {
40*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(length % 3 != 0, "the 3d lut raw buffer is not divisible by 3");
41*d57664e9SAndroid Build Coastguard Worker         int32_t lengthPerChannel = length / 3;
42*d57664e9SAndroid Build Coastguard Worker         float sizeForDim = std::cbrt(static_cast<float>(lengthPerChannel));
43*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(sizeForDim != (int)(sizeForDim),
44*d57664e9SAndroid Build Coastguard Worker                             "the 3d lut buffer length is incorrect");
45*d57664e9SAndroid Build Coastguard Worker         size = (int)sizeForDim;
46*d57664e9SAndroid Build Coastguard Worker     } else {
47*d57664e9SAndroid Build Coastguard Worker         size = length;
48*d57664e9SAndroid Build Coastguard Worker     }
49*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(size < 2, "the lut size for each dimension is too small");
50*d57664e9SAndroid Build Coastguard Worker 
51*d57664e9SAndroid Build Coastguard Worker     ADisplayLutsEntry* entry = new ADisplayLutsEntry();
52*d57664e9SAndroid Build Coastguard Worker     entry->buffer.data.resize(length);
53*d57664e9SAndroid Build Coastguard Worker     std::copy(buffer, buffer + length, entry->buffer.data.begin());
54*d57664e9SAndroid Build Coastguard Worker     entry->properties = {dimension, size, key};
55*d57664e9SAndroid Build Coastguard Worker 
56*d57664e9SAndroid Build Coastguard Worker     entry->incStrong((void*)ADisplayLutsEntry_createEntry);
57*d57664e9SAndroid Build Coastguard Worker     return static_cast<ADisplayLutsEntry*>(entry);
58*d57664e9SAndroid Build Coastguard Worker }
59*d57664e9SAndroid Build Coastguard Worker 
ADisplayLutsEntry_destroy(ADisplayLutsEntry * entry)60*d57664e9SAndroid Build Coastguard Worker void ADisplayLutsEntry_destroy(ADisplayLutsEntry* entry) {
61*d57664e9SAndroid Build Coastguard Worker     if (entry != NULL) {
62*d57664e9SAndroid Build Coastguard Worker         entry->decStrong((void*)ADisplayLutsEntry_createEntry);
63*d57664e9SAndroid Build Coastguard Worker     }
64*d57664e9SAndroid Build Coastguard Worker }
65*d57664e9SAndroid Build Coastguard Worker 
ADisplayLutsEntry_getDimension(const ADisplayLutsEntry * entry)66*d57664e9SAndroid Build Coastguard Worker ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* entry) {
67*d57664e9SAndroid Build Coastguard Worker     CHECK_NOT_NULL(entry);
68*d57664e9SAndroid Build Coastguard Worker     return entry->properties.dimension;
69*d57664e9SAndroid Build Coastguard Worker }
70*d57664e9SAndroid Build Coastguard Worker 
ADisplayLutsEntry_getSize(const ADisplayLutsEntry * entry)71*d57664e9SAndroid Build Coastguard Worker int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) {
72*d57664e9SAndroid Build Coastguard Worker     CHECK_NOT_NULL(entry);
73*d57664e9SAndroid Build Coastguard Worker     return entry->properties.size;
74*d57664e9SAndroid Build Coastguard Worker }
75*d57664e9SAndroid Build Coastguard Worker 
ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry * entry)76*d57664e9SAndroid Build Coastguard Worker ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* entry) {
77*d57664e9SAndroid Build Coastguard Worker     CHECK_NOT_NULL(entry);
78*d57664e9SAndroid Build Coastguard Worker     return entry->properties.samplingKey;
79*d57664e9SAndroid Build Coastguard Worker }
80*d57664e9SAndroid Build Coastguard Worker 
ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry * _Nonnull entry)81*d57664e9SAndroid Build Coastguard Worker const float* ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry) {
82*d57664e9SAndroid Build Coastguard Worker     CHECK_NOT_NULL(entry);
83*d57664e9SAndroid Build Coastguard Worker     return entry->buffer.data.data();
84*d57664e9SAndroid Build Coastguard Worker }
85*d57664e9SAndroid Build Coastguard Worker 
ADisplayLuts_create()86*d57664e9SAndroid Build Coastguard Worker ADisplayLuts* ADisplayLuts_create() {
87*d57664e9SAndroid Build Coastguard Worker     ADisplayLuts* luts = new ADisplayLuts();
88*d57664e9SAndroid Build Coastguard Worker     if (luts == NULL) {
89*d57664e9SAndroid Build Coastguard Worker         delete luts;
90*d57664e9SAndroid Build Coastguard Worker         return NULL;
91*d57664e9SAndroid Build Coastguard Worker     }
92*d57664e9SAndroid Build Coastguard Worker     luts->incStrong((void*)ADisplayLuts_create);
93*d57664e9SAndroid Build Coastguard Worker     return static_cast<ADisplayLuts*>(luts);
94*d57664e9SAndroid Build Coastguard Worker }
95*d57664e9SAndroid Build Coastguard Worker 
ADisplayLuts_clearLuts(ADisplayLuts * luts)96*d57664e9SAndroid Build Coastguard Worker void ADisplayLuts_clearLuts(ADisplayLuts* luts) {
97*d57664e9SAndroid Build Coastguard Worker     for (auto& entry : luts->entries) {
98*d57664e9SAndroid Build Coastguard Worker         entry->decStrong((void*)ADisplayLuts_setEntries); // Decrement ref count
99*d57664e9SAndroid Build Coastguard Worker     }
100*d57664e9SAndroid Build Coastguard Worker     luts->entries.clear();
101*d57664e9SAndroid Build Coastguard Worker     luts->offsets.clear();
102*d57664e9SAndroid Build Coastguard Worker     luts->totalBufferSize = 0;
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker 
ADisplayLuts_destroy(ADisplayLuts * luts)105*d57664e9SAndroid Build Coastguard Worker void ADisplayLuts_destroy(ADisplayLuts* luts) {
106*d57664e9SAndroid Build Coastguard Worker     if (luts != NULL) {
107*d57664e9SAndroid Build Coastguard Worker         ADisplayLuts_clearLuts(luts);
108*d57664e9SAndroid Build Coastguard Worker         luts->decStrong((void*)ADisplayLuts_create);
109*d57664e9SAndroid Build Coastguard Worker     }
110*d57664e9SAndroid Build Coastguard Worker }
111*d57664e9SAndroid Build Coastguard Worker 
ADisplayLuts_setEntries(ADisplayLuts * luts,ADisplayLutsEntry ** entries,int32_t numEntries)112*d57664e9SAndroid Build Coastguard Worker void ADisplayLuts_setEntries(ADisplayLuts* luts, ADisplayLutsEntry** entries, int32_t numEntries) {
113*d57664e9SAndroid Build Coastguard Worker     CHECK_NOT_NULL(luts);
114*d57664e9SAndroid Build Coastguard Worker     // always clear the previously set lut(s)
115*d57664e9SAndroid Build Coastguard Worker     ADisplayLuts_clearLuts(luts);
116*d57664e9SAndroid Build Coastguard Worker 
117*d57664e9SAndroid Build Coastguard Worker     // do nothing
118*d57664e9SAndroid Build Coastguard Worker     if (!entries || numEntries == 0) {
119*d57664e9SAndroid Build Coastguard Worker         return;
120*d57664e9SAndroid Build Coastguard Worker     }
121*d57664e9SAndroid Build Coastguard Worker 
122*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(numEntries > 2, "The number of entries should be not over 2!");
123*d57664e9SAndroid Build Coastguard Worker     if (numEntries == 2 && entries[0]->properties.dimension != ADISPLAYLUTS_ONE_DIMENSION &&
124*d57664e9SAndroid Build Coastguard Worker         entries[1]->properties.dimension != ADISPLAYLUTS_THREE_DIMENSION) {
125*d57664e9SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("The entries should be 1D and 3D in order!");
126*d57664e9SAndroid Build Coastguard Worker     }
127*d57664e9SAndroid Build Coastguard Worker 
128*d57664e9SAndroid Build Coastguard Worker     luts->offsets.reserve(numEntries);
129*d57664e9SAndroid Build Coastguard Worker     luts->entries.reserve(numEntries);
130*d57664e9SAndroid Build Coastguard Worker     for (int32_t i = 0; i < numEntries; i++) {
131*d57664e9SAndroid Build Coastguard Worker         luts->offsets.emplace_back(luts->totalBufferSize);
132*d57664e9SAndroid Build Coastguard Worker         luts->totalBufferSize += entries[i]->buffer.data.size();
133*d57664e9SAndroid Build Coastguard Worker         luts->entries.emplace_back(entries[i]);
134*d57664e9SAndroid Build Coastguard Worker         luts->entries.back()->incStrong((void*)ADisplayLuts_setEntries);
135*d57664e9SAndroid Build Coastguard Worker     }
136*d57664e9SAndroid Build Coastguard Worker }