[automerger skipped] Merge Android 14 am: 13c58a5ba6 -s ours am: 8731c09aee -s ours am: eacaaa2eff -s ours am: 56ddccbb1c -s ours
am skip reason: Merged-In I2450bb23241a33c6e94bc5d039e44bf782c07ef9 with SHA-1 4c45770465 is already in history
Original change: https://android-review.googlesource.com/c/platform/hardware/google/graphics/common/+/2776762
Change-Id: I49b0cba029f16686f23cef4930dd8b2f38ea98ee
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.clang-format b/.clang-format
index 03af56d..f63f670 100644
--- a/.clang-format
+++ b/.clang-format
@@ -11,3 +11,7 @@
IndentWidth: 4
PenaltyBreakBeforeFirstCallParameter: 100000
SpacesBeforeTrailingComments: 1
+IncludeBlocks: Preserve
+
+DerivePointerAlignment: false
+PointerAlignment: Left
diff --git a/gralloc-headers/Android.bp b/gralloc-headers/Android.bp
new file mode 100644
index 0000000..b87e472
--- /dev/null
+++ b/gralloc-headers/Android.bp
@@ -0,0 +1,20 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library_headers {
+ name: "pixel-gralloc-headers",
+ // TODO(270442578): Change to vendor: true
+ vendor_available: true,
+ export_include_dirs: [
+ ".",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.common-V4-ndk",
+ "libgralloctypes",
+ ],
+ visibility: [
+ "//visibility:public",
+ ],
+}
+
diff --git a/gralloc-headers/OWNERS b/gralloc-headers/OWNERS
new file mode 100644
index 0000000..0b8b903
--- /dev/null
+++ b/gralloc-headers/OWNERS
@@ -0,0 +1,3 @@
+jessehall@google.com
+layog@google.com
+spyffe@google.com
diff --git a/gralloc-headers/pixel-gralloc/format.h b/gralloc-headers/pixel-gralloc/format.h
new file mode 100644
index 0000000..4463067
--- /dev/null
+++ b/gralloc-headers/pixel-gralloc/format.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+
+#include <cstdint>
+
+namespace pixel::graphics {
+
+using FrameworkFormat = aidl::android::hardware::graphics::common::PixelFormat;
+
+#define MapFormat(f) f = static_cast<uint32_t>(FrameworkFormat::f)
+
+enum class Format : uint32_t {
+ MapFormat(UNSPECIFIED),
+ MapFormat(RGBA_8888),
+ MapFormat(RGBX_8888),
+ MapFormat(RGB_888),
+ MapFormat(RGB_565),
+ MapFormat(BGRA_8888),
+ MapFormat(YCBCR_422_SP),
+ MapFormat(YCRCB_420_SP),
+ MapFormat(YCBCR_422_I),
+ MapFormat(RGBA_FP16),
+ MapFormat(RAW16),
+ MapFormat(BLOB),
+ MapFormat(IMPLEMENTATION_DEFINED),
+ MapFormat(YCBCR_420_888),
+ MapFormat(RAW_OPAQUE),
+ MapFormat(RAW10),
+ MapFormat(RAW12),
+ MapFormat(RGBA_1010102),
+ MapFormat(Y8),
+ MapFormat(Y16),
+ MapFormat(YV12),
+ MapFormat(DEPTH_16),
+ MapFormat(DEPTH_24),
+ MapFormat(DEPTH_24_STENCIL_8),
+ MapFormat(DEPTH_32F),
+ MapFormat(DEPTH_32F_STENCIL_8),
+ MapFormat(STENCIL_8),
+ MapFormat(YCBCR_P010),
+ MapFormat(HSV_888),
+ MapFormat(R_8),
+ MapFormat(R_16_UINT),
+ MapFormat(RG_1616_UINT),
+ MapFormat(RGBA_10101010),
+
+ // Pixel specific formats
+ GOOGLE_NV12 = 0x301,
+};
+
+#undef MapFormat
+
+} // namespace pixel::graphics
diff --git a/gralloc-headers/pixel-gralloc/metadata.h b/gralloc-headers/pixel-gralloc/metadata.h
new file mode 100644
index 0000000..7502f29
--- /dev/null
+++ b/gralloc-headers/pixel-gralloc/metadata.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
+#include <gralloctypes/Gralloc4.h>
+
+#include <cstdint>
+#include <limits>
+
+namespace pixel::graphics {
+
+constexpr const char* kGralloc4StandardMetadataTypeName = GRALLOC4_STANDARD_METADATA_TYPE;
+constexpr const char* kPixelMetadataTypeName = "android.hardware.graphics.common.PixelMetadataType";
+
+using StandardMetadataType = aidl::android::hardware::graphics::common::StandardMetadataType;
+
+#define MapMetadataType(f) f = static_cast<uint64_t>(StandardMetadataType::f)
+
+// This seemingly clashes with MetadataType in Mapper, but this enum represents just the "value"
+// member of that struct. MetadataType comprises of a metadata name and value. Name is just there to
+// identify what kind of metadata it is. So, for all StandardMetadataType, clients need to use
+// kGralloc4StandardMetadataType and for pixel specific metadata, clients should use
+// kPixelMetadataType.
+enum class MetadataType : int64_t {
+ MapMetadataType(INVALID),
+ MapMetadataType(BUFFER_ID),
+ MapMetadataType(NAME),
+ MapMetadataType(WIDTH),
+ MapMetadataType(HEIGHT),
+ MapMetadataType(LAYER_COUNT),
+ MapMetadataType(PIXEL_FORMAT_REQUESTED),
+ MapMetadataType(PIXEL_FORMAT_FOURCC),
+ MapMetadataType(PIXEL_FORMAT_MODIFIER),
+ MapMetadataType(USAGE),
+ MapMetadataType(ALLOCATION_SIZE),
+ MapMetadataType(PROTECTED_CONTENT),
+ MapMetadataType(COMPRESSION),
+ MapMetadataType(INTERLACED),
+ MapMetadataType(CHROMA_SITING),
+ MapMetadataType(PLANE_LAYOUTS),
+ MapMetadataType(CROP),
+ MapMetadataType(DATASPACE),
+ MapMetadataType(BLEND_MODE),
+ MapMetadataType(SMPTE2086),
+ MapMetadataType(CTA861_3),
+ MapMetadataType(SMPTE2094_40),
+ MapMetadataType(SMPTE2094_10),
+ MapMetadataType(STRIDE),
+
+ // Pixel specific metadata
+ // Make sure to use kPixelMetadataType as the name when using these metadata.
+
+ // TODO: These metadata queries returns a pointer inside metadata for now. Need to change that
+ // so we are returning proper data only.
+ VIDEO_HDR = std::numeric_limits<int64_t>::max() - (1 << 16),
+
+ // TODO(b/289448426#comment2): ROIINFO is probably not being used. Remove this after
+ // confirmation.
+ VIDEO_ROI,
+};
+
+#undef MapMetadataType
+
+} // namespace pixel::graphics
diff --git a/gralloc-headers/pixel-gralloc/usage.h b/gralloc-headers/pixel-gralloc/usage.h
new file mode 100644
index 0000000..323e3c2
--- /dev/null
+++ b/gralloc-headers/pixel-gralloc/usage.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+
+#include <cstdint>
+
+namespace pixel::graphics {
+
+using FrameworkUsage = aidl::android::hardware::graphics::common::BufferUsage;
+
+#define MapUsage(f) f = static_cast<uint32_t>(FrameworkUsage::f)
+
+enum Usage : uint64_t {
+ MapUsage(CPU_READ_MASK),
+ MapUsage(CPU_READ_NEVER),
+ MapUsage(CPU_READ_RARELY),
+ MapUsage(CPU_READ_OFTEN),
+ MapUsage(CPU_WRITE_MASK),
+ MapUsage(CPU_WRITE_NEVER),
+ MapUsage(CPU_WRITE_RARELY),
+ MapUsage(CPU_WRITE_OFTEN),
+ MapUsage(GPU_TEXTURE),
+ MapUsage(GPU_RENDER_TARGET),
+ MapUsage(COMPOSER_OVERLAY),
+ MapUsage(COMPOSER_CLIENT_TARGET),
+ MapUsage(PROTECTED),
+ MapUsage(COMPOSER_CURSOR),
+ MapUsage(VIDEO_ENCODER),
+ MapUsage(CAMERA_OUTPUT),
+ MapUsage(CAMERA_INPUT),
+ MapUsage(RENDERSCRIPT),
+ MapUsage(VIDEO_DECODER),
+ MapUsage(SENSOR_DIRECT_DATA),
+ MapUsage(GPU_DATA_BUFFER),
+ MapUsage(GPU_CUBE_MAP),
+ MapUsage(GPU_MIPMAP_COMPLETE),
+ MapUsage(HW_IMAGE_ENCODER),
+ MapUsage(FRONT_BUFFER),
+ MapUsage(VENDOR_MASK),
+ MapUsage(VENDOR_MASK_HI),
+
+ // Pixel specific usage
+ NO_COMPRESSION = 1ULL << 29,
+};
+
+#undef MapUsage
+
+} // namespace pixel::graphics
diff --git a/hwc3/Android.mk b/hwc3/Android.mk
index 28ed88d..6358a90 100644
--- a/hwc3/Android.mk
+++ b/hwc3/Android.mk
@@ -28,14 +28,15 @@
LOCAL_CFLAGS += \
-DSOC_VERSION=$(soc_ver) \
- -DLOG_TAG=\"hwc-3\"
+ -DLOG_TAG=\"hwc-3\" \
+ -Wthread-safety
# hwc3 re-uses hwc2.2 ComposerResource and libexynosdisplay
LOCAL_SHARED_LIBRARIES := android.hardware.graphics.composer3-V2-ndk \
android.hardware.graphics.composer@2.1-resources \
android.hardware.graphics.composer@2.2-resources \
android.hardware.graphics.composer@2.4 \
- com.google.hardware.pixel.display-V8-ndk \
+ com.google.hardware.pixel.display-V9-ndk \
libbase \
libbinder \
libbinder_ndk \
diff --git a/hwc3/Composer.h b/hwc3/Composer.h
index 9324c0b..d35c3de 100644
--- a/hwc3/Composer.h
+++ b/hwc3/Composer.h
@@ -43,7 +43,7 @@
const std::unique_ptr<IComposerHal> mHal;
std::mutex mClientMutex;
- bool mClientAlive GUARDED_BY(mClientMutex) = false;
+ bool mClientAlive = false; // GUARDED_BY(mClientMutex)
std::condition_variable mClientDestroyedCondition;
};
diff --git a/hwc3/ComposerCommandEngine.cpp b/hwc3/ComposerCommandEngine.cpp
index 8b0f005..eac4df2 100644
--- a/hwc3/ComposerCommandEngine.cpp
+++ b/hwc3/ComposerCommandEngine.cpp
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+#include "ComposerCommandEngine.h"
+
+#include <hardware/hwcomposer2.h>
+
#include <set>
-#include "ComposerCommandEngine.h"
#include "Util.h"
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -145,7 +148,7 @@
&requestedLayers, &requestMasks, &clientTargetProperty,
&dimmingStage);
mResources->setDisplayMustValidateState(display, false);
- if (!err) {
+ if (err == HWC2_ERROR_NONE || err == HWC2_ERROR_HAS_CHANGES) {
mWriter->setChangedCompositionTypes(display, changedLayers, compositionTypes);
mWriter->setDisplayRequests(display, displayRequestMask, requestedLayers, requestMasks);
static constexpr float kBrightness = 1.f;
@@ -233,17 +236,31 @@
int64_t display, const std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
executeSetExpectedPresentTimeInternal(display, expectedPresentTime);
// First try to Present as is.
- auto err = mResources->mustValidateDisplay(display) ? IComposerClient::EX_NOT_VALIDATED
- : executePresentDisplay(display);
- if (!err) {
+ auto presentErr = mResources->mustValidateDisplay(display) ? IComposerClient::EX_NOT_VALIDATED
+ : executePresentDisplay(display);
+ if (!presentErr) {
mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented);
return;
}
// Fallback to validate
- err = executeValidateDisplayInternal(display);
- if (!err) {
+ auto validateErr = executeValidateDisplayInternal(display);
+ if (validateErr != HWC2_ERROR_NONE && validateErr != HWC2_ERROR_HAS_CHANGES) return;
+
+ bool hasClientComp = false;
+ bool cannotPresentDirectly = (validateErr == HWC2_ERROR_HAS_CHANGES) ||
+ (mHal->getHasClientComposition(display, hasClientComp) == HWC2_ERROR_NONE &&
+ hasClientComp);
+ if (cannotPresentDirectly) {
mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Validated);
+ return;
+ }
+
+ // Try to call present again
+ executeAcceptDisplayChanges(display);
+ presentErr = executePresentDisplay(display);
+ if (!presentErr) {
+ mWriter->setPresentOrValidateResult(display, PresentOrValidate::Result::Presented);
}
}
diff --git a/hwc3/impl/HalImpl.cpp b/hwc3/impl/HalImpl.cpp
index 93cc6ad..d8fe206 100644
--- a/hwc3/impl/HalImpl.cpp
+++ b/hwc3/impl/HalImpl.cpp
@@ -691,6 +691,15 @@
return halDisplay->setClientTarget(target, hwcFence, hwcDataspace);
}
+int32_t HalImpl::getHasClientComposition(int64_t display, bool& outHasClientComp) {
+ ExynosDisplay* halDisplay;
+ RET_IF_ERR(getHalDisplay(display, halDisplay));
+
+ outHasClientComp = halDisplay->hasClientComposition();
+
+ return HWC2_ERROR_NONE;
+}
+
int32_t HalImpl::setColorMode(int64_t display, ColorMode mode, RenderIntent intent) {
ExynosDisplay* halDisplay;
RET_IF_ERR(getHalDisplay(display, halDisplay));
@@ -1032,7 +1041,7 @@
h2a::translate(hwcProperty, *outClientTargetProperty);
} // else ignore this error
- return HWC2_ERROR_NONE;
+ return err;
}
int HalImpl::setExpectedPresentTime(
diff --git a/hwc3/impl/HalImpl.h b/hwc3/impl/HalImpl.h
index 9cb8f1d..9822ff7 100644
--- a/hwc3/impl/HalImpl.h
+++ b/hwc3/impl/HalImpl.h
@@ -99,6 +99,7 @@
int32_t setClientTarget(int64_t display, buffer_handle_t target,
const ndk::ScopedFileDescriptor& fence, common::Dataspace dataspace,
const std::vector<common::Rect>& damage) override;
+ int32_t getHasClientComposition(int64_t display, bool& outHasClientComp) override;
int32_t setColorMode(int64_t display, ColorMode mode, RenderIntent intent) override;
int32_t setColorTransform(int64_t display, const std::vector<float>& matrix) override;
int32_t setContentType(int64_t display, ContentType contentType) override;
diff --git a/hwc3/include/IComposerHal.h b/hwc3/include/IComposerHal.h
index 9a9108f..93dda20 100644
--- a/hwc3/include/IComposerHal.h
+++ b/hwc3/include/IComposerHal.h
@@ -174,6 +174,7 @@
const ndk::ScopedFileDescriptor& fence,
common::Dataspace dataspace,
const std::vector<common::Rect>& damage) = 0; // cmd
+ virtual int32_t getHasClientComposition(int64_t display, bool& outHasClientComp) = 0;
virtual int32_t setColorMode(int64_t display, ColorMode mode, RenderIntent intent) = 0;
virtual int32_t setColorTransform(int64_t display, const std::vector<float>& matrix) = 0; // cmd
virtual int32_t setContentType(int64_t display, ContentType contentType) = 0;
diff --git a/include/displaycolor/displaycolor.h b/include/displaycolor/displaycolor.h
index 4161bee..8cef849 100644
--- a/include/displaycolor/displaycolor.h
+++ b/include/displaycolor/displaycolor.h
@@ -142,6 +142,7 @@
virtual std::optional<uint32_t> NitsToDbv(BrightnessMode bm, float nits) const = 0;
virtual std::optional<float> DbvToNits(BrightnessMode bm, uint32_t dbv) const = 0;
virtual std::optional<float> NitsToBrightness(float nits) const = 0;
+ virtual std::optional<float> DbvToBrightness(uint32_t dbv) const = 0;
};
/**
@@ -320,6 +321,7 @@
lhbm_on == rhs.lhbm_on &&
dbv == rhs.dbv &&
refresh_rate == rhs.refresh_rate &&
+ operation_rate == rhs.operation_rate &&
hdr_layer_state == rhs.hdr_layer_state;
}
bool operator!=(const DisplayScene &rhs) const {
@@ -359,6 +361,9 @@
/// refresh rate
float refresh_rate = 60.0f;
+ /// operation rate to switch between hs/ns mode
+ uint32_t operation_rate;
+
/// hdr layer state on screen
HdrLayerState hdr_layer_state = HdrLayerState::kHdrNone;
};
diff --git a/libacryl/Android.mk b/libacryl/Android.mk
index 2984d2d..98a51f2 100644
--- a/libacryl/Android.mk
+++ b/libacryl/Android.mk
@@ -17,6 +17,7 @@
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DLOG_TAG=\"hwc-libacryl\"
+LOCAL_CFLAGS += -Wthread-safety
#LOCAL_CFLAGS += -DLIBACRYL_DEBUG
ifdef BOARD_LIBACRYL_DEFAULT_COMPOSITOR
diff --git a/libhwc2.1/Android.mk b/libhwc2.1/Android.mk
index 1e23ab7..5224595 100644
--- a/libhwc2.1/Android.mk
+++ b/libhwc2.1/Android.mk
@@ -44,6 +44,7 @@
LOCAL_CFLAGS := -DHLOG_CODE=0
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
+LOCAL_CFLAGS += -Wthread-safety
LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libdrm
LOCAL_MODULE := libdrmresource
@@ -68,7 +69,7 @@
android.hardware.power-V2-ndk pixel-power-ext-V1-ndk
LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V2-ndk \
- com.google.hardware.pixel.display-V8-ndk \
+ com.google.hardware.pixel.display-V9-ndk \
libbinder_ndk \
libbase \
libpng \
@@ -112,6 +113,7 @@
libdevice/ExynosDisplay.cpp \
libdevice/ExynosDevice.cpp \
libdevice/ExynosLayer.cpp \
+ libdevice/HistogramDevice.cpp \
libmaindisplay/ExynosPrimaryDisplay.cpp \
libresource/ExynosMPP.cpp \
libresource/ExynosResourceManager.cpp \
@@ -138,6 +140,7 @@
LOCAL_CFLAGS += -DLOG_TAG=\"hwc-display\"
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
+LOCAL_CFLAGS += -Wthread-safety
LOCAL_MODULE := libexynosdisplay
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
@@ -162,7 +165,7 @@
android.hardware.graphics.mapper@2.0 \
android.hardware.graphics.composer3-V2-ndk
-LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V8-ndk \
+LOCAL_SHARED_LIBRARIES += com.google.hardware.pixel.display-V9-ndk \
libbinder_ndk \
libbase
@@ -195,6 +198,7 @@
LOCAL_CFLAGS := -DHLOG_CODE=0
LOCAL_CFLAGS += -DLOG_TAG=\"hwc-service\"
LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
+LOCAL_CFLAGS += -Wthread-safety
LOCAL_SRC_FILES := \
libhwcService/IExynosHWC.cpp \
@@ -224,7 +228,7 @@
libui
LOCAL_SHARED_LIBRARIES += android.hardware.graphics.composer3-V2-ndk \
- com.google.hardware.pixel.display-V8-ndk \
+ com.google.hardware.pixel.display-V9-ndk \
libbinder_ndk \
libbase
@@ -235,6 +239,7 @@
LOCAL_CFLAGS := -DHLOG_CODE=0
LOCAL_CFLAGS += -DLOG_TAG=\"hwc-2\"
LOCAL_CFLAGS += -DSOC_VERSION=$(soc_ver)
+LOCAL_CFLAGS += -Wthread-safety
ifeq ($(BOARD_USES_HWC_SERVICES),true)
LOCAL_CFLAGS += -DUSES_HWC_SERVICES
diff --git a/libhwc2.1/ExynosHWCDebug.cpp b/libhwc2.1/ExynosHWCDebug.cpp
index 3473d50..d43f76d 100644
--- a/libhwc2.1/ExynosHWCDebug.cpp
+++ b/libhwc2.1/ExynosHWCDebug.cpp
@@ -39,37 +39,3 @@
fileWriter.flush();
return ret;
}
-
-int32_t saveFenceTrace(ExynosDisplay *display) {
- int32_t ret = NO_ERROR;
- auto &fileWriter = display->mFenceFileWriter;
-
- if (!fileWriter.chooseOpenedFile()) {
- return -1;
- }
-
- ExynosDevice *device = display->mDevice;
-
- String8 saveString;
-
- struct timeval tv;
- gettimeofday(&tv, NULL);
- saveString.appendFormat("\n====== Fences at time:%s ======\n", getLocalTimeStr(tv).c_str());
-
- if (device != NULL) {
- for (const auto &[fd, info] : device->mFenceInfos) {
- saveString.appendFormat("---- Fence FD : %d, Display(%d) ----\n", fd, info.displayId);
- saveString.appendFormat("usage: %d, dupFrom: %d, pendingAllowed: %d, leaking: %d\n",
- info.usage, info.dupFrom, info.pendingAllowed, info.leaking);
-
- for (const auto &trace : info.traces) {
- saveString.appendFormat("> dir: %d, type: %d, ip: %d, time:%s\n", trace.direction,
- trace.type, trace.ip, getLocalTimeStr(trace.time).c_str());
- }
- }
- }
-
- fileWriter.write(saveString);
- fileWriter.flush();
- return ret;
-}
diff --git a/libhwc2.1/ExynosHWCDebug.h b/libhwc2.1/ExynosHWCDebug.h
index 2f2d0b3..bd62a2e 100644
--- a/libhwc2.1/ExynosHWCDebug.h
+++ b/libhwc2.1/ExynosHWCDebug.h
@@ -68,7 +68,18 @@
}
int32_t saveErrorLog(const android::String8 &errString, ExynosDisplay *display = NULL);
-int32_t saveFenceTrace(ExynosDisplay *display);
+
+#if defined(DISABLE_HWC_DEBUG)
+#define ALOGD_AND_ATRACE_NAME(debugFlag, fmt, ...)
+#else
+#define ALOGD_AND_ATRACE_NAME(debugFlag, fmt, ...) \
+ if (hwcCheckDebugMessages(debugFlag) || CC_UNLIKELY(ATRACE_ENABLED())) { \
+ String8 log; \
+ log.appendFormat((fmt), ##__VA_ARGS__); \
+ ALOGD("%s", log.c_str()); \
+ if (CC_UNLIKELY(ATRACE_ENABLED())) ATRACE_NAME(log.c_str()); \
+ }
+#endif
#if defined(DISABLE_HWC_DEBUG)
#define HDEBUGLOGD(...)
diff --git a/libhwc2.1/histogram_mediator.cpp b/libhwc2.1/histogram_mediator.cpp
index f23feec..b446d24 100644
--- a/libhwc2.1/histogram_mediator.cpp
+++ b/libhwc2.1/histogram_mediator.cpp
@@ -22,7 +22,6 @@
mIDLHistogram = std::make_shared<HistogramReceiver>();
moduleDisplayInterface->registerHistogramInfo(mIDLHistogram);
- moduleDisplayInterface->getPanelResolution();
}
uint32_t histogram::HistogramMediator::getFrameCount() {
ExynosDisplayDrmInterface *moduleDisplayInterface =
@@ -30,27 +29,8 @@
return moduleDisplayInterface->getFrameCount();
}
-bool histogram::HistogramMediator::isDisplayPowerOff() {
- if (!mDisplay->mPowerModeState.has_value() ||
- ((mDisplay->mPowerModeState.value() == HWC2_POWER_MODE_OFF) ||
- (mDisplay->mPowerModeState.value() == HWC2_POWER_MODE_DOZE))) {
- return true;
- }
- return false;
-}
-
-bool histogram::HistogramMediator::isSecureContentPresenting() {
- Mutex::Autolock lock(mDisplay->mDRMutex);
- for (uint32_t i = 0; i < mDisplay->mLayers.size(); i++) {
- ExynosLayer *layer = mDisplay->mLayers[i];
- if (layer != NULL && layer->isDrm()) { /* there is some DRM layer */
- return true;
- }
- }
- return false;
-}
histogram::HistogramErrorCode histogram::HistogramMediator::requestHist() {
- if (isSecureContentPresenting()) { /* there is some DRM layer */
+ if (mDisplay->isSecureContentPresenting()) {
return histogram::HistogramErrorCode::DRM_PLAYING;
}
ExynosDisplayDrmInterface *moduleDisplayInterface =
@@ -110,7 +90,7 @@
std::unique_lock<std::mutex> lk(mIDLHistogram->mDataCollectingMutex);
mIDLHistogram->mHistData_cv.wait_for(lk, std::chrono::milliseconds(50), [this]() {
- return (!isDisplayPowerOff() && !mIDLHistogram->mHistReq_pending);
+ return (!mDisplay->isPowerModeOff() && !mIDLHistogram->mHistReq_pending);
});
if (mIDLHistogram->mHistReq_pending == false) setSampleFrameCounter(getFrameCount());
buf->assign(mIDLHistogram->mHistData, mIDLHistogram->mHistData + HISTOGRAM_BINS_SIZE);
@@ -123,12 +103,12 @@
ExynosDisplayDrmInterface *moduleDisplayInterface =
static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get());
roi_return.left = roi.left * moduleDisplayInterface->getActiveModeHDisplay() /
- moduleDisplayInterface->panelHsize();
+ moduleDisplayInterface->getPanelFullResolutionHSize();
roi_return.top = roi.top * moduleDisplayInterface->getActiveModeVDisplay() /
- moduleDisplayInterface->panelVsize();
+ moduleDisplayInterface->getPanelFullResolutionVSize();
roi_return.right = roi.right * moduleDisplayInterface->getActiveModeHDisplay() /
- moduleDisplayInterface->panelHsize();
+ moduleDisplayInterface->getPanelFullResolutionHSize();
roi_return.bottom = roi.bottom * moduleDisplayInterface->getActiveModeVDisplay() /
- moduleDisplayInterface->panelVsize();
+ moduleDisplayInterface->getPanelFullResolutionVSize();
return roi_return;
}
diff --git a/libhwc2.1/histogram_mediator.h b/libhwc2.1/histogram_mediator.h
index 54d28c9..493524b 100644
--- a/libhwc2.1/histogram_mediator.h
+++ b/libhwc2.1/histogram_mediator.h
@@ -57,8 +57,6 @@
HistogramMediator(ExynosDisplay *display);
~HistogramMediator() {}
- bool isDisplayPowerOff();
- bool isSecureContentPresenting();
HistogramErrorCode requestHist();
HistogramErrorCode cancelHistRequest();
HistogramErrorCode collectRoiLuma(std::vector<char16_t> *buf);
diff --git a/libhwc2.1/libdevice/BrightnessController.cpp b/libhwc2.1/libdevice/BrightnessController.cpp
index 08912e0..2f9327e 100644
--- a/libhwc2.1/libdevice/BrightnessController.cpp
+++ b/libhwc2.1/libdevice/BrightnessController.cpp
@@ -64,6 +64,21 @@
return brightness;
}
+std::optional<float> BrightnessController::LinearBrightnessTable::DbvToBrightness(
+ uint32_t dbv) const {
+ BrightnessMode bm = getBrightnessModeForDbv(dbv);
+ if (bm == BrightnessMode::BM_INVALID) {
+ return std::nullopt;
+ }
+
+ std::optional<float> nits = DbvToNits(bm, dbv);
+ if (nits == std::nullopt) {
+ return std::nullopt;
+ }
+
+ return NitsToBrightness(nits.value());
+}
+
std::optional<float> BrightnessController::LinearBrightnessTable::BrightnessToNits(
float brightness, BrightnessMode& bm) const {
bm = GetBrightnessMode(brightness);
@@ -439,6 +454,20 @@
return processDisplayBrightness(brightness.value(), vsyncNs);
}
+int BrightnessController::setBrightnessDbv(uint32_t dbv, const nsecs_t vsyncNs) {
+ ALOGI("%s set brightness to %u dbv", __func__, dbv);
+
+ std::optional<float> brightness =
+ mBrightnessTable ? mBrightnessTable->DbvToBrightness(dbv) : std::nullopt;
+
+ if (brightness == std::nullopt) {
+ ALOGI("%s could not find brightness for %d dbv", __func__, dbv);
+ return -EINVAL;
+ }
+
+ return processDisplayBrightness(brightness.value(), vsyncNs);
+}
+
// In HWC3, brightness change could be applied via drm commit or sysfs path.
// If a brightness change command does not come with a frame update, this
// function wil be called to apply the brghtness change via sysfs path.
@@ -528,6 +557,7 @@
if (mColorRenderIntent.is_dirty()) {
updateAclMode();
ALOGI("%s Color Render Intent = %d", __func__, mColorRenderIntent.get());
+ mColorRenderIntent.clear_dirty();
}
}
diff --git a/libhwc2.1/libdevice/BrightnessController.h b/libhwc2.1/libdevice/BrightnessController.h
index 6733d46..63747f6 100644
--- a/libhwc2.1/libdevice/BrightnessController.h
+++ b/libhwc2.1/libdevice/BrightnessController.h
@@ -71,6 +71,7 @@
int processDisplayBrightness(float bl, const nsecs_t vsyncNs, bool waitPresent = false);
int ignoreBrightnessUpdateRequests(bool ignore);
int setBrightnessNits(float nits, const nsecs_t vsyncNs);
+ int setBrightnessDbv(uint32_t dbv, const nsecs_t vsyncNs);
int processLocalHbm(bool on);
int processDimBrightness(bool on);
int processOperationRate(int32_t hz);
@@ -264,6 +265,7 @@
}
std::optional<float> BrightnessToNits(float brightness, BrightnessMode& bm) const override;
std::optional<float> NitsToBrightness(float nits) const override;
+ std::optional<float> DbvToBrightness(uint32_t dbv) const override;
std::optional<uint32_t> NitsToDbv(BrightnessMode bm, float nits) const override;
std::optional<float> DbvToNits(BrightnessMode bm, uint32_t dbv) const override;
@@ -289,6 +291,16 @@
return BrightnessMode::BM_INVALID;
}
+ BrightnessMode getBrightnessModeForDbv(uint32_t dbv) const {
+ for (const auto& [mode, range] : mBrightnessRanges) {
+ if (dbv >= range.dbv_min && dbv <= range.dbv_max) {
+ return mode;
+ }
+ }
+ // return BM_INVALID if there is no matching range
+ return BrightnessMode::BM_INVALID;
+ }
+
private:
static void setBrightnessRangeFromAttribute(const struct brightness_attribute& attr,
displaycolor::DisplayBrightnessRange& range) {
@@ -359,14 +371,14 @@
void initDimmingUsage();
int applyBrightnessViaSysfs(uint32_t level);
int applyCabcModeViaSysfs(uint8_t mode);
- int updateStates() REQUIRES(mBrightnessMutex);
+ int updateStates(); // REQUIRES(mBrightnessMutex)
void dimmingThread();
void processDimmingOff();
int updateAclMode();
void parseHbmModeEnums(const DrmProperty& property);
- void printBrightnessStates(const char* path) REQUIRES(mBrightnessMutex);
+ void printBrightnessStates(const char* path); // REQUIRES(mBrightnessMutex)
bool mLhbmSupported = false;
bool mGhbmSupported = false;
@@ -382,19 +394,19 @@
// brightness state
std::recursive_mutex mBrightnessMutex;
// requests
- CtrlValue<bool> mEnhanceHbmReq GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mLhbmReq GUARDED_BY(mBrightnessMutex);
- CtrlValue<float> mBrightnessFloatReq GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mInstantHbmReq GUARDED_BY(mBrightnessMutex);
+ CtrlValue<bool> mEnhanceHbmReq; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mLhbmReq; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<float> mBrightnessFloatReq; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mInstantHbmReq; // GUARDED_BY(mBrightnessMutex)
// states to drm after updateStates call
- CtrlValue<uint32_t> mBrightnessLevel GUARDED_BY(mBrightnessMutex);
- CtrlValue<HbmMode> mGhbm GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mDimming GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mLhbm GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mSdrDim GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mPrevSdrDim GUARDED_BY(mBrightnessMutex);
- CtrlValue<bool> mDimBrightnessReq GUARDED_BY(mBrightnessMutex);
- CtrlValue<uint32_t> mOperationRate GUARDED_BY(mBrightnessMutex);
+ CtrlValue<uint32_t> mBrightnessLevel; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<HbmMode> mGhbm; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mDimming; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mLhbm; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mSdrDim; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mPrevSdrDim; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<bool> mDimBrightnessReq; // GUARDED_BY(mBrightnessMutex)
+ CtrlValue<uint32_t> mOperationRate; // GUARDED_BY(mBrightnessMutex)
// Indicating if the last LHBM on has changed the brightness level
bool mLhbmBrightnessAdj = false;
@@ -419,7 +431,7 @@
// these are dimming related
BrightnessDimmingUsage mBrightnessDimmingUsage = BrightnessDimmingUsage::NORMAL;
- bool mHbmDimming GUARDED_BY(mBrightnessMutex) = false;
+ bool mHbmDimming = false; // GUARDED_BY(mBrightnessMutex)
int32_t mHbmDimmingTimeUs = 0;
std::thread mDimmingThread;
std::atomic<bool> mDimmingThreadRunning;
@@ -461,9 +473,9 @@
static constexpr const char* kLocalCabcModeFileNode =
"/sys/class/backlight/panel%d-backlight/cabc_mode";
std::recursive_mutex mCabcModeMutex;
- bool mOutdoorVisibility GUARDED_BY(mCabcModeMutex) = false;
+ bool mOutdoorVisibility = false; // GUARDED_BY(mCabcModeMutex)
bool isHdrLayerOn() { return mHdrLayerState.get() == HdrLayerState::kHdrLarge; }
- CtrlValue<CabcMode> mCabcMode GUARDED_BY(mCabcModeMutex);
+ CtrlValue<CabcMode> mCabcMode; // GUARDED_BY(mCabcModeMutex)
};
#endif // _BRIGHTNESS_CONTROLLER_H_
diff --git a/libhwc2.1/libdevice/ExynosDevice.cpp b/libhwc2.1/libdevice/ExynosDevice.cpp
index 7ff868a..0f2d202 100644
--- a/libhwc2.1/libdevice/ExynosDevice.cpp
+++ b/libhwc2.1/libdevice/ExynosDevice.cpp
@@ -884,7 +884,8 @@
* All display's validateDisplay should be skipped or all display's validateDisplay
* should not be skipped.
*/
- if (mDisplays[i]->mPlugState) {
+ if (mDisplays[i]->mPlugState && mDisplays[i]->mPowerModeState.has_value() &&
+ mDisplays[i]->mPowerModeState.value() != HWC2_POWER_MODE_OFF) {
/*
* presentDisplay is called without validateDisplay.
* Call functions that should be called in validateDiplay
@@ -893,9 +894,11 @@
mDisplays[i]->checkLayerFps();
if ((ret = mDisplays[i]->canSkipValidate()) != NO_ERROR) {
- HDEBUGLOGD(eDebugSkipValidate, "Display[%d] can't skip validate (%d), renderingState(%d), geometryChanged(0x%" PRIx64 ")",
- mDisplays[i]->mDisplayId, ret,
- mDisplays[i]->mRenderingState, mGeometryChanged);
+ ALOGD_AND_ATRACE_NAME(eDebugSkipValidate,
+ "Display[%d] can't skip validate (%d), renderingState(%d), "
+ "geometryChanged(0x%" PRIx64 ")",
+ mDisplays[i]->mDisplayId, ret, mDisplays[i]->mRenderingState,
+ mGeometryChanged);
return false;
} else {
HDEBUGLOGD(eDebugSkipValidate, "Display[%d] can skip validate (%d), renderingState(%d), geometryChanged(0x%" PRIx64 ")",
@@ -908,27 +911,7 @@
}
bool ExynosDevice::validateFences(ExynosDisplay *display) {
- std::scoped_lock lock(display->mDevice->mFenceMutex);
-
- if (!validateFencePerFrame(display)) {
- ALOGE("You should doubt fence leak!");
- saveFenceTrace(display);
- return false;
- }
-
- if (fenceWarn(display, MAX_FENCE_THRESHOLD)) {
- printLeakFds(display);
- saveFenceTrace(display);
- return false;
- }
-
- if (exynosHWCControl.doFenceFileDump) {
- ALOGD("Fence file dump !");
- saveFenceTrace(display);
- exynosHWCControl.doFenceFileDump = false;
- }
-
- return true;
+ return mFenceTracker.validateFences(display);
}
void ExynosDevice::compareVsyncPeriod() {
diff --git a/libhwc2.1/libdevice/ExynosDevice.h b/libhwc2.1/libdevice/ExynosDevice.h
index 69c0839..bcfb112 100644
--- a/libhwc2.1/libdevice/ExynosDevice.h
+++ b/libhwc2.1/libdevice/ExynosDevice.h
@@ -207,9 +207,7 @@
uint32_t mDisplayMode;
- // Variable for fence tracer
- std::map<int, HwcFenceInfo> mFenceInfos GUARDED_BY(mFenceMutex);
- std::mutex mFenceMutex;
+ FenceTracker mFenceTracker;
/**
* This will be initialized with differnt class
diff --git a/libhwc2.1/libdevice/ExynosDisplay.cpp b/libhwc2.1/libdevice/ExynosDisplay.cpp
index fc15a14..a69c4b9 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.cpp
+++ b/libhwc2.1/libdevice/ExynosDisplay.cpp
@@ -38,6 +38,7 @@
#include "BrightnessController.h"
#include "ExynosExternalDisplay.h"
#include "ExynosLayer.h"
+#include "HistogramController.h"
#include "VendorGraphicBuffer.h"
#include "exynos_format.h"
#include "utils/Timers.h"
@@ -924,8 +925,7 @@
mCompressionInfo.type = compressionType;
}
-void ExynosCompositionInfo::dump(String8& result)
-{
+void ExynosCompositionInfo::dump(String8& result) const {
result.appendFormat("CompositionInfo (%d)\n", mType);
result.appendFormat("mHasCompositionLayer(%d)\n", mHasCompositionLayer);
if (mHasCompositionLayer) {
@@ -1498,10 +1498,6 @@
}
}
-bool ExynosDisplay::isFrameUpdate() {
- return mGeometryChanged > 0 || mBufferUpdates > 0;
-}
-
int ExynosDisplay::handleStaticLayers(ExynosCompositionInfo& compositionInfo)
{
if (compositionInfo.mType != COMPOSITION_CLIENT)
@@ -2453,8 +2449,8 @@
result.appendFormat("Device mGeometryChanged(%" PRIx64 "), mGeometryChanged(%" PRIx64 "), mRenderingState(%d)\n",
mDevice->mGeometryChanged, mGeometryChanged, mRenderingState);
result.appendFormat("======================= dump composition infos ================================\n");
- ExynosCompositionInfo clientCompInfo = mClientCompositionInfo;
- ExynosCompositionInfo exynosCompInfo = mExynosCompositionInfo;
+ const ExynosCompositionInfo& clientCompInfo = mClientCompositionInfo;
+ const ExynosCompositionInfo& exynosCompInfo = mExynosCompositionInfo;
clientCompInfo.dump(result);
exynosCompInfo.dump(result);
ALOGD("%s", result.c_str());
@@ -3518,8 +3514,6 @@
DISPLAY_LOGD(eDebugSkipValidate, "validate is skipped");
}
- updateBrightnessState();
-
if (updateColorConversionInfo() != NO_ERROR) {
ALOGE("%s:: updateColorConversionInfo() fail, ret(%d)",
__func__, ret);
@@ -3553,6 +3547,7 @@
if ((mLayers.size() == 0) &&
(mType != HWC_DISPLAY_VIRTUAL)) {
+ ALOGI("%s:: layer size is 0", __func__);
clearDisplay();
*outRetireFence = -1;
mLastRetireFence = fence_close(mLastRetireFence, this,
@@ -3563,6 +3558,7 @@
}
if (!checkFrameValidation()) {
+ ALOGW("%s: checkFrameValidation fail", __func__);
clearDisplay();
*outRetireFence = -1;
mLastRetireFence = fence_close(mLastRetireFence, this,
@@ -3633,7 +3629,7 @@
mPowerHalHint.signalIdle();
}
- if (isFrameUpdate()) {
+ if (needUpdateRRIndicator()) {
updateRefreshRateIndicator();
}
@@ -4062,6 +4058,23 @@
return HWC2_ERROR_UNSUPPORTED;
}
+int32_t ExynosDisplay::setBrightnessDbv(const uint32_t dbv) {
+ if (mBrightnessController) {
+ int32_t ret = mBrightnessController->setBrightnessDbv(dbv, mVsyncPeriod);
+
+ if (ret == NO_ERROR) {
+ setMinIdleRefreshRate(0, VrrThrottleRequester::BRIGHTNESS);
+ if (mOperationRateManager) {
+ mOperationRateManager->onBrightness(mBrightnessController->getBrightnessLevel());
+ }
+ }
+
+ return ret;
+ }
+
+ return HWC2_ERROR_UNSUPPORTED;
+}
+
int32_t ExynosDisplay::getDisplayConnectionType(uint32_t* outType)
{
if (mType == HWC_DISPLAY_PRIMARY)
@@ -4180,8 +4193,8 @@
mXres, mYres, mVsyncPeriod, mXdpi, mYdpi);
if (mConfigRequestState == hwc_request_state_t::SET_CONFIG_STATE_REQUESTED) {
- DISPLAY_LOGI("%s, previous request config is processing (mDesiredConfig: %d)", __func__,
- mDesiredConfig);
+ DISPLAY_LOGI("%s, previous request config is processing (desird %d, new request %d)",
+ __func__, mDesiredConfig, config);
}
/* Config would be requested on present time */
mConfigRequestState = hwc_request_state_t::SET_CONFIG_STATE_PENDING;
@@ -4413,7 +4426,7 @@
current, actualChangeTime,
mVsyncPeriodChangeConstraints.desiredTimeNanos);
if (actualChangeTime >= mVsyncPeriodChangeConstraints.desiredTimeNanos) {
- DISPLAY_LOGD(eDebugDisplayConfig, "Request setActiveConfig");
+ DISPLAY_LOGD(eDebugDisplayConfig, "Request setActiveConfig %d", mDesiredConfig);
needSetActiveConfig = true;
DISPLAY_ATRACE_INT("Pending ActiveConfig", 0);
DISPLAY_ATRACE_INT64("TimeToChangeConfig", 0);
@@ -4606,8 +4619,6 @@
mDisplayInterface->setForcePanic();
}
- updateBrightnessState();
-
if ((ret = skipStaticLayers(mClientCompositionInfo)) != NO_ERROR) {
validateError = true;
HWC_LOGE(this, "%s:: skipStaticLayers() fail, display(%d), ret(%d)", __func__, mDisplayId, ret);
@@ -4779,24 +4790,30 @@
result.appendFormat("PanelGammaSource (%d)\n\n", GetCurrentPanelGammaSource());
- if (mLayers.size()) {
- result.appendFormat("============================== dump layers ===========================================\n");
- for (uint32_t i = 0; i < mLayers.size(); i++) {
- ExynosLayer *layer = mLayers[i];
- layer->dump(result);
+ {
+ Mutex::Autolock lock(mDRMutex);
+ if (mLayers.size()) {
+ result.appendFormat("============================== dump layers ===========================================\n");
+ for (uint32_t i = 0; i < mLayers.size(); i++) {
+ ExynosLayer *layer = mLayers[i];
+ layer->dump(result);
+ }
}
- }
- if (mIgnoreLayers.size()) {
- result.appendFormat("\n============================== dump ignore layers ===========================================\n");
- for (uint32_t i = 0; i < mIgnoreLayers.size(); i++) {
- ExynosLayer *layer = mIgnoreLayers[i];
- layer->dump(result);
+ if (mIgnoreLayers.size()) {
+ result.appendFormat("\n============================== dump ignore layers ===========================================\n");
+ for (uint32_t i = 0; i < mIgnoreLayers.size(); i++) {
+ ExynosLayer *layer = mIgnoreLayers[i];
+ layer->dump(result);
+ }
}
}
result.appendFormat("\n");
if (mBrightnessController) {
mBrightnessController->dump(result);
}
+ if (mHistogramController) {
+ mHistogramController->dump(result);
+ }
}
void ExynosDisplay::dumpConfig(String8 &result, const exynos_win_config_data &c)
@@ -4852,14 +4869,11 @@
int32_t ExynosDisplay::setCompositionTargetExynosImage(uint32_t targetType, exynos_image *src_img, exynos_image *dst_img)
{
- std::optional<ExynosCompositionInfo> compositionInfo;
-
- if (targetType == COMPOSITION_CLIENT)
- compositionInfo = mClientCompositionInfo;
- else if (targetType == COMPOSITION_EXYNOS)
- compositionInfo = mExynosCompositionInfo;
-
- if (!compositionInfo) return -EINVAL;
+ if (targetType != COMPOSITION_CLIENT && targetType != COMPOSITION_EXYNOS) {
+ return -EINVAL;
+ }
+ const ExynosCompositionInfo& compositionInfo =
+ (targetType == COMPOSITION_CLIENT) ? mClientCompositionInfo : mExynosCompositionInfo;
src_img->fullWidth = mXres;
src_img->fullHeight = mYres;
@@ -4870,10 +4884,10 @@
src_img->w = mXres;
src_img->h = mYres;
- if (compositionInfo->mTargetBuffer != NULL) {
- src_img->bufferHandle = compositionInfo->mTargetBuffer;
+ if (compositionInfo.mTargetBuffer != NULL) {
+ src_img->bufferHandle = compositionInfo.mTargetBuffer;
- VendorGraphicBufferMeta gmeta(compositionInfo->mTargetBuffer);
+ VendorGraphicBufferMeta gmeta(compositionInfo.mTargetBuffer);
src_img->format = gmeta.format;
src_img->usageFlags = gmeta.producer_usage;
} else {
@@ -4882,21 +4896,21 @@
src_img->usageFlags = 0;
}
src_img->layerFlags = 0x0;
- src_img->acquireFenceFd = compositionInfo->mAcquireFence;
+ src_img->acquireFenceFd = compositionInfo.mAcquireFence;
src_img->releaseFenceFd = -1;
- src_img->dataSpace = compositionInfo->mDataSpace;
+ src_img->dataSpace = compositionInfo.mDataSpace;
src_img->blending = HWC2_BLEND_MODE_PREMULTIPLIED;
src_img->transform = 0;
- src_img->compressionInfo = compositionInfo->mCompressionInfo;
+ src_img->compressionInfo = compositionInfo.mCompressionInfo;
src_img->planeAlpha = 1;
src_img->zOrder = 0;
if ((targetType == COMPOSITION_CLIENT) && (mType == HWC_DISPLAY_VIRTUAL)) {
- if (compositionInfo->mLastIndex < mExynosCompositionInfo.mLastIndex)
+ if (compositionInfo.mLastIndex < mExynosCompositionInfo.mLastIndex)
src_img->zOrder = 0;
else
src_img->zOrder = 1000;
}
- src_img->needPreblending = compositionInfo->mNeedPreblending;
+ src_img->needPreblending = compositionInfo.mNeedPreblending;
dst_img->fullWidth = mXres;
dst_img->fullHeight = mYres;
@@ -4919,7 +4933,7 @@
dst_img->dataSpace = colorModeToDataspace(mColorMode);
dst_img->blending = HWC2_BLEND_MODE_NONE;
dst_img->transform = 0;
- dst_img->compressionInfo = compositionInfo->mCompressionInfo;
+ dst_img->compressionInfo = compositionInfo.mCompressionInfo;
dst_img->planeAlpha = 1;
dst_img->zOrder = src_img->zOrder;
@@ -5093,6 +5107,10 @@
return ret;
}
+bool ExynosDisplay::hasClientComposition() {
+ return mClientCompositionInfo.mHasCompositionLayer;
+}
+
int32_t ExynosDisplay::addExynosCompositionLayer(uint32_t layerIndex, float totalUsedCapa) {
bool invalidFlag = false;
int32_t changeFlag = NO_ERROR;
@@ -5337,6 +5355,24 @@
return changeFlag;
}
+bool ExynosDisplay::isPowerModeOff() const {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mDisplayMutex);
+ return mPowerModeState.has_value() && mPowerModeState.value() == HWC2_POWER_MODE_OFF;
+}
+
+bool ExynosDisplay::isSecureContentPresenting() const {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mDRMutex);
+ for (uint32_t i = 0; i < mLayers.size(); i++) {
+ ExynosLayer *layer = mLayers[i];
+ if (layer != NULL && layer->isDrm()) { /* there is some DRM layer */
+ return true;
+ }
+ }
+ return false;
+}
+
bool ExynosDisplay::windowUpdateExceptions()
{
@@ -5950,6 +5986,8 @@
for (size_t i = 0; i < mLayers.size(); i++) {
if (mLayers[i]->mIsHdrLayer) {
+ // TODO(longling): Below code block for RGB HDR is obsolete also
+ // need some fix (mExynosCompositionType is invalid at this time)
if (mLayers[i]->isLayerFormatRgb()) {
auto meta = mLayers[i]->getMetaParcel();
if ((meta != nullptr) && (meta->eType & VIDEO_INFO_TYPE_HDR_STATIC) &&
@@ -6260,7 +6298,11 @@
}
ExynosDisplay::RefreshRateIndicatorHandler::RefreshRateIndicatorHandler(ExynosDisplay *display)
- : mDisplay(display), mLastRefreshRate(0), mLastCallbackTime(0) {}
+ : mDisplay(display),
+ mLastRefreshRate(0),
+ mLastCallbackTime(0),
+ mIgnoringLastUpdate(false),
+ mCanIgnoreIncreaseUpdate(false) {}
int32_t ExynosDisplay::RefreshRateIndicatorHandler::init() {
auto path = String8::format(kRefreshRateStatePathFormat, mDisplay->mIndex);
@@ -6277,11 +6319,12 @@
void ExynosDisplay::RefreshRateIndicatorHandler::updateRefreshRateLocked(int refreshRate) {
ATRACE_CALL();
ATRACE_INT("Refresh rate indicator event", refreshRate);
- auto lastUpdate = mDisplay->getLastLayerUpdateTime();
// Ignore refresh rate increase that is caused by refresh rate indicator update but there's
// no update for the other layers
- if (refreshRate > mLastRefreshRate && mLastRefreshRate > 0 && lastUpdate < mLastCallbackTime) {
+ if (mCanIgnoreIncreaseUpdate && refreshRate > mLastRefreshRate && mLastRefreshRate > 0 &&
+ mDisplay->getLastLayerUpdateTime() < mLastCallbackTime) {
mIgnoringLastUpdate = true;
+ mCanIgnoreIncreaseUpdate = false;
return;
}
mIgnoringLastUpdate = false;
@@ -6292,6 +6335,7 @@
mLastCallbackTime = systemTime(CLOCK_MONOTONIC);
ATRACE_INT("Refresh rate indicator callback", mLastRefreshRate);
mDisplay->mDevice->onRefreshRateChangedDebug(mDisplay->mDisplayId, s2ns(1) / mLastRefreshRate);
+ mCanIgnoreIncreaseUpdate = true;
}
void ExynosDisplay::RefreshRateIndicatorHandler::handleSysfsEvent() {
@@ -6379,6 +6423,11 @@
mRefreshRateIndicatorHandler->handleSysfsEvent();
}
+bool ExynosDisplay::needUpdateRRIndicator() {
+ uint64_t exclude = GEOMETRY_LAYER_TYPE_CHANGED;
+ return (mGeometryChanged & ~exclude) > 0 || mBufferUpdates > 0;
+}
+
uint32_t ExynosDisplay::getPeakRefreshRate() {
float opRate = mBrightnessController->getOperationRate();
return static_cast<uint32_t>(std::round(opRate ?: mPeakRefreshRate));
diff --git a/libhwc2.1/libdevice/ExynosDisplay.h b/libhwc2.1/libdevice/ExynosDisplay.h
index faf055a..51286ad 100644
--- a/libhwc2.1/libdevice/ExynosDisplay.h
+++ b/libhwc2.1/libdevice/ExynosDisplay.h
@@ -57,6 +57,7 @@
class ExynosDevice;
class ExynosMPP;
class ExynosMPPSource;
+class HistogramController;
namespace aidl {
namespace google {
@@ -331,7 +332,7 @@
void setTargetBuffer(ExynosDisplay *display, buffer_handle_t handle,
int32_t acquireFence, android_dataspace dataspace);
void setCompressionType(uint32_t compressionType);
- void dump(String8& result);
+ void dump(String8& result) const;
String8 getTypeStr();
};
@@ -418,7 +419,7 @@
const String8 mDisplayName;
const String8 mDisplayTraceName;
HwcMountOrientation mMountOrientation = HwcMountOrientation::ROT_0;
- Mutex mDisplayMutex;
+ mutable Mutex mDisplayMutex;
/** State variables */
bool mPlugState;
@@ -486,7 +487,7 @@
dynamic_recomp_mode mDynamicReCompMode;
bool mDREnable;
bool mDRDefault;
- Mutex mDRMutex;
+ mutable Mutex mDRMutex;
nsecs_t mLastFpsTime;
uint64_t mFrameCount;
@@ -540,6 +541,9 @@
std::unique_ptr<BrightnessController> mBrightnessController;
+ /* For histogram */
+ std::unique_ptr<HistogramController> mHistogramController;
+
/* For debugging */
hwc_display_contents_1_t *mHWC1LayerList;
@@ -576,8 +580,12 @@
int32_t initializeValidateInfos();
int32_t addClientCompositionLayer(uint32_t layerIndex);
int32_t removeClientCompositionLayer(uint32_t layerIndex);
+ bool hasClientComposition();
int32_t addExynosCompositionLayer(uint32_t layerIndex, float totalUsedCapa);
+ bool isPowerModeOff() const;
+ bool isSecureContentPresenting() const;
+
/**
* Dynamic AFBC Control solution : To get the prepared information is applied to current or not.
*/
@@ -1202,7 +1210,6 @@
void setHWCControl(uint32_t ctrl, int32_t val);
void setGeometryChanged(uint64_t changedBit);
void clearGeometryChanged();
- bool isFrameUpdate();
virtual void setDDIScalerEnable(int width, int height);
virtual int getDDIScalerMode(int width, int height);
@@ -1267,6 +1274,9 @@
/* set brightness to specific nits value */
virtual int32_t setBrightnessNits(const float nits);
+ /* set brightness by dbv value */
+ virtual int32_t setBrightnessDbv(const uint32_t dbv);
+
protected:
virtual bool getHDRException(ExynosLayer *layer);
virtual int32_t getActiveConfigInternal(hwc2_config_t* outConfig);
@@ -1640,6 +1650,7 @@
int mLastRefreshRate GUARDED_BY(mMutex);
nsecs_t mLastCallbackTime GUARDED_BY(mMutex);
std::atomic_bool mIgnoringLastUpdate = false;
+ bool mCanIgnoreIncreaseUpdate GUARDED_BY(mMutex) = false;
UniqueFd mFd;
std::mutex mMutex;
@@ -1651,6 +1662,7 @@
int32_t setRefreshRateChangedCallbackDebugEnabled(bool enabled);
void updateRefreshRateIndicator();
nsecs_t getLastLayerUpdateTime();
+ bool needUpdateRRIndicator();
virtual void checkPreblendingRequirement(){};
void resetColorMappingInfoForClientComp();
diff --git a/libhwc2.1/libdevice/HistogramDevice.cpp b/libhwc2.1/libdevice/HistogramDevice.cpp
new file mode 100644
index 0000000..f31961f
--- /dev/null
+++ b/libhwc2.1/libdevice/HistogramDevice.cpp
@@ -0,0 +1,899 @@
+/*
+ * Copyright (C) 2023 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 ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "HistogramDevice.h"
+
+#include <drm/samsung_drm.h>
+
+#include <sstream>
+#include <string>
+
+#include "ExynosDisplayDrmInterface.h"
+#include "ExynosHWCHelper.h"
+#include "android-base/macros.h"
+
+/**
+ * histogramOnBinderDied
+ *
+ * The binderdied callback function which is registered in registerHistogram and would trigger
+ * unregisterHistogram to cleanup the channel.
+ *
+ * @cookie pointer to the TokenInfo of the binder object.
+ */
+static void histogramOnBinderDied(void *cookie) {
+ ATRACE_CALL();
+ HistogramDevice::HistogramErrorCode histogramErrorCode;
+ HistogramDevice::TokenInfo *tokenInfo = (HistogramDevice::TokenInfo *)cookie;
+ ALOGI("%s: histogram channel #%u: client with token(%p) is died", __func__,
+ tokenInfo->channelId, tokenInfo->token.get());
+
+ /* release the histogram channel */
+ tokenInfo->histogramDevice->unregisterHistogram(tokenInfo->token, &histogramErrorCode);
+
+ if (histogramErrorCode != HistogramDevice::HistogramErrorCode::NONE) {
+ ALOGE("%s: histogram channel #%u: failed to unregisterHistogram: %s", __func__,
+ tokenInfo->channelId,
+ aidl::com::google::hardware::pixel::display::toString(histogramErrorCode).c_str());
+ }
+}
+
+HistogramDevice::ChannelInfo::ChannelInfo()
+ : status(ChannelStatus_t::DISABLED),
+ token(nullptr),
+ pid(-1),
+ requestedRoi(),
+ workingConfig(),
+ threshold(0),
+ histDataCollecting(false) {}
+
+HistogramDevice::ChannelInfo::ChannelInfo(const ChannelInfo &other) {
+ std::scoped_lock lock(other.channelInfoMutex);
+ status = other.status;
+ token = other.token;
+ pid = other.pid;
+ requestedRoi = other.requestedRoi;
+ workingConfig = other.workingConfig;
+ threshold = other.threshold;
+ histDataCollecting = other.histDataCollecting;
+}
+
+HistogramDevice::HistogramDevice(ExynosDisplay *display, uint8_t channelCount,
+ std::vector<uint8_t> reservedChannels) {
+ mDisplay = display;
+
+ // TODO: b/295786065 - Get available channels from crtc property.
+ initChannels(channelCount, reservedChannels);
+
+ /* Create the death recipient which will be deleted in the destructor */
+ mDeathRecipient = AIBinder_DeathRecipient_new(histogramOnBinderDied);
+}
+
+HistogramDevice::~HistogramDevice() {
+ if (mDeathRecipient) {
+ AIBinder_DeathRecipient_delete(mDeathRecipient);
+ }
+}
+
+void HistogramDevice::initDrm(const DrmCrtc &crtc) {
+ // TODO: b/295786065 - Get available channels from crtc property.
+
+ // TODO: b/295786065 - Check if the multi channel property is supported.
+ initHistogramCapability(crtc.histogram_channel_property(0).id() != 0);
+}
+
+ndk::ScopedAStatus HistogramDevice::getHistogramCapability(
+ HistogramCapability *histogramCapability) const {
+ ATRACE_CALL();
+
+ if (!histogramCapability) {
+ ALOGE("%s: binder error, histogramCapability is nullptr", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+
+ *histogramCapability = mHistogramCapability;
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HistogramDevice::registerHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *histogramErrorCode) {
+ ATRACE_CALL();
+
+ if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
+ ALOGE("%s: histogram interface is not supported", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ return configHistogram(token, histogramConfig, histogramErrorCode, false);
+}
+
+ndk::ScopedAStatus HistogramDevice::queryHistogram(const ndk::SpAIBinder &token,
+ std::vector<char16_t> *histogramBuffer,
+ HistogramErrorCode *histogramErrorCode) {
+ ATRACE_CALL();
+
+ if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
+ ALOGE("%s: histogram interface is not supported", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ /* No need to validate the argument (token), if the token is not correct it cannot be converted
+ * to the channel id later. */
+
+ /* validate the argument (histogramBuffer) */
+ if (!histogramBuffer) {
+ ALOGE("%s: binder error, histogramBuffer is nullptr", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+
+ /* validate the argument (histogramErrorCode) */
+ if (!histogramErrorCode) {
+ ALOGE("%s: binder error, histogramErrorCode is nullptr", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+
+ /* default histogramErrorCode: no error */
+ *histogramErrorCode = HistogramErrorCode::NONE;
+
+ if (mDisplay->isPowerModeOff()) {
+ ALOGW("%s: DISPLAY_POWEROFF, histogram is not available when display is off", __func__);
+ *histogramErrorCode = HistogramErrorCode::DISPLAY_POWEROFF;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ if (mDisplay->isSecureContentPresenting()) {
+ ALOGV("%s: DRM_PLAYING, histogram is not available when secure content is presenting",
+ __func__);
+ *histogramErrorCode = HistogramErrorCode::DRM_PLAYING;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ uint8_t channelId;
+
+ /* Hold the mAllocatorMutex for a short time just to convert the token to channel id. Prevent
+ * holding the mAllocatorMutex when waiting for the histogram data back which may takes several
+ * milliseconds */
+ {
+ ATRACE_NAME("getChannelId");
+ std::scoped_lock lock(mAllocatorMutex);
+ if ((*histogramErrorCode = getChannelIdByTokenLocked(token, channelId)) !=
+ HistogramErrorCode::NONE) {
+ return ndk::ScopedAStatus::ok();
+ }
+ }
+
+ getHistogramData(channelId, histogramBuffer, histogramErrorCode);
+
+ /* Clear the histogramBuffer when error occurs */
+ if (*histogramErrorCode != HistogramErrorCode::NONE) {
+ histogramBuffer->assign(HISTOGRAM_BIN_COUNT, 0);
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HistogramDevice::reconfigHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *histogramErrorCode) {
+ ATRACE_CALL();
+
+ if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
+ ALOGE("%s: histogram interface is not supported", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ return configHistogram(token, histogramConfig, histogramErrorCode, true);
+}
+
+ndk::ScopedAStatus HistogramDevice::unregisterHistogram(const ndk::SpAIBinder &token,
+ HistogramErrorCode *histogramErrorCode) {
+ ATRACE_CALL();
+
+ if (UNLIKELY(!mHistogramCapability.supportMultiChannel)) {
+ ALOGE("%s: histogram interface is not supported", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ /* No need to validate the argument (token), if the token is not correct it cannot be converted
+ * to the channel id later. */
+
+ /* validate the argument (histogramErrorCode) */
+ if (!histogramErrorCode) {
+ ALOGE("%s: binder error, histogramErrorCode is nullptr", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+
+ /* default histogramErrorCode: no error */
+ *histogramErrorCode = HistogramErrorCode::NONE;
+
+ ATRACE_BEGIN("getChannelId");
+ uint8_t channelId;
+ std::scoped_lock lock(mAllocatorMutex);
+
+ if ((*histogramErrorCode = getChannelIdByTokenLocked(token, channelId)) !=
+ HistogramErrorCode::NONE) {
+ ATRACE_END();
+ return ndk::ScopedAStatus::ok();
+ }
+ ATRACE_END();
+
+ releaseChannelLocked(channelId);
+
+ /*
+ * If AIBinder is alive, the unregisterHistogram is triggered from the histogram client, and we
+ * need to unlink the binder object from death notification.
+ * If AIBinder is already dead, the unregisterHistogram is triggered from binderdied callback,
+ * no need to unlink here.
+ */
+ if (LIKELY(AIBinder_isAlive(token.get()))) {
+ binder_status_t status;
+ if ((status = AIBinder_unlinkToDeath(token.get(), mDeathRecipient,
+ &mTokenInfoMap[token.get()]))) {
+ /* Not return error due to the AIBinder_unlinkToDeath */
+ ALOGE("%s: histogram channel #%u: AIBinder_linkToDeath error %d", __func__, channelId,
+ status);
+ }
+ }
+
+ /* Delete the corresponding TokenInfo after the binder object is already unlinked. */
+ mTokenInfoMap.erase(token.get());
+
+ return ndk::ScopedAStatus::ok();
+}
+
+void HistogramDevice::handleDrmEvent(void *event) {
+ int ret = NO_ERROR;
+ uint8_t channelId;
+ char16_t *buffer;
+
+ if ((ret = parseDrmEvent(event, channelId, buffer))) {
+ ALOGE("%s: failed to parseDrmEvent, ret %d", __func__, ret);
+ return;
+ }
+
+ ATRACE_NAME(String8::format("handleHistogramDrmEvent #%u", channelId).c_str());
+ if (channelId >= mChannels.size()) {
+ ALOGE("%s: histogram channel #%u: invalid channelId", __func__, channelId);
+ return;
+ }
+
+ ChannelInfo &channel = mChannels[channelId];
+ std::unique_lock<std::mutex> lock(channel.histDataCollectingMutex);
+
+ /* Check if the histogram channel is collecting the histogram data */
+ if (channel.histDataCollecting == true) {
+ std::memcpy(channel.histData, buffer, HISTOGRAM_BIN_COUNT * sizeof(char16_t));
+ channel.histDataCollecting = false;
+ } else {
+ ALOGW("%s: histogram channel #%u: ignore the histogram channel event", __func__, channelId);
+ }
+
+ channel.histDataCollecting_cv.notify_all();
+}
+
+void HistogramDevice::prepareAtomicCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
+ ATRACE_NAME("HistogramAtomicCommit");
+
+ /* Loop through every channel and call prepareChannelCommit */
+ for (uint8_t channelId = 0; channelId < mChannels.size(); ++channelId) {
+ int channelRet = prepareChannelCommit(drmReq, channelId);
+
+ /* Every channel is independent, no early return when the channel commit fails. */
+ if (channelRet) {
+ ALOGE("%s: histogram channel #%u: failed to prepare atomic commit: %d", __func__,
+ channelId, channelRet);
+ }
+ }
+}
+
+void HistogramDevice::postAtomicCommit() {
+ /* Atomic commit is success, loop through every channel and update the channel status */
+ for (uint8_t channelId = 0; channelId < mChannels.size(); ++channelId) {
+ ChannelInfo &channel = mChannels[channelId];
+ std::scoped_lock lock(channel.channelInfoMutex);
+
+ switch (channel.status) {
+ case ChannelStatus_t::CONFIG_BLOB_ADDED:
+ channel.status = ChannelStatus_t::CONFIG_COMMITTED;
+ break;
+ case ChannelStatus_t::DISABLE_BLOB_ADDED:
+ channel.status = ChannelStatus_t::DISABLED;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void HistogramDevice::dump(String8 &result) const {
+ /* Do not dump the Histogram Device if it is not supported. */
+ if (!mHistogramCapability.supportMultiChannel) {
+ return;
+ }
+
+ /* print the histogram capability */
+ dumpHistogramCapability(result);
+
+ result.appendFormat("\n");
+
+ /* print the histogram channel info*/
+ result.appendFormat("Histogram channel info:\n");
+ for (uint8_t channelId = 0; channelId < mChannels.size(); ++channelId) {
+ // TODO: b/294489887 - Use buildForMiniDump can eliminate the redundant rows.
+ TableBuilder tb;
+ const ChannelInfo &channel = mChannels[channelId];
+ std::scoped_lock lock(channel.channelInfoMutex);
+ tb.add("ID", (int)channelId);
+ tb.add("status", toString(channel.status));
+ tb.add("token", channel.token.get());
+ tb.add("pid", channel.pid);
+ tb.add("requestedRoi", toString(channel.requestedRoi));
+ tb.add("workingRoi", toString(channel.workingConfig.roi));
+ tb.add("threshold", channel.threshold);
+ tb.add("weightRGB", toString(channel.workingConfig.weights));
+ tb.add("samplePos",
+ aidl::com::google::hardware::pixel::display::toString(
+ channel.workingConfig.samplePos));
+ result.append(tb.build().c_str());
+ }
+
+ result.appendFormat("\n");
+}
+
+void HistogramDevice::initChannels(uint8_t channelCount,
+ const std::vector<uint8_t> &reservedChannels) {
+ mChannels.resize(channelCount);
+ ALOGI("%s: init histogram with %d channels", __func__, channelCount);
+
+ for (const uint8_t reservedChannelId : reservedChannels) {
+ if (reservedChannelId < mChannels.size()) {
+ std::scoped_lock channelLock(mChannels[reservedChannelId].channelInfoMutex);
+ mChannels[reservedChannelId].status = ChannelStatus_t::RESERVED;
+ }
+ }
+
+ std::scoped_lock lock(mAllocatorMutex);
+ for (uint8_t channelId = 0; channelId < channelCount; ++channelId) {
+ std::scoped_lock channelLock(mChannels[channelId].channelInfoMutex);
+
+ if (mChannels[channelId].status == ChannelStatus_t::RESERVED) {
+ ALOGI("%s: histogram channel #%u: reserved for driver", __func__, (int)channelId);
+ continue;
+ }
+
+ mFreeChannels.push(channelId);
+ }
+}
+
+void HistogramDevice::initHistogramCapability(bool supportMultiChannel) {
+ ExynosDisplayDrmInterface *moduleDisplayInterface =
+ static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get());
+
+ if (!moduleDisplayInterface) {
+ ALOGE("%s: failed to get ExynosDisplayDrmInterface (nullptr), cannot get panel full "
+ "resolution",
+ __func__);
+ mHistogramCapability.fullResolutionWidth = 0;
+ mHistogramCapability.fullResolutionHeight = 0;
+ } else {
+ mHistogramCapability.fullResolutionWidth =
+ moduleDisplayInterface->getPanelFullResolutionHSize();
+ mHistogramCapability.fullResolutionHeight =
+ moduleDisplayInterface->getPanelFullResolutionVSize();
+ }
+ ALOGI("%s: full screen roi: (0,0)x(%dx%d)", __func__, mHistogramCapability.fullResolutionWidth,
+ mHistogramCapability.fullResolutionHeight);
+
+ mHistogramCapability.channelCount = mChannels.size();
+ mHistogramCapability.supportMultiChannel = supportMultiChannel;
+
+ initSupportSamplePosList();
+}
+
+void HistogramDevice::initSupportSamplePosList() {
+ mHistogramCapability.supportSamplePosList.push_back(HistogramSamplePos::PRE_POSTPROC);
+ mHistogramCapability.supportSamplePosList.push_back(HistogramSamplePos::POST_POSTPROC);
+}
+
+ndk::ScopedAStatus HistogramDevice::configHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *histogramErrorCode,
+ bool isReconfig) {
+ /* validate the argument (histogramErrorCode) */
+ if (!histogramErrorCode) {
+ ALOGE("%s: binder error, histogramErrorCode is nullptr", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
+
+ /* default histogramErrorCode: no error */
+ *histogramErrorCode = HistogramErrorCode::NONE;
+
+ /* validate the argument (token) */
+ if (token.get() == nullptr) {
+ ALOGE("%s: BAD_TOKEN, token is nullptr", __func__);
+ *histogramErrorCode = HistogramErrorCode::BAD_TOKEN;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ /* validate the argument (histogramConfig) */
+ if ((*histogramErrorCode = validateHistogramConfig(histogramConfig)) !=
+ HistogramErrorCode::NONE) {
+ return ndk::ScopedAStatus::ok();
+ }
+
+ /* threshold is calculated based on the roi coordinates rather than configured by the client */
+ int threshold = calculateThreshold(histogramConfig.roi);
+
+ {
+ ATRACE_BEGIN("getOrAcquireChannelId");
+ uint8_t channelId;
+ std::scoped_lock lock(mAllocatorMutex);
+
+ /* isReconfig is false: registerHistogram, need to allcoate the histogram channel
+ * isReconfig is true: reconfigHistogram, already registered, only need to get channel id
+ */
+ if (!isReconfig) {
+ if ((*histogramErrorCode = acquireChannelLocked(token, channelId)) !=
+ HistogramErrorCode::NONE) {
+ ATRACE_END();
+ return ndk::ScopedAStatus::ok();
+ }
+ } else {
+ if ((*histogramErrorCode = getChannelIdByTokenLocked(token, channelId)) !=
+ HistogramErrorCode::NONE) {
+ ATRACE_END();
+ return ndk::ScopedAStatus::ok();
+ }
+ }
+ ATRACE_END();
+
+ /* store the histogram information, and mark the channel ready for atomic commit by setting
+ * the status to CONFIG_PENDING */
+ fillupChannelInfo(channelId, token, histogramConfig, threshold);
+
+ if (!isReconfig) {
+ /* link the binder object (token) to the death recipient. When the binder object is
+ * destructed, the callback function histogramOnBinderDied can release the histogram
+ * resources automatically. */
+ binder_status_t status;
+ if ((status = AIBinder_linkToDeath(token.get(), mDeathRecipient,
+ &mTokenInfoMap[token.get()]))) {
+ /* Not return error due to the AIBinder_linkToDeath because histogram function can
+ * still work */
+ ALOGE("%s: histogram channel #%u: AIBinder_linkToDeath error %d", __func__,
+ channelId, status);
+ }
+ }
+ }
+
+ if (!mDisplay->isPowerModeOff()) {
+ mDisplay->mDevice->onRefresh(mDisplay->mDisplayId);
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+void HistogramDevice::getHistogramData(uint8_t channelId, std::vector<char16_t> *histogramBuffer,
+ HistogramErrorCode *histogramErrorCode) {
+ ATRACE_NAME(String8::format("%s #%u", __func__, channelId).c_str());
+ int32_t ret;
+ ExynosDisplayDrmInterface *moduleDisplayInterface =
+ static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get());
+ if (!moduleDisplayInterface) {
+ *histogramErrorCode = HistogramErrorCode::BAD_HIST_DATA;
+ ALOGE("%s: histogram channel #%u: BAD_HIST_DATA, moduleDisplayInterface is nullptr",
+ __func__, channelId);
+ return;
+ }
+
+ ChannelInfo &channel = mChannels[channelId];
+
+ std::unique_lock<std::mutex> lock(channel.histDataCollectingMutex);
+
+ /* Check if the previous queryHistogram is finished */
+ if (channel.histDataCollecting) {
+ *histogramErrorCode = HistogramErrorCode::BAD_HIST_DATA;
+ ALOGE("%s: histogram channel #%u: BAD_HIST_DATA, previous %s not finished", __func__,
+ channelId, __func__);
+ return;
+ }
+
+ /* Send the ioctl request (histogram_channel_request_ioctl) which allocate the drm event and
+ * send back the drm event with data when available. */
+ if ((ret = moduleDisplayInterface->sendHistogramChannelIoctl(HistogramChannelIoctl_t::REQUEST,
+ channelId)) != NO_ERROR) {
+ *histogramErrorCode = HistogramErrorCode::BAD_HIST_DATA;
+ ALOGE("%s: histogram channel #%u: BAD_HIST_DATA, sendHistogramChannelIoctl (REQUEST) "
+ "error "
+ "(%d)",
+ __func__, channelId, ret);
+ return;
+ }
+ channel.histDataCollecting = true;
+
+ {
+ ATRACE_NAME(String8::format("waitDrmEvent #%u", channelId).c_str());
+ /* Wait until the condition variable is notified or timeout. */
+ channel.histDataCollecting_cv.wait_for(lock, std::chrono::milliseconds(50),
+ [this, &channel]() {
+ return (!mDisplay->isPowerModeOff() &&
+ !channel.histDataCollecting);
+ });
+ }
+
+ /* If the histDataCollecting is not cleared, check the reason and clear the histogramBuffer.
+ */
+ if (channel.histDataCollecting) {
+ if (mDisplay->isPowerModeOff()) {
+ *histogramErrorCode = HistogramErrorCode::DISPLAY_POWEROFF;
+ ALOGW("%s: histogram channel #%u: DISPLAY_POWEROFF, histogram is not available "
+ "when "
+ "display is off",
+ __func__, channelId);
+ } else {
+ *histogramErrorCode = HistogramErrorCode::BAD_HIST_DATA;
+ ALOGE("%s: histogram channel #%u: BAD_HIST_DATA, no histogram channel event is "
+ "handled",
+ __func__, channelId);
+ }
+
+ /* Cancel the histogram data request */
+ ALOGI("%s: histogram channel #%u: cancel histogram data request", __func__, channelId);
+ if ((ret = moduleDisplayInterface
+ ->sendHistogramChannelIoctl(HistogramChannelIoctl_t::CANCEL,
+ channelId)) != NO_ERROR) {
+ ALOGE("%s: histogram channel #%u: sendHistogramChannelIoctl (CANCEL) error (%d)",
+ __func__, channelId, ret);
+ }
+
+ channel.histDataCollecting = false;
+ return;
+ }
+
+ if (mDisplay->isSecureContentPresenting()) {
+ ALOGV("%s: histogram channel #%u: DRM_PLAYING, histogram is not available when secure "
+ "content is presenting",
+ __func__, channelId);
+ *histogramErrorCode = HistogramErrorCode::DRM_PLAYING;
+ return;
+ }
+
+ /* Copy the histogram data from histogram info to histogramBuffer */
+ histogramBuffer->assign(channel.histData, channel.histData + HISTOGRAM_BIN_COUNT);
+}
+
+int HistogramDevice::parseDrmEvent(void *event, uint8_t &channelId, char16_t *&buffer) const {
+ channelId = 0;
+ buffer = nullptr;
+ return INVALID_OPERATION;
+}
+
+HistogramDevice::HistogramErrorCode HistogramDevice::acquireChannelLocked(
+ const ndk::SpAIBinder &token, uint8_t &channelId) {
+ ATRACE_CALL();
+ if (mFreeChannels.size() == 0) {
+ ALOGE("%s: NO_CHANNEL_AVAILABLE, there is no histogram channel available", __func__);
+ return HistogramErrorCode::NO_CHANNEL_AVAILABLE;
+ }
+
+ if (mTokenInfoMap.find(token.get()) != mTokenInfoMap.end()) {
+ ALOGE("%s: BAD_TOKEN, token (%p) is already registered", __func__, token.get());
+ return HistogramErrorCode::BAD_TOKEN;
+ }
+
+ /* Acquire free channel id from the free list */
+ channelId = mFreeChannels.front();
+ mFreeChannels.pop();
+ mTokenInfoMap[token.get()] = {.channelId = channelId, .histogramDevice = this, .token = token};
+
+ return HistogramErrorCode::NONE;
+}
+
+void HistogramDevice::releaseChannelLocked(uint8_t channelId) {
+ /* Add the channel id back to the free list and cleanup the channel info with status set to
+ * DISABLE_PENDING */
+ mFreeChannels.push(channelId);
+ cleanupChannelInfo(channelId);
+}
+
+HistogramDevice::HistogramErrorCode HistogramDevice::getChannelIdByTokenLocked(
+ const ndk::SpAIBinder &token, uint8_t &channelId) {
+ if (mTokenInfoMap.find(token.get()) == mTokenInfoMap.end()) {
+ ALOGE("%s: BAD_TOKEN, token (%p) is not registered", __func__, token.get());
+ return HistogramErrorCode::BAD_TOKEN;
+ }
+
+ channelId = mTokenInfoMap[token.get()].channelId;
+
+ return HistogramErrorCode::NONE;
+}
+
+void HistogramDevice::cleanupChannelInfo(uint8_t channelId) {
+ ATRACE_NAME(String8::format("%s #%u", __func__, channelId).c_str());
+ ChannelInfo &channel = mChannels[channelId];
+ std::scoped_lock lock(channel.channelInfoMutex);
+ channel.status = ChannelStatus_t::DISABLE_PENDING;
+ channel.token = nullptr;
+ channel.pid = -1;
+ channel.requestedRoi = {.left = 0, .top = 0, .right = 0, .bottom = 0};
+ channel.workingConfig = {.roi.left = 0,
+ .roi.top = 0,
+ .roi.right = 0,
+ .roi.bottom = 0,
+ .weights.weightR = 0,
+ .weights.weightG = 0,
+ .weights.weightB = 0,
+ .samplePos = HistogramSamplePos::POST_POSTPROC};
+ channel.threshold = 0;
+}
+
+void HistogramDevice::fillupChannelInfo(uint8_t channelId, const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig, int threshold) {
+ ATRACE_NAME(String8::format("%s #%u", __func__, channelId).c_str());
+ ChannelInfo &channel = mChannels[channelId];
+ std::scoped_lock lock(channel.channelInfoMutex);
+ channel.status = ChannelStatus_t::CONFIG_PENDING;
+ channel.token = token;
+ channel.pid = AIBinder_getCallingPid();
+ channel.requestedRoi = histogramConfig.roi;
+ channel.workingConfig = histogramConfig;
+ channel.workingConfig.roi = {};
+ channel.threshold = threshold;
+}
+
+int HistogramDevice::prepareChannelCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
+ uint8_t channelId) {
+ int ret = NO_ERROR;
+ ExynosDisplayDrmInterface *moduleDisplayInterface =
+ static_cast<ExynosDisplayDrmInterface *>(mDisplay->mDisplayInterface.get());
+ if (!moduleDisplayInterface) {
+ HWC_LOGE(mDisplay, "%s: failed to get ExynosDisplayDrmInterface (nullptr)", __func__);
+ return -EINVAL;
+ }
+
+ ChannelInfo &channel = mChannels[channelId];
+ std::scoped_lock lock(channel.channelInfoMutex);
+
+ if (channel.status == ChannelStatus_t::CONFIG_COMMITTED ||
+ channel.status == ChannelStatus_t::CONFIG_PENDING) {
+ HistogramRoiRect workingRoi;
+
+ /* calculate the roi based on the current active resolution */
+ ret = convertRoiLocked(moduleDisplayInterface, channel.requestedRoi, workingRoi);
+ if (ret == -EAGAIN) {
+ /* postpone the histogram config to next atomic commit */
+ ALOGD("%s: histogram channel #%u: set status (CONFIG_PENDING)", __func__, channelId);
+ channel.status = ChannelStatus_t::CONFIG_PENDING;
+ return NO_ERROR;
+ } else if (ret) {
+ ALOGE("%s: histogram channel #%u: failed to convert to workingRoi, ret: %d", __func__,
+ channelId, ret);
+ channel.status = ChannelStatus_t::CONFIG_ERROR;
+ return ret;
+ }
+
+ /* If the channel status is CONFIG_COMMITTED, also check if the working roi needs to be
+ * updated due to resolution changed. */
+ if (channel.status == ChannelStatus_t::CONFIG_COMMITTED) {
+ if (LIKELY(channel.workingConfig.roi == workingRoi)) {
+ return NO_ERROR;
+ } else {
+ ALOGI("%s: histogram channel #%u: detect resolution changed, update roi setting",
+ __func__, channelId);
+ }
+ }
+
+ /* Adopt the roi calculated from convertRoiLocked */
+ channel.workingConfig.roi = workingRoi;
+
+ /* Create histogram drm config struct (platform dependent) */
+ std::shared_ptr<void> blobData;
+ size_t blobLength = 0;
+ if ((ret = createHistogramDrmConfigLocked(channel, blobData, blobLength))) {
+ ALOGE("%s: histogram channel #%u: failed to createHistogramDrmConfig, ret: %d",
+ __func__, channelId, ret);
+ channel.status = ChannelStatus_t::CONFIG_ERROR;
+ return ret;
+ }
+
+ /* Add histogram blob to atomic commit */
+ ret = moduleDisplayInterface->setDisplayHistogramChannelSetting(drmReq, channelId,
+ blobData.get(), blobLength);
+ if (ret == NO_ERROR) {
+ channel.status = ChannelStatus_t::CONFIG_BLOB_ADDED;
+ } else {
+ ALOGE("%s: histogram channel #%u: failed to setDisplayHistogramChannelSetting, ret: %d",
+ __func__, channelId, ret);
+ channel.status = ChannelStatus_t::CONFIG_ERROR;
+ return ret;
+ }
+ } else if (channel.status == ChannelStatus_t::DISABLE_PENDING) {
+ ret = moduleDisplayInterface->clearDisplayHistogramChannelSetting(drmReq, channelId);
+ if (ret == NO_ERROR) {
+ channel.status = ChannelStatus_t::DISABLE_BLOB_ADDED;
+ } else {
+ ALOGE("%s: histogram channel #%u: failed to clearDisplayHistogramChannelSetting, ret: "
+ "%d",
+ __func__, channelId, ret);
+ channel.status = ChannelStatus_t::DISABLE_ERROR;
+ }
+ }
+
+ return ret;
+}
+
+int HistogramDevice::createHistogramDrmConfigLocked(const ChannelInfo &channel,
+ std::shared_ptr<void> &configPtr,
+ size_t &length) const {
+ /* Default implementation doesn't know the histogram channel config struct in the kernel.
+ * Cannot allocate and initialize the channel config. */
+ configPtr = nullptr;
+ length = 0;
+ return INVALID_OPERATION;
+}
+
+int HistogramDevice::convertRoiLocked(ExynosDisplayDrmInterface *moduleDisplayInterface,
+ const HistogramRoiRect &requestedRoi,
+ HistogramRoiRect &workingRoi) const {
+ int32_t activeH = moduleDisplayInterface->getActiveModeHDisplay();
+ int32_t activeV = moduleDisplayInterface->getActiveModeVDisplay();
+ int32_t panelH = mHistogramCapability.fullResolutionWidth;
+ int32_t panelV = mHistogramCapability.fullResolutionHeight;
+
+ ALOGV("%s: active: (%dx%d), panel: (%dx%d)", __func__, activeH, activeV, panelH, panelV);
+
+ if (panelH < activeH || activeH < 0 || panelV < activeV || activeV < 0) {
+ ALOGE("%s: failed to convert roi, active: (%dx%d), panel: (%dx%d)", __func__, activeH,
+ activeV, panelH, panelV);
+ return -EINVAL;
+ } else if (activeH == 0 || activeV == 0) {
+ /* mActiveModeState is not initialized, postpone histogram config to next atomic commit */
+ ALOGW("%s: mActiveModeState is not initialized, active: (%dx%d), postpone histogram config "
+ "to next atomic commit",
+ __func__, activeH, activeV);
+ return -EAGAIN;
+ }
+
+ /* Linear transform from full resolution to active resolution */
+ workingRoi.left = requestedRoi.left * activeH / panelH;
+ workingRoi.top = requestedRoi.top * activeV / panelV;
+ workingRoi.right = requestedRoi.right * activeH / panelH;
+ workingRoi.bottom = requestedRoi.bottom * activeV / panelV;
+
+ ALOGV("%s: working roi: %s", __func__, toString(workingRoi).c_str());
+
+ return NO_ERROR;
+}
+
+void HistogramDevice::dumpHistogramCapability(String8 &result) const {
+ /* Append the histogram capability info to the dump string */
+ result.appendFormat("Histogram capability:\n");
+ result.appendFormat("\tsupportMultiChannel: %s\n",
+ mHistogramCapability.supportMultiChannel ? "true" : "false");
+ result.appendFormat("\tchannelCount: %d\n", mHistogramCapability.channelCount);
+ result.appendFormat("\tfullscreen roi: (0,0)x(%dx%d)\n",
+ mHistogramCapability.fullResolutionWidth,
+ mHistogramCapability.fullResolutionHeight);
+ result.appendFormat("\tsupportSamplePosList:");
+ for (HistogramSamplePos samplePos : mHistogramCapability.supportSamplePosList) {
+ result.appendFormat(" %s",
+ aidl::com::google::hardware::pixel::display::toString(samplePos)
+ .c_str());
+ }
+ result.appendFormat("\n");
+}
+
+HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramConfig(
+ const HistogramConfig &histogramConfig) const {
+ HistogramErrorCode ret;
+
+ if ((ret = validateHistogramRoi(histogramConfig.roi)) != HistogramErrorCode::NONE ||
+ (ret = validateHistogramWeights(histogramConfig.weights)) != HistogramErrorCode::NONE ||
+ (ret = validateHistogramSamplePos(histogramConfig.samplePos)) != HistogramErrorCode::NONE) {
+ return ret;
+ }
+
+ return HistogramErrorCode::NONE;
+}
+
+HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramRoi(
+ const HistogramRoiRect &roi) const {
+ if ((roi.left < 0) || (roi.top < 0) || (roi.right - roi.left <= 0) ||
+ (roi.bottom - roi.top <= 0) || (roi.right > mHistogramCapability.fullResolutionWidth) ||
+ (roi.bottom > mHistogramCapability.fullResolutionHeight)) {
+ ALOGE("%s: BAD_ROI, roi: %s, full screen roi: (0,0)x(%dx%d)", __func__,
+ toString(roi).c_str(), mHistogramCapability.fullResolutionWidth,
+ mHistogramCapability.fullResolutionHeight);
+ return HistogramErrorCode::BAD_ROI;
+ }
+
+ return HistogramErrorCode::NONE;
+}
+
+HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramWeights(
+ const HistogramWeights &weights) const {
+ if ((weights.weightR + weights.weightG + weights.weightB) != WEIGHT_SUM) {
+ ALOGE("%s: BAD_WEIGHT, weights(%d,%d,%d)\n", __func__, weights.weightR, weights.weightG,
+ weights.weightB);
+ return HistogramErrorCode::BAD_WEIGHT;
+ }
+
+ return HistogramErrorCode::NONE;
+}
+
+HistogramDevice::HistogramErrorCode HistogramDevice::validateHistogramSamplePos(
+ const HistogramSamplePos &samplePos) const {
+ for (HistogramSamplePos mSamplePos : mHistogramCapability.supportSamplePosList) {
+ if (samplePos == mSamplePos) {
+ return HistogramErrorCode::NONE;
+ }
+ }
+
+ ALOGE("%s: BAD_POSITION, samplePos is %d", __func__, (int)samplePos);
+ return HistogramErrorCode::BAD_POSITION;
+}
+
+int HistogramDevice::calculateThreshold(const HistogramRoiRect &roi) {
+ // TODO: b/294491895 - Check if the threshold plus one really need it
+ int threshold = ((roi.bottom - roi.top) * (roi.right - roi.left)) >> 16;
+ return threshold + 1;
+}
+
+std::string HistogramDevice::toString(const ChannelStatus_t &status) {
+ switch (status) {
+ case ChannelStatus_t::RESERVED:
+ return "RESERVED";
+ case ChannelStatus_t::DISABLED:
+ return "DISABLED";
+ case ChannelStatus_t::CONFIG_PENDING:
+ return "CONFIG_PENDING";
+ case ChannelStatus_t::CONFIG_BLOB_ADDED:
+ return "CONFIG_BLOB_ADDED";
+ case ChannelStatus_t::CONFIG_COMMITTED:
+ return "CONFIG_COMMITTED";
+ case ChannelStatus_t::CONFIG_ERROR:
+ return "CONFIG_ERROR";
+ case ChannelStatus_t::DISABLE_PENDING:
+ return "DISABLE_PENDING";
+ case ChannelStatus_t::DISABLE_BLOB_ADDED:
+ return "DISABLE_BLOB_ADDED";
+ case ChannelStatus_t::DISABLE_ERROR:
+ return "DISABLE_ERROR";
+ }
+
+ return "UNDEFINED";
+}
+
+std::string HistogramDevice::toString(const HistogramRoiRect &roi) {
+ std::ostringstream os;
+ os << "(" << roi.left << "," << roi.top << ")";
+ os << "x";
+ os << "(" << roi.right << "," << roi.bottom << ")";
+ return os.str();
+}
+
+std::string HistogramDevice::toString(const HistogramWeights &weights) {
+ std::ostringstream os;
+ os << "(";
+ os << (int)weights.weightR << ",";
+ os << (int)weights.weightG << ",";
+ os << (int)weights.weightB;
+ os << ")";
+ return os.str();
+}
diff --git a/libhwc2.1/libdevice/HistogramDevice.h b/libhwc2.1/libdevice/HistogramDevice.h
new file mode 100644
index 0000000..ee74cae
--- /dev/null
+++ b/libhwc2.1/libdevice/HistogramDevice.h
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/com/google/hardware/pixel/display/HistogramCapability.h>
+#include <aidl/com/google/hardware/pixel/display/HistogramConfig.h>
+#include <aidl/com/google/hardware/pixel/display/HistogramErrorCode.h>
+#include <aidl/com/google/hardware/pixel/display/HistogramSamplePos.h>
+#include <aidl/com/google/hardware/pixel/display/Weight.h>
+#include <android-base/thread_annotations.h>
+#include <drm/samsung_drm.h>
+#include <utils/String8.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+
+#include "ExynosDisplay.h"
+#include "ExynosDisplayDrmInterface.h"
+#include "drmcrtc.h"
+
+using namespace android;
+
+class HistogramDevice {
+public:
+ using HistogramCapability = aidl::com::google::hardware::pixel::display::HistogramCapability;
+ using HistogramConfig = aidl::com::google::hardware::pixel::display::HistogramConfig;
+ using HistogramErrorCode = aidl::com::google::hardware::pixel::display::HistogramErrorCode;
+ using HistogramRoiRect = aidl::android::hardware::graphics::common::Rect;
+ using HistogramSamplePos = aidl::com::google::hardware::pixel::display::HistogramSamplePos;
+ using HistogramWeights = aidl::com::google::hardware::pixel::display::Weight;
+ using HistogramChannelIoctl_t = ExynosDisplayDrmInterface::HistogramChannelIoctl_t;
+
+ /* Histogram weight constraint: weightR + weightG + weightB = WEIGHT_SUM */
+ static constexpr size_t WEIGHT_SUM = 1024;
+
+ /* Histogram channel status */
+ enum class ChannelStatus_t : uint32_t {
+ /* occupied by the driver for specific usage such as LHBM */
+ RESERVED = 0,
+
+ /* channel is off */
+ DISABLED,
+
+ /* channel config is ready and requires to be added into an atomic commit */
+ CONFIG_PENDING,
+
+ /* channel config (blob) is added to an atomic commit but not committed yet */
+ CONFIG_BLOB_ADDED,
+
+ /* channel config is committed to drm driver successfully */
+ CONFIG_COMMITTED,
+
+ /* channel config has error */
+ CONFIG_ERROR,
+
+ /* channel is released and requires an atomic commit to cleanup completely */
+ DISABLE_PENDING,
+
+ /* channel is released and the cleanup blob is added but not committed yet */
+ DISABLE_BLOB_ADDED,
+
+ /* channel disable has error */
+ DISABLE_ERROR,
+ };
+
+ struct ChannelInfo {
+ /* protect the channel info fields */
+ mutable std::mutex channelInfoMutex;
+
+ /* protect histDataCollecting variable */
+ mutable std::mutex histDataCollectingMutex;
+
+ /* track the channel status */
+ ChannelStatus_t status GUARDED_BY(channelInfoMutex);
+
+ /* token passed in by the histogram client */
+ ndk::SpAIBinder token GUARDED_BY(channelInfoMutex);
+
+ /* histogram client process id */
+ pid_t pid GUARDED_BY(channelInfoMutex);
+
+ /* requested roi from the client by registerHistogram or reconfigHistogram */
+ HistogramRoiRect requestedRoi GUARDED_BY(channelInfoMutex);
+
+ /* histogram config that would be applied to hardware, the requestedRoi may be different
+ * from the roi described in workingConfig due to RRS (Runtime Resolution Switch) */
+ HistogramConfig workingConfig GUARDED_BY(channelInfoMutex);
+
+ /* histogram threshold that would be applied to the hardware which is used to prevent the
+ * histogram data (16 bits) overflow */
+ int threshold GUARDED_BY(channelInfoMutex);
+
+ /* histogram data would be stored as part of the channel info */
+ uint16_t histData[HISTOGRAM_BIN_COUNT];
+ bool histDataCollecting; // GUARDED_BY(histDataCollectingMutex);
+ std::condition_variable histDataCollecting_cv;
+
+ ChannelInfo();
+ ChannelInfo(const ChannelInfo &other);
+ };
+
+ /* TokenInfo is not only used to stored the corresponding channel id but also passed to the
+ * binderdied callback */
+ struct TokenInfo {
+ /* corresponding channel id of the token */
+ uint8_t channelId;
+
+ /* pointer to the HistogramDevice, binderdied callback would use this pointer to cleanup the
+ * channel in HistogramDevice by the member function unregisterHistogram */
+ HistogramDevice *histogramDevice;
+
+ /* binderdied callback would call unregisterHistogram with this token */
+ ndk::SpAIBinder token;
+ };
+
+ /**
+ * HistogramDevice
+ *
+ * Construct the HistogramDevice to mange histogram channel.
+ *
+ * @display display pointer which would be stored in mDisplay.
+ * @channelCount number of the histogram channels in the system.
+ * @reservedChannels a list of channel id that are reserved by the driver.
+ */
+ explicit HistogramDevice(ExynosDisplay *display, uint8_t channelCount,
+ std::vector<uint8_t> reservedChannels);
+
+ /**
+ * ~HistogramDevice
+ *
+ * Destruct the HistogramDevice.
+ */
+ virtual ~HistogramDevice();
+
+ /**
+ * initDrm
+ *
+ * Get histogram info from crtc property and initialize the mHistogramCapability.
+ * 1. The available histogram channel bitmask.
+ * 2. Determine kernel support multi channel property or not.
+ *
+ * @crtc drm crtc object which would contain histogram related information.
+ */
+ void initDrm(const DrmCrtc &crtc);
+
+ /**
+ * getHistogramCapability
+ *
+ * Return the histogram capability for the system.
+ *
+ * @histogramCapability: describe the histogram capability for the system.
+ * @return ok() when the interface is supported and arguments are valid, else otherwise.
+ */
+ ndk::ScopedAStatus getHistogramCapability(HistogramCapability *histogramCapability) const;
+
+ /**
+ * registerHistogram
+ *
+ * Register the histogram sampling config, and allocate a histogram channel if available.
+ * If the display is not turned on, just store the histogram config. Otherwise, trigger the
+ * onRefresh call to force the config take effect, and then the DPU hardware will continuously
+ * sample the histogram data.
+ *
+ * @token binder object created by the client whose lifetime should be equal to the client. When
+ * the binder object is destructed, the unregisterHistogram would be called automatically. Token
+ * serves as the handle in every histogram operation.
+ * @histogramConfig histogram config from the client.
+ * @histogramErrorCode NONE when no error, or else otherwise. Client should retry when failed.
+ * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
+ * is not supported yet.
+ */
+ ndk::ScopedAStatus registerHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *histogramErrorCode);
+
+ /**
+ * queryHistogram
+ *
+ * Query the histogram data from the corresponding channel of the token.
+ *
+ * @token is the handle registered via registerHistogram which would be used to identify the
+ * channel.
+ * @histogramBuffer 256 * 16 bits buffer to store the luma counts return by the histogram
+ * hardware.
+ * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
+ * errorcode.
+ * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
+ * is not supported yet.
+ */
+ ndk::ScopedAStatus queryHistogram(const ndk::SpAIBinder &token,
+ std::vector<char16_t> *histogramBuffer,
+ HistogramErrorCode *histogramErrorCode);
+
+ /**
+ * reconfigHistogram
+ *
+ * Change the histogram config for the corresponding channel of the token.
+ *
+ * @token is the handle registered via registerHistogram which would be used to identify the
+ * channel.
+ * @histogramConfig histogram config from the client.
+ * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
+ * errorcode.
+ * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
+ * is not supported yet.
+ */
+ ndk::ScopedAStatus reconfigHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *histogramErrorCode);
+
+ /**
+ * unregisterHistogram
+ *
+ * Release the corresponding channel of the token and add the channel id to free channel list.
+ *
+ * @token is the handle registered via registerHistogram which would be used to identify the
+ * channel.
+ * @histogramErrorCode NONE when no error, or else otherwise. Client should examine this
+ * errorcode.
+ * @return ok() when the interface is supported, or EX_UNSUPPORTED_OPERATION when the interface
+ * is not supported yet.
+ */
+ ndk::ScopedAStatus unregisterHistogram(const ndk::SpAIBinder &token,
+ HistogramErrorCode *histogramErrorCode);
+
+ /**
+ * handleDrmEvent
+ *
+ * Handle the histogram channel drm event (EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT) and copy the
+ * histogram data from event struct to channel info.
+ *
+ * @event histogram channel drm event pointer (struct exynos_drm_histogram_channel_event *)
+ */
+ void handleDrmEvent(void *event);
+
+ /**
+ * prepareAtomicCommit
+ *
+ * Prepare the histogram atomic commit for each channel (see prepareChannelCommit).
+ *
+ * @drmReq drm atomic request object
+ */
+ void prepareAtomicCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq);
+
+ /**
+ * postAtomicCommit
+ *
+ * After the atomic commit is done, update the channel status as below.
+ * Channel_Status:
+ * CONFIG_BLOB_ADDED -> CONFIG_COMMITTED
+ * DISABLE_BLOB_ADDED -> DISABLED
+ */
+ void postAtomicCommit();
+
+ /**
+ * dump
+ *
+ * Dump every histogram channel information.
+ *
+ * @result histogram channel dump information would be appended to this string
+ */
+ void dump(String8 &result) const;
+
+protected:
+ HistogramCapability mHistogramCapability;
+
+private:
+ mutable std::mutex mAllocatorMutex;
+ std::queue<uint8_t> mFreeChannels GUARDED_BY(mAllocatorMutex); // free channel list
+ std::unordered_map<AIBinder *, TokenInfo> mTokenInfoMap GUARDED_BY(mAllocatorMutex);
+ std::vector<ChannelInfo> mChannels;
+ ExynosDisplay *mDisplay = nullptr;
+
+ /* Death recipient for the binderdied callback, would be deleted in the destructor */
+ AIBinder_DeathRecipient *mDeathRecipient = nullptr;
+
+ /**
+ * initChannels
+ *
+ * Allocate channelCount channels and initialize the channel status for every channel.
+ *
+ * @channelCount number of channels in the system including the reserved channels.
+ * @reservedChannels a list of channel id that are reserved by the driver.
+ */
+ void initChannels(uint8_t channelCount, const std::vector<uint8_t> &reservedChannels);
+
+ /**
+ * initHistogramCapability
+ *
+ * Initialize the histogramCapability which would be queried by the client (see
+ * getHistogramCapability).
+ *
+ * @supportMultiChannel true if the kernel support multi channel property, false otherwise.
+ */
+ void initHistogramCapability(bool supportMultiChannel);
+
+ /**
+ * initSupportSamplePosList
+ *
+ * Initialize the supported sample position list.
+ */
+ virtual void initSupportSamplePosList();
+
+ /**
+ * configHistogram
+ *
+ * Implementation of the registerHistogram and reconfigHistogram.
+ *
+ * @token binder object created by the client.
+ * @histogramConfig histogram config requested by the client.
+ * @histogramErrorCode::NONE when success, or else otherwise.
+ * @isReconfig is true if it is not the register request, only need to change the config.
+ * @return ok() when the interface is supported, or else otherwise.
+ */
+ ndk::ScopedAStatus configHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *histogramErrorCode, bool isReconfig);
+
+ /**
+ * getHistogramData
+ *
+ * Get the histogram data by sending ioctl request which will allocate the drm event for
+ * histogram, and wait on the condition variable histDataCollecting_cv until the drm event is
+ * handled or timeout. Copy the histogram data from channel info to histogramBuffer.
+ *
+ * @channelId histogram channel id.
+ * @histogramBuffer AIDL created buffer which will be sent back to the client.
+ * @histogramErrorCode::NONE when success, or else otherwise.
+ */
+ void getHistogramData(uint8_t channelId, std::vector<char16_t> *histogramBuffer,
+ HistogramErrorCode *histogramErrorCode);
+
+ /**
+ * parseDrmEvent
+ *
+ * Parse the histogram drm event (struct may vary between different platform), need to be
+ * overrided in the derived HistogramController class if needed. This function should get the
+ * histogram channel id and the histogram buffer address from the event struct.
+ *
+ * @event histogram drm event struct.
+ * @channelId stores the extracted channel id from the event.
+ * @buffer stores the extracted buffer address from the event.
+ * @return NO_ERROR on success, else otherwise.
+ */
+ virtual int parseDrmEvent(void *event, uint8_t &channelId, char16_t *&buffer) const;
+
+ /**
+ * acquireChannelLocked
+ *
+ * Acquire an available channel from the mFreeChannels, and record the token to channel id
+ * mapping info. Should be called with mAllocatorMutex held.
+ *
+ * @token binder object created by the client.
+ * @channelId store the acquired channel id.
+ * @return HistogramErrorCode::NONE when success, or else otherwise.
+ */
+ HistogramErrorCode acquireChannelLocked(const ndk::SpAIBinder &token, uint8_t &channelId)
+ REQUIRES(mAllocatorMutex);
+
+ /**
+ * releaseChannelLocked
+ *
+ * Find the corresponding channel id of the token and release the channel. Add the channel id to
+ * the mFreeChannels and cleanup the channel. Should be called with mAllocatorMutex held.
+ *
+ * @channelId the channel id to be cleanup.
+ */
+ void releaseChannelLocked(uint8_t channelId) REQUIRES(mAllocatorMutex);
+
+ /**
+ * getChannelIdByTokenLocked
+ *
+ * Convert the token to the channel id. Should be called with mAllocatorMutex held.
+ *
+ * @token binder object created by the client.
+ * @return HistogramErrorCode::NONE when success, or else otherwise.
+ */
+ HistogramErrorCode getChannelIdByTokenLocked(const ndk::SpAIBinder &token, uint8_t &channelId)
+ REQUIRES(mAllocatorMutex);
+
+ /**
+ * cleanupChannelInfo
+ *
+ * Cleanup the channel info and set status to DISABLE_PENDING which means need to wait
+ * for the atomic commit to release the kernel and hardware channel resources.
+ *
+ * @channelId the channel id to be cleanup.
+ */
+ void cleanupChannelInfo(uint8_t channelId);
+
+ /**
+ * fillupChannelInfo
+ *
+ * Fillup the channel info with the histogramConfig from the client, and set status to
+ * CONFIG_PENDING which means need to wait for the atomic commit to configure the
+ * channel.
+ *
+ * @channelId the channel id to be configured.
+ * @token binder object created by the client.
+ * @histogramConfig histogram config requested by the client.
+ * @threshold histogram threshold calculated from the roi.
+ */
+ void fillupChannelInfo(uint8_t channelId, const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig, int threshold);
+
+ /**
+ * prepareChannelCommit
+ *
+ * For the histogram channel needed to be configured, prepare the histogram channel config into
+ * the struct histogram_channel_config which will be used to creating the drm blob in
+ * setDisplayHistogramChannelSetting.
+ * ChannelStatus_t:
+ * CONFIG_PENDING -> CONFIG_BLOB_ADDED
+ * CONFIG_DONE (detect roi needs update due to resolution change) -> CONFIG_BLOB_ADDED
+ *
+ * For the histogram channel needed to be disabled, call clearDisplayHistogramChannelSetting to
+ * disable.
+ * ChannelStatus_t:
+ * DISABLE_PENDING -> DISABLE_BLOB_ADDED
+ *
+ * @drmReq drm atomic request object
+ * @channelId histogram channel id
+ * @return NO_ERROR on success, else otherwise
+ */
+ int prepareChannelCommit(ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq,
+ uint8_t channelId);
+
+ /**
+ * createHistogramDrmConfigLocked
+ *
+ * Allocate and initialize the histogram config for the drm driver. Composer would trigger
+ * setDisplayHistogramChannelSetting and create the property blob with this config. The
+ * allcoated config should be deleted via deleteHistogramDrmConfig after the property blob
+ * is created. This function should be called with channelInfoMutex hold.
+ *
+ * @channel histogram channel.
+ * @configPtr shared pointer to the allocated histogram config struct.
+ * @length size of the histogram config.
+ * @return NO_ERROR on success, else otherwise
+ */
+ virtual int createHistogramDrmConfigLocked(const ChannelInfo &channel,
+ std::shared_ptr<void> &configPtr,
+ size_t &length) const
+ REQUIRES(channel.channelInfoMutex);
+
+ /**
+ * convertRoiLocked
+ *
+ * Linear transform the requested roi (based on panel full resolution) into the working roi
+ * (active resolution).
+ *
+ * @moduleDisplayInterface the displayInterface which contains the full resolution info
+ * @requestedRoi requested roi
+ * @workingRoi converted roi from the requested roi
+ * @return NO_ERROR on success, else otherwise
+ */
+ int convertRoiLocked(ExynosDisplayDrmInterface *moduleDisplayInterface,
+ const HistogramRoiRect &requestedRoi, HistogramRoiRect &workingRoi) const;
+
+ void dumpHistogramCapability(String8 &result) const;
+
+ HistogramErrorCode validateHistogramConfig(const HistogramConfig &histogramConfig) const;
+ HistogramErrorCode validateHistogramRoi(const HistogramRoiRect &roi) const;
+ HistogramErrorCode validateHistogramWeights(const HistogramWeights &weights) const;
+ HistogramErrorCode validateHistogramSamplePos(const HistogramSamplePos &samplePos) const;
+
+ static int calculateThreshold(const HistogramRoiRect &roi);
+ static std::string toString(const ChannelStatus_t &status);
+ static std::string toString(const HistogramRoiRect &roi);
+ static std::string toString(const HistogramWeights &weights);
+};
diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp
index beaf94c..fbf5fc4 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.cpp
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#include <drm/drm_mode.h>
#include "ExynosDeviceDrmInterface.h"
-#include "ExynosDisplayDrmInterface.h"
-#include "ExynosHWCDebug.h"
+
+#include <drm/drm_mode.h>
+#include <drm/samsung_drm.h>
+#include <hardware/hwcomposer_defs.h>
+
#include "ExynosDevice.h"
#include "ExynosDisplay.h"
+#include "ExynosDisplayDrmInterface.h"
#include "ExynosExternalDisplayModule.h"
-#include <hardware/hwcomposer_defs.h>
-#include <drm/samsung_drm.h>
+#include "ExynosHWCDebug.h"
+#include "HistogramController.h"
void set_hwc_dpp_size_range(hwc_dpp_size_range &hwc_dpp_range, dpp_size_range &dpp_range) {
hwc_dpp_range.min = dpp_range.min;
@@ -72,6 +75,8 @@
static_cast<DrmEventHandler *>(&mExynosDrmEventHandler));
mDrmDevice->event_listener()->UnRegisterHistogramHandler(
static_cast<DrmHistogramEventHandler *>(&mExynosDrmEventHandler));
+ mDrmDevice->event_listener()->UnRegisterHistogramChannelHandler(
+ static_cast<DrmHistogramChannelEventHandler *>(&mExynosDrmEventHandler));
mDrmDevice->event_listener()->UnRegisterTUIHandler(
static_cast<DrmTUIEventHandler *>(&mExynosDrmEventHandler));
mDrmDevice->event_listener()->UnRegisterPanelIdleHandler(
@@ -92,6 +97,8 @@
static_cast<DrmEventHandler *>(&mExynosDrmEventHandler));
mDrmDevice->event_listener()->RegisterHistogramHandler(
static_cast<DrmHistogramEventHandler *>(&mExynosDrmEventHandler));
+ mDrmDevice->event_listener()->RegisterHistogramChannelHandler(
+ static_cast<DrmHistogramChannelEventHandler *>(&mExynosDrmEventHandler));
mDrmDevice->event_listener()->RegisterTUIHandler(
static_cast<DrmTUIEventHandler *>(&mExynosDrmEventHandler));
mDrmDevice->event_listener()->RegisterPanelIdleHandler(
@@ -240,6 +247,32 @@
}
}
+#if defined(EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT)
+void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramChannelEvent(void *event) {
+ struct exynos_drm_histogram_channel_event *histogram_channel_event =
+ (struct exynos_drm_histogram_channel_event *)event;
+
+ for (auto display : mExynosDevice->mDisplays) {
+ ExynosDisplayDrmInterface *displayInterface =
+ static_cast<ExynosDisplayDrmInterface *>(display->mDisplayInterface.get());
+ if (histogram_channel_event->crtc_id == displayInterface->getCrtcId()) {
+ if (display->mHistogramController) {
+ display->mHistogramController->handleDrmEvent(histogram_channel_event);
+ } else {
+ ALOGE("%s: no valid mHistogramController for crtc_id (%u)", __func__,
+ histogram_channel_event->crtc_id);
+ }
+
+ return;
+ }
+ }
+
+ ALOGE("%s: no display with crtc_id (%u)", __func__, histogram_channel_event->crtc_id);
+}
+#else
+void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleHistogramChannelEvent(void *event) {}
+#endif
+
void ExynosDeviceDrmInterface::ExynosDrmEventHandler::handleTUIEvent() {
if (mDrmDevice->event_listener()->IsDrmInTUI()) {
/* Received TUI Enter event */
diff --git a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h
index 647407e..4465783 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDeviceDrmInterface.h
@@ -39,11 +39,13 @@
protected:
class ExynosDrmEventHandler : public DrmEventHandler,
public DrmHistogramEventHandler,
+ public DrmHistogramChannelEventHandler,
public DrmTUIEventHandler,
public DrmPanelIdleEventHandler {
public:
void handleEvent(uint64_t timestamp_us) override;
void handleHistogramEvent(uint32_t crtc_id, void *bin) override;
+ void handleHistogramChannelEvent(void *event) override;
void handleTUIEvent() override;
void handleIdleEnterEvent(char const *event) override;
void init(ExynosDevice *exynosDevice, DrmDevice *drmDevice);
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
index 4d265b5..e8a4001 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.cpp
@@ -32,6 +32,7 @@
#include "ExynosHWCHelper.h"
#include "ExynosLayer.h"
#include "ExynosPrimaryDisplay.h"
+#include "HistogramController.h"
using namespace std::chrono_literals;
using namespace SOC_VERSION;
@@ -761,6 +762,12 @@
chosePreferredConfig();
+ // After chosePreferredConfig, the mDrmConnector->modes array is initialized, get the panel full
+ // resolution information here.
+ if (mExynosDisplay->mType == HWC_DISPLAY_PRIMARY) {
+ retrievePanelFullResolution();
+ }
+
parseColorModeEnums(mDrmCrtc->color_mode_property());
parseMipiSyncEnums(mDrmConnector->mipi_sync());
updateMountOrientation();
@@ -772,6 +779,10 @@
ALOGW("%s failed to init brightness controller", __func__);
}
+ if (mExynosDisplay->mHistogramController) {
+ mExynosDisplay->mHistogramController->initDrm(*mDrmCrtc);
+ }
+
return NO_ERROR;
}
@@ -1232,8 +1243,9 @@
return HWC2_ERROR_BAD_CONFIG;
}
- if ((mActiveModeState.blob_id != 0) &&
- (mActiveModeState.mode.id() == config)) {
+ if (mDesiredModeState.needsModeSet()) {
+ ALOGI("Previous mode change %d request is not applied", mDesiredModeState.mode.id());
+ } else if ((mActiveModeState.blob_id != 0) && (mActiveModeState.mode.id() == config)) {
ALOGD("%s:: same mode %d", __func__, config);
/* trigger resetConfigRequestStateLocked() */
mVsyncCallback.setDesiredVsyncPeriod(nsecsPerSec / mActiveModeState.mode.v_refresh());
@@ -1241,10 +1253,6 @@
return HWC2_ERROR_NONE;
}
- if (mDesiredModeState.needsModeSet()) {
- ALOGD("Previous mode change request is not applied");
- }
-
int32_t ret = HWC2_ERROR_NONE;
DrmModeAtomicReq drmReq(this);
uint32_t modeBlob = 0;
@@ -1368,18 +1376,6 @@
return 0;
}
-int32_t ExynosDisplayDrmInterface::getPanelResolution() {
- std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
-
- for (auto it = mDrmConnector->modes().begin(); it != mDrmConnector->modes().end(); it++) {
- if (it->h_display() * it->v_display() > mPanelResolutionHsize * mPanelResolutionVsize) {
- mPanelResolutionHsize = it->h_display();
- mPanelResolutionVsize = it->v_display();
- }
- }
- return 0;
-}
-
int32_t ExynosDisplayDrmInterface::createModeBlob(const DrmMode &mode,
uint32_t &modeBlob)
{
@@ -1820,9 +1816,8 @@
bool hasSecureFrameBuffer = false;
bool hasM2mSecureLayerBuffer = false;
- if (mExynosDisplay->isFrameUpdate()) {
- mFrameCounter++;
- }
+ mFrameCounter++;
+
funcReturnCallback retCallback([&]() {
if ((ret == NO_ERROR) && !drmReq.getError()) {
mFBManager.flip(hasSecureFrameBuffer, hasM2mSecureLayerBuffer);
@@ -2016,9 +2011,14 @@
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
/* For Histogram */
+ // TODO: b/300026478 - Skip setDisplayHistogramSetting when multi channel is enabled
if (dqeEnable && (ret = setDisplayHistogramSetting(drmReq)) != 0) {
HWC_LOGE(mExynosDisplay, "Failed to set display histogram setting (%d)", ret);
- return ret;
+ }
+
+ /* For multichannel histogram */
+ if (dqeEnable && mExynosDisplay->mHistogramController) {
+ mExynosDisplay->mHistogramController->prepareAtomicCommit(drmReq);
}
if (mDrmConnector->mipi_sync().id() && (mipi_sync_type != 0)) {
@@ -2039,7 +2039,22 @@
/* TODO: don't pass expected present time before we can provide accurate time that desire
* refresh rate take effect (b/202346402)
*/
- if (!mVsyncCallback.getDesiredVsyncPeriod()) {
+ bool ignoreExpectedPresentTime = false;
+ if (mVsyncCallback.getDesiredVsyncPeriod()) {
+ ignoreExpectedPresentTime = true;
+
+ /* limit the condition to avoid unexpected early present */
+ auto desiredVsyncPeriod = mVsyncCallback.getDesiredVsyncPeriod();
+ auto currentVsyncPeriod = mExynosDisplay->mVsyncPeriod;
+ constexpr auto nsecsPerMs = std::chrono::nanoseconds(1ms).count();
+ if (currentVsyncPeriod > desiredVsyncPeriod &&
+ (((currentVsyncPeriod % desiredVsyncPeriod) < nsecsPerMs) ||
+ (desiredVsyncPeriod - (currentVsyncPeriod % desiredVsyncPeriod)) < nsecsPerMs)) {
+ ignoreExpectedPresentTime = false;
+ }
+ }
+
+ if (!ignoreExpectedPresentTime) {
if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(),
mDrmCrtc->expected_present_time_property(),
expectedPresentTime)) < 0) {
@@ -2082,6 +2097,11 @@
mDrmVSyncWorker.VSyncControl(true);
}
+ /* For multichannel histogram */
+ if (dqeEnable && mExynosDisplay->mHistogramController) {
+ mExynosDisplay->mHistogramController->postAtomicCommit();
+ }
+
return NO_ERROR;
}
@@ -2673,3 +2693,81 @@
return (mDrmConnector->state() == DRM_MODE_CONNECTED);
}
+
+void ExynosDisplayDrmInterface::retrievePanelFullResolution() {
+ std::lock_guard<std::recursive_mutex> lock(mDrmConnector->modesLock());
+
+ // The largest resolution in the modes of mDrmConnector is the panel full resolution.
+ for (auto it = mDrmConnector->modes().begin(); it != mDrmConnector->modes().end(); it++) {
+ if (it->h_display() * it->v_display() >
+ mPanelFullResolutionHSize * mPanelFullResolutionVSize) {
+ mPanelFullResolutionHSize = it->h_display();
+ mPanelFullResolutionVSize = it->v_display();
+ }
+ }
+
+ if (mPanelFullResolutionHSize <= 0 || mPanelFullResolutionVSize <= 0) {
+ ALOGE("%s: failed to get panel full resolution", __func__);
+ } else {
+ ALOGI("%s: panel full resolution: (%dx%d)", __func__, mPanelFullResolutionHSize,
+ mPanelFullResolutionVSize);
+ }
+}
+
+int32_t ExynosDisplayDrmInterface::setDisplayHistogramChannelSetting(
+ ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq, uint8_t channelId, void *blobData,
+ size_t blobLength) {
+ int ret = NO_ERROR;
+ uint32_t blobId = 0;
+
+ ATRACE_NAME(String8::format("%s #%u", __func__, channelId).c_str());
+
+ const DrmProperty &prop = mDrmCrtc->histogram_channel_property(channelId);
+ if (!prop.id()) {
+ ALOGE("Unsupported multi-channel histrogram for channel:%d", channelId);
+ return -ENOTSUP;
+ }
+
+ ret = mDrmDevice->CreatePropertyBlob(blobData, blobLength, &blobId);
+ if (ret) {
+ HWC_LOGE(mExynosDisplay, "Failed to create histogram channel(%d) blob %d", channelId, ret);
+ return ret;
+ }
+
+ if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, blobId)) < 0) {
+ HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
+ return ret;
+ }
+
+ // TODO: b/295794044 - Clear the old histogram channel blob
+
+ return ret;
+}
+
+int32_t ExynosDisplayDrmInterface::clearDisplayHistogramChannelSetting(
+ ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq, uint8_t channelId) {
+ int ret = NO_ERROR;
+
+ ATRACE_NAME(String8::format("%s #%u", __func__, channelId).c_str());
+
+ const DrmProperty &prop = mDrmCrtc->histogram_channel_property(channelId);
+ if (!prop.id()) {
+ ALOGE("Unsupported multi-channel histrogram for channel:%d", channelId);
+ return -ENOTSUP;
+ }
+
+ if ((ret = drmReq.atomicAddProperty(mDrmCrtc->id(), prop, 0)) < 0) {
+ HWC_LOGE(mExynosDisplay, "%s: Failed to add property", __func__);
+ return ret;
+ }
+
+ // TODO: b/295794044 - Clear the old histogram channel blob
+
+ return ret;
+}
+
+int32_t ExynosDisplayDrmInterface::sendHistogramChannelIoctl(HistogramChannelIoctl_t control,
+ uint8_t channelId) const {
+ ALOGE("%s: kernel doesn't support multi channel histogram ioctl", __func__);
+ return INVALID_OPERATION;
+}
diff --git a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
index ef9338b..d47e45a 100644
--- a/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
+++ b/libhwc2.1/libdisplayinterface/ExynosDisplayDrmInterface.h
@@ -328,12 +328,35 @@
virtual int32_t waitVBlank();
float getDesiredRefreshRate() { return mDesiredModeState.mode.v_refresh(); }
+ int32_t getOperationRate() {
+ if (mExynosDisplay->mOperationRateManager) {
+ return mExynosDisplay->mOperationRateManager->getTargetOperationRate();
+ }
+ return 0;
+ }
/* For Histogram */
virtual int32_t setDisplayHistogramSetting(
ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq) {
return NO_ERROR;
}
+
+ /* For Histogram Multi Channel support */
+ int32_t setDisplayHistogramChannelSetting(
+ ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq, uint8_t channelId,
+ void *blobData, size_t blobLength);
+ int32_t clearDisplayHistogramChannelSetting(
+ ExynosDisplayDrmInterface::DrmModeAtomicReq &drmReq, uint8_t channelId);
+ enum class HistogramChannelIoctl_t {
+ /* send the histogram data request by calling histogram_channel_request_ioctl */
+ REQUEST = 0,
+
+ /* cancel the histogram data request by calling histogram_channel_cancel_ioctl */
+ CANCEL,
+ };
+ virtual int32_t sendHistogramChannelIoctl(HistogramChannelIoctl_t control,
+ uint8_t channelId) const;
+
int32_t getFrameCount() { return mFrameCounter; }
virtual void registerHistogramInfo(const std::shared_ptr<IDLHistogram> &info) { return; }
virtual int32_t setHistogramControl(hidl_histogram_control_t enabled) { return NO_ERROR; }
@@ -341,9 +364,8 @@
int32_t getActiveModeHDisplay() { return mActiveModeState.mode.h_display(); }
int32_t getActiveModeVDisplay() { return mActiveModeState.mode.v_display(); }
uint32_t getActiveModeId() { return mActiveModeState.mode.id(); }
- int32_t panelHsize() { return mPanelResolutionHsize; }
- int32_t panelVsize() { return mPanelResolutionVsize; }
- int32_t getPanelResolution();
+ int32_t getPanelFullResolutionHSize() { return mPanelFullResolutionHSize; }
+ int32_t getPanelFullResolutionVSize() { return mPanelFullResolutionVSize; }
uint32_t getCrtcId() { return mDrmCrtc->id(); }
int32_t triggerClearDisplayPlanes();
@@ -520,8 +542,19 @@
DrmMode mDozeDrmMode;
uint32_t mMaxWindowNum = 0;
int32_t mFrameCounter = 0;
- int32_t mPanelResolutionHsize = 0;
- int32_t mPanelResolutionVsize = 0;
+ int32_t mPanelFullResolutionHSize = 0;
+ int32_t mPanelFullResolutionVSize = 0;
+
+ /**
+ * retrievePanelFullResolution
+ *
+ * Retrieve the panel full resolution by looking into the modes of the mDrmConnector
+ * and store the full resolution info in mPanelFullResolutionHSize (x component) and
+ * mPanelFullResolutionVSize (y component).
+ *
+ * Note: this function will be called only once in initDrmDevice()
+ */
+ void retrievePanelFullResolution();
public:
virtual bool readHotplugStatus();
diff --git a/libhwc2.1/libdrmresource/drm/drmcrtc.cpp b/libhwc2.1/libdrmresource/drm/drmcrtc.cpp
index 55cee3c..2d7d1d2 100644
--- a/libhwc2.1/libdrmresource/drm/drmcrtc.cpp
+++ b/libhwc2.1/libdrmresource/drm/drmcrtc.cpp
@@ -87,6 +87,8 @@
ALOGI("Failed to get color mode property");
if (drm_->GetCrtcProperty(*this, "expected_present_time", &expected_present_time_property_))
ALOGI("Failed to get expected_present_time property");
+ if (drm_->GetCrtcProperty(*this, "rcd_plane_id", &rcd_plane_id_property_))
+ ALOGI("Failed to get &rcd_plane_id property");
/* Histogram Properties */
if (drm_->GetCrtcProperty(*this, "histogram_roi", &histogram_roi_property_))
@@ -97,8 +99,6 @@
ALOGI("Failed to get &histogram_threshold property");
if (drm_->GetCrtcProperty(*this, "histogram_pos", &histogram_position_property_))
ALOGI("Failed to get &histogram_position property");
- if (drm_->GetCrtcProperty(*this, "rcd_plane_id", &rcd_plane_id_property_))
- ALOGI("Failed to get &rcd_plane_id property");
properties_.push_back(&active_property_);
properties_.push_back(&mode_property_);
@@ -121,6 +121,7 @@
properties_.push_back(&dqe_enabled_property_);
properties_.push_back(&color_mode_property_);
properties_.push_back(&expected_present_time_property_);
+ properties_.push_back(&rcd_plane_id_property_);
/* Histogram Properties */
properties_.push_back(&histogram_roi_property_);
@@ -128,8 +129,20 @@
properties_.push_back(&histogram_threshold_property_);
properties_.push_back(&histogram_position_property_);
- properties_.push_back(&rcd_plane_id_property_);
+ /* Histogram Properties :: multichannel */
+ // TODO: b/295786065 - Get available channels from crtc property.
+ for (int i = 0; i < histogram_channels_max; i++) {
+ char pname[64];
+ sprintf(pname, "histogram_%d", i);
+ if (!drm_->GetCrtcProperty(*this, pname, &histogram_channel_property_[i])) {
+ ALOGD("histogram_channel #%d property found", i);
+ properties_.push_back(&histogram_channel_property_[i]);
+ } else {
+ ALOGD("histogram_channel #%d property not found, break", i);
+ break;
+ }
+ }
return 0;
}
@@ -270,4 +283,13 @@
return rcd_plane_id_property_;
}
+/* Histogram Properties */
+const DrmProperty &DrmCrtc::histogram_channel_property(uint8_t channelId) const {
+ if (histogram_channels_max <= channelId) {
+ ALOGE("Invalid histogram channel number %u\n", channelId);
+ return histogram_channel_property_[0];
+ }
+ return histogram_channel_property_[channelId];
+}
+
} // namespace android
diff --git a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp
index 0eeb917..bab23fe 100644
--- a/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp
+++ b/libhwc2.1/libdrmresource/drm/drmeventlistener.cpp
@@ -122,6 +122,25 @@
if (handler == histogram_handler_.get()) histogram_handler_ = NULL;
}
+void DrmEventListener::RegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler) {
+ assert(!histogram_channel_handler_);
+
+ if (handler) {
+ histogram_channel_handler_.reset(handler);
+ } else {
+ ALOGE("%s: failed to register, handler is nullptr", __func__);
+ }
+}
+
+void DrmEventListener::UnRegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler) {
+ if (handler == histogram_channel_handler_.get()) {
+ histogram_channel_handler_ = NULL;
+ } else {
+ ALOGE("%s: failed to unregister, handler(%p), histogram_channel_handler(%p)", __func__,
+ handler, histogram_channel_handler_.get());
+ }
+}
+
void DrmEventListener::RegisterTUIHandler(DrmTUIEventHandler *handler) {
if (tui_handler_) {
ALOGE("TUI handler was already registered");
@@ -278,6 +297,15 @@
(void *)&(histo->bins));
}
break;
+#if defined(EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT)
+ case EXYNOS_DRM_HISTOGRAM_CHANNEL_EVENT:
+ if (histogram_channel_handler_) {
+ histogram_channel_handler_->handleHistogramChannelEvent((void *)e);
+ } else {
+ ALOGE("%s: no valid histogram channel event handler", __func__);
+ }
+ break;
+#endif
case DRM_EVENT_FLIP_COMPLETE:
vblank = (struct drm_event_vblank *)e;
user_data = (void *)(unsigned long)(vblank->user_data);
diff --git a/libhwc2.1/libdrmresource/include/drmcrtc.h b/libhwc2.1/libdrmresource/include/drmcrtc.h
index 6bb73fd..7148e46 100644
--- a/libhwc2.1/libdrmresource/include/drmcrtc.h
+++ b/libhwc2.1/libdrmresource/include/drmcrtc.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_DRM_CRTC_H_
#define ANDROID_DRM_CRTC_H_
-#include "drmmode.h"
-#include "drmproperty.h"
-
#include <stdint.h>
#include <xf86drmMode.h>
+#include <array>
+
+#include "drmmode.h"
+#include "drmproperty.h"
+
namespace android {
class DrmDevice;
@@ -65,6 +67,7 @@
const DrmProperty &dqe_enabled_property() const;
const DrmProperty &color_mode_property() const;
const DrmProperty &expected_present_time_property() const;
+ const DrmProperty &rcd_plane_id_property() const;
/* Histogram Properties */
const DrmProperty &histogram_roi_property() const;
@@ -72,7 +75,8 @@
const DrmProperty &histogram_threshold_property() const;
const DrmProperty &histogram_position_property() const;
- const DrmProperty &rcd_plane_id_property() const;
+ /* Histogram Properties:: multi channel */
+ const DrmProperty &histogram_channel_property(uint8_t channelId) const;
const std::vector<DrmProperty *> &properties() const {
return properties_;
@@ -108,6 +112,7 @@
DrmProperty dqe_enabled_property_;
DrmProperty color_mode_property_;
DrmProperty expected_present_time_property_;
+ DrmProperty rcd_plane_id_property_;
/* Histogram Properties */
DrmProperty histogram_roi_property_;
@@ -115,10 +120,15 @@
DrmProperty histogram_threshold_property_;
DrmProperty histogram_position_property_;
- DrmProperty rcd_plane_id_property_;
+ /* Histogram Properties :: multichannel support */
+ // TODO: b/295786065 - Get available channels from crtc property.
+ static const uint8_t histogram_channels_max = 4;
+ std::array<DrmProperty, histogram_channels_max> histogram_channel_property_;
+ /* all properties */
std::vector<DrmProperty *> properties_;
};
+
} // namespace android
#endif // ANDROID_DRM_CRTC_H_
diff --git a/libhwc2.1/libdrmresource/include/drmdevice.h b/libhwc2.1/libdrmresource/include/drmdevice.h
index 1f733bc..a24329b 100644
--- a/libhwc2.1/libdrmresource/include/drmdevice.h
+++ b/libhwc2.1/libdrmresource/include/drmdevice.h
@@ -84,6 +84,9 @@
void RegisterHistogramHandler(DrmHistogramEventHandler *handler) {
event_listener_.RegisterHistogramHandler(handler);
}
+ void RegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler) {
+ event_listener_.RegisterHistogramChannelHandler(handler);
+ }
int CallVendorIoctl(unsigned long request, void *arg);
diff --git a/libhwc2.1/libdrmresource/include/drmeventlistener.h b/libhwc2.1/libdrmresource/include/drmeventlistener.h
index e85ca0a..c26a458 100644
--- a/libhwc2.1/libdrmresource/include/drmeventlistener.h
+++ b/libhwc2.1/libdrmresource/include/drmeventlistener.h
@@ -46,6 +46,14 @@
virtual void handleHistogramEvent(uint32_t crtc_id, void *) = 0;
};
+class DrmHistogramChannelEventHandler {
+ public:
+ DrmHistogramChannelEventHandler() {}
+ virtual ~DrmHistogramChannelEventHandler() {}
+
+ virtual void handleHistogramChannelEvent(void *) = 0;
+};
+
class DrmTUIEventHandler {
public:
DrmTUIEventHandler() {
@@ -87,6 +95,8 @@
void UnRegisterHotplugHandler(DrmEventHandler *handler);
void RegisterHistogramHandler(DrmHistogramEventHandler *handler);
void UnRegisterHistogramHandler(DrmHistogramEventHandler *handler);
+ void RegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler);
+ void UnRegisterHistogramChannelHandler(DrmHistogramChannelEventHandler *handler);
void RegisterTUIHandler(DrmTUIEventHandler *handler);
void UnRegisterTUIHandler(DrmTUIEventHandler *handler);
void RegisterPanelIdleHandler(DrmPanelIdleEventHandler *handler);
@@ -115,6 +125,7 @@
DrmDevice *drm_;
std::unique_ptr<DrmEventHandler> hotplug_handler_;
std::unique_ptr<DrmHistogramEventHandler> histogram_handler_;
+ std::unique_ptr<DrmHistogramChannelEventHandler> histogram_channel_handler_;
std::unique_ptr<DrmTUIEventHandler> tui_handler_;
std::unique_ptr<DrmPanelIdleEventHandler> panel_idle_handler_;
std::mutex mutex_;
diff --git a/libhwc2.1/libdrmresource/include/worker.h b/libhwc2.1/libdrmresource/include/worker.h
index 153cbce..eeae4c1 100644
--- a/libhwc2.1/libdrmresource/include/worker.h
+++ b/libhwc2.1/libdrmresource/include/worker.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_WORKER_H_
#define ANDROID_WORKER_H_
+#include <android-base/thread_annotations.h>
#include <stdint.h>
#include <stdlib.h>
#include <string>
@@ -29,10 +30,10 @@
class Worker {
public:
- void Lock() {
+ void Lock() ACQUIRE(mutex_) {
mutex_.lock();
}
- void Unlock() {
+ void Unlock() RELEASE(mutex_) {
mutex_.unlock();
}
diff --git a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp
index 48d7f49..84a6971 100644
--- a/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp
+++ b/libhwc2.1/libexternaldisplay/ExynosExternalDisplay.cpp
@@ -35,8 +35,6 @@
: ExynosDisplay(HWC_DISPLAY_EXTERNAL, index, device, displayName) {
DISPLAY_LOGD(eDebugExternalDisplay, "");
- mDisplayControl.cursorSupport = true;
-
mEnabled = false;
mBlanked = false;
diff --git a/libhwc2.1/libhwcService/ExynosHWCService.cpp b/libhwc2.1/libhwcService/ExynosHWCService.cpp
index 79f414d..4ae010a 100644
--- a/libhwc2.1/libhwcService/ExynosHWCService.cpp
+++ b/libhwc2.1/libhwcService/ExynosHWCService.cpp
@@ -431,6 +431,18 @@
return -EINVAL;
}
+int32_t ExynosHWCService::setDisplayBrightnessDbv(int32_t display_id, uint32_t dbv) {
+ auto display = mHWCCtx->device->getDisplay(display_id);
+
+ if (display != nullptr) {
+ return display->setBrightnessDbv(dbv);
+ } else {
+ ALOGE("ExynosHWCService::%s() invalid display id: %d\n", __func__, display_id);
+ }
+
+ return -EINVAL;
+}
+
int32_t ExynosHWCService::setDisplayLhbm(int32_t display_id, uint32_t on) {
if (on > 1) return -EINVAL;
diff --git a/libhwc2.1/libhwcService/ExynosHWCService.h b/libhwc2.1/libhwcService/ExynosHWCService.h
index 460d12e..b443ca4 100644
--- a/libhwc2.1/libhwcService/ExynosHWCService.h
+++ b/libhwc2.1/libhwcService/ExynosHWCService.h
@@ -72,6 +72,7 @@
virtual int32_t setDisplayBrightness(int32_t display_id, float brightness);
virtual int32_t ignoreDisplayBrightnessUpdateRequests(int32_t displayId, bool ignore);
virtual int32_t setDisplayBrightnessNits(const int32_t display_id, const float nits);
+ virtual int32_t setDisplayBrightnessDbv(const int32_t display_id, const uint32_t dbv);
virtual int32_t setDisplayLhbm(int32_t display_id, uint32_t on);
virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t fps);
diff --git a/libhwc2.1/libhwcService/IExynosHWC.cpp b/libhwc2.1/libhwcService/IExynosHWC.cpp
index bf08d85..d09a3f6 100644
--- a/libhwc2.1/libhwcService/IExynosHWC.cpp
+++ b/libhwc2.1/libhwcService/IExynosHWC.cpp
@@ -68,6 +68,7 @@
TRIGGER_REFRESH_RATE_INDICATOR_UPDATE = 1011,
IGNORE_DISPLAY_BRIGHTNESS_UPDATE_REQUESTS = 1012,
SET_DISPLAY_BRIGHTNESS_NITS = 1013,
+ SET_DISPLAY_BRIGHTNESS_DBV = 1014,
};
class BpExynosHWCService : public BpInterface<IExynosHWCService> {
@@ -422,6 +423,18 @@
return result;
}
+ virtual int32_t setDisplayBrightnessDbv(int32_t displayId, uint32_t dbv) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor());
+ data.writeInt32(displayId);
+ data.writeUint32(dbv);
+ int result = remote()->transact(SET_DISPLAY_BRIGHTNESS_DBV, data, &reply);
+ if (result) {
+ ALOGE("SET_DISPLAY_BRIGHTNESS_DBV transact error(%d)", result);
+ }
+ return result;
+ }
+
virtual int32_t setDisplayLhbm(int32_t display_id, uint32_t on) {
Parcel data, reply;
data.writeInterfaceToken(IExynosHWCService::getInterfaceDescriptor());
@@ -795,6 +808,15 @@
return NO_ERROR;
} break;
+ case SET_DISPLAY_BRIGHTNESS_DBV: {
+ CHECK_INTERFACE(IExynosHWCService, data, reply);
+ int32_t displayId = data.readInt32();
+ uint32_t dbv = data.readUint32();
+ int32_t error = setDisplayBrightnessDbv(displayId, dbv);
+ reply->writeInt32(error);
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libhwc2.1/libhwcService/IExynosHWC.h b/libhwc2.1/libhwcService/IExynosHWC.h
index 71a4677..a454c4a 100644
--- a/libhwc2.1/libhwcService/IExynosHWC.h
+++ b/libhwc2.1/libhwcService/IExynosHWC.h
@@ -70,6 +70,7 @@
virtual int32_t setDisplayBrightness(int32_t display_id, float brightness) = 0;
virtual int32_t ignoreDisplayBrightnessUpdateRequests(int32_t displayId, bool ignore) = 0;
virtual int32_t setDisplayBrightnessNits(int32_t displayId, float nits) = 0;
+ virtual int32_t setDisplayBrightnessDbv(int32_t displayId, uint32_t dbv) = 0;
virtual int32_t setDisplayLhbm(int32_t display_id, uint32_t on) = 0;
virtual int32_t setMinIdleRefreshRate(uint32_t display_id, int32_t refresh_rate) = 0;
virtual int32_t setRefreshRateThrottle(uint32_t display_id, int32_t throttle) = 0;
diff --git a/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp b/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp
index d8befce..56b58c4 100644
--- a/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp
+++ b/libhwc2.1/libhwchelper/ExynosHWCHelper.cpp
@@ -918,14 +918,22 @@
((tv.tv_sec * 1000) + (tv.tv_usec / 1000)));
}
-void setFenceInfo(uint32_t fd, ExynosDisplay* display, HwcFdebugFenceType type, HwcFdebugIpType ip,
- HwcFenceDirection direction, bool pendingAllowed, int32_t dupFrom) {
+void setFenceInfo(uint32_t fd, const ExynosDisplay *display, HwcFdebugFenceType type,
+ HwcFdebugIpType ip, HwcFenceDirection direction, bool pendingAllowed,
+ int32_t dupFrom) {
if (!fence_valid(fd) || display == NULL) return;
ExynosDevice* device = display->mDevice;
+ device->mFenceTracker.updateFenceInfo(fd, display, type, ip, direction, pendingAllowed,
+ dupFrom);
+}
- std::scoped_lock lock(device->mFenceMutex);
- HwcFenceInfo& info = device->mFenceInfos[fd];
+void FenceTracker::updateFenceInfo(uint32_t fd, const ExynosDisplay *display,
+ HwcFdebugFenceType type, HwcFdebugIpType ip,
+ HwcFenceDirection direction, bool pendingAllowed,
+ int32_t dupFrom) {
+ std::scoped_lock lock(mFenceMutex);
+ HwcFenceInfo &info = mFenceInfos[fd];
info.displayId = display->mDisplayId;
if (info.leaking) {
@@ -955,11 +963,11 @@
}
if (info.usage == 0) {
- device->mFenceInfos.erase(fd);
+ mFenceInfos.erase(fd);
return;
} else if (info.usage < 0) {
ALOGE("%s : Invalid negative usage (%d) for Fence FD:%d", __func__, info.usage, fd);
- printLastFenceInfo(fd, display);
+ printLastFenceInfoLocked(fd);
}
HwcFenceTrace trace = {.direction = direction, .type = type, .ip = ip, .time = {0, 0}};
@@ -975,45 +983,39 @@
info.pendingAllowed = pendingAllowed;
}
-void printLastFenceInfo(uint32_t fd, ExynosDisplay* display) {
+void FenceTracker::printLastFenceInfoLocked(uint32_t fd) {
if (!fence_valid(fd)) return;
- ExynosDevice* device = display->mDevice;
-
- auto it = device->mFenceInfos.find(fd);
- if (it == device->mFenceInfos.end()) return;
- HwcFenceInfo& info = it->second;
+ auto it = mFenceInfos.find(fd);
+ if (it == mFenceInfos.end()) return;
+ HwcFenceInfo &info = it->second;
FT_LOGD("---- Fence FD : %d, Display(%d) ----", fd, info.displayId);
FT_LOGD("usage: %d, dupFrom: %d, pendingAllowed: %d, leaking: %d", info.usage, info.dupFrom,
info.pendingAllowed, info.leaking);
- for (const auto& trace : info.traces) {
+ for (const auto &trace : info.traces) {
FT_LOGD("> dir: %d, type: %d, ip: %d, time:%s", trace.direction, trace.type, trace.ip,
getLocalTimeStr(trace.time).c_str());
}
}
-void dumpFenceInfo(ExynosDisplay* display, int32_t count) {
- ExynosDevice* device = display->mDevice;
-
+void FenceTracker::dumpFenceInfoLocked(int32_t count) {
FT_LOGD("Dump fence (up to %d fences) ++", count);
- for (const auto& [fd, info] : device->mFenceInfos) {
+ for (const auto &[fd, info] : mFenceInfos) {
if (info.pendingAllowed) continue;
if (count-- <= 0) break;
- printLastFenceInfo(fd, display);
+ printLastFenceInfoLocked(fd);
}
FT_LOGD("Dump fence --");
}
-void printLeakFds(ExynosDisplay* display) {
- ExynosDevice* device = display->mDevice;
-
- auto reportLeakFds = [&fenceInfos = device->mFenceInfos](int sign) {
+void FenceTracker::printLeakFdsLocked() {
+ auto reportLeakFdsLocked = [&fenceInfos = mFenceInfos](int sign) REQUIRES(mFenceMutex) {
String8 errString;
errString.appendFormat("Leak Fds (%d) :\n", sign);
int cnt = 0;
- for (const auto& [fd, info] : fenceInfos) {
+ for (const auto &[fd, info] : fenceInfos) {
if (!info.leaking) continue;
if (info.usage * sign > 0) {
errString.appendFormat("%d,", fd);
@@ -1026,52 +1028,48 @@
FT_LOGW("%s", errString.c_str());
};
- reportLeakFds(+1);
- reportLeakFds(-1);
+ reportLeakFdsLocked(+1);
+ reportLeakFdsLocked(-1);
}
-void dumpNCheckLeak(ExynosDisplay* display, int32_t __unused depth) {
- ExynosDevice* device = display->mDevice;
-
+void FenceTracker::dumpNCheckLeakLocked() {
FT_LOGD("Dump leaking fence ++");
- for (auto& [fd, info] : device->mFenceInfos) {
+ for (auto &[fd, info] : mFenceInfos) {
if (!info.pendingAllowed) {
- // leak is occured in this frame first
+ // leak is occurred in this frame first
if (!info.leaking) {
info.leaking = true;
- printLastFenceInfo(fd, display);
+ printLastFenceInfoLocked(fd);
}
}
}
int priv = exynosHWCControl.fenceTracer;
exynosHWCControl.fenceTracer = 3;
- printLeakFds(display);
+ printLeakFdsLocked();
exynosHWCControl.fenceTracer = priv;
FT_LOGD("Dump leaking fence --");
}
-bool fenceWarn(ExynosDisplay* display, uint32_t threshold) {
- ExynosDevice* device = display->mDevice;
- uint32_t cnt = device->mFenceInfos.size();
+bool FenceTracker::fenceWarnLocked(uint32_t threshold) {
+ uint32_t cnt = mFenceInfos.size();
if (cnt > threshold) {
ALOGE("Fence leak! -- the number of fences(%d) exceeds threshold(%d)", cnt, threshold);
int priv = exynosHWCControl.fenceTracer;
exynosHWCControl.fenceTracer = 3;
- dumpFenceInfo(display, 10);
+ dumpFenceInfoLocked(10);
exynosHWCControl.fenceTracer = priv;
}
return (cnt > threshold);
}
-bool validateFencePerFrame(ExynosDisplay* display) {
- ExynosDevice* device = display->mDevice;
+bool FenceTracker::validateFencePerFrameLocked(const ExynosDisplay *display) {
bool ret = true;
- for (const auto& [fd, info] : device->mFenceInfos) {
+ for (const auto &[fd, info] : mFenceInfos) {
if (info.displayId != display->mDisplayId) continue;
if ((!info.pendingAllowed) && (!info.leaking)) {
ret = false;
@@ -1082,13 +1080,67 @@
if (!ret) {
int priv = exynosHWCControl.fenceTracer;
exynosHWCControl.fenceTracer = 3;
- dumpNCheckLeak(display, 0);
+ dumpNCheckLeakLocked();
exynosHWCControl.fenceTracer = priv;
}
return ret;
}
+bool FenceTracker::validateFences(ExynosDisplay *display) {
+ std::scoped_lock lock(mFenceMutex);
+
+ if (!validateFencePerFrameLocked(display)) {
+ ALOGE("You should doubt fence leak!");
+ saveFenceTraceLocked(display);
+ return false;
+ }
+
+ if (fenceWarnLocked(MAX_FENCE_THRESHOLD)) {
+ printLeakFdsLocked();
+ saveFenceTraceLocked(display);
+ return false;
+ }
+
+ if (exynosHWCControl.doFenceFileDump) {
+ ALOGD("Fence file dump !");
+ saveFenceTraceLocked(display);
+ exynosHWCControl.doFenceFileDump = false;
+ }
+
+ return true;
+}
+
+int32_t FenceTracker::saveFenceTraceLocked(ExynosDisplay *display) {
+ int32_t ret = NO_ERROR;
+ auto &fileWriter = display->mFenceFileWriter;
+
+ if (!fileWriter.chooseOpenedFile()) {
+ return -1;
+ }
+
+ String8 saveString;
+
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ saveString.appendFormat("\n====== Fences at time:%s ======\n", getLocalTimeStr(tv).c_str());
+
+ for (const auto &[fd, info] : mFenceInfos) {
+ saveString.appendFormat("---- Fence FD : %d, Display(%d) ----\n", fd, info.displayId);
+ saveString.appendFormat("usage: %d, dupFrom: %d, pendingAllowed: %d, leaking: %d\n",
+ info.usage, info.dupFrom, info.pendingAllowed, info.leaking);
+
+ for (const auto &trace : info.traces) {
+ saveString.appendFormat("> dir: %d, type: %d, ip: %d, time:%s\n", trace.direction,
+ trace.type, trace.ip, getLocalTimeStr(trace.time).c_str());
+ }
+ }
+
+ fileWriter.write(saveString);
+ fileWriter.flush();
+ return ret;
+}
+
String8 getMPPStr(int typeId) {
if (typeId < MPP_DPP_NUM){
int cnt = sizeof(available_otf_mpp_units)/sizeof(exynos_mpp_t);
diff --git a/libhwc2.1/libhwchelper/ExynosHWCHelper.h b/libhwc2.1/libhwchelper/ExynosHWCHelper.h
index 1efde16..ed9964a 100644
--- a/libhwc2.1/libhwchelper/ExynosHWCHelper.h
+++ b/libhwc2.1/libhwchelper/ExynosHWCHelper.h
@@ -162,6 +162,8 @@
1, 1, 32, RGB | BIT10 | COMP_TYPE_NONE | COMP_TYPE_AFBC, true, String8("RGBA_1010102"), 0},
{HAL_PIXEL_FORMAT_EXYNOS_ARGB_8888, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_ARGB8888,
1, 1, 32, RGB | BIT8 | COMP_TYPE_NONE | COMP_TYPE_AFBC, true, String8("EXYNOS_ARGB_8888"), 0},
+ {HAL_PIXEL_FORMAT_RGBA_FP16, DECON_PIXEL_FORMAT_MAX, DRM_FORMAT_ARGB16161616F,
+ 1, 1, 64, RGB | BIT16 | COMP_TYPE_NONE | COMP_TYPE_AFBC, true, String8("RGBA_FP16"), 0},
/* YUV 420 */
{HAL_PIXEL_FORMAT_EXYNOS_YCbCr_420_P_M, DECON_PIXEL_FORMAT_YUV420M, DRM_FORMAT_UNDEFINED,
@@ -538,23 +540,41 @@
};
class funcReturnCallback {
- public:
- funcReturnCallback(const std::function<void(void)> cb) : mCb(cb) {}
- ~funcReturnCallback() { mCb(); }
- private:
- const std::function<void(void)> mCb;
+public:
+ funcReturnCallback(const std::function<void(void)> cb) : mCb(cb) {}
+ ~funcReturnCallback() { mCb(); }
+
+private:
+ const std::function<void(void)> mCb;
};
String8 getLocalTimeStr(struct timeval tv);
void setFenceName(int fenceFd, HwcFenceType fenceType);
-void setFenceInfo(uint32_t fd, ExynosDisplay *display, HwcFdebugFenceType type, HwcFdebugIpType ip,
- HwcFenceDirection direction, bool pendingAllowed = false, int32_t dupFrom = -1);
-void printLastFenceInfo(uint32_t fd, ExynosDisplay *display);
-void dumpFenceInfo(ExynosDisplay *display, int32_t count);
-bool fenceWarn(ExynosDisplay *display, uint32_t threshold);
-void printLeakFds(ExynosDisplay *display);
-bool validateFencePerFrame(ExynosDisplay *display);
+void setFenceInfo(uint32_t fd, const ExynosDisplay *display, HwcFdebugFenceType type,
+ HwcFdebugIpType ip, HwcFenceDirection direction, bool pendingAllowed = false,
+ int32_t dupFrom = -1);
+
+class FenceTracker {
+public:
+ void updateFenceInfo(uint32_t fd, const ExynosDisplay *display, HwcFdebugFenceType type,
+ HwcFdebugIpType ip, HwcFenceDirection direction,
+ bool pendingAllowed = false, int32_t dupFrom = -1);
+ bool validateFences(ExynosDisplay *display);
+
+private:
+ void printLastFenceInfoLocked(uint32_t fd) REQUIRES(mFenceMutex);
+ void dumpFenceInfoLocked(int32_t count) REQUIRES(mFenceMutex);
+ void printLeakFdsLocked() REQUIRES(mFenceMutex);
+ void dumpNCheckLeakLocked() REQUIRES(mFenceMutex);
+ bool fenceWarnLocked(uint32_t threshold) REQUIRES(mFenceMutex);
+ bool validateFencePerFrameLocked(const ExynosDisplay *display) REQUIRES(mFenceMutex);
+ int32_t saveFenceTraceLocked(ExynosDisplay *display) REQUIRES(mFenceMutex);
+
+ std::map<int, HwcFenceInfo> mFenceInfos GUARDED_BY(mFenceMutex);
+ mutable std::mutex mFenceMutex;
+};
+
android_dataspace colorModeToDataspace(android_color_mode_t mode);
bool hasPPC(uint32_t physicalType, uint32_t formatIndex, uint32_t rotIndex);
diff --git a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
index a46e086..ec1e8ba 100644
--- a/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
+++ b/libhwc2.1/libmaindisplay/ExynosPrimaryDisplay.cpp
@@ -33,6 +33,7 @@
#include "ExynosHWCDebug.h"
#include "ExynosHWCHelper.h"
#include "ExynosLayer.h"
+#include "HistogramController.h"
extern struct exynos_hwc_control exynosHWCControl;
@@ -155,6 +156,7 @@
mBrightnessController = std::make_unique<BrightnessController>(
mIndex, [this]() { mDevice->onRefresh(mDisplayId); },
[this]() { updatePresentColorConversionInfo(); });
+ mHistogramController = std::make_unique<HistogramController>(this);
mDisplayControl.multiThreadedPresent = true;
}
diff --git a/libhwc2.1/libresource/ExynosMPP.cpp b/libhwc2.1/libresource/ExynosMPP.cpp
index 778aa1a..406996a 100644
--- a/libhwc2.1/libresource/ExynosMPP.cpp
+++ b/libhwc2.1/libresource/ExynosMPP.cpp
@@ -125,14 +125,12 @@
mMidImg.releaseFenceFd = -1;
}
-void ExynosMPPSource::setExynosImage(exynos_image src_img, exynos_image dst_img)
-{
+void ExynosMPPSource::setExynosImage(const exynos_image& src_img, const exynos_image& dst_img) {
mSrcImg = src_img;
mDstImg = dst_img;
}
-void ExynosMPPSource::setExynosMidImage(exynos_image mid_img)
-{
+void ExynosMPPSource::setExynosMidImage(const exynos_image& mid_img) {
mMidImg = mid_img;
}
diff --git a/libhwc2.1/libresource/ExynosMPP.h b/libhwc2.1/libresource/ExynosMPP.h
index 0877841..7ea3fbe 100644
--- a/libhwc2.1/libresource/ExynosMPP.h
+++ b/libhwc2.1/libresource/ExynosMPP.h
@@ -451,8 +451,8 @@
ExynosMPPSource();
ExynosMPPSource(uint32_t sourceType, void *source);
~ExynosMPPSource(){};
- void setExynosImage(exynos_image src_img, exynos_image dst_img);
- void setExynosMidImage(exynos_image mid_img);
+ void setExynosImage(const exynos_image& src_img, const exynos_image& dst_img);
+ void setExynosMidImage(const exynos_image& mid_img);
uint32_t mSourceType;
void *mSource;
diff --git a/libhwc2.1/libresource/ExynosResourceManager.cpp b/libhwc2.1/libresource/ExynosResourceManager.cpp
index d92d32a..47a1fb2 100644
--- a/libhwc2.1/libresource/ExynosResourceManager.cpp
+++ b/libhwc2.1/libresource/ExynosResourceManager.cpp
@@ -808,9 +808,11 @@
return ret;
}
-int32_t ExynosResourceManager::changeLayerFromClientToDevice(ExynosDisplay *display, ExynosLayer *layer,
- uint32_t layer_index, exynos_image m2m_out_img, ExynosMPP *m2mMPP, ExynosMPP *otfMPP)
-{
+int32_t ExynosResourceManager::changeLayerFromClientToDevice(ExynosDisplay* display,
+ ExynosLayer* layer,
+ uint32_t layer_index,
+ const exynos_image& m2m_out_img,
+ ExynosMPP* m2mMPP, ExynosMPP* otfMPP) {
int ret = NO_ERROR;
if ((ret = display->removeClientCompositionLayer(layer_index)) != NO_ERROR) {
ALOGD("removeClientCompositionLayer return error(%d)", ret);
diff --git a/libhwc2.1/libresource/ExynosResourceManager.h b/libhwc2.1/libresource/ExynosResourceManager.h
index e996554..c8f308f 100644
--- a/libhwc2.1/libresource/ExynosResourceManager.h
+++ b/libhwc2.1/libresource/ExynosResourceManager.h
@@ -187,8 +187,9 @@
struct exynos_image &dst, ExynosMPPSource *mppSrc);
private:
- int32_t changeLayerFromClientToDevice(ExynosDisplay *display, ExynosLayer *layer,
- uint32_t layer_index, exynos_image m2m_out_img, ExynosMPP *m2mMPP, ExynosMPP *otfMPP);
+ int32_t changeLayerFromClientToDevice(ExynosDisplay* display, ExynosLayer* layer,
+ uint32_t layer_index, const exynos_image& m2m_out_img,
+ ExynosMPP* m2mMPP, ExynosMPP* otfMPP);
void dump(const restriction_classification_t, String8 &result) const;
sp<DstBufMgrThread> mDstBufMgrThread;
diff --git a/libhwc2.1/pixel-display-default.xml b/libhwc2.1/pixel-display-default.xml
index 7f2e4ba..50835eb 100644
--- a/libhwc2.1/pixel-display-default.xml
+++ b/libhwc2.1/pixel-display-default.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>com.google.hardware.pixel.display</name>
- <version>8</version>
+ <version>9</version>
<fqname>IDisplay/default</fqname>
</hal>
</manifest>
diff --git a/libhwc2.1/pixel-display-secondary.xml b/libhwc2.1/pixel-display-secondary.xml
index ff313be..3cf2883 100644
--- a/libhwc2.1/pixel-display-secondary.xml
+++ b/libhwc2.1/pixel-display-secondary.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>com.google.hardware.pixel.display</name>
- <version>8</version>
+ <version>9</version>
<fqname>IDisplay/secondary</fqname>
</hal>
</manifest>
diff --git a/libhwc2.1/pixel-display.cpp b/libhwc2.1/pixel-display.cpp
index d2eb986..c958346 100644
--- a/libhwc2.1/pixel-display.cpp
+++ b/libhwc2.1/pixel-display.cpp
@@ -25,6 +25,7 @@
#include "ExynosDisplay.h"
#include "ExynosPrimaryDisplay.h"
+#include "HistogramController.h"
extern int32_t load_png_image(const char *filepath, buffer_handle_t buffer);
@@ -205,7 +206,7 @@
histogram::HistogramMediator::HistogramConfig pendingConfig(roi, weight, pos);
{
- std::unique_lock<std::mutex> lk(mMediator.mConfigMutex);
+ std::scoped_lock lock(mMediator.mConfigMutex);
isConfigChanged = mMediator.mConfig != pendingConfig;
if (isConfigChanged &&
@@ -251,11 +252,11 @@
*_aidl_return = HistogramErrorCode::BAD_HIST_DATA;
return ndk::ScopedAStatus::ok();
}
- if (mMediator.isDisplayPowerOff() == true) {
+ if (mDisplay->isPowerModeOff() == true) {
*_aidl_return = HistogramErrorCode::DISPLAY_POWEROFF; // panel is off
return ndk::ScopedAStatus::ok();
}
- if (mMediator.isSecureContentPresenting() == true) {
+ if (mDisplay->isSecureContentPresenting() == true) {
*_aidl_return = HistogramErrorCode::DRM_PLAYING; // panel is playing DRM content
return ndk::ScopedAStatus::ok();
}
@@ -284,7 +285,7 @@
}
RoiRect roiCaled = mMediator.calRoi(roi); // fit roi coordinates to RRS
runMediator(roiCaled, weight, pos, histogrambuffer);
- if (mMediator.isSecureContentPresenting() == true) {
+ if (mDisplay->isSecureContentPresenting() == true) {
/* clear data to avoid leakage */
std::fill(histogrambuffer->begin(), histogrambuffer->end(), 0);
histogrambuffer->clear();
@@ -320,6 +321,50 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Display::getHistogramCapability(HistogramCapability *_aidl_return) {
+ if (mDisplay && mDisplay->mHistogramController) {
+ return mDisplay->mHistogramController->getHistogramCapability(_aidl_return);
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Display::registerHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *_aidl_return) {
+ if (mDisplay && mDisplay->mHistogramController) {
+ return mDisplay->mHistogramController->registerHistogram(token, histogramConfig,
+ _aidl_return);
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Display::queryHistogram(const ndk::SpAIBinder &token,
+ std::vector<char16_t> *histogramBuffer,
+ HistogramErrorCode *_aidl_return) {
+ if (mDisplay && mDisplay->mHistogramController) {
+ return mDisplay->mHistogramController->queryHistogram(token, histogramBuffer, _aidl_return);
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Display::reconfigHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *_aidl_return) {
+ if (mDisplay && mDisplay->mHistogramController) {
+ return mDisplay->mHistogramController->reconfigHistogram(token, histogramConfig,
+ _aidl_return);
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Display::unregisterHistogram(const ndk::SpAIBinder &token,
+ HistogramErrorCode *_aidl_return) {
+ if (mDisplay && mDisplay->mHistogramController) {
+ return mDisplay->mHistogramController->unregisterHistogram(token, _aidl_return);
+ }
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
} // namespace display
} // namespace pixel
} // namespace hardware
diff --git a/libhwc2.1/pixel-display.h b/libhwc2.1/pixel-display.h
index df437af..63aa037 100644
--- a/libhwc2.1/pixel-display.h
+++ b/libhwc2.1/pixel-display.h
@@ -64,6 +64,18 @@
ndk::ScopedAStatus setPeakRefreshRate(int rate) override;
ndk::ScopedAStatus setLowPowerMode(bool enabled) override;
ndk::ScopedAStatus isOperationRateSupported(bool *_aidl_return) override;
+ ndk::ScopedAStatus getHistogramCapability(HistogramCapability *_aidl_return) override;
+ ndk::ScopedAStatus registerHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *_aidl_return) override;
+ ndk::ScopedAStatus queryHistogram(const ndk::SpAIBinder &token,
+ std::vector<char16_t> *histogramBuffer,
+ HistogramErrorCode *_aidl_return) override;
+ ndk::ScopedAStatus reconfigHistogram(const ndk::SpAIBinder &token,
+ const HistogramConfig &histogramConfig,
+ HistogramErrorCode *_aidl_return) override;
+ ndk::ScopedAStatus unregisterHistogram(const ndk::SpAIBinder &token,
+ HistogramErrorCode *_aidl_return) override;
private:
bool runMediator(const RoiRect &roi, const Weight &weight, const HistogramPos &pos,