diff options
author | 2024-11-04 11:45:23 -0800 | |
---|---|---|
committer | 2024-11-20 13:24:20 -0800 | |
commit | 176e379d58764acd0d543ac880c9fa8bc3419aee (patch) | |
tree | ea0dc41a535f38d1fa27ad99dba29530124bdc17 | |
parent | 6dadb742dc8e1b4221bc3ed8fe582cd2c33b5891 (diff) |
[Lut NDK] Define ASurfaceTransaction_setLuts API
- And also ADisplayLuts, ADisplayLutsEntry struct and correspsonding NDK
APIs.
Bug: 377329333
Test: android.view.surfacecontrol.cts.ASurfaceControlTest#testSurfaceTransaction_setLuts_*
Flag: EXEMPT NDK
Change-Id: I23eaef36725a0d63ceba557811812b82b157f83e
-rw-r--r-- | native/android/Android.bp | 1 | ||||
-rw-r--r-- | native/android/display_luts.cpp | 135 | ||||
-rw-r--r-- | native/android/libandroid.map.txt | 10 | ||||
-rw-r--r-- | native/android/surface_control.cpp | 63 |
4 files changed, 209 insertions, 0 deletions
diff --git a/native/android/Android.bp b/native/android/Android.bp index da29c49f9d7b..cd6de5a5c8f0 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -55,6 +55,7 @@ cc_library_shared { "surface_control_input_receiver.cpp", "choreographer.cpp", "configuration.cpp", + "display_luts.cpp", "dynamic_instrumentation_manager.cpp", "hardware_buffer_jni.cpp", "input.cpp", diff --git a/native/android/display_luts.cpp b/native/android/display_luts.cpp new file mode 100644 index 000000000000..179a32bd1c03 --- /dev/null +++ b/native/android/display_luts.cpp @@ -0,0 +1,135 @@ +/* + * 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 <android/display_luts.h> +#include <display_luts_private.h> +#include <utils/Log.h> + +#include <cmath> + +#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, int32_t dimension, + int32_t 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<float>(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<ADisplayLutsEntry*>(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 static_cast<ADisplayLuts_Dimension>(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 static_cast<ADisplayLuts_SamplingKey>(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<ADisplayLuts*>(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); + } +}
\ No newline at end of file diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 2d1fbf9e7f66..5dd4542c020f 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -95,6 +95,15 @@ LIBANDROID { AConfiguration_setTouchscreen; AConfiguration_setUiModeNight; AConfiguration_setUiModeType; + ADisplayLuts_create; # introduced=36 + ADisplayLuts_setEntries; # introduced=36 + ADisplayLuts_destroy; # introduced=36 + ADisplayLutsEntry_createEntry; # introduced=36 + ADisplayLutsEntry_getDimension; # introduced=36 + ADisplayLutsEntry_getSize; # introduced=36 + ADisplayLutsEntry_getSamplingKey; # introduced=36 + ADisplayLutsEntry_getBuffer; # introduced=36 + ADisplayLutsEntry_destroy; # introduced=36 AInputEvent_getDeviceId; AInputEvent_getSource; AInputEvent_getType; @@ -300,6 +309,7 @@ LIBANDROID { ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29 ASurfaceTransaction_setExtendedRangeBrightness; # introduced=UpsideDownCake ASurfaceTransaction_setDesiredHdrHeadroom; # introduced=VanillaIceCream + ASurfaceTransaction_setLuts; # introduced=36 ASurfaceTransaction_setOnComplete; # introduced=29 ASurfaceTransaction_setOnCommit; # introduced=31 ASurfaceTransaction_setPosition; # introduced=31 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 698bc84a78b9..fc64e9b48f6d 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -14,12 +14,15 @@ * limitations under the License. */ +#include <android/gui/LutProperties.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/native_window.h> #include <android/surface_control.h> #include <android/surface_control_jni.h> #include <android_runtime/android_view_SurfaceControl.h> #include <configstore/Utils.h> +#include <cutils/ashmem.h> +#include <display_luts_private.h> #include <gui/HdrMetadata.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> @@ -53,6 +56,14 @@ static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPA static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3)); static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ)); +static_assert(static_cast<int>(ADISPLAYLUTS_ONE_DIMENSION) == + static_cast<int>(android::gui::LutProperties::Dimension::ONE_D)); +static_assert(static_cast<int>(ADISPLAYLUTS_THREE_DIMENSION) == + static_cast<int>(android::gui::LutProperties::Dimension::THREE_D)); +static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_RGB) == + static_cast<int>(android::gui::LutProperties::SamplingKey::RGB)); +static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_MAX_RGB) == + static_cast<int>(android::gui::LutProperties::SamplingKey::MAX_RGB)); Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) { return reinterpret_cast<Transaction*>(aSurfaceTransaction); @@ -693,6 +704,58 @@ void ASurfaceTransaction_setDesiredHdrHeadroom(ASurfaceTransaction* aSurfaceTran transaction->setDesiredHdrHeadroom(surfaceControl, desiredRatio); } +void ASurfaceTransaction_setLuts(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + const struct ADisplayLuts* luts) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + int fd = -1; + std::vector<int32_t> offsets; + std::vector<int32_t> dimensions; + std::vector<int32_t> sizes; + std::vector<int32_t> samplingKeys; + + if (luts) { + std::vector<float> buffer(luts->totalBufferSize); + int32_t count = luts->offsets.size(); + offsets = luts->offsets; + + dimensions.reserve(count); + sizes.reserve(count); + samplingKeys.reserve(count); + for (int32_t i = 0; i < count; i++) { + dimensions.emplace_back(luts->entries[i]->properties.dimension); + sizes.emplace_back(luts->entries[i]->properties.size); + samplingKeys.emplace_back(luts->entries[i]->properties.samplingKey); + std::copy(luts->entries[i]->buffer.data.begin(), luts->entries[i]->buffer.data.end(), + buffer.begin() + offsets[i]); + } + + // mmap + fd = ashmem_create_region("lut_shared_mem", luts->totalBufferSize * sizeof(float)); + if (fd < 0) { + LOG_ALWAYS_FATAL("setLuts, ashmem_create_region() failed"); + return; + } + void* ptr = mmap(nullptr, luts->totalBufferSize * sizeof(float), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + LOG_ALWAYS_FATAL("setLuts, Failed to map the shared memory"); + return; + } + + memcpy(ptr, buffer.data(), luts->totalBufferSize * sizeof(float)); + munmap(ptr, luts->totalBufferSize * sizeof(float)); + } + + transaction->setLuts(surfaceControl, base::unique_fd(fd), offsets, dimensions, sizes, + samplingKeys); +} + void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, float r, float g, float b, float alpha, |