/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "DisplayLuts" #include #include #include #include #define ADISPLAYLUTS_BUFFER_LENGTH_LIMIT (100000) #define CHECK_NOT_NULL(name) \ LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument"); ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length, ADisplayLuts_Dimension dimension, ADisplayLuts_SamplingKey key) { CHECK_NOT_NULL(buffer); LOG_ALWAYS_FATAL_IF(length >= ADISPLAYLUTS_BUFFER_LENGTH_LIMIT, "the lut raw buffer length is too big to handle"); if (dimension != ADISPLAYLUTS_ONE_DIMENSION && dimension != ADISPLAYLUTS_THREE_DIMENSION) { LOG_ALWAYS_FATAL("the lut dimension is be either 1 or 3"); } int32_t size = 0; if (dimension == ADISPLAYLUTS_THREE_DIMENSION) { LOG_ALWAYS_FATAL_IF(length % 3 != 0, "the 3d lut raw buffer is not divisible by 3"); int32_t lengthPerChannel = length / 3; float sizeForDim = std::cbrt(static_cast(lengthPerChannel)); LOG_ALWAYS_FATAL_IF(sizeForDim != (int)(sizeForDim), "the 3d lut buffer length is incorrect"); size = (int)sizeForDim; } else { size = length; } LOG_ALWAYS_FATAL_IF(size < 2, "the lut size for each dimension is too small"); ADisplayLutsEntry* entry = new ADisplayLutsEntry(); entry->buffer.data.resize(length); std::copy(buffer, buffer + length, entry->buffer.data.begin()); entry->properties = {dimension, size, key}; entry->incStrong((void*)ADisplayLutsEntry_createEntry); return static_cast(entry); } void ADisplayLutsEntry_destroy(ADisplayLutsEntry* entry) { if (entry != NULL) { entry->decStrong((void*)ADisplayLutsEntry_createEntry); } } ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* entry) { CHECK_NOT_NULL(entry); return entry->properties.dimension; } int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) { CHECK_NOT_NULL(entry); return entry->properties.size; } ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* entry) { CHECK_NOT_NULL(entry); return entry->properties.samplingKey; } const float* ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry) { CHECK_NOT_NULL(entry); return entry->buffer.data.data(); } ADisplayLuts* ADisplayLuts_create() { ADisplayLuts* luts = new ADisplayLuts(); if (luts == NULL) { delete luts; return NULL; } luts->incStrong((void*)ADisplayLuts_create); return static_cast(luts); } void ADisplayLuts_clearLuts(ADisplayLuts* luts) { for (auto& entry : luts->entries) { entry->decStrong((void*)ADisplayLuts_setEntries); // Decrement ref count } luts->entries.clear(); luts->offsets.clear(); luts->totalBufferSize = 0; } void ADisplayLuts_destroy(ADisplayLuts* luts) { if (luts != NULL) { ADisplayLuts_clearLuts(luts); luts->decStrong((void*)ADisplayLuts_create); } } void ADisplayLuts_setEntries(ADisplayLuts* luts, ADisplayLutsEntry** entries, int32_t numEntries) { CHECK_NOT_NULL(luts); // always clear the previously set lut(s) ADisplayLuts_clearLuts(luts); // do nothing if (!entries || numEntries == 0) { return; } LOG_ALWAYS_FATAL_IF(numEntries > 2, "The number of entries should be not over 2!"); if (numEntries == 2 && entries[0]->properties.dimension != ADISPLAYLUTS_ONE_DIMENSION && entries[1]->properties.dimension != ADISPLAYLUTS_THREE_DIMENSION) { LOG_ALWAYS_FATAL("The entries should be 1D and 3D in order!"); } luts->offsets.reserve(numEntries); luts->entries.reserve(numEntries); for (int32_t i = 0; i < numEntries; i++) { luts->offsets.emplace_back(luts->totalBufferSize); luts->totalBufferSize += entries[i]->buffer.data.size(); luts->entries.emplace_back(entries[i]); luts->entries.back()->incStrong((void*)ADisplayLuts_setEntries); } }