Merge "jpegrecoverymap: Fix XMP metadata test"
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index bdd5172..a737bd3 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -167,6 +167,12 @@
}
prebuilt_etc {
+ name: "android.hardware.telephony.satellite.prebuilt.xml",
+ src: "android.hardware.telephony.satellite.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.usb.accessory.prebuilt.xml",
src: "android.hardware.usb.accessory.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.satellite.xml b/data/etc/android.hardware.telephony.satellite.xml
new file mode 100644
index 0000000..5966cba
--- /dev/null
+++ b/data/etc/android.hardware.telephony.satellite.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<!-- Feature for devices that support Satellite communication via Satellite HAL APIs. -->
+<permissions>
+ <feature name="android.hardware.telephony.satellite" />
+</permissions>
diff --git a/include/input/Input.h b/include/input/Input.h
index 62d84e1..e281675 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -1132,6 +1132,7 @@
TYPE_ZOOM_OUT = 1019,
TYPE_GRAB = 1020,
TYPE_GRABBING = 1021,
+ TYPE_HANDWRITING = 1022,
TYPE_SPOT_HOVER = 2000,
TYPE_SPOT_TOUCH = 2001,
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 09933d3..66d3435 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -214,6 +214,12 @@
std::string layoutType;
};
+// The version of the Universal Stylus Initiative (USI) protocol supported by the input device.
+struct InputDeviceUsiVersion {
+ int32_t majorVersion = -1;
+ int32_t minorVersion = -1;
+};
+
/*
* Describes the characteristics and capabilities of an input device.
*/
@@ -235,7 +241,7 @@
void initialize(int32_t id, int32_t generation, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, const std::string& alias,
- bool isExternal, bool hasMic);
+ bool isExternal, bool hasMic, int32_t associatedDisplayId);
inline int32_t getId() const { return mId; }
inline int32_t getControllerNumber() const { return mControllerNumber; }
@@ -295,8 +301,12 @@
std::vector<InputDeviceLightInfo> getLights();
- inline void setSupportsUsi(bool supportsUsi) { mSupportsUsi = supportsUsi; }
- inline bool supportsUsi() const { return mSupportsUsi; }
+ inline void setUsiVersion(std::optional<InputDeviceUsiVersion> usiVersion) {
+ mUsiVersion = std::move(usiVersion);
+ }
+ inline std::optional<InputDeviceUsiVersion> getUsiVersion() const { return mUsiVersion; }
+
+ inline int32_t getAssociatedDisplayId() const { return mAssociatedDisplayId; }
private:
int32_t mId;
@@ -310,8 +320,8 @@
uint32_t mSources;
int32_t mKeyboardType;
std::shared_ptr<KeyCharacterMap> mKeyCharacterMap;
- // Whether this device supports the Universal Stylus Initiative (USI) protocol for styluses.
- bool mSupportsUsi;
+ std::optional<InputDeviceUsiVersion> mUsiVersion;
+ int32_t mAssociatedDisplayId;
bool mHasVibrator;
bool mHasBattery;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 19445d1..808b1ec 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -76,7 +76,6 @@
srcs: [
"Binder.cpp",
- "BinderRecordReplay.cpp",
"BpBinder.cpp",
"Debug.cpp",
"FdTrigger.cpp",
@@ -84,6 +83,7 @@
"IResultReceiver.cpp",
"Parcel.cpp",
"ParcelFileDescriptor.cpp",
+ "RecordedTransaction.cpp",
"RpcSession.cpp",
"RpcServer.cpp",
"RpcState.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 5fa8bfa..3e49656 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -21,13 +21,13 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
-#include <binder/BinderRecordReplay.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
+#include <binder/RecordedTransaction.h>
#include <binder/RpcServer.h>
#include <cutils/compiler.h>
#include <private/android_filesystem_config.h>
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 1c470a1..d03326e 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -388,7 +388,7 @@
{
if (isRpcBinder()) {
if (rpcSession()->getMaxIncomingThreads() < 1) {
- LOG_ALWAYS_FATAL("Cannot register a DeathRecipient without any incoming connections.");
+ ALOGE("Cannot register a DeathRecipient without any incoming connections.");
return INVALID_OPERATION;
}
} else if constexpr (!kEnableKernelIpc) {
diff --git a/libs/binder/BinderRecordReplay.cpp b/libs/binder/RecordedTransaction.cpp
similarity index 99%
rename from libs/binder/BinderRecordReplay.cpp
rename to libs/binder/RecordedTransaction.cpp
index 389c49e..5406205 100644
--- a/libs/binder/BinderRecordReplay.cpp
+++ b/libs/binder/RecordedTransaction.cpp
@@ -17,7 +17,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
-#include <binder/BinderRecordReplay.h>
+#include <binder/RecordedTransaction.h>
#include <sys/mman.h>
#include <algorithm>
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 08dbd13..d960a0b 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -106,7 +106,7 @@
const sp<IBinder>& keepAliveBinder);
// Start recording transactions to the unique_fd in data.
- // See BinderRecordReplay.h for more details.
+ // See RecordedTransaction.h for more details.
[[nodiscard]] status_t startRecordingTransactions(const Parcel& data);
// Stop the current recording.
[[nodiscard]] status_t stopRecordingTransactions();
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 57e103d..5496d61 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -91,7 +91,7 @@
std::optional<int32_t> getDebugBinderHandle() const;
// Start recording transactions to the unique_fd.
- // See BinderRecordReplay.h for more details.
+ // See RecordedTransaction.h for more details.
status_t startRecordingBinder(const android::base::unique_fd& fd);
// Stop the current recording.
status_t stopRecordingBinder();
diff --git a/libs/binder/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/RecordedTransaction.h
similarity index 98%
rename from libs/binder/include/binder/BinderRecordReplay.h
rename to libs/binder/include/binder/RecordedTransaction.h
index 9602c9f..4966330 100644
--- a/libs/binder/include/binder/BinderRecordReplay.h
+++ b/libs/binder/include/binder/RecordedTransaction.h
@@ -26,7 +26,7 @@
// Warning: Transactions are sequentially recorded to the file descriptor in a
// non-stable format. A detailed description of the recording format can be found in
-// BinderRecordReplay.cpp.
+// RecordedTransaction.cpp.
class RecordedTransaction {
public:
diff --git a/libs/binder/tests/binderRecordedTransactionTest.cpp b/libs/binder/tests/binderRecordedTransactionTest.cpp
index d900e86..2f5c8c6 100644
--- a/libs/binder/tests/binderRecordedTransactionTest.cpp
+++ b/libs/binder/tests/binderRecordedTransactionTest.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/BinderRecordReplay.h>
+#include <binder/RecordedTransaction.h>
#include <gtest/gtest.h>
#include <utils/Errors.h>
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 9be5b87..36c8d8c 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -683,7 +683,7 @@
proc.expectAlreadyShutdown = true;
}
-TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) {
+TEST_P(BinderRpc, DeathRecipientFailsWithoutIncoming) {
class MyDeathRec : public IBinder::DeathRecipient {
public:
void binderDied(const wp<IBinder>& /* who */) override {}
@@ -693,8 +693,7 @@
{.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0});
auto dr = sp<MyDeathRec>::make();
- EXPECT_DEATH(proc.rootBinder->linkToDeath(dr, (void*)1, 0),
- "Cannot register a DeathRecipient without any incoming connections.");
+ EXPECT_EQ(INVALID_OPERATION, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
}
TEST_P(BinderRpc, UnlinkDeathRecipient) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 87333f2..9c7c0c1 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -22,6 +22,7 @@
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
+#include <gui/constants.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
@@ -166,7 +167,7 @@
// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
- initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false);
+ initialize(-1, 0, -1, InputDeviceIdentifier(), "", false, false, ADISPLAY_ID_NONE);
}
InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other)
@@ -181,7 +182,8 @@
mSources(other.mSources),
mKeyboardType(other.mKeyboardType),
mKeyCharacterMap(other.mKeyCharacterMap),
- mSupportsUsi(other.mSupportsUsi),
+ mUsiVersion(other.mUsiVersion),
+ mAssociatedDisplayId(other.mAssociatedDisplayId),
mHasVibrator(other.mHasVibrator),
mHasBattery(other.mHasBattery),
mHasButtonUnderPad(other.mHasButtonUnderPad),
@@ -195,7 +197,7 @@
void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, const std::string& alias,
- bool isExternal, bool hasMic) {
+ bool isExternal, bool hasMic, int32_t associatedDisplayId) {
mId = id;
mGeneration = generation;
mControllerNumber = controllerNumber;
@@ -205,11 +207,12 @@
mHasMic = hasMic;
mSources = 0;
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
+ mAssociatedDisplayId = associatedDisplayId;
mHasVibrator = false;
mHasBattery = false;
mHasButtonUnderPad = false;
mHasSensor = false;
- mSupportsUsi = false;
+ mUsiVersion.reset();
mMotionRanges.clear();
mSensors.clear();
mLights.clear();
diff --git a/libs/jpegrecoverymap/Android.bp b/libs/jpegrecoverymap/Android.bp
index c9bed70..01318dc 100644
--- a/libs/jpegrecoverymap/Android.bp
+++ b/libs/jpegrecoverymap/Android.bp
@@ -39,6 +39,7 @@
"libjpeg",
"libjpegencoder",
"libjpegdecoder",
+ "liblog",
],
}
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
index 2f9799d..0695bb7 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/recoverymapmath.h
@@ -17,12 +17,15 @@
#ifndef ANDROID_JPEGRECOVERYMAP_RECOVERYMAPMATH_H
#define ANDROID_JPEGRECOVERYMAP_RECOVERYMAPMATH_H
+#include <cmath>
#include <stdint.h>
#include <jpegrecoverymap/recoverymap.h>
namespace android::recoverymap {
+#define CLIP3(x, min, max) ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x)
+
////////////////////////////////////////////////////////////////////////////////
// Framework
@@ -112,6 +115,31 @@
return temp /= rhs;
}
+constexpr size_t kRecoveryFactorPrecision = 10;
+constexpr size_t kRecoveryFactorNumEntries = 1 << kRecoveryFactorPrecision;
+struct RecoveryLUT {
+ RecoveryLUT(float hdrRatio) {
+ float increment = 2.0 / kRecoveryFactorNumEntries;
+ float value = -1.0f;
+ for (int idx = 0; idx < kRecoveryFactorNumEntries; idx++, value += increment) {
+ mRecoveryTable[idx] = pow(hdrRatio, value);
+ }
+ }
+
+ ~RecoveryLUT() {
+ }
+
+ float getRecoveryFactor(float recovery) {
+ uint32_t value = static_cast<uint32_t>(((recovery + 1.0f) / 2.0f) * kRecoveryFactorNumEntries);
+ //TODO() : Remove once conversion modules have appropriate clamping in place
+ value = CLIP3(value, 0, kRecoveryFactorNumEntries - 1);
+ return mRecoveryTable[value];
+ }
+
+private:
+ float mRecoveryTable[kRecoveryFactorNumEntries];
+};
+
struct ShepardsIDW {
ShepardsIDW(int mapScaleFactor) : mMapScaleFactor{mapScaleFactor} {
const int size = mMapScaleFactor * mMapScaleFactor * 4;
@@ -158,7 +186,6 @@
void fillShepardsIDW(float *weights, int incR, int incB);
};
-
////////////////////////////////////////////////////////////////////////////////
// sRGB transformations
// NOTE: sRGB has the same color primaries as BT.709, but different transfer
@@ -189,7 +216,8 @@
*/
float srgbInvOetf(float e_gamma);
Color srgbInvOetf(Color e_gamma);
-
+float srgbInvOetfLUT(float e_gamma);
+Color srgbInvOetfLUT(Color e_gamma);
////////////////////////////////////////////////////////////////////////////////
// Display-P3 transformations
@@ -229,6 +257,8 @@
*/
float hlgOetf(float e);
Color hlgOetf(Color e);
+float hlgOetfLUT(float e);
+Color hlgOetfLUT(Color e);
/*
* Convert from HLG to scene luminance.
@@ -237,6 +267,8 @@
*/
float hlgInvOetf(float e_gamma);
Color hlgInvOetf(Color e_gamma);
+float hlgInvOetfLUT(float e_gamma);
+Color hlgInvOetfLUT(Color e_gamma);
/*
* Convert from scene luminance to PQ.
@@ -245,6 +277,8 @@
*/
float pqOetf(float e);
Color pqOetf(Color e);
+float pqOetfLUT(float e);
+Color pqOetfLUT(Color e);
/*
* Convert from PQ to scene luminance in nits.
@@ -253,6 +287,8 @@
*/
float pqInvOetf(float e_gamma);
Color pqInvOetf(Color e_gamma);
+float pqInvOetfLUT(float e_gamma);
+Color pqInvOetfLUT(Color e_gamma);
////////////////////////////////////////////////////////////////////////////////
@@ -297,6 +333,7 @@
* value, with the given hdr ratio, to the given sdr input in the range [0, 1].
*/
Color applyRecovery(Color e, float recovery, float hdr_ratio);
+Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT);
/*
* Helper for sampling from YUV 420 images.
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index 22fa35b..eb557e5 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -25,17 +25,30 @@
#include <image_io/jpeg/jpeg_scanner.h>
#include <image_io/jpeg/jpeg_info_builder.h>
#include <image_io/base/data_segment_data_source.h>
+#include <utils/Log.h>
#include <memory>
#include <sstream>
#include <string>
#include <cmath>
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+#include <unistd.h>
using namespace std;
using namespace photos_editing_formats::image_io;
namespace android::recoverymap {
+#define USE_SRGB_INVOETF_LUT 1
+#define USE_HLG_OETF_LUT 1
+#define USE_PQ_OETF_LUT 1
+#define USE_HLG_INVOETF_LUT 1
+#define USE_PQ_INVOETF_LUT 1
+#define USE_APPLY_RECOVERY_LUT 1
+
#define JPEGR_CHECK(x) \
{ \
status_t status = (x); \
@@ -49,6 +62,10 @@
// Map is quarter res / sixteenth size
static const size_t kMapDimensionScaleFactor = 4;
+// JPEG block size.
+// JPEG encoding / decoding will require 8 x 8 DCT transform.
+// Width must be 8 dividable, and height must be 2 dividable.
+static const size_t kJpegBlock = 8;
// JPEG compress quality (0 ~ 100) for recovery map
static const int kMapCompressQuality = 85;
@@ -62,6 +79,20 @@
1.0f,
};
+#define CONFIG_MULTITHREAD 1
+int GetCPUCoreCount() {
+ int cpuCoreCount = 1;
+#if CONFIG_MULTITHREAD
+#if defined(_SC_NPROCESSORS_ONLN)
+ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ // _SC_NPROC_ONLN must be defined...
+ cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+#endif
+ return cpuCoreCount;
+}
+
/*
* Helper function used for writing data to destination.
*
@@ -230,6 +261,13 @@
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
+ if (uncompressed_p010_image->width % kJpegBlock != 0
+ || uncompressed_p010_image->height % 2 != 0) {
+ ALOGE("Image size can not be handled: %dx%d",
+ uncompressed_p010_image->width, uncompressed_p010_image->height);
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
jpegr_metadata metadata;
metadata.version = kJpegrVersion;
metadata.transferFunction = hdr_tf;
@@ -304,6 +342,13 @@
return ERROR_JPEGR_RESOLUTION_MISMATCH;
}
+ if (uncompressed_p010_image->width % kJpegBlock != 0
+ || uncompressed_p010_image->height % 2 != 0) {
+ ALOGE("Image size can not be handled: %dx%d",
+ uncompressed_p010_image->width, uncompressed_p010_image->height);
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
jpegr_metadata metadata;
metadata.version = kJpegrVersion;
metadata.transferFunction = hdr_tf;
@@ -369,6 +414,13 @@
return ERROR_JPEGR_RESOLUTION_MISMATCH;
}
+ if (uncompressed_p010_image->width % kJpegBlock != 0
+ || uncompressed_p010_image->height % 2 != 0) {
+ ALOGE("Image size can not be handled: %dx%d",
+ uncompressed_p010_image->width, uncompressed_p010_image->height);
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
jpegr_metadata metadata;
metadata.version = kJpegrVersion;
metadata.transferFunction = hdr_tf;
@@ -444,6 +496,13 @@
return ERROR_JPEGR_INVALID_NULL_PTR;
}
+ if (uncompressed_p010_image->width % kJpegBlock != 0
+ || uncompressed_p010_image->height % 2 != 0) {
+ ALOGE("Image size can not be handled: %dx%d",
+ uncompressed_p010_image->width, uncompressed_p010_image->height);
+ return ERROR_JPEGR_INVALID_INPUT_TYPE;
+ }
+
JpegDecoder jpeg_decoder;
if (!jpeg_decoder.decompressImage(compressed_jpeg_image->data, compressed_jpeg_image->length)) {
return ERROR_JPEGR_DECODE_ERROR;
@@ -626,6 +685,62 @@
return NO_ERROR;
}
+const int kJobSzInRows = 16;
+static_assert(kJobSzInRows > 0 && kJobSzInRows % kMapDimensionScaleFactor == 0,
+ "align job size to kMapDimensionScaleFactor");
+
+class JobQueue {
+ public:
+ bool dequeueJob(size_t& rowStart, size_t& rowEnd);
+ void enqueueJob(size_t rowStart, size_t rowEnd);
+ void markQueueForEnd();
+ void reset();
+
+ private:
+ bool mQueuedAllJobs = false;
+ std::deque<std::tuple<size_t, size_t>> mJobs;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+};
+
+bool JobQueue::dequeueJob(size_t& rowStart, size_t& rowEnd) {
+ std::unique_lock<std::mutex> lock{mMutex};
+ while (true) {
+ if (mJobs.empty()) {
+ if (mQueuedAllJobs) {
+ return false;
+ } else {
+ mCv.wait(lock);
+ }
+ } else {
+ auto it = mJobs.begin();
+ rowStart = std::get<0>(*it);
+ rowEnd = std::get<1>(*it);
+ mJobs.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+void JobQueue::enqueueJob(size_t rowStart, size_t rowEnd) {
+ std::unique_lock<std::mutex> lock{mMutex};
+ mJobs.push_back(std::make_tuple(rowStart, rowEnd));
+ lock.unlock();
+ mCv.notify_one();
+}
+
+void JobQueue::markQueueForEnd() {
+ std::unique_lock<std::mutex> lock{mMutex};
+ mQueuedAllJobs = true;
+}
+
+void JobQueue::reset() {
+ std::unique_lock<std::mutex> lock{mMutex};
+ mJobs.clear();
+ mQueuedAllJobs = false;
+}
+
status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image,
jr_uncompressed_ptr uncompressed_p010_image,
jr_metadata_ptr metadata,
@@ -651,11 +766,14 @@
size_t image_height = uncompressed_yuv_420_image->height;
size_t map_width = image_width / kMapDimensionScaleFactor;
size_t map_height = image_height / kMapDimensionScaleFactor;
+ size_t map_stride = static_cast<size_t>(
+ floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock;
+ size_t map_height_aligned = ((map_height + 1) >> 1) << 1;
- dest->width = map_width;
- dest->height = map_height;
+ dest->width = map_stride;
+ dest->height = map_height_aligned;
dest->colorGamut = JPEGR_COLORGAMUT_UNSPECIFIED;
- dest->data = new uint8_t[map_width * map_height];
+ dest->data = new uint8_t[map_stride * map_height_aligned];
std::unique_ptr<uint8_t[]> map_data;
map_data.reset(reinterpret_cast<uint8_t*>(dest->data));
@@ -666,11 +784,19 @@
hdrInvOetf = identityConversion;
break;
case JPEGR_TF_HLG:
+#if USE_HLG_INVOETF_LUT
+ hdrInvOetf = hlgInvOetfLUT;
+#else
hdrInvOetf = hlgInvOetf;
+#endif
hdr_white_nits = kHlgMaxNits;
break;
case JPEGR_TF_PQ:
+#if USE_PQ_INVOETF_LUT
+ hdrInvOetf = pqInvOetfLUT;
+#else
hdrInvOetf = pqInvOetf;
+#endif
hdr_white_nits = kPqMaxNits;
break;
case JPEGR_TF_UNSPECIFIED:
@@ -697,22 +823,87 @@
return ERROR_JPEGR_INVALID_COLORGAMUT;
}
+ std::mutex mutex;
float hdr_y_nits_max = 0.0f;
double hdr_y_nits_avg = 0.0f;
- for (size_t y = 0; y < image_height; ++y) {
- for (size_t x = 0; x < image_width; ++x) {
- Color hdr_yuv_gamma = getP010Pixel(uncompressed_p010_image, x, y);
- Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
- Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma);
- hdr_rgb = hdrGamutConversionFn(hdr_rgb);
- float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;
+ const int threads = std::clamp(GetCPUCoreCount(), 1, 4);
+ size_t rowStep = threads == 1 ? image_height : kJobSzInRows;
+ JobQueue jobQueue;
- hdr_y_nits_avg += hdr_y_nits;
- if (hdr_y_nits > hdr_y_nits_max) {
- hdr_y_nits_max = hdr_y_nits;
+ std::function<void()> computeMetadata = [uncompressed_p010_image, hdrInvOetf,
+ hdrGamutConversionFn, luminanceFn, hdr_white_nits,
+ threads, &mutex, &hdr_y_nits_avg,
+ &hdr_y_nits_max, &jobQueue]() -> void {
+ size_t rowStart, rowEnd;
+ float hdr_y_nits_max_th = 0.0f;
+ double hdr_y_nits_avg_th = 0.0f;
+ while (jobQueue.dequeueJob(rowStart, rowEnd)) {
+ for (size_t y = rowStart; y < rowEnd; ++y) {
+ for (size_t x = 0; x < uncompressed_p010_image->width; ++x) {
+ Color hdr_yuv_gamma = getP010Pixel(uncompressed_p010_image, x, y);
+ Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
+ Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma);
+ hdr_rgb = hdrGamutConversionFn(hdr_rgb);
+ float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;
+
+ hdr_y_nits_avg_th += hdr_y_nits;
+ if (hdr_y_nits > hdr_y_nits_max_th) {
+ hdr_y_nits_max_th = hdr_y_nits;
+ }
+ }
}
}
+ std::unique_lock<std::mutex> lock{mutex};
+ hdr_y_nits_avg += hdr_y_nits_avg_th;
+ hdr_y_nits_max = std::max(hdr_y_nits_max, hdr_y_nits_max_th);
+ };
+
+ std::function<void()> generateMap = [uncompressed_yuv_420_image, uncompressed_p010_image,
+ metadata, dest, hdrInvOetf, hdrGamutConversionFn,
+ luminanceFn, hdr_white_nits, &jobQueue]() -> void {
+ size_t rowStart, rowEnd;
+ while (jobQueue.dequeueJob(rowStart, rowEnd)) {
+ for (size_t y = rowStart; y < rowEnd; ++y) {
+ for (size_t x = 0; x < dest->width; ++x) {
+ Color sdr_yuv_gamma =
+ sampleYuv420(uncompressed_yuv_420_image, kMapDimensionScaleFactor, x, y);
+ Color sdr_rgb_gamma = srgbYuvToRgb(sdr_yuv_gamma);
+#if USE_SRGB_INVOETF_LUT
+ Color sdr_rgb = srgbInvOetfLUT(sdr_rgb_gamma);
+#else
+ Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma);
+#endif
+ float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits;
+
+ Color hdr_yuv_gamma = sampleP010(uncompressed_p010_image, kMapDimensionScaleFactor, x, y);
+ Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
+ Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma);
+ hdr_rgb = hdrGamutConversionFn(hdr_rgb);
+ float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;
+
+ size_t pixel_idx = x + y * dest->width;
+ reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] =
+ encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->rangeScalingFactor);
+ }
+ }
+ }
+ };
+
+ std::vector<std::thread> workers;
+ for (int th = 0; th < threads - 1; th++) {
+ workers.push_back(std::thread(computeMetadata));
}
+
+ // compute metadata
+ for (size_t rowStart = 0; rowStart < image_height;) {
+ size_t rowEnd = std::min(rowStart + rowStep, image_height);
+ jobQueue.enqueueJob(rowStart, rowEnd);
+ rowStart = rowEnd;
+ }
+ jobQueue.markQueueForEnd();
+ computeMetadata();
+ std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
+ workers.clear();
hdr_y_nits_avg /= image_width * image_height;
metadata->rangeScalingFactor = hdr_y_nits_max / kSdrWhiteNits;
@@ -721,26 +912,22 @@
metadata->hdr10Metadata.maxCLL = hdr_y_nits_max;
}
- for (size_t y = 0; y < map_height; ++y) {
- for (size_t x = 0; x < map_width; ++x) {
- Color sdr_yuv_gamma = sampleYuv420(uncompressed_yuv_420_image,
- kMapDimensionScaleFactor, x, y);
- Color sdr_rgb_gamma = srgbYuvToRgb(sdr_yuv_gamma);
- Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma);
- float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits;
-
- Color hdr_yuv_gamma = sampleP010(uncompressed_p010_image, kMapDimensionScaleFactor, x, y);
- Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
- Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma);
- hdr_rgb = hdrGamutConversionFn(hdr_rgb);
- float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;
-
- size_t pixel_idx = x + y * map_width;
- reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] =
- encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->rangeScalingFactor);
- }
+ // generate map
+ jobQueue.reset();
+ for (int th = 0; th < threads - 1; th++) {
+ workers.push_back(std::thread(generateMap));
}
+ rowStep = (threads == 1 ? image_height : kJobSzInRows) / kMapDimensionScaleFactor;
+ for (size_t rowStart = 0; rowStart < map_height;) {
+ size_t rowEnd = std::min(rowStart + rowStep, map_height);
+ jobQueue.enqueueJob(rowStart, rowEnd);
+ rowStart = rowEnd;
+ }
+ jobQueue.markQueueForEnd();
+ generateMap();
+ std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
+
map_data.release();
return NO_ERROR;
}
@@ -756,58 +943,95 @@
return ERROR_JPEGR_INVALID_NULL_PTR;
}
- size_t width = uncompressed_yuv_420_image->width;
- size_t height = uncompressed_yuv_420_image->height;
-
- dest->width = width;
- dest->height = height;
- size_t pixel_count = width * height;
-
- ColorTransformFn hdrOetf = nullptr;
- switch (metadata->transferFunction) {
- case JPEGR_TF_LINEAR:
- hdrOetf = identityConversion;
- break;
- case JPEGR_TF_HLG:
- hdrOetf = hlgOetf;
- break;
- case JPEGR_TF_PQ:
- hdrOetf = pqOetf;
- break;
- case JPEGR_TF_UNSPECIFIED:
- // Should be impossible to hit after input validation.
- return ERROR_JPEGR_INVALID_TRANS_FUNC;
- }
-
+ dest->width = uncompressed_yuv_420_image->width;
+ dest->height = uncompressed_yuv_420_image->height;
ShepardsIDW idwTable(kMapDimensionScaleFactor);
+ RecoveryLUT recoveryLUT(metadata->rangeScalingFactor);
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- Color yuv_gamma_sdr = getYuv420Pixel(uncompressed_yuv_420_image, x, y);
- Color rgb_gamma_sdr = srgbYuvToRgb(yuv_gamma_sdr);
- Color rgb_sdr = srgbInvOetf(rgb_gamma_sdr);
+ JobQueue jobQueue;
+ std::function<void()> applyRecMap = [uncompressed_yuv_420_image, uncompressed_recovery_map,
+ metadata, dest, &jobQueue, &idwTable,
+ &recoveryLUT]() -> void {
+ const float hdr_ratio = metadata->rangeScalingFactor;
+ size_t width = uncompressed_yuv_420_image->width;
+ size_t height = uncompressed_yuv_420_image->height;
- float recovery;
- // TODO: determine map scaling factor based on actual map dims
- size_t map_scale_factor = kMapDimensionScaleFactor;
- // TODO: If map_scale_factor is guaranteed to be an integer, then remove the following.
- // Currently map_scale_factor is of type size_t, but it could be changed to a float
- // later.
- if (map_scale_factor != floorf(map_scale_factor)) {
- recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y);
- } else {
- recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y,
- idwTable);
- }
- Color rgb_hdr = applyRecovery(rgb_sdr, recovery, metadata->rangeScalingFactor);
-
- Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->rangeScalingFactor);
- uint32_t rgba1010102 = colorToRgba1010102(rgb_gamma_hdr);
-
- size_t pixel_idx = x + y * width;
- reinterpret_cast<uint32_t*>(dest->data)[pixel_idx] = rgba1010102;
+ ColorTransformFn hdrOetf = nullptr;
+ switch (metadata->transferFunction) {
+ case JPEGR_TF_LINEAR:
+ hdrOetf = identityConversion;
+ break;
+ case JPEGR_TF_HLG:
+#if USE_HLG_OETF_LUT
+ hdrOetf = hlgOetfLUT;
+#else
+ hdrOetf = hlgOetf;
+#endif
+ break;
+ case JPEGR_TF_PQ:
+#if USE_PQ_OETF_LUT
+ hdrOetf = pqOetfLUT;
+#else
+ hdrOetf = pqOetf;
+#endif
+ break;
+ case JPEGR_TF_UNSPECIFIED:
+ // Should be impossible to hit after input validation.
+ hdrOetf = identityConversion;
}
+
+ size_t rowStart, rowEnd;
+ while (jobQueue.dequeueJob(rowStart, rowEnd)) {
+ for (size_t y = rowStart; y < rowEnd; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ Color yuv_gamma_sdr = getYuv420Pixel(uncompressed_yuv_420_image, x, y);
+ Color rgb_gamma_sdr = srgbYuvToRgb(yuv_gamma_sdr);
+#if USE_SRGB_INVOETF_LUT
+ Color rgb_sdr = srgbInvOetfLUT(rgb_gamma_sdr);
+#else
+ Color rgb_sdr = srgbInvOetf(rgb_gamma_sdr);
+#endif
+ float recovery;
+ // TODO: determine map scaling factor based on actual map dims
+ size_t map_scale_factor = kMapDimensionScaleFactor;
+ // TODO: If map_scale_factor is guaranteed to be an integer, then remove the following.
+ // Currently map_scale_factor is of type size_t, but it could be changed to a float
+ // later.
+ if (map_scale_factor != floorf(map_scale_factor)) {
+ recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y);
+ } else {
+ recovery = sampleMap(uncompressed_recovery_map, map_scale_factor, x, y,
+ idwTable);
+ }
+#if USE_APPLY_RECOVERY_LUT
+ Color rgb_hdr = applyRecoveryLUT(rgb_sdr, recovery, recoveryLUT);
+#else
+ Color rgb_hdr = applyRecovery(rgb_sdr, recovery, hdr_ratio);
+#endif
+ Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->rangeScalingFactor);
+ uint32_t rgba1010102 = colorToRgba1010102(rgb_gamma_hdr);
+
+ size_t pixel_idx = x + y * width;
+ reinterpret_cast<uint32_t*>(dest->data)[pixel_idx] = rgba1010102;
+ }
+ }
+ }
+ };
+
+ const int threads = std::clamp(GetCPUCoreCount(), 1, 4);
+ std::vector<std::thread> workers;
+ for (int th = 0; th < threads - 1; th++) {
+ workers.push_back(std::thread(applyRecMap));
}
+ const int rowStep = threads == 1 ? uncompressed_yuv_420_image->height : kJobSzInRows;
+ for (int rowStart = 0; rowStart < uncompressed_yuv_420_image->height;) {
+ int rowEnd = std::min(rowStart + rowStep, uncompressed_yuv_420_image->height);
+ jobQueue.enqueueJob(rowStart, rowEnd);
+ rowStart = rowEnd;
+ }
+ jobQueue.markQueueForEnd();
+ applyRecMap();
+ std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
return NO_ERROR;
}
diff --git a/libs/jpegrecoverymap/recoverymapmath.cpp b/libs/jpegrecoverymap/recoverymapmath.cpp
index 4a6feca..4f21ac6 100644
--- a/libs/jpegrecoverymap/recoverymapmath.cpp
+++ b/libs/jpegrecoverymap/recoverymapmath.cpp
@@ -15,11 +15,74 @@
*/
#include <cmath>
-
+#include <vector>
#include <jpegrecoverymap/recoverymapmath.h>
namespace android::recoverymap {
+constexpr size_t kPqOETFPrecision = 10;
+constexpr size_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
+
+static const std::vector<float> kPqOETF = [] {
+ std::vector<float> result;
+ float increment = 1.0 / kPqOETFNumEntries;
+ float value = 0.0f;
+ for (int idx = 0; idx < kPqOETFNumEntries; idx++, value += increment) {
+ result.push_back(pqOetf(value));
+ }
+ return result;
+}();
+
+constexpr size_t kPqInvOETFPrecision = 10;
+constexpr size_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
+
+static const std::vector<float> kPqInvOETF = [] {
+ std::vector<float> result;
+ float increment = 1.0 / kPqInvOETFNumEntries;
+ float value = 0.0f;
+ for (int idx = 0; idx < kPqInvOETFNumEntries; idx++, value += increment) {
+ result.push_back(pqInvOetf(value));
+ }
+ return result;
+}();
+
+constexpr size_t kHlgOETFPrecision = 10;
+constexpr size_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
+
+static const std::vector<float> kHlgOETF = [] {
+ std::vector<float> result;
+ float increment = 1.0 / kHlgOETFNumEntries;
+ float value = 0.0f;
+ for (int idx = 0; idx < kHlgOETFNumEntries; idx++, value += increment) {
+ result.push_back(hlgOetf(value));
+ }
+ return result;
+}();
+
+constexpr size_t kHlgInvOETFPrecision = 10;
+constexpr size_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
+
+static const std::vector<float> kHlgInvOETF = [] {
+ std::vector<float> result;
+ float increment = 1.0 / kHlgInvOETFNumEntries;
+ float value = 0.0f;
+ for (int idx = 0; idx < kHlgInvOETFNumEntries; idx++, value += increment) {
+ result.push_back(hlgInvOetf(value));
+ }
+ return result;
+}();
+
+constexpr size_t kSRGBInvOETFPrecision = 10;
+constexpr size_t kSRGBInvOETFNumEntries = 1 << kSRGBInvOETFPrecision;
+static const std::vector<float> kSRGBInvOETF = [] {
+ std::vector<float> result;
+ float increment = 1.0 / kSRGBInvOETFNumEntries;
+ float value = 0.0f;
+ for (int idx = 0; idx < kSRGBInvOETFNumEntries; idx++, value += increment) {
+ result.push_back(srgbInvOetf(value));
+ }
+ return result;
+}();
// Use Shepard's method for inverse distance weighting. For more information:
// en.wikipedia.org/wiki/Inverse_distance_weighting#Shepard's_method
@@ -70,6 +133,11 @@
////////////////////////////////////////////////////////////////////////////////
// sRGB transformations
+static const float kMaxPixelFloat = 1.0f;
+static float clampPixelFloat(float value) {
+ return (value < 0.0f) ? 0.0f : (value > kMaxPixelFloat) ? kMaxPixelFloat : value;
+}
+
// See IEC 61966-2-1, Equation F.7.
static const float kSrgbR = 0.2126f, kSrgbG = 0.7152f, kSrgbB = 0.0722f;
@@ -81,9 +149,9 @@
static const float kSrgbRCr = 1.402f, kSrgbGCb = 0.34414f, kSrgbGCr = 0.71414f, kSrgbBCb = 1.772f;
Color srgbYuvToRgb(Color e_gamma) {
- return {{{ e_gamma.y + kSrgbRCr * e_gamma.v,
- e_gamma.y - kSrgbGCb * e_gamma.u - kSrgbGCr * e_gamma.v,
- e_gamma.y + kSrgbBCb * e_gamma.u }}};
+ return {{{ clampPixelFloat(e_gamma.y + kSrgbRCr * e_gamma.v),
+ clampPixelFloat(e_gamma.y - kSrgbGCb * e_gamma.u - kSrgbGCr * e_gamma.v),
+ clampPixelFloat(e_gamma.y + kSrgbBCb * e_gamma.u) }}};
}
// See ECMA TR/98, Section 7.
@@ -112,6 +180,19 @@
srgbInvOetf(e_gamma.b) }}};
}
+// See IEC 61966-2-1, Equations F.5 and F.6.
+float srgbInvOetfLUT(float e_gamma) {
+ uint32_t value = static_cast<uint32_t>(e_gamma * kSRGBInvOETFNumEntries);
+ //TODO() : Remove once conversion modules have appropriate clamping in place
+ value = CLIP3(value, 0, kSRGBInvOETFNumEntries - 1);
+ return kSRGBInvOETF[value];
+}
+
+Color srgbInvOetfLUT(Color e_gamma) {
+ return {{{ srgbInvOetfLUT(e_gamma.r),
+ srgbInvOetfLUT(e_gamma.g),
+ srgbInvOetfLUT(e_gamma.b) }}};
+}
////////////////////////////////////////////////////////////////////////////////
// Display-P3 transformations
@@ -169,9 +250,9 @@
static const float kBt2100GCr = kBt2100R * kBt2100Cr / kBt2100G;
Color bt2100YuvToRgb(Color e_gamma) {
- return {{{ e_gamma.y + kBt2100Cr * e_gamma.v,
- e_gamma.y - kBt2100GCb * e_gamma.u - kBt2100GCr * e_gamma.v,
- e_gamma.y + kBt2100Cb * e_gamma.u }}};
+ return {{{ clampPixelFloat(e_gamma.y + kBt2100Cr * e_gamma.v),
+ clampPixelFloat(e_gamma.y - kBt2100GCb * e_gamma.u - kBt2100GCr * e_gamma.v),
+ clampPixelFloat(e_gamma.y + kBt2100Cb * e_gamma.u) }}};
}
// See ITU-R BT.2100-2, Table 5, HLG Reference OETF.
@@ -189,6 +270,18 @@
return {{{ hlgOetf(e.r), hlgOetf(e.g), hlgOetf(e.b) }}};
}
+float hlgOetfLUT(float e) {
+ uint32_t value = static_cast<uint32_t>(e * kHlgOETFNumEntries);
+ //TODO() : Remove once conversion modules have appropriate clamping in place
+ value = CLIP3(value, 0, kHlgOETFNumEntries - 1);
+
+ return kHlgOETF[value];
+}
+
+Color hlgOetfLUT(Color e) {
+ return {{{ hlgOetfLUT(e.r), hlgOetfLUT(e.g), hlgOetfLUT(e.b) }}};
+}
+
// See ITU-R BT.2100-2, Table 5, HLG Reference EOTF.
float hlgInvOetf(float e_gamma) {
if (e_gamma <= 0.5f) {
@@ -204,6 +297,20 @@
hlgInvOetf(e_gamma.b) }}};
}
+float hlgInvOetfLUT(float e_gamma) {
+ uint32_t value = static_cast<uint32_t>(e_gamma * kHlgInvOETFNumEntries);
+ //TODO() : Remove once conversion modules have appropriate clamping in place
+ value = CLIP3(value, 0, kHlgInvOETFNumEntries - 1);
+
+ return kHlgInvOETF[value];
+}
+
+Color hlgInvOetfLUT(Color e_gamma) {
+ return {{{ hlgInvOetfLUT(e_gamma.r),
+ hlgInvOetfLUT(e_gamma.g),
+ hlgInvOetfLUT(e_gamma.b) }}};
+}
+
// See ITU-R BT.2100-2, Table 4, Reference PQ OETF.
static const float kPqM1 = 2610.0f / 16384.0f, kPqM2 = 2523.0f / 4096.0f * 128.0f;
static const float kPqC1 = 3424.0f / 4096.0f, kPqC2 = 2413.0f / 4096.0f * 32.0f,
@@ -219,6 +326,18 @@
return {{{ pqOetf(e.r), pqOetf(e.g), pqOetf(e.b) }}};
}
+float pqOetfLUT(float e) {
+ uint32_t value = static_cast<uint32_t>(e * kPqOETFNumEntries);
+ //TODO() : Remove once conversion modules have appropriate clamping in place
+ value = CLIP3(value, 0, kPqOETFNumEntries - 1);
+
+ return kPqOETF[value];
+}
+
+Color pqOetfLUT(Color e) {
+ return {{{ pqOetfLUT(e.r), pqOetfLUT(e.g), pqOetfLUT(e.b) }}};
+}
+
// Derived from the inverse of the Reference PQ OETF.
static const float kPqInvA = 128.0f, kPqInvB = 107.0f, kPqInvC = 2413.0f, kPqInvD = 2392.0f,
kPqInvE = 6.2773946361f, kPqInvF = 0.0126833f;
@@ -239,6 +358,20 @@
pqInvOetf(e_gamma.b) }}};
}
+float pqInvOetfLUT(float e_gamma) {
+ uint32_t value = static_cast<uint32_t>(e_gamma * kPqInvOETFNumEntries);
+ //TODO() : Remove once conversion modules have appropriate clamping in place
+ value = CLIP3(value, 0, kPqInvOETFNumEntries - 1);
+
+ return kPqInvOETF[value];
+}
+
+Color pqInvOetfLUT(Color e_gamma) {
+ return {{{ pqInvOetfLUT(e_gamma.r),
+ pqInvOetfLUT(e_gamma.g),
+ pqInvOetfLUT(e_gamma.b) }}};
+}
+
////////////////////////////////////////////////////////////////////////////////
// Color conversions
@@ -346,6 +479,11 @@
return e * recoveryFactor;
}
+Color applyRecoveryLUT(Color e, float recovery, RecoveryLUT& recoveryLUT) {
+ float recoveryFactor = recoveryLUT.getRecoveryFactor(recovery);
+ return e * recoveryFactor;
+}
+
Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) {
size_t pixel_count = image->width * image->height;
diff --git a/libs/jpegrecoverymap/tests/recoverymap_test.cpp b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
index 67f3350..dfab76a 100644
--- a/libs/jpegrecoverymap/tests/recoverymap_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymap_test.cpp
@@ -15,6 +15,7 @@
*/
#include <jpegrecoverymap/recoverymap.h>
+#include <jpegrecoverymap/recoverymapmath.h>
#include <jpegrecoverymap/recoverymaputils.h>
#include <fcntl.h>
#include <fstream>
@@ -30,6 +31,7 @@
#define SAVE_ENCODING_RESULT true
#define SAVE_DECODING_RESULT true
+#define SAVE_INPUT_RGBA true
namespace android::recoverymap {
@@ -313,6 +315,29 @@
mRawP010Image.height = TEST_IMAGE_HEIGHT;
mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
+ if (SAVE_INPUT_RGBA) {
+ size_t rgbaSize = mRawP010Image.width * mRawP010Image.height * sizeof(uint32_t);
+ uint32_t *data = (uint32_t *)malloc(rgbaSize);
+
+ for (size_t y = 0; y < mRawP010Image.height; ++y) {
+ for (size_t x = 0; x < mRawP010Image.width; ++x) {
+ Color hdr_yuv_gamma = getP010Pixel(&mRawP010Image, x, y);
+ Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
+ uint32_t rgba1010102 = colorToRgba1010102(hdr_rgb_gamma);
+ size_t pixel_idx = x + y * mRawP010Image.width;
+ reinterpret_cast<uint32_t*>(data)[pixel_idx] = rgba1010102;
+ }
+ }
+
+ // Output image data to file
+ std::string filePath = "/sdcard/Documents/input_from_p010.rgb10";
+ std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
+ if (!imageFile.is_open()) {
+ ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
+ }
+ imageFile.write((const char*)data, rgbaSize);
+ free(data);
+ }
if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
FAIL() << "Load file " << JPEG_IMAGE << " failed";
}
diff --git a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
index 58c139d..1d522d1 100644
--- a/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
+++ b/libs/jpegrecoverymap/tests/recoverymapmath_test.cpp
@@ -517,6 +517,65 @@
EXPECT_RGB_NEAR(pqInvOetf(e_gamma), e);
}
+TEST_F(RecoveryMapMathTest, PqInvOetfLUT) {
+ float increment = 1.0 / 1024.0;
+ float value = 0.0f;
+ for (int idx = 0; idx < 1024; idx++, value += increment) {
+ EXPECT_FLOAT_EQ(pqInvOetf(value), pqInvOetfLUT(value));
+ }
+}
+
+TEST_F(RecoveryMapMathTest, HlgInvOetfLUT) {
+ float increment = 1.0 / 1024.0;
+ float value = 0.0f;
+ for (int idx = 0; idx < 1024; idx++, value += increment) {
+ EXPECT_FLOAT_EQ(hlgInvOetf(value), hlgInvOetfLUT(value));
+ }
+}
+
+TEST_F(RecoveryMapMathTest, pqOetfLUT) {
+ float increment = 1.0 / 1024.0;
+ float value = 0.0f;
+ for (int idx = 0; idx < 1024; idx++, value += increment) {
+ EXPECT_FLOAT_EQ(pqOetf(value), pqOetfLUT(value));
+ }
+}
+
+TEST_F(RecoveryMapMathTest, hlgOetfLUT) {
+ float increment = 1.0 / 1024.0;
+ float value = 0.0f;
+ for (int idx = 0; idx < 1024; idx++, value += increment) {
+ EXPECT_FLOAT_EQ(hlgOetf(value), hlgOetfLUT(value));
+ }
+}
+
+TEST_F(RecoveryMapMathTest, srgbInvOetfLUT) {
+ float increment = 1.0 / 1024.0;
+ float value = 0.0f;
+ for (int idx = 0; idx < 1024; idx++, value += increment) {
+ EXPECT_FLOAT_EQ(srgbInvOetf(value), srgbInvOetfLUT(value));
+ }
+}
+
+TEST_F(RecoveryMapMathTest, applyRecoveryLUT) {
+ float increment = 2.0 / kRecoveryFactorNumEntries;
+ for (float hdrRatio = 1.0f; hdrRatio <= 10.0f; hdrRatio += 1.0f) {
+ RecoveryLUT recoveryLUT(hdrRatio);
+ for (float value = -1.0f; value <= -1.0f; value += increment) {
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, hdrRatio),
+ applyRecoveryLUT(RgbBlack(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), value, hdrRatio),
+ applyRecoveryLUT(RgbWhite(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbRed(), value, hdrRatio),
+ applyRecoveryLUT(RgbRed(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbGreen(), value, hdrRatio),
+ applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
+ EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, hdrRatio),
+ applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
+ }
+ }
+}
+
TEST_F(RecoveryMapMathTest, PqTransferFunctionRoundtrip) {
EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(0.0f)), 0.0f);
EXPECT_NEAR(pqInvOetf(pqOetf(0.01f)), 0.01f, ComparisonEpsilon());
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index b2e8bea..85a5249 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -311,6 +311,16 @@
*/
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
+ /**
+ * Usage: The buffer is used for front-buffer rendering. When
+ * front-buffering rendering is specified, different usages may adjust their
+ * behavior as a result. For example, when used as GPU_COLOR_OUTPUT the buffer
+ * will behave similar to a single-buffered window. When used with
+ * COMPOSER_OVERLAY, the system will try to prioritize the buffer receiving
+ * an overlay plane & avoid caching it in intermediate composition buffers.
+ */
+ AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1UL << 32,
+
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
AHARDWAREBUFFER_USAGE_VENDOR_2 = 1ULL << 30,
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index dd14bcf..34b1251 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -502,7 +502,6 @@
void* so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
if (so) {
- ALOGD("dlopen_ext from APK (%s) success at %p", name.c_str(), so);
return so;
} else {
ALOGE("dlopen_ext(\"%s\") failed: %s", name.c_str(), dlerror());
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index 72bd292..614a78e 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -53,4 +53,6 @@
vintf_fragments: [
"manifest_android.frameworks.automotive.display@1.0.xml",
],
+
+ system_ext_specific: true,
}
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
index 5c7f344..ea1077a 100644
--- a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -1,4 +1,4 @@
-service automotive_display /system/bin/android.frameworks.automotive.display@1.0-service
+service automotive_display /system_ext/bin/android.frameworks.automotive.display@1.0-service
class hal
user graphics
group automotive_evs
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 6e78e82..9bd50f7 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -452,7 +452,8 @@
InputDeviceInfo InputDevice::getDeviceInfo() {
InputDeviceInfo outDeviceInfo;
outDeviceInfo.initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
- mHasMic);
+ mHasMic, getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE));
+
for_each_mapper(
[&outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(&outDeviceInfo); });
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 8cd2cf0..ddddca2 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -55,6 +55,10 @@
return p.x >= rect.left && p.x < rect.right && p.y >= rect.top && p.y < rect.bottom;
}
+static std::string toString(const InputDeviceUsiVersion& v) {
+ return base::StringPrintf("%d.%d", v.majorVersion, v.minorVersion);
+}
+
template <typename T>
inline static void swap(T& a, T& b) {
T temp = a;
@@ -188,7 +192,7 @@
info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
}
info->setButtonUnderPad(mParameters.hasButtonUnderPad);
- info->setSupportsUsi(mParameters.supportsUsi);
+ info->setUsiVersion(mParameters.usiVersion);
}
void TouchInputMapper::dump(std::string& dump) {
@@ -421,9 +425,13 @@
mParameters.wake = getDeviceContext().isExternal();
getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake);
- mParameters.supportsUsi = false;
- getDeviceContext().getConfiguration().tryGetProperty("touch.supportsUsi",
- mParameters.supportsUsi);
+ InputDeviceUsiVersion usiVersion;
+ if (getDeviceContext().getConfiguration().tryGetProperty("touch.usiVersionMajor",
+ usiVersion.majorVersion) &&
+ getDeviceContext().getConfiguration().tryGetProperty("touch.usiVersionMinor",
+ usiVersion.minorVersion)) {
+ mParameters.usiVersion = usiVersion;
+ }
mParameters.enableForInactiveViewport = false;
getDeviceContext().getConfiguration().tryGetProperty("touch.enableForInactiveViewport",
@@ -472,7 +480,8 @@
mParameters.uniqueDisplayId.c_str());
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n";
- dump += StringPrintf(INDENT4 "SupportsUsi: %s\n", toString(mParameters.supportsUsi));
+ dump += StringPrintf(INDENT4 "UsiVersion: %s\n",
+ toString(mParameters.usiVersion, toString).c_str());
dump += StringPrintf(INDENT4 "EnableForInactiveViewport: %s\n",
toString(mParameters.enableForInactiveViewport));
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 6e35b46..87deb39 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -234,8 +234,8 @@
bool wake;
- // Whether the device supports the Universal Stylus Initiative (USI) protocol for styluses.
- bool supportsUsi;
+ // The Universal Stylus Initiative (USI) protocol version supported by this device.
+ std::optional<InputDeviceUsiVersion> usiVersion;
// Allows touches while the display is off.
bool enableForInactiveViewport;
diff --git a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
index bd05360..7265362 100644
--- a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
+++ b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp
@@ -15,6 +15,7 @@
*/
#include <gtest/gtest.h>
+#include <gui/constants.h>
#include "../PreferStylusOverTouchBlocker.h"
namespace android {
@@ -438,7 +439,7 @@
InputDeviceInfo stylusDevice;
stylusDevice.initialize(STYLUS_DEVICE_ID, 1 /*generation*/, 1 /*controllerNumber*/,
{} /*identifier*/, "stylus device", false /*external*/,
- false /*hasMic*/);
+ false /*hasMic*/, ADISPLAY_ID_NONE);
notifyInputDevicesChanged({stylusDevice});
// The touchscreen device was removed, so we no longer remember anything about it. We should
// again start blocking touch events from it.
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index 4c84160..e12f88e 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -105,7 +105,7 @@
auto info = InputDeviceInfo();
info.initialize(DEVICE_ID, /*generation*/ 1, /*controllerNumber*/ 1, identifier, "alias",
- /*isExternal*/ false, /*hasMic*/ false);
+ /*isExternal*/ false, /*hasMic*/ false, ADISPLAY_ID_NONE);
info.addSource(AINPUT_SOURCE_TOUCHSCREEN);
info.addMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN, 0, 1599, /*flat*/ 0,
/*fuzz*/ 0, X_RESOLUTION);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 0982077..2b6a519 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -479,8 +479,9 @@
const auto& desiredMode = *info.modeOpt->modePtr;
// Check if we are already at the desired mode
- if (!force && refreshRateSelector().getActiveMode().modePtr->getId() == desiredMode.getId()) {
- if (refreshRateSelector().getActiveMode() == info.modeOpt) {
+ const auto currentMode = refreshRateSelector().getActiveMode();
+ if (!force && currentMode.modePtr->getId() == desiredMode.getId()) {
+ if (currentMode == info.modeOpt) {
return DesiredActiveModeAction::None;
}
@@ -488,6 +489,11 @@
return DesiredActiveModeAction::InitiateRenderRateSwitch;
}
+ // Set the render frame rate to the current physical refresh rate to schedule the next
+ // frame as soon as possible.
+ setActiveMode(currentMode.modePtr->getId(), currentMode.modePtr->getFps(),
+ currentMode.modePtr->getFps());
+
// Initiate a mode change.
mDesiredActiveModeChanged = true;
mDesiredActiveMode = info;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 31074b1..d54d22d 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -314,12 +314,12 @@
virtual void parseArgs(const Vector<String16>& args, std::string& result) = 0;
// Sets the max number of display frames that can be stored. Called by SF backdoor.
- virtual void setMaxDisplayFrames(uint32_t size);
+ virtual void setMaxDisplayFrames(uint32_t size) = 0;
// Computes the historical fps for the provided set of layer IDs
// The fps is compted from the linear timeline of present timestamps for DisplayFrames
// containing at least one layer ID.
- virtual float computeFps(const std::unordered_set<int32_t>& layerIds);
+ virtual float computeFps(const std::unordered_set<int32_t>& layerIds) = 0;
// Restores the max number of display frames to default. Called by SF backdoor.
virtual void reset() = 0;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 04c2d41..30821d8 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -32,6 +32,7 @@
#include <ftl/fake_guard.h>
#include <ftl/match.h>
#include <ftl/unit.h>
+#include <gui/TraceUtils.h>
#include <scheduler/FrameRateMode.h>
#include <utils/Trace.h>
@@ -416,8 +417,10 @@
// Keep the display at max frame rate for the duration of powering on the display.
if (signals.powerOnImminent) {
ALOGV("Power On Imminent");
- return {rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Descending),
- GlobalSignals{.powerOnImminent = true}};
+ const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Descending);
+ ATRACE_FORMAT_INSTANT("%s (Power On Imminent)",
+ to_string(ranking.front().frameRateMode.fps).c_str());
+ return {ranking, GlobalSignals{.powerOnImminent = true}};
}
int noVoteLayers = 0;
@@ -476,8 +479,10 @@
// selected a refresh rate to see if we should apply touch boost.
if (signals.touch && !hasExplicitVoteLayers) {
ALOGV("Touch Boost");
- return {rankFrameRates(anchorGroup, RefreshRateOrder::Descending),
- GlobalSignals{.touch = true}};
+ const auto ranking = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
+ ATRACE_FORMAT_INSTANT("%s (Touch Boost)",
+ to_string(ranking.front().frameRateMode.fps).c_str());
+ return {ranking, GlobalSignals{.touch = true}};
}
// If the primary range consists of a single refresh rate then we can only
@@ -488,19 +493,26 @@
if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
ALOGV("Idle");
- return {rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending),
- GlobalSignals{.idle = true}};
+ const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending);
+ ATRACE_FORMAT_INSTANT("%s (Idle)", to_string(ranking.front().frameRateMode.fps).c_str());
+ return {ranking, GlobalSignals{.idle = true}};
}
if (layers.empty() || noVoteLayers == layers.size()) {
ALOGV("No layers with votes");
- return {rankFrameRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals};
+ const auto ranking = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
+ ATRACE_FORMAT_INSTANT("%s (No layers with votes)",
+ to_string(ranking.front().frameRateMode.fps).c_str());
+ return {ranking, kNoSignals};
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
ALOGV("All layers Min");
- return {rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending), kNoSignals};
+ const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending);
+ ATRACE_FORMAT_INSTANT("%s (All layers Min)",
+ to_string(ranking.front().frameRateMode.fps).c_str());
+ return {ranking, kNoSignals};
}
// Find the best refresh rate based on score
@@ -670,8 +682,13 @@
// range instead of picking a random score from the app range.
if (noLayerScore) {
ALOGV("Layers not scored");
- return {rankFrameRates(anchorGroup, RefreshRateOrder::Descending), kNoSignals};
+ const auto descending = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
+ ATRACE_FORMAT_INSTANT("%s (Layers not scored)",
+ to_string(descending.front().frameRateMode.fps).c_str());
+ return {descending, kNoSignals};
} else {
+ ATRACE_FORMAT_INSTANT("%s (primaryRangeIsSingleRate)",
+ to_string(ranking.front().frameRateMode.fps).c_str());
return {ranking, kNoSignals};
}
}
@@ -696,17 +713,22 @@
if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
ALOGV("Touch Boost");
+ ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
+ to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
return {touchRefreshRates, GlobalSignals{.touch = true}};
}
// If we never scored any layers, and we don't favor high refresh rates, prefer to stay with the
// current config
if (noLayerScore && refreshRateOrder == RefreshRateOrder::Ascending) {
- const auto preferredDisplayMode = activeMode.getId();
- return {rankFrameRates(anchorGroup, RefreshRateOrder::Ascending, preferredDisplayMode),
- kNoSignals};
+ const auto ascendingWithPreferred =
+ rankFrameRates(anchorGroup, RefreshRateOrder::Ascending, activeMode.getId());
+ ATRACE_FORMAT_INSTANT("%s (preferredDisplayMode)",
+ to_string(ascendingWithPreferred.front().frameRateMode.fps).c_str());
+ return {ascendingWithPreferred, kNoSignals};
}
+ ATRACE_FORMAT_INSTANT("%s (scored))", to_string(ranking.front().frameRateMode.fps).c_str());
return {ranking, kNoSignals};
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2d8b9c1..40de4d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1152,6 +1152,10 @@
switch (display->setDesiredActiveMode(DisplayDevice::ActiveModeInfo(std::move(request)),
force)) {
case DisplayDevice::DesiredActiveModeAction::InitiateDisplayModeSwitch:
+ // Set the render rate as setDesiredActiveMode updated it.
+ mScheduler->setRenderRate(display->refreshRateSelector().getActiveMode().fps);
+
+ // Schedule a new frame to initiate the display mode switch.
scheduleComposite(FrameHint::kNone);
// Start receiving vsync samples now, so that we can detect a period
@@ -1833,17 +1837,6 @@
return NO_ERROR;
}
-bool SurfaceFlinger::hasVisibleHdrLayer(const sp<DisplayDevice>& display) {
- bool hasHdrLayers = false;
- mDrawingState.traverse([&,
- compositionDisplay = display->getCompositionDisplay()](Layer* layer) {
- hasHdrLayers |= (layer->isVisible() &&
- compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) &&
- isHdrDataspace(layer->getDataSpace()));
- });
- return hasHdrLayers;
-}
-
status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
if (!displayToken) {
@@ -2638,7 +2631,8 @@
int32_t maxArea = 0;
mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
const auto layerFe = layer->getCompositionEngineLayerFE();
- if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) {
+ if (layer->isVisible() &&
+ compositionDisplay->includesLayer(layer->getOutputFilter())) {
if (isHdrLayer(layer)) {
const auto* outputLayer =
compositionDisplay->getOutputLayerForLayer(layerFe);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 33f0402..5457be8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -673,9 +673,6 @@
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock, kMainThreadContext);
- // Returns true if the display has a visible HDR layer in its layer stack.
- bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
-
// Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that
// display. Falls back to the display's defaultModeId otherwise.
ftl::Optional<scheduler::FrameRateMode> getPreferredDisplayMode(