Upgrade drm_hwcomposer to 851ea4dc268c4da612c65a5dfedbd3ed85960405 am: 32e0a72311 am: 0e86a316f0
Original change: undetermined
Change-Id: Iab46cd74595a23a580a3989e462f599f019bf9df
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index 3f597c3..1ca2876 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -61,7 +61,7 @@
exit 1
fi
- git show "$h" -- | clang-format-diff-19 -p 1 -style=file > /tmp/format-fixup.patch
+ git show -U0 "$h" -- | clang-format-diff-19 -p 1 -style=file > /tmp/format-fixup.patch
if [ -s /tmp/format-fixup.patch ]; then
cat /tmp/format-fixup.patch >&2
exit 1
diff --git a/.ci/Dockerfile b/.ci/Dockerfile
index a9e2242..8a3172e 100644
--- a/.ci/Dockerfile
+++ b/.ci/Dockerfile
@@ -41,10 +41,10 @@
USER ${RUN_USER}
# Install aospless package (produced by GloDroid/aospext)
-RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/-/project/5/uploads/97f99b51143107ba02a51cf1c0ddb542/aospless_drm_hwcomposer_arm64.tar.xz && \
+RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/-/project/5/uploads/cafa930dad28acf7ee44d50101d5e8f0/aospless_drm_hwcomposer_arm64.tar.xz && \
cd ${USER_HOME} && \
sha256sum aospless_drm_hwcomposer_arm64.tar.xz && \
- (echo dae29adb121f51e59c95fb7b29e0f7aed5b2983d10c7f1d5f1b9fd551c4bbb47 aospless_drm_hwcomposer_arm64.tar.xz | sha256sum --check) && \
+ (echo f792b1140861112f80c8a3a22e1af8e3eccf4910fe4449705e62d2032b713bf9 aospless_drm_hwcomposer_arm64.tar.xz | sha256sum --check) && \
tar xf aospless_drm_hwcomposer_arm64.tar.xz && ln -s ../drm_hwcomposer/ ${USER_HOME}/aospless/src
# Create project path
diff --git a/.ci/Makefile b/.ci/Makefile
index 051a437..0dba6cc 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -16,8 +16,6 @@
CXXARGS := $(subst [BASE_DIR],$(BASE_DIR),$(CXXARGS))
# clang-tidy doesn't like -mcpu=xxx flag
CXXARGS := $(patsubst -mcpu=%,,$(CXXARGS))
-# TODO: build aospless with gtest enabled and remove line below
-CXXARGS := $(subst -nostdlibinc,,$(CXXARGS))
CXXARGS += -I. -I./tests/test_include $(CXXFLAGS)
TIDY_FILES_OVERRIDE := \
@@ -55,14 +53,6 @@
-readability-redundant-member-init \
-cppcoreguidelines-avoid-const-or-ref-data-members \
-cert-err33-c \
- -readability-math-missing-parentheses \
- -readability-avoid-unconditional-preprocessor-if \
- -modernize-type-traits \
- -clang-analyzer-optin.core.EnumCastOutOfRange \
- -performance-inefficient-vector-operation \
- -readability-static-accessed-through-instance \
- -misc-use-internal-linkage \
- -performance-avoid-endl \
TIDY_CHECKS_NORMAL := \
$(TIDY_CHECKS_FINE) \
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9f3d022..fbe2a85 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -26,12 +26,13 @@
- cd ..
- rm -f aospless_drm_hwcomposer_arm64.tar.xz
- rm -rf aospless/*
- - wget https://gitlab.freedesktop.org/-/project/5/uploads/97f99b51143107ba02a51cf1c0ddb542/aospless_drm_hwcomposer_arm64.tar.xz
+ - wget https://gitlab.freedesktop.org/-/project/5/uploads/cafa930dad28acf7ee44d50101d5e8f0/aospless_drm_hwcomposer_arm64.tar.xz
- tar xf aospless_drm_hwcomposer_arm64.tar.xz
- rm -rf aospless/src
- ln -s ../drm-hwcomposer/ aospless/src
- make -C ./aospless install
- cp -r aospless/install/* drm-hwcomposer/install/arm64
+ - ls drm-hwcomposer/install/arm64
artifacts:
paths:
@@ -44,7 +45,7 @@
- cd ..
- rm -f aospless_drm_hwcomposer_arm64.tar.xz
- rm -rf aospless/*
- - wget https://gitlab.freedesktop.org/-/project/5/uploads/97f99b51143107ba02a51cf1c0ddb542/aospless_drm_hwcomposer_arm64.tar.xz
+ - wget https://gitlab.freedesktop.org/-/project/5/uploads/cafa930dad28acf7ee44d50101d5e8f0/aospless_drm_hwcomposer_arm64.tar.xz
- tar xf aospless_drm_hwcomposer_arm64.tar.xz
- cd -
- make -j$(nproc) -k -f .ci/Makefile
diff --git a/Android.bp b/Android.bp
index 2cbdc44..3951949 100644
--- a/Android.bp
+++ b/Android.bp
@@ -56,6 +56,7 @@
static_libs: [
"libaidlcommonsupport",
+ "libdisplay_info",
],
header_libs: [
@@ -68,6 +69,7 @@
],
cppflags: [
+ "-DHAS_LIBDISPLAY_INFO",
"-DHWC2_INCLUDE_STRINGIFICATION",
"-DHWC2_USE_CPP11",
],
@@ -117,6 +119,7 @@
"hwc2_device/HwcLayer.cpp",
"hwc2_device/hwc2_device.cpp",
+ "utils/LibdisplayEdidWrapper.cpp",
"utils/fd.cpp",
"utils/properties.cpp",
],
@@ -154,32 +157,6 @@
],
}
-// Kept only for compatibility with older Android version. Please do not use!
-cc_library_static {
- name: "drm_hwcomposer",
- defaults: ["hwcomposer.drm_defaults"],
- srcs: [":drm_hwcomposer_common"],
-}
-
-cc_library_shared {
- name: "hwcomposer.drm",
- defaults: ["hwcomposer.drm_defaults"],
- srcs: [
- ":drm_hwcomposer_common",
- "bufferinfo/legacy/BufferInfoLibdrm.cpp",
- ],
- cflags: ["-DUSE_IMAPPER4_METADATA_API"],
-}
-
-cc_library_shared {
- name: "hwcomposer.drm_minigbm",
- defaults: ["hwcomposer.drm_defaults"],
- srcs: [
- ":drm_hwcomposer_common",
- "bufferinfo/legacy/BufferInfoMinigbm.cpp",
- ],
-}
-
cc_defaults {
name: "android.hardware.composer.hwc3-service.drm.defaults",
diff --git a/METADATA b/METADATA
index 0c9c1ce..dacef3a 100644
--- a/METADATA
+++ b/METADATA
@@ -1,15 +1,19 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/drm_hwcomposer
+# For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
+
name: "drm_hwcomposer"
description: "KMS-based HWComposer implementation."
third_party {
license_type: NOTICE
last_upgrade_date {
year: 2025
- month: 1
- day: 14
+ month: 2
+ day: 4
}
identifier {
type: "Git"
value: "https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer"
- version: "a29289940d7cf806029a36e2e01667708294c67b"
+ version: "851ea4dc268c4da612c65a5dfedbd3ed85960405"
}
}
diff --git a/compositor/DisplayInfo.h b/compositor/DisplayInfo.h
index 6ddc66f..f580d99 100644
--- a/compositor/DisplayInfo.h
+++ b/compositor/DisplayInfo.h
@@ -18,6 +18,31 @@
#include <cstdint>
+/*
+ * Display colorimetry enums.
+ */
+// NOLINTBEGIN(readability-identifier-naming)
+enum class Colormode : int32_t {
+ kNative,
+ kBt601_625,
+ kBt601_625Unadjusted,
+ kBt601_525,
+ kBt601_525Unadjusted,
+ kBt709,
+ kDciP3,
+ kSrgb,
+ kAdobeRgb,
+ kDisplayP3,
+ kBt2020,
+ kBt2100Pq,
+ kBt2100Hlg,
+ kDisplayBt2020,
+};
+// NOLINTEND(readability-identifier-naming)
+
+/**
+ * Display panel colorspace property values.
+ */
enum class Colorspace : int32_t {
kDefault,
kSmpte170MYcc,
diff --git a/compositor/LayerData.h b/compositor/LayerData.h
index a808adc..7eb6cba 100644
--- a/compositor/LayerData.h
+++ b/compositor/LayerData.h
@@ -34,13 +34,11 @@
class DrmFbIdHandle;
/* Rotation is defined in the clockwise direction */
-enum LayerTransform : uint32_t {
- kIdentity = 0,
- kFlipH = 1 << 0,
- kFlipV = 1 << 1,
- kRotate90 = 1 << 2,
- kRotate180 = 1 << 3,
- kRotate270 = 1 << 4,
+/* The flip is done before rotation */
+struct LayerTransform {
+ bool hflip;
+ bool vflip;
+ bool rotate90;
};
struct PresentInfo {
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index 9a8769a..9ce9a93 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -150,6 +150,21 @@
return -EINVAL;
}
+ if (args.hdr_metadata && connector->GetHdrOutputMetadataProperty()) {
+ auto blob = drm->RegisterUserPropertyBlob(args.hdr_metadata.get(),
+ sizeof(hdr_output_metadata));
+ new_frame_state.hdr_metadata_blob = std::move(blob);
+ if (!new_frame_state.hdr_metadata_blob) {
+ ALOGE("Failed to create %s blob",
+ connector->GetHdrOutputMetadataProperty().GetName().c_str());
+ return -EINVAL;
+ }
+
+ if (!connector->GetHdrOutputMetadataProperty()
+ .AtomicSet(*pset, *new_frame_state.hdr_metadata_blob))
+ return -EINVAL;
+ }
+
auto unused_planes = new_frame_state.used_planes;
if (args.composition) {
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index 8d22b99..4af04d1 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -40,6 +40,7 @@
std::shared_ptr<drm_color_ctm> color_matrix;
std::optional<Colorspace> colorspace;
std::optional<int32_t> content_type;
+ std::shared_ptr<hdr_output_metadata> hdr_metadata;
std::shared_ptr<DrmFbIdHandle> writeback_fb;
SharedFd writeback_release_fence;
@@ -84,6 +85,7 @@
DrmModeUserPropertyBlobUnique mode_blob;
DrmModeUserPropertyBlobUnique ctm_blob;
+ DrmModeUserPropertyBlobUnique hdr_metadata_blob;
int release_fence_pt_index{};
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index eeec3b1..37e1be4 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -89,6 +89,12 @@
}
UpdateEdidProperty();
+#if HAS_LIBDISPLAY_INFO
+ auto edid = LibdisplayEdidWrapper::Create(GetEdidBlob());
+ edid_wrapper_ = edid ? std::move(edid) : std::make_unique<EdidWrapper>();
+#else
+ edid_wrapper_ = std::make_unique<EdidWrapper>();
+#endif
if (IsWriteback() &&
(!GetConnectorProperty("WRITEBACK_PIXEL_FORMATS",
@@ -99,8 +105,7 @@
return false;
}
- if (GetConnectorProperty("Colorspace", &colorspace_property_,
- /*is_optional=*/true)) {
+ if (GetOptionalConnectorProperty("Colorspace", &colorspace_property_)) {
colorspace_property_.AddEnumToMap("Default", Colorspace::kDefault,
colorspace_enum_map_);
colorspace_property_.AddEnumToMap("SMPTE_170M_YCC", Colorspace::kSmpte170MYcc,
@@ -129,17 +134,19 @@
colorspace_enum_map_);
colorspace_property_.AddEnumToMap("RGB_WIDE_FIXED", Colorspace::kRgbWideFixed,
colorspace_enum_map_);
- colorspace_property_.AddEnumToMap("RGB_WIDE_FLOAT", Colorspace::kRgbWideFloat,
+ colorspace_property_.AddEnumToMap("RGB_WIDE_FLOAT",
+ Colorspace::kRgbWideFloat,
colorspace_enum_map_);
colorspace_property_.AddEnumToMap("BT601_YCC", Colorspace::kBt601Ycc,
colorspace_enum_map_);
}
- GetConnectorProperty("content type", &content_type_property_,
- /*is_optional=*/true);
+ GetOptionalConnectorProperty("content type", &content_type_property_);
- if (GetConnectorProperty("panel orientation", &panel_orientation_,
- /*is_optional=*/true)) {
+ GetOptionalConnectorProperty("HDR_OUTPUT_METADATA",
+ &hdr_output_metadata_property_);
+
+ if (GetOptionalConnectorProperty("panel orientation", &panel_orientation_)) {
panel_orientation_
.AddEnumToMapReverse("Normal",
PanelOrientation::kModePanelOrientationNormal,
@@ -162,9 +169,7 @@
}
int DrmConnector::UpdateEdidProperty() {
- return GetConnectorProperty("EDID", &edid_property_, /*is_optional=*/true)
- ? 0
- : -EINVAL;
+ return GetOptionalConnectorProperty("EDID", &edid_property_) ? 0 : -EINVAL;
}
auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index be84ae3..c22d059 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -27,11 +27,14 @@
#include "DrmProperty.h"
#include "DrmUnique.h"
#include "compositor/DisplayInfo.h"
+#include "utils/EdidWrapper.h"
namespace android {
class DrmDevice;
+using EdidWrapperUnique = std::unique_ptr<EdidWrapper>;
+
class DrmConnector : public PipelineBindable<DrmConnector> {
public:
static auto CreateInstance(DrmDevice &dev, uint32_t connector_id,
@@ -42,6 +45,9 @@
int UpdateEdidProperty();
auto GetEdidBlob() -> DrmModePropertyBlobUnique;
+ auto GetParsedEdid() -> EdidWrapperUnique & {
+ return edid_wrapper_;
+ }
auto GetDev() const -> DrmDevice & {
return *drm_;
@@ -109,6 +115,10 @@
return content_type_property_;
}
+ auto &GetHdrOutputMetadataProperty() const {
+ return hdr_output_metadata_property_;
+ }
+
auto &GetWritebackFbIdProperty() const {
return writeback_fb_id_;
}
@@ -147,6 +157,12 @@
auto Init() -> bool;
auto GetConnectorProperty(const char *prop_name, DrmProperty *property,
bool is_optional = false) -> bool;
+ auto GetOptionalConnectorProperty(const char *prop_name,
+ DrmProperty *property) -> bool {
+ return GetConnectorProperty(prop_name, property, /*is_optional=*/true);
+ }
+
+ EdidWrapperUnique edid_wrapper_;
const uint32_t index_in_res_array_;
@@ -157,6 +173,7 @@
DrmProperty edid_property_;
DrmProperty colorspace_property_;
DrmProperty content_type_property_;
+ DrmProperty hdr_output_metadata_property_;
DrmProperty link_status_property_;
DrmProperty writeback_pixel_formats_;
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index dbb5ad6..0010742 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -88,22 +88,8 @@
GetPlaneProperty("zpos", zpos_property_, Presence::kOptional);
- /* DRM/KMS uses counter-clockwise rotations, while HWC API uses
- * clockwise. That's why 90 and 270 are swapped here.
- */
if (GetPlaneProperty("rotation", rotation_property_, Presence::kOptional)) {
- rotation_property_.AddEnumToMap("rotate-0", LayerTransform::kIdentity,
- transform_enum_map_);
- rotation_property_.AddEnumToMap("rotate-90", LayerTransform::kRotate270,
- transform_enum_map_);
- rotation_property_.AddEnumToMap("rotate-180", LayerTransform::kRotate180,
- transform_enum_map_);
- rotation_property_.AddEnumToMap("rotate-270", LayerTransform::kRotate90,
- transform_enum_map_);
- rotation_property_.AddEnumToMap("reflect-x", LayerTransform::kFlipH,
- transform_enum_map_);
- rotation_property_.AddEnumToMap("reflect-y", LayerTransform::kFlipV,
- transform_enum_map_);
+ rotation_property_.GetEnumMask(transform_enum_mask_);
}
GetPlaneProperty("alpha", alpha_property_, Presence::kOptional);
@@ -166,22 +152,40 @@
return ((1 << crtc.GetIndexInResArray()) & plane_->possible_crtcs) != 0;
}
+static uint64_t ToDrmRotation(LayerTransform transform) {
+ /* DRM/KMS uses counter-clockwise rotations, while HWC API uses
+ * clockwise. That's why 90 and 270 are swapped here.
+ */
+ uint64_t rotation = DRM_MODE_ROTATE_0;
+
+ if (transform.rotate90) {
+ rotation |= DRM_MODE_ROTATE_270;
+ }
+
+ if (transform.hflip) {
+ rotation |= DRM_MODE_REFLECT_X;
+ }
+
+ if (transform.vflip) {
+ rotation |= DRM_MODE_REFLECT_Y;
+ }
+
+ // TODO(nobody): Respect transform_enum_mask_ to find alternative rotation
+ // values
+
+ return rotation;
+}
+
bool DrmPlane::IsValidForLayer(LayerData *layer) {
if (layer == nullptr || !layer->bi) {
ALOGE("%s: Invalid parameters", __func__);
return false;
}
- if (!rotation_property_) {
- if (layer->pi.transform != LayerTransform::kIdentity) {
- ALOGV("No rotation property on plane %d", GetId());
- return false;
- }
- } else {
- if (transform_enum_map_.count(layer->pi.transform) == 0) {
- ALOGV("Transform is not supported on plane %d", GetId());
- return false;
- }
+ uint64_t drm_rotation = ToDrmRotation(layer->pi.transform);
+ if ((drm_rotation & transform_enum_mask_) != drm_rotation) {
+ ALOGV("Transform is not supported on plane %d", GetId());
+ return false;
}
if (!alpha_property_ && layer->pi.alpha != UINT16_MAX) {
@@ -218,27 +222,6 @@
}) != std::end(formats_);
}
-static uint64_t ToDrmRotation(LayerTransform transform) {
- uint64_t rotation = 0;
- /* DRM/KMS uses counter-clockwise rotations, while HWC API uses
- * clockwise. That's why 90 and 270 are swapped here.
- */
- if ((transform & LayerTransform::kFlipH) != 0)
- rotation |= DRM_MODE_REFLECT_X;
- if ((transform & LayerTransform::kFlipV) != 0)
- rotation |= DRM_MODE_REFLECT_Y;
- if ((transform & LayerTransform::kRotate90) != 0)
- rotation |= DRM_MODE_ROTATE_270;
- else if ((transform & LayerTransform::kRotate180) != 0)
- rotation |= DRM_MODE_ROTATE_180;
- else if ((transform & LayerTransform::kRotate270) != 0)
- rotation |= DRM_MODE_ROTATE_90;
- else
- rotation |= DRM_MODE_ROTATE_0;
-
- return rotation;
-}
-
/* Convert float to 16.16 fixed point */
static int To1616FixPt(float in) {
constexpr int kBitShift = 16;
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index c26a3cc..24d21c8 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -96,6 +96,6 @@
std::map<BufferBlendMode, uint64_t> blending_enum_map_;
std::map<BufferColorSpace, uint64_t> color_encoding_enum_map_;
std::map<BufferSampleRange, uint64_t> color_range_enum_map_;
- std::map<LayerTransform, uint64_t> transform_enum_map_;
+ uint64_t transform_enum_mask_ = DRM_MODE_ROTATE_0;
};
} // namespace android
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index dbd307e..8dc62f6 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -144,4 +144,24 @@
return {};
}
+auto DrmProperty::GetEnumMask(uint64_t &mask) -> bool {
+ if (enums_.empty()) {
+ ALOGE("No enum values for property: %s", name_.c_str());
+ return false;
+ }
+
+ if (!IsBitmask()) {
+ ALOGE("Property %s is not a bitmask property.", name_.c_str());
+ return false;
+ }
+
+ mask = 0;
+
+ for (const auto &it : enums_) {
+ mask |= (1 << it.value);
+ }
+
+ return true;
+}
+
} // namespace android
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index 2683ad8..99bddb1 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -54,6 +54,10 @@
return id_ != 0 && (flags_ & DRM_MODE_PROP_RANGE) != 0;
}
+ bool IsBitmask() const {
+ return id_ != 0 && (flags_ & DRM_MODE_PROP_BITMASK) != 0;
+ }
+
auto RangeMin() const -> std::tuple<int, uint64_t>;
auto RangeMax() const -> std::tuple<int, uint64_t>;
@@ -68,6 +72,8 @@
auto AddEnumToMapReverse(const std::string &name, E value,
std::map<uint64_t, E> &map) -> bool;
+ auto GetEnumMask(uint64_t &mask) -> bool;
+
explicit operator bool() const {
return id_ != 0;
}
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index 9c68816..c866263 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -124,7 +124,7 @@
struct timespec ts {};
clock_gettime(CLOCK_MONOTONIC, &ts);
constexpr int64_t kNsInSec = 1000000000LL;
- return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
+ return (int64_t(ts.tv_sec) * kNsInSec) + int64_t(ts.tv_nsec);
}
void ResourceManager::UpdateFrontendDisplays() {
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 64152ab..defbe42 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -124,7 +124,7 @@
if (last_timestamp_ < 0)
return current + frame_ns;
- return frame_ns * ((current - last_timestamp_) / frame_ns + 1) +
+ return (frame_ns * ((current - last_timestamp_) / frame_ns + 1)) +
last_timestamp_;
}
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 3469c85..16d8bac 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -21,7 +21,10 @@
#include <cinttypes>
+#include <xf86drmMode.h>
+
#include <hardware/gralloc.h>
+#include <ui/ColorSpace.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/PixelFormat.h>
@@ -37,10 +40,61 @@
#include "utils/properties.h"
using ::android::DrmDisplayPipeline;
+using ColorGamut = ::android::ColorSpace;
namespace android {
namespace {
+
+constexpr int kCtmRows = 3;
+constexpr int kCtmCols = 3;
+
+constexpr std::array<float, 16> kIdentityMatrix = {
+ 1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F,
+ 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F,
+};
+
+uint64_t To3132FixPt(float in) {
+ constexpr uint64_t kSignMask = (1ULL << 63);
+ constexpr uint64_t kValueMask = ~(1ULL << 63);
+ constexpr auto kValueScale = static_cast<float>(1ULL << 32);
+ if (in < 0)
+ return (static_cast<uint64_t>(-in * kValueScale) & kValueMask) | kSignMask;
+ return static_cast<uint64_t>(in * kValueScale) & kValueMask;
+}
+
+auto ToColorTransform(const std::array<float, 16> &color_transform_matrix) {
+ /* HAL provides a 4x4 float type matrix:
+ * | 0 1 2 3|
+ * | 4 5 6 7|
+ * | 8 9 10 11|
+ * |12 13 14 15|
+ *
+ * R_out = R*0 + G*4 + B*8 + 12
+ * G_out = R*1 + G*5 + B*9 + 13
+ * B_out = R*2 + G*6 + B*10 + 14
+ *
+ * DRM expects a 3x3 s31.32 fixed point matrix:
+ * out matrix in
+ * |R| |0 1 2| |R|
+ * |G| = |3 4 5| x |G|
+ * |B| |6 7 8| |B|
+ *
+ * R_out = R*0 + G*1 + B*2
+ * G_out = R*3 + G*4 + B*5
+ * B_out = R*6 + G*7 + B*8
+ */
+ auto color_matrix = std::make_shared<drm_color_ctm>();
+ for (int i = 0; i < kCtmCols; i++) {
+ for (int j = 0; j < kCtmRows; j++) {
+ constexpr int kInCtmRows = 4;
+ color_matrix->matrix[(i * kCtmRows) + j] = To3132FixPt(
+ color_transform_matrix[(j * kInCtmRows) + i]);
+ }
+ }
+ return color_matrix;
+}
+
// Allocate a black buffer that can be used for an initial modeset when there.
// is no appropriate client buffer available to be used.
// Caller must free the returned buffer with GraphicBufferAllocator::free.
@@ -105,10 +159,38 @@
}
} // namespace
+static BufferColorSpace Hwc2ToColorSpace(int32_t dataspace) {
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ return BufferColorSpace::kItuRec709;
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ return BufferColorSpace::kItuRec601;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ return BufferColorSpace::kItuRec2020;
+ default:
+ return BufferColorSpace::kUndefined;
+ }
+}
+
+static BufferSampleRange Hwc2ToSampleRange(int32_t dataspace) {
+ switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
+ case HAL_DATASPACE_RANGE_FULL:
+ return BufferSampleRange::kFullRange;
+ case HAL_DATASPACE_RANGE_LIMITED:
+ return BufferSampleRange::kLimitedRange;
+ default:
+ return BufferSampleRange::kUndefined;
+ }
+}
+
std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
if (delta.total_pixops_ == 0)
return "No stats yet";
- auto ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
+ auto ratio = 1.0 - (double(delta.gpu_pixops_) / double(delta.total_pixops_));
std::stringstream ss;
ss << " Total frames count: " << delta.total_frames_ << "\n"
@@ -150,12 +232,30 @@
}
}
+void HwcDisplay::SetColorTransformMatrix(
+ const std::array<float, 16> &color_transform_matrix) {
+ auto almost_equal = [](auto a, auto b) {
+ const float epsilon = 0.001F;
+ return std::abs(a - b) < epsilon;
+ };
+ const bool is_identity = std::equal(color_transform_matrix.begin(),
+ color_transform_matrix.end(),
+ kIdentityMatrix.begin(), almost_equal);
+ color_transform_hint_ = is_identity ? HAL_COLOR_TRANSFORM_IDENTITY
+ : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+ if (color_transform_hint_ == is_identity) {
+ SetColorMatrixToIdentity();
+ } else {
+ color_matrix_ = ToColorTransform(color_transform_matrix);
+ }
+}
+
void HwcDisplay::SetColorMatrixToIdentity() {
color_matrix_ = std::make_shared<drm_color_ctm>();
for (int i = 0; i < kCtmCols; i++) {
for (int j = 0; j < kCtmRows; j++) {
constexpr uint64_t kOne = (1ULL << 32); /* 1.0 in s31.32 format */
- color_matrix_->matrix[i * kCtmRows + j] = (i == j) ? kOne : 0;
+ color_matrix_->matrix[(i * kCtmRows) + j] = (i == j) ? kOne : 0;
}
}
@@ -270,6 +370,68 @@
return ConfigError::kNone;
}
+auto HwcDisplay::ValidateStagedComposition() -> std::vector<ChangedLayer> {
+ if (IsInHeadlessMode()) {
+ return {};
+ }
+
+ /* In current drm_hwc design in case previous frame layer was not validated as
+ * a CLIENT, it is used by display controller (Front buffer). We have to store
+ * this state to provide the CLIENT with the release fences for such buffers.
+ */
+ for (auto &l : layers_) {
+ l.second.SetPriorBufferScanOutFlag(l.second.GetValidatedType() !=
+ HWC2::Composition::Client);
+ }
+
+ // ValidateDisplay returns the number of layers that may be changed.
+ uint32_t num_types = 0;
+ uint32_t num_requests = 0;
+ backend_->ValidateDisplay(this, &num_types, &num_requests);
+
+ if (num_types == 0) {
+ return {};
+ }
+
+ // Iterate through the layers to find which layers actually changed.
+ std::vector<ChangedLayer> changed_layers;
+ for (auto &l : layers_) {
+ if (l.second.IsTypeChanged()) {
+ changed_layers.emplace_back(l.first, l.second.GetValidatedType());
+ }
+ }
+ return changed_layers;
+}
+
+auto HwcDisplay::AcceptValidatedComposition() -> void {
+ for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
+ l.second.AcceptTypeChange();
+ }
+}
+
+auto HwcDisplay::PresentStagedComposition(
+ SharedFd &out_present_fence, std::vector<ReleaseFence> &out_release_fences)
+ -> bool {
+ int out_fd = -1;
+ auto error = PresentDisplay(&out_fd);
+ out_present_fence = MakeSharedFd(out_fd);
+ if (error != HWC2::Error::None) {
+ return false;
+ }
+
+ if (!out_present_fence) {
+ return true;
+ }
+
+ for (auto &l : layers_) {
+ if (l.second.GetPriorBufferScanOutFlag()) {
+ out_release_fences.emplace_back(l.first, out_present_fence);
+ }
+ }
+
+ return true;
+}
+
void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
Deinit();
@@ -330,7 +492,9 @@
flatcon_ = FlatteningController::CreateInstance(flatcbk);
}
- client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
+ HwcLayer::LayerProperties lp;
+ lp.blend_mode = BufferBlendMode::kPreMult;
+ client_layer_.SetLayerProperties(lp);
SetColorMatrixToIdentity();
@@ -449,11 +613,23 @@
}
HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) {
- if (!modes)
- *num_modes = 1;
+ if (!modes) {
+ std::vector<Colormode> temp_modes;
+ GetEdid()->GetColorModes(temp_modes);
+ *num_modes = temp_modes.size();
+ return HWC2::Error::None;
+ }
- if (modes)
- *modes = HAL_COLOR_MODE_NATIVE;
+ std::vector<Colormode> temp_modes;
+ std::vector<int32_t> out_modes(modes, modes + *num_modes);
+ GetEdid()->GetColorModes(temp_modes);
+ if (temp_modes.empty()) {
+ out_modes.emplace_back(HAL_COLOR_MODE_NATIVE);
+ return HWC2::Error::None;
+ }
+
+ for (auto &c : temp_modes)
+ out_modes.emplace_back(static_cast<int32_t>(c));
return HWC2::Error::None;
}
@@ -569,12 +745,35 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types,
- int32_t * /*types*/,
- float * /*max_luminance*/,
- float * /*max_average_luminance*/,
- float * /*min_luminance*/) {
- *num_types = 0;
+HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types, int32_t *types,
+ float *max_luminance,
+ float *max_average_luminance,
+ float *min_luminance) {
+ if (!types) {
+ std::vector<ui::Hdr> temp_types;
+ float lums[3] = {0.F};
+ GetEdid()->GetHdrCapabilities(temp_types, &lums[0], &lums[1], &lums[2]);
+ *num_types = temp_types.size();
+ return HWC2::Error::None;
+ }
+
+ std::vector<ui::Hdr> temp_types;
+ std::vector<int32_t> out_types(types, types + *num_types);
+ GetEdid()->GetHdrCapabilities(temp_types, max_luminance,
+ max_average_luminance, min_luminance);
+ for (auto &t : temp_types) {
+ switch (t) {
+ case ui::Hdr::HDR10:
+ out_types.emplace_back(HAL_HDR_HDR10);
+ break;
+ case ui::Hdr::HLG:
+ out_types.emplace_back(HAL_HDR_HLG);
+ break;
+ default:
+ // Ignore any other HDR types
+ break;
+ }
+ }
return HWC2::Error::None;
}
@@ -625,6 +824,7 @@
args.color_matrix = color_matrix_;
args.content_type = content_type_;
args.colorspace = colorspace_;
+ args.hdr_metadata = hdr_metadata_;
std::vector<LayerData> composition_layers;
if (modeset_layer) {
@@ -654,6 +854,7 @@
a_args.color_matrix = color_matrix_;
a_args.content_type = content_type_;
a_args.colorspace = colorspace_;
+ a_args.hdr_metadata = hdr_metadata_;
uint32_t prev_vperiod_ns = 0;
GetDisplayVsyncPeriod(&prev_vperiod_ns);
@@ -666,11 +867,14 @@
if (staged_config == nullptr) {
return HWC2::Error::BadConfig;
}
- client_layer_.SetLayerDisplayFrame(
- (hwc_rect_t){.left = 0,
- .top = 0,
- .right = int(staged_config->mode.GetRawMode().hdisplay),
- .bottom = int(staged_config->mode.GetRawMode().vdisplay)});
+ HwcLayer::LayerProperties lp;
+ lp.display_frame = {
+ .left = 0,
+ .top = 0,
+ .right = int(staged_config->mode.GetRawMode().hdisplay),
+ .bottom = int(staged_config->mode.GetRawMode().vdisplay),
+ };
+ client_layer_.SetLayerProperties(lp);
configs_.active_config_id = staged_mode_config_id_.value();
a_args.display_mode = staged_config->mode;
@@ -828,8 +1032,12 @@
int32_t acquire_fence,
int32_t dataspace,
hwc_region_t /*damage*/) {
- client_layer_.SetLayerBuffer(target, acquire_fence);
- client_layer_.SetLayerDataspace(dataspace);
+ HwcLayer::LayerProperties lp;
+ lp.buffer = {.buffer_handle = target,
+ .acquire_fence = MakeSharedFd(acquire_fence)};
+ lp.color_space = Hwc2ToColorSpace(dataspace);
+ lp.sample_range = Hwc2ToSampleRange(dataspace);
+ client_layer_.SetLayerProperties(lp);
/*
* target can be nullptr, this does mean the Composer Service is calling
@@ -857,11 +1065,12 @@
return HWC2::Error::BadLayer;
}
- auto source_crop = (hwc_frect_t){.left = 0.0F,
- .top = 0.0F,
- .right = static_cast<float>(bi->width),
- .bottom = static_cast<float>(bi->height)};
- client_layer_.SetLayerSourceCrop(source_crop);
+ lp = {};
+ lp.source_crop = {.left = 0.0F,
+ .top = 0.0F,
+ .right = float(bi->width),
+ .bottom = float(bi->height)};
+ client_layer_.SetLayerProperties(lp);
return HWC2::Error::None;
}
@@ -870,29 +1079,47 @@
/* Maps to the Colorspace DRM connector property:
* https://elixir.bootlin.com/linux/v6.11/source/include/drm/drm_connector.h#L538
*/
- if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3)
+ if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_BT2020)
return HWC2::Error::BadParameter;
switch (mode) {
case HAL_COLOR_MODE_NATIVE:
+ hdr_metadata_.reset();
colorspace_ = Colorspace::kDefault;
break;
case HAL_COLOR_MODE_STANDARD_BT601_625:
case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
case HAL_COLOR_MODE_STANDARD_BT601_525:
case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
+ hdr_metadata_.reset();
// The DP spec does not say whether this is the 525 or the 625 line version.
colorspace_ = Colorspace::kBt601Ycc;
break;
case HAL_COLOR_MODE_STANDARD_BT709:
case HAL_COLOR_MODE_SRGB:
+ hdr_metadata_.reset();
colorspace_ = Colorspace::kBt709Ycc;
break;
case HAL_COLOR_MODE_DCI_P3:
case HAL_COLOR_MODE_DISPLAY_P3:
+ hdr_metadata_.reset();
colorspace_ = Colorspace::kDciP3RgbD65;
break;
+ case HAL_COLOR_MODE_DISPLAY_BT2020: {
+ std::vector<ui::Hdr> hdr_types;
+ GetEdid()->GetSupportedHdrTypes(hdr_types);
+ if (!hdr_types.empty()) {
+ auto ret = SetHdrOutputMetadata(hdr_types.front());
+ if (ret != HWC2::Error::None)
+ return ret;
+ }
+ colorspace_ = Colorspace::kBt2020Rgb;
+ break;
+ }
case HAL_COLOR_MODE_ADOBE_RGB:
+ case HAL_COLOR_MODE_BT2020:
+ case HAL_COLOR_MODE_BT2100_PQ:
+ case HAL_COLOR_MODE_BT2100_HLG:
default:
return HWC2::Error::Unsupported;
}
@@ -901,17 +1128,6 @@
return HWC2::Error::None;
}
-#include <xf86drmMode.h>
-
-static uint64_t To3132FixPt(float in) {
- constexpr uint64_t kSignMask = (1ULL << 63);
- constexpr uint64_t kValueMask = ~(1ULL << 63);
- constexpr auto kValueScale = static_cast<float>(1ULL << 32);
- if (in < 0)
- return (static_cast<uint64_t>(-in * kValueScale) & kValueMask) | kSignMask;
- return static_cast<uint64_t>(in * kValueScale) & kValueMask;
-}
-
HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
@@ -934,37 +1150,14 @@
break;
case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
// Without HW support, we cannot correctly process matrices with an offset.
- for (int i = 12; i < 14; i++) {
- if (matrix[i] != 0.F)
- return HWC2::Error::Unsupported;
- }
-
- /* HAL provides a 4x4 float type matrix:
- * | 0 1 2 3|
- * | 4 5 6 7|
- * | 8 9 10 11|
- * |12 13 14 15|
- *
- * R_out = R*0 + G*4 + B*8 + 12
- * G_out = R*1 + G*5 + B*9 + 13
- * B_out = R*2 + G*6 + B*10 + 14
- *
- * DRM expects a 3x3 s31.32 fixed point matrix:
- * out matrix in
- * |R| |0 1 2| |R|
- * |G| = |3 4 5| x |G|
- * |B| |6 7 8| |B|
- *
- * R_out = R*0 + G*1 + B*2
- * G_out = R*3 + G*4 + B*5
- * B_out = R*6 + G*7 + B*8
- */
- color_matrix_ = std::make_shared<drm_color_ctm>();
- for (int i = 0; i < kCtmCols; i++) {
- for (int j = 0; j < kCtmRows; j++) {
- constexpr int kInCtmRows = 4;
- color_matrix_->matrix[i * kCtmRows + j] = To3132FixPt(matrix[j * kInCtmRows + i]);
+ {
+ for (int i = 12; i < 14; i++) {
+ if (matrix[i] != 0.F)
+ return HWC2::Error::Unsupported;
}
+ std::array<float, 16> aidl_matrix = kIdentityMatrix;
+ memcpy(aidl_matrix.data(), matrix, aidl_matrix.size() * sizeof(float));
+ color_matrix_ = ToColorTransform(aidl_matrix);
}
break;
default:
@@ -989,7 +1182,10 @@
HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t buffer,
int32_t release_fence) {
- writeback_layer_->SetLayerBuffer(buffer, release_fence);
+ HwcLayer::LayerProperties lp;
+ lp.buffer = {.buffer_handle = buffer,
+ .acquire_fence = MakeSharedFd(release_fence)};
+ writeback_layer_->SetLayerProperties(lp);
writeback_layer_->PopulateLayerData();
if (!writeback_layer_->IsLayerUsableAsDevice()) {
ALOGE("Output layer must be always usable by DRM/KMS");
@@ -1107,6 +1303,61 @@
(int32_t *)(outVsyncPeriod));
}
+// Display primary values are coded as unsigned 16-bit values in units of
+// 0.00002, where 0x0000 represents zero and 0xC350 represents 1.0000.
+static uint64_t ToU16ColorValue(float in) {
+ constexpr float kPrimariesFixedPoint = 50000.F;
+ return static_cast<uint64_t>(kPrimariesFixedPoint * in);
+}
+
+HWC2::Error HwcDisplay::SetHdrOutputMetadata(ui::Hdr type) {
+ hdr_metadata_ = std::make_shared<hdr_output_metadata>();
+ hdr_metadata_->metadata_type = 0;
+ auto *m = &hdr_metadata_->hdmi_metadata_type1;
+ m->metadata_type = 0;
+
+ switch (type) {
+ case ui::Hdr::HDR10:
+ m->eotf = 2; // PQ
+ break;
+ case ui::Hdr::HLG:
+ m->eotf = 3; // HLG
+ break;
+ default:
+ return HWC2::Error::Unsupported;
+ }
+
+ // Most luminance values are coded as an unsigned 16-bit value in units of 1
+ // cd/m2, where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
+ std::vector<ui::Hdr> types;
+ float hdr_luminance[3]{0.F, 0.F, 0.F};
+ GetEdid()->GetHdrCapabilities(types, &hdr_luminance[0], &hdr_luminance[1],
+ &hdr_luminance[2]);
+ m->max_display_mastering_luminance = m->max_cll = static_cast<uint64_t>(
+ hdr_luminance[0]);
+ m->max_fall = static_cast<uint64_t>(hdr_luminance[1]);
+ // The min luminance value is coded as an unsigned 16-bit value in units of
+ // 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
+ // represents 6.5535 cd/m2.
+ m->min_display_mastering_luminance = static_cast<uint64_t>(hdr_luminance[2] *
+ 10000.F);
+
+ auto gamut = ColorGamut::BT2020();
+ auto primaries = gamut.getPrimaries();
+ m->display_primaries[0].x = ToU16ColorValue(primaries[0].x);
+ m->display_primaries[0].y = ToU16ColorValue(primaries[0].y);
+ m->display_primaries[1].x = ToU16ColorValue(primaries[1].x);
+ m->display_primaries[1].y = ToU16ColorValue(primaries[1].y);
+ m->display_primaries[2].x = ToU16ColorValue(primaries[2].x);
+ m->display_primaries[2].y = ToU16ColorValue(primaries[2].y);
+
+ auto whitePoint = gamut.getWhitePoint();
+ m->white_point.x = ToU16ColorValue(whitePoint.x);
+ m->white_point.y = ToU16ColorValue(whitePoint.y);
+
+ return HWC2::Error::None;
+}
+
#if __ANDROID_API__ > 29
HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
if (IsInHeadlessMode()) {
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index acefff8..7522c8d 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -22,6 +22,8 @@
#include <optional>
#include <sstream>
+#include <ui/GraphicTypes.h>
+
#include "HwcDisplayConfigs.h"
#include "compositor/DisplayInfo.h"
#include "compositor/FlatteningController.h"
@@ -52,6 +54,9 @@
HwcDisplay(const HwcDisplay &) = delete;
~HwcDisplay();
+ void SetColorTransformMatrix(
+ const std::array<float, 16> &color_transform_matrix);
+
/* SetPipeline should be carefully used only by DrmHwcTwo hotplug handlers */
void SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline);
@@ -86,6 +91,23 @@
// Get the HwcDisplayConfig, or nullptor if none.
auto GetConfig(hwc2_config_t config_id) const -> const HwcDisplayConfig *;
+ // To be called after SetDisplayProperties. Returns an empty vector if the
+ // requested layers have been validated, otherwise the vector describes
+ // the requested composition type changes.
+ using ChangedLayer = std::pair<hwc2_layer_t, HWC2::Composition>;
+ auto ValidateStagedComposition() -> std::vector<ChangedLayer>;
+
+ // Mark previously validated properties as ready to present.
+ auto AcceptValidatedComposition() -> void;
+
+ // Present previously staged properties, and return fences to indicate when
+ // the new content has been presented, and when the previous buffers have
+ // been released.
+ using ReleaseFence = std::pair<hwc2_layer_t, SharedFd>;
+ auto PresentStagedComposition(SharedFd &out_present_fence,
+ std::vector<ReleaseFence> &out_release_fences)
+ -> bool;
+
// HWC2 Hooks - these should not be used outside of the hwc2 device.
HWC2::Error AcceptDisplayChanges();
HWC2::Error CreateLayer(hwc2_layer_t *layer);
@@ -260,12 +282,11 @@
uint16_t virtual_disp_width_{};
uint16_t virtual_disp_height_{};
int32_t color_mode_{};
- static constexpr int kCtmRows = 3;
- static constexpr int kCtmCols = 3;
std::shared_ptr<drm_color_ctm> color_matrix_;
android_color_transform_t color_transform_hint_{};
int32_t content_type_{};
Colorspace colorspace_{};
+ std::shared_ptr<hdr_output_metadata> hdr_metadata_;
std::shared_ptr<DrmKmsPlan> current_plan_;
@@ -279,6 +300,10 @@
HWC2::Error Init();
HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
+ HWC2::Error SetHdrOutputMetadata(ui::Hdr hdrType);
+ auto GetEdid() -> EdidWrapperUnique & {
+ return GetPipe().connector->Get()->GetParsedEdid();
+ }
};
} // namespace android
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index cb18fdd..1d1e118 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -60,148 +60,6 @@
}
}
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
-HWC2::Error HwcLayer::SetCursorPosition(int32_t /*x*/, int32_t /*y*/) {
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) {
- switch (static_cast<HWC2::BlendMode>(mode)) {
- case HWC2::BlendMode::None:
- blend_mode_ = BufferBlendMode::kNone;
- break;
- case HWC2::BlendMode::Premultiplied:
- blend_mode_ = BufferBlendMode::kPreMult;
- break;
- case HWC2::BlendMode::Coverage:
- blend_mode_ = BufferBlendMode::kCoverage;
- break;
- default:
- ALOGE("Unknown blending mode b=%d", mode);
- blend_mode_ = BufferBlendMode::kUndefined;
- break;
- }
- return HWC2::Error::None;
-}
-
-/* Find API details at:
- * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=2314
- */
-HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
- int32_t acquire_fence) {
- layer_data_.acquire_fence = MakeSharedFd(acquire_fence);
- buffer_handle_ = buffer;
- buffer_handle_updated_ = true;
-
- return HWC2::Error::None;
-}
-
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
-HWC2::Error HwcLayer::SetLayerColor(hwc_color_t /*color*/) {
- // TODO(nobody): Put to client composition here?
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerCompositionType(int32_t type) {
- sf_type_ = static_cast<HWC2::Composition>(type);
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerDataspace(int32_t dataspace) {
- switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
- case HAL_DATASPACE_STANDARD_BT709:
- color_space_ = BufferColorSpace::kItuRec709;
- break;
- case HAL_DATASPACE_STANDARD_BT601_625:
- case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
- case HAL_DATASPACE_STANDARD_BT601_525:
- case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
- color_space_ = BufferColorSpace::kItuRec601;
- break;
- case HAL_DATASPACE_STANDARD_BT2020:
- case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
- color_space_ = BufferColorSpace::kItuRec2020;
- break;
- default:
- color_space_ = BufferColorSpace::kUndefined;
- }
-
- switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
- case HAL_DATASPACE_RANGE_FULL:
- sample_range_ = BufferSampleRange::kFullRange;
- break;
- case HAL_DATASPACE_RANGE_LIMITED:
- sample_range_ = BufferSampleRange::kLimitedRange;
- break;
- default:
- sample_range_ = BufferSampleRange::kUndefined;
- }
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
- layer_data_.pi.display_frame = frame;
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerPlaneAlpha(float alpha) {
- layer_data_.pi.alpha = std::lround(alpha * UINT16_MAX);
- return HWC2::Error::None;
-}
-
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
-HWC2::Error HwcLayer::SetLayerSidebandStream(
- const native_handle_t* /*stream*/) {
- // TODO(nobody): We don't support sideband
- return HWC2::Error::Unsupported;
-}
-
-HWC2::Error HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) {
- layer_data_.pi.source_crop = crop;
- return HWC2::Error::None;
-}
-
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
-HWC2::Error HwcLayer::SetLayerSurfaceDamage(hwc_region_t /*damage*/) {
- // TODO(nobody): We don't use surface damage, marking as unsupported
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerTransform(int32_t transform) {
- uint32_t l_transform = 0;
-
- // 270* and 180* cannot be combined with flips. More specifically, they
- // already contain both horizontal and vertical flips, so those fields are
- // redundant in this case. 90* rotation can be combined with either horizontal
- // flip or vertical flip, so treat it differently
- if (transform == HWC_TRANSFORM_ROT_270) {
- l_transform = LayerTransform::kRotate270;
- } else if (transform == HWC_TRANSFORM_ROT_180) {
- l_transform = LayerTransform::kRotate180;
- } else {
- if ((transform & HWC_TRANSFORM_FLIP_H) != 0)
- l_transform |= LayerTransform::kFlipH;
- if ((transform & HWC_TRANSFORM_FLIP_V) != 0)
- l_transform |= LayerTransform::kFlipV;
- if ((transform & HWC_TRANSFORM_ROT_90) != 0)
- l_transform |= LayerTransform::kRotate90;
- }
-
- layer_data_.pi.transform = static_cast<LayerTransform>(l_transform);
- return HWC2::Error::None;
-}
-
-// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
-HWC2::Error HwcLayer::SetLayerVisibleRegion(hwc_region_t /*visible*/) {
- // TODO(nobody): We don't use this information, marking as unsupported
- return HWC2::Error::None;
-}
-
-HWC2::Error HwcLayer::SetLayerZOrder(uint32_t order) {
- z_order_ = order;
- return HWC2::Error::None;
-}
-
void HwcLayer::ImportFb() {
if (!IsLayerUsableAsDevice() || !buffer_handle_updated_) {
return;
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index e1d62b7..93fd18f 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -82,22 +82,6 @@
void SetLayerProperties(const LayerProperties &layer_properties);
- // HWC2 Layer hooks
- HWC2::Error SetCursorPosition(int32_t /*x*/, int32_t /*y*/);
- HWC2::Error SetLayerBlendMode(int32_t mode);
- HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence);
- HWC2::Error SetLayerColor(hwc_color_t /*color*/);
- HWC2::Error SetLayerCompositionType(int32_t type);
- HWC2::Error SetLayerDataspace(int32_t dataspace);
- HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame);
- HWC2::Error SetLayerPlaneAlpha(float alpha);
- HWC2::Error SetLayerSidebandStream(const native_handle_t *stream);
- HWC2::Error SetLayerSourceCrop(hwc_frect_t crop);
- HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage);
- HWC2::Error SetLayerTransform(int32_t transform);
- HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
- HWC2::Error SetLayerZOrder(uint32_t order);
-
private:
// sf_type_ stores the initial type given to us by surfaceflinger,
// validated_type_ stores the type after running ValidateDisplay
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index 28b6963..842dd9d 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -54,6 +54,7 @@
template <typename PFN, typename T>
static hwc2_function_pointer_t ToHook(T function) {
+ // NOLINTNEXTLINE(modernize-type-traits): ToHook is going to be removed
static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast):
return reinterpret_cast<hwc2_function_pointer_t>(function);
@@ -81,24 +82,6 @@
return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...));
}
-template <typename HookType, HookType func, typename... Args>
-static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
- hwc2_layer_t layer_handle, Args... args) {
- ALOGV("Display #%" PRIu64 " Layer: #%" PRIu64 " hook: %s", display_handle,
- layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str());
- DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
- const std::unique_lock lock(hwc->GetResMan().GetMainLock());
- auto *display = hwc->GetDisplay(display_handle);
- if (display == nullptr)
- return static_cast<int32_t>(HWC2::Error::BadDisplay);
-
- HwcLayer *layer = display->get_layer(layer_handle);
- if (!layer)
- return static_cast<int32_t>(HWC2::Error::BadLayer);
-
- return static_cast<int32_t>((layer->*func)(std::forward<Args>(args)...));
-}
-
static int HookDevClose(hw_device_t *dev) {
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-reinterpret-cast): Safe
auto *hwc2_dev = reinterpret_cast<hwc2_device_t *>(dev);
@@ -111,6 +94,249 @@
*out_count = 0;
}
+// NOLINTBEGIN(cppcoreguidelines-macro-usage)
+
+#define LOCK_COMPOSER(dev) \
+ auto *ihwc = ToDrmHwcTwo(dev); \
+ const std::unique_lock lock(ihwc->GetResMan().GetMainLock());
+
+#define GET_DISPLAY(display_id) \
+ auto *idisplay = ihwc->GetDisplay(display_id); \
+ if (!idisplay) \
+ return static_cast<int32_t>(HWC2::Error::BadDisplay);
+
+#define GET_LAYER(layer_id) \
+ auto *ilayer = idisplay->get_layer(layer_id); \
+ if (!ilayer) \
+ return static_cast<int32_t>(HWC2::Error::BadLayer);
+
+// NOLINTEND(cppcoreguidelines-macro-usage)
+
+static BufferColorSpace Hwc2ToColorSpace(int32_t dataspace) {
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ return BufferColorSpace::kItuRec709;
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ return BufferColorSpace::kItuRec601;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ return BufferColorSpace::kItuRec2020;
+ default:
+ return BufferColorSpace::kUndefined;
+ }
+}
+
+static BufferSampleRange Hwc2ToSampleRange(int32_t dataspace) {
+ switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
+ case HAL_DATASPACE_RANGE_FULL:
+ return BufferSampleRange::kFullRange;
+ case HAL_DATASPACE_RANGE_LIMITED:
+ return BufferSampleRange::kLimitedRange;
+ default:
+ return BufferSampleRange::kUndefined;
+ }
+}
+
+static int32_t SetLayerBlendMode(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer,
+ int32_t /*hwc2_blend_mode_t*/ mode) {
+ ALOGV("SetLayerBlendMode");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ BufferBlendMode blend_mode{};
+ switch (static_cast<HWC2::BlendMode>(mode)) {
+ case HWC2::BlendMode::None:
+ blend_mode = BufferBlendMode::kNone;
+ break;
+ case HWC2::BlendMode::Premultiplied:
+ blend_mode = BufferBlendMode::kPreMult;
+ break;
+ case HWC2::BlendMode::Coverage:
+ blend_mode = BufferBlendMode::kCoverage;
+ break;
+ default:
+ ALOGE("Unknown blending mode b=%d", mode);
+ blend_mode = BufferBlendMode::kUndefined;
+ break;
+ }
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.blend_mode = blend_mode;
+
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerBuffer(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer, buffer_handle_t buffer,
+ int32_t acquire_fence) {
+ ALOGV("SetLayerBuffer");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.buffer = {.buffer_handle = buffer,
+ .acquire_fence = MakeSharedFd(acquire_fence)};
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerDataspace(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer,
+ int32_t /*android_dataspace_t*/ dataspace) {
+ ALOGV("SetLayerDataspace");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.color_space = Hwc2ToColorSpace(dataspace);
+ layer_properties.sample_range = Hwc2ToSampleRange(dataspace);
+ ilayer->SetLayerProperties(layer_properties);
+ return 0;
+}
+
+static int32_t SetCursorPosition(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ hwc2_layer_t /*layer*/, int32_t /*x*/,
+ int32_t /*y*/) {
+ ALOGV("SetCursorPosition");
+ return 0;
+}
+
+static int32_t SetLayerColor(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/, hwc2_layer_t /*layer*/,
+ hwc_color_t /*color*/) {
+ ALOGV("SetLayerColor");
+ return 0;
+}
+
+static int32_t SetLayerCompositionType(hwc2_device_t *device,
+ hwc2_display_t display,
+ hwc2_layer_t layer,
+ int32_t /*hwc2_composition_t*/ type) {
+ ALOGV("SetLayerCompositionType");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.composition_type = static_cast<HWC2::Composition>(type);
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerDisplayFrame(hwc2_device_t *device,
+ hwc2_display_t display, hwc2_layer_t layer,
+ hwc_rect_t frame) {
+ ALOGV("SetLayerDisplayFrame");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.display_frame = frame;
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerPlaneAlpha(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer, float alpha) {
+ ALOGV("SetLayerPlaneAlpha");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.alpha = alpha;
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerSidebandStream(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ hwc2_layer_t /*layer*/,
+ const native_handle_t * /*stream*/) {
+ ALOGV("SetLayerSidebandStream");
+ return static_cast<int32_t>(HWC2::Error::Unsupported);
+}
+
+static int32_t SetLayerSourceCrop(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer, hwc_frect_t crop) {
+ ALOGV("SetLayerSourceCrop");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.source_crop = crop;
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerSurfaceDamage(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ hwc2_layer_t /*layer*/,
+ hwc_region_t /*damage*/) {
+ ALOGV("SetLayerSurfaceDamage");
+ return 0;
+}
+
+static int32_t SetLayerTransform(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer, int32_t transform) {
+ ALOGV("SetLayerTransform");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.transform = {
+ .hflip = (transform & HAL_TRANSFORM_FLIP_H) != 0,
+ .vflip = (transform & HAL_TRANSFORM_FLIP_V) != 0,
+ .rotate90 = (transform & HAL_TRANSFORM_ROT_90) != 0,
+ };
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+static int32_t SetLayerVisibleRegion(hwc2_device_t * /*device*/,
+ hwc2_display_t /*display*/,
+ hwc2_layer_t /*layer*/,
+ hwc_region_t /*visible*/) {
+ ALOGV("SetLayerVisibleRegion");
+ return 0;
+}
+
+static int32_t SetLayerZOrder(hwc2_device_t *device, hwc2_display_t display,
+ hwc2_layer_t layer, uint32_t z) {
+ ALOGV("SetLayerZOrder");
+ LOCK_COMPOSER(device);
+ GET_DISPLAY(display);
+ GET_LAYER(layer);
+
+ HwcLayer::LayerProperties layer_properties;
+ layer_properties.z_order = z;
+ ilayer->SetLayerProperties(layer_properties);
+
+ return 0;
+}
+
+/* Entry point for the HWC2 API */
+// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
+
static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/,
int32_t descriptor) {
auto func = static_cast<HWC2::FunctionDescriptor>(descriptor);
@@ -307,68 +533,41 @@
#endif
// Layer functions
case HWC2::FunctionDescriptor::SetCursorPosition:
- return ToHook<HWC2_PFN_SET_CURSOR_POSITION>(
- LayerHook<decltype(&HwcLayer::SetCursorPosition),
- &HwcLayer::SetCursorPosition, int32_t, int32_t>);
+ return (hwc2_function_pointer_t)SetCursorPosition;
case HWC2::FunctionDescriptor::SetLayerBlendMode:
- return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>(
- LayerHook<decltype(&HwcLayer::SetLayerBlendMode),
- &HwcLayer::SetLayerBlendMode, int32_t>);
+ return (hwc2_function_pointer_t)SetLayerBlendMode;
case HWC2::FunctionDescriptor::SetLayerBuffer:
- return ToHook<HWC2_PFN_SET_LAYER_BUFFER>(
- LayerHook<decltype(&HwcLayer::SetLayerBuffer),
- &HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>);
+ return (hwc2_function_pointer_t)SetLayerBuffer;
case HWC2::FunctionDescriptor::SetLayerColor:
- return ToHook<HWC2_PFN_SET_LAYER_COLOR>(
- LayerHook<decltype(&HwcLayer::SetLayerColor),
- &HwcLayer::SetLayerColor, hwc_color_t>);
+ return (hwc2_function_pointer_t)SetLayerColor;
case HWC2::FunctionDescriptor::SetLayerCompositionType:
- return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
- LayerHook<decltype(&HwcLayer::SetLayerCompositionType),
- &HwcLayer::SetLayerCompositionType, int32_t>);
+ return (hwc2_function_pointer_t)SetLayerCompositionType;
case HWC2::FunctionDescriptor::SetLayerDataspace:
- return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>(
- LayerHook<decltype(&HwcLayer::SetLayerDataspace),
- &HwcLayer::SetLayerDataspace, int32_t>);
+ return (hwc2_function_pointer_t)SetLayerDataspace;
case HWC2::FunctionDescriptor::SetLayerDisplayFrame:
- return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
- LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame),
- &HwcLayer::SetLayerDisplayFrame, hwc_rect_t>);
+ return (hwc2_function_pointer_t)SetLayerDisplayFrame;
case HWC2::FunctionDescriptor::SetLayerPlaneAlpha:
- return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
- LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha),
- &HwcLayer::SetLayerPlaneAlpha, float>);
+ return (hwc2_function_pointer_t)SetLayerPlaneAlpha;
case HWC2::FunctionDescriptor::SetLayerSidebandStream:
- return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>(
- LayerHook<decltype(&HwcLayer::SetLayerSidebandStream),
- &HwcLayer::SetLayerSidebandStream,
- const native_handle_t *>);
+ return (hwc2_function_pointer_t)SetLayerSidebandStream;
case HWC2::FunctionDescriptor::SetLayerSourceCrop:
- return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
- LayerHook<decltype(&HwcLayer::SetLayerSourceCrop),
- &HwcLayer::SetLayerSourceCrop, hwc_frect_t>);
+ return (hwc2_function_pointer_t)SetLayerSourceCrop;
case HWC2::FunctionDescriptor::SetLayerSurfaceDamage:
- return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
- LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage),
- &HwcLayer::SetLayerSurfaceDamage, hwc_region_t>);
+ return (hwc2_function_pointer_t)SetLayerSurfaceDamage;
case HWC2::FunctionDescriptor::SetLayerTransform:
- return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>(
- LayerHook<decltype(&HwcLayer::SetLayerTransform),
- &HwcLayer::SetLayerTransform, int32_t>);
+ return (hwc2_function_pointer_t)SetLayerTransform;
case HWC2::FunctionDescriptor::SetLayerVisibleRegion:
- return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
- LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion),
- &HwcLayer::SetLayerVisibleRegion, hwc_region_t>);
+ return (hwc2_function_pointer_t)SetLayerVisibleRegion;
case HWC2::FunctionDescriptor::SetLayerZOrder:
- return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>(
- LayerHook<decltype(&HwcLayer::SetLayerZOrder),
- &HwcLayer::SetLayerZOrder, uint32_t>);
+ return (hwc2_function_pointer_t)SetLayerZOrder;
case HWC2::FunctionDescriptor::Invalid:
default:
return nullptr;
}
}
+// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
+
static int HookDevOpen(const struct hw_module_t *module, const char *name,
struct hw_device_t **dev) {
if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) {
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 13fc7d9..b03ddd7 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -62,8 +62,12 @@
namespace aidl::android::hardware::graphics::composer3::impl {
namespace {
+constexpr int kCtmRows = 4;
+constexpr int kCtmColumns = 4;
+constexpr int kCtmSize = kCtmRows * kCtmColumns;
+
// clang-format off
-constexpr std::array<float, 16> kIdentityMatrix = {
+constexpr std::array<float, kCtmSize> kIdentityMatrix = {
1.0F, 0.0F, 0.0F, 0.0F,
0.0F, 1.0F, 0.0F, 0.0F,
0.0F, 0.0F, 1.0F, 0.0F,
@@ -91,12 +95,8 @@
}
std::optional<BufferColorSpace> AidlToColorSpace(
- const std::optional<ParcelableDataspace>& dataspace) {
- if (!dataspace) {
- return std::nullopt;
- }
-
- int32_t standard = static_cast<int32_t>(dataspace->dataspace) &
+ const common::Dataspace& dataspace) {
+ int32_t standard = static_cast<int32_t>(dataspace) &
static_cast<int32_t>(common::Dataspace::STANDARD_MASK);
switch (standard) {
case static_cast<int32_t>(common::Dataspace::STANDARD_BT709):
@@ -118,13 +118,17 @@
}
}
-std::optional<BufferSampleRange> AidlToSampleRange(
+std::optional<BufferColorSpace> AidlToColorSpace(
const std::optional<ParcelableDataspace>& dataspace) {
if (!dataspace) {
return std::nullopt;
}
+ return AidlToColorSpace(dataspace->dataspace);
+}
- int32_t sample_range = static_cast<int32_t>(dataspace->dataspace) &
+std::optional<BufferSampleRange> AidlToSampleRange(
+ const common::Dataspace& dataspace) {
+ int32_t sample_range = static_cast<int32_t>(dataspace) &
static_cast<int32_t>(common::Dataspace::RANGE_MASK);
switch (sample_range) {
case static_cast<int32_t>(common::Dataspace::RANGE_FULL):
@@ -139,6 +143,14 @@
}
}
+std::optional<BufferSampleRange> AidlToSampleRange(
+ const std::optional<ParcelableDataspace>& dataspace) {
+ if (!dataspace) {
+ return std::nullopt;
+ }
+ return AidlToSampleRange(dataspace->dataspace);
+}
+
bool IsSupportedCompositionType(
const std::optional<ParcelableComposition> composition) {
if (!composition) {
@@ -163,6 +175,27 @@
}
}
+hwc3::Error ValidateColorTransformMatrix(
+ const std::optional<std::vector<float>>& color_transform_matrix) {
+ if (!color_transform_matrix) {
+ return hwc3::Error::kNone;
+ }
+
+ if (color_transform_matrix->size() != kCtmSize) {
+ ALOGE("Expected color transform matrix of size %d, got size %d.", kCtmSize,
+ (int)color_transform_matrix->size());
+ return hwc3::Error::kBadParameter;
+ }
+
+ // Without HW support, we cannot correctly process matrices with an offset.
+ constexpr int kOffsetIndex = kCtmColumns * 3;
+ for (int i = kOffsetIndex; i < kOffsetIndex + 3; i++) {
+ if (color_transform_matrix.value()[i] != 0.F)
+ return hwc3::Error::kUnsupported;
+ }
+ return hwc3::Error::kNone;
+}
+
bool ValidateLayerBrightness(const std::optional<LayerBrightness>& brightness) {
if (!brightness) {
return true;
@@ -171,6 +204,19 @@
std::isnan(brightness->brightness));
}
+std::optional<std::array<float, kCtmSize>> AidlToColorTransformMatrix(
+ const std::optional<std::vector<float>>& aidl_color_transform_matrix) {
+ if (!aidl_color_transform_matrix ||
+ aidl_color_transform_matrix->size() < kCtmSize) {
+ return std::nullopt;
+ }
+
+ std::array<float, kCtmSize> color_transform_matrix = kIdentityMatrix;
+ std::copy(aidl_color_transform_matrix->begin(),
+ aidl_color_transform_matrix->end(), color_transform_matrix.begin());
+ return color_transform_matrix;
+}
+
std::optional<HWC2::Composition> AidlToCompositionType(
const std::optional<ParcelableComposition> composition) {
if (!composition) {
@@ -281,28 +327,16 @@
return std::nullopt;
}
- uint32_t transform = LayerTransform::kIdentity;
- // 270* and 180* cannot be combined with flips. More specifically, they
- // already contain both horizontal and vertical flips, so those fields are
- // redundant in this case. 90* rotation can be combined with either horizontal
- // flip or vertical flip, so treat it differently
- if (aidl_transform->transform == common::Transform::ROT_270) {
- transform = LayerTransform::kRotate270;
- } else if (aidl_transform->transform == common::Transform::ROT_180) {
- transform = LayerTransform::kRotate180;
- } else {
- auto aidl_transform_bits = static_cast<uint32_t>(aidl_transform->transform);
- if ((aidl_transform_bits &
- static_cast<uint32_t>(common::Transform::FLIP_H)) != 0)
- transform |= LayerTransform::kFlipH;
- if ((aidl_transform_bits &
- static_cast<uint32_t>(common::Transform::FLIP_V)) != 0)
- transform |= LayerTransform::kFlipV;
- if ((aidl_transform_bits &
- static_cast<uint32_t>(common::Transform::ROT_90)) != 0)
- transform |= LayerTransform::kRotate90;
- }
- return static_cast<LayerTransform>(transform);
+ using aidl::android::hardware::graphics::common::Transform;
+
+ return (LayerTransform){
+ .hflip = (int32_t(aidl_transform->transform) &
+ int32_t(Transform::FLIP_H)) != 0,
+ .vflip = (int32_t(aidl_transform->transform) &
+ int32_t(Transform::FLIP_V)) != 0,
+ .rotate90 = (int32_t(aidl_transform->transform) &
+ int32_t(Transform::ROT_90)) != 0,
+ };
}
} // namespace
@@ -322,7 +356,7 @@
ComposerClient::~ComposerClient() {
DEBUG_FUNC();
- {
+ if (hwc_) {
const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
hwc_->DeinitDisplays();
hwc_.reset();
@@ -413,113 +447,6 @@
return ToBinderStatus(err);
}
-hwc3::Error ComposerClient::ValidateDisplayInternal(
- HwcDisplay& display, std::vector<int64_t>* out_changed_layers,
- std::vector<Composition>* out_composition_types,
- int32_t* out_display_request_mask,
- std::vector<int64_t>* out_requested_layers,
- std::vector<int32_t>* out_request_masks,
- ClientTargetProperty* /*out_client_target_property*/,
- DimmingStage* /*out_dimming_stage*/) {
- DEBUG_FUNC();
-
- uint32_t num_types = 0;
- uint32_t num_requests = 0;
- const HWC2::Error hwc2_error = display.ValidateDisplay(&num_types,
- &num_requests);
-
- /* Check if display has pending changes and no errors */
- if (hwc2_error != HWC2::Error::None &&
- hwc2_error != HWC2::Error::HasChanges) {
- return Hwc2toHwc3Error(hwc2_error);
- }
-
- hwc3::Error error = Hwc2toHwc3Error(
- display.GetChangedCompositionTypes(&num_types, nullptr, nullptr));
- if (error != hwc3::Error::kNone) {
- return error;
- }
-
- std::vector<hwc2_layer_t> hwc_changed_layers(num_types);
- std::vector<int32_t> hwc_composition_types(num_types);
- error = Hwc2toHwc3Error(
- display.GetChangedCompositionTypes(&num_types, hwc_changed_layers.data(),
- hwc_composition_types.data()));
- if (error != hwc3::Error::kNone) {
- return error;
- }
-
- int32_t display_reqs = 0;
- out_request_masks->resize(num_requests);
- std::vector<hwc2_layer_t> hwc_requested_layers(num_requests);
- error = Hwc2toHwc3Error(
- display.GetDisplayRequests(&display_reqs, &num_requests,
- hwc_requested_layers.data(),
- out_request_masks->data()));
- if (error != hwc3::Error::kNone) {
- return error;
- }
-
- for (const auto& layer : hwc_changed_layers) {
- out_changed_layers->emplace_back(Hwc2LayerToHwc3(layer));
- }
- for (const auto& type : hwc_composition_types) {
- out_composition_types->emplace_back(Hwc2CompositionTypeToHwc3(type));
- }
- for (const auto& layer : hwc_requested_layers) {
- out_requested_layers->emplace_back(Hwc2LayerToHwc3(layer));
- }
- *out_display_request_mask = display_reqs;
-
- /* Client target property/dimming stage unsupported */
- return hwc3::Error::kNone;
-}
-
-hwc3::Error ComposerClient::PresentDisplayInternal(
- uint64_t display_id, ::android::base::unique_fd& out_display_fence,
- std::unordered_map<int64_t, ::android::base::unique_fd>&
- out_release_fences) {
- DEBUG_FUNC();
- auto* display = GetDisplay(display_id);
- if (display == nullptr) {
- return hwc3::Error::kBadDisplay;
- }
-
- if (composer_resources_->MustValidateDisplay(display_id)) {
- return hwc3::Error::kNotValidated;
- }
-
- int32_t present_fence = -1;
- auto error = Hwc2toHwc3Error(display->PresentDisplay(&present_fence));
- if (error != hwc3::Error::kNone) {
- return error;
- }
- out_display_fence.reset(present_fence);
-
- uint32_t release_fence_count = 0;
- error = Hwc2toHwc3Error(
- display->GetReleaseFences(&release_fence_count, nullptr, nullptr));
- if (error != hwc3::Error::kNone) {
- return error;
- }
-
- std::vector<hwc2_layer_t> hwc_layers(release_fence_count);
- std::vector<int32_t> hwc_fences(release_fence_count);
- error = Hwc2toHwc3Error(display->GetReleaseFences(&release_fence_count,
- hwc_layers.data(),
- hwc_fences.data()));
- if (error != hwc3::Error::kNone) {
- return error;
- }
-
- for (size_t i = 0; i < hwc_layers.size(); i++) {
- auto layer = Hwc2LayerToHwc3(hwc_layers[i]);
- out_release_fences[layer] = ::android::base::unique_fd{hwc_fences[i]};
- }
-
- return hwc3::Error::kNone;
-}
-
::android::HwcDisplay* ComposerClient::GetDisplay(uint64_t display_id) {
return hwc_->GetDisplay(display_id);
}
@@ -556,13 +483,11 @@
if (command.buffer) {
HwcLayer::Buffer buffer;
auto err = ImportLayerBuffer(display_id, command.layer, *command.buffer,
- &buffer.buffer_handle);
+ &buffer);
if (err != hwc3::Error::kNone) {
cmd_result_writer_->AddError(err);
return;
}
- buffer.acquire_fence = ::android::MakeSharedFd(
- command.buffer->fence.dup().release());
properties.buffer.emplace(buffer);
}
@@ -599,7 +524,8 @@
void ComposerClient::ExecuteDisplayCommand(const DisplayCommand& command) {
const int64_t display_id = command.display;
- if (hwc_->GetDisplay(display_id) == nullptr) {
+ HwcDisplay* display = hwc_->GetDisplay(display_id);
+ if (display == nullptr) {
cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
return;
}
@@ -610,14 +536,22 @@
return;
}
+ hwc3::Error error = ValidateColorTransformMatrix(
+ command.colorTransformMatrix);
+ if (error != hwc3::Error::kNone) {
+ ALOGE("Invalid color transform matrix.");
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+
for (const auto& layer_cmd : command.layers) {
DispatchLayerCommand(command.display, layer_cmd);
}
- if (command.colorTransformMatrix) {
- ExecuteSetDisplayColorTransform(command.display,
- *command.colorTransformMatrix);
+ if (cmd_result_writer_->HasError()) {
+ return;
}
+
if (command.clientTarget) {
ExecuteSetDisplayClientTarget(command.display, *command.clientTarget);
}
@@ -625,18 +559,65 @@
ExecuteSetDisplayOutputBuffer(command.display,
*command.virtualDisplayOutputBuffer);
}
- if (command.validateDisplay) {
- ExecuteValidateDisplay(command.display, command.expectedPresentTime);
+
+ std::optional<std::array<float, kCtmSize>> ctm = AidlToColorTransformMatrix(
+ command.colorTransformMatrix);
+ if (ctm) {
+ display->SetColorTransformMatrix(ctm.value());
}
+
+ if (command.validateDisplay || command.presentOrValidateDisplay) {
+ std::vector<HwcDisplay::ChangedLayer>
+ changed_layers = display->ValidateStagedComposition();
+ DisplayChanges changes{};
+ for (auto [layer_id, composition_type] : changed_layers) {
+ changes.AddLayerCompositionChange(command.display,
+ Hwc2LayerToHwc3(layer_id),
+ static_cast<Composition>(
+ composition_type));
+ }
+ cmd_result_writer_->AddChanges(changes);
+ composer_resources_->SetDisplayMustValidateState(display_id, false);
+
+ // TODO: DisplayRequests are not implemented.
+
+ /* TODO: Add check if it's possible to skip display validation for
+ * presentOrValidateDisplay */
+ if (command.presentOrValidateDisplay) {
+ cmd_result_writer_
+ ->AddPresentOrValidateResult(display_id,
+ PresentOrValidate::Result::Validated);
+ }
+ }
+
if (command.acceptDisplayChanges) {
- ExecuteAcceptDisplayChanges(command.display);
+ display->AcceptDisplayChanges();
}
+
if (command.presentDisplay) {
- ExecutePresentDisplay(command.display);
- }
- if (command.presentOrValidateDisplay) {
- ExecutePresentOrValidateDisplay(command.display,
- command.expectedPresentTime);
+ if (composer_resources_->MustValidateDisplay(display_id)) {
+ cmd_result_writer_->AddError(hwc3::Error::kNotValidated);
+ return;
+ }
+ ::android::SharedFd present_fence;
+ std::vector<HwcDisplay::ReleaseFence> release_fences;
+ bool ret = display->PresentStagedComposition(present_fence, release_fences);
+
+ if (!ret) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ using ::android::base::unique_fd;
+ cmd_result_writer_->AddPresentFence( //
+ display_id, unique_fd(::android::DupFd(present_fence)));
+
+ std::unordered_map<int64_t, unique_fd> hal_release_fences;
+ for (const auto& [layer_id, release_fence] : release_fences) {
+ hal_release_fences[Hwc2LayerToHwc3(layer_id)] = //
+ unique_fd(::android::DupFd(release_fence));
+ }
+ cmd_result_writer_->AddReleaseFence(display_id, hal_release_fences);
}
}
@@ -966,8 +947,28 @@
return ToBinderStatus(hwc3::Error::kBadDisplay);
}
- /* No HDR capabilities */
- caps->types.clear();
+ uint32_t num_types = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->GetHdrCapabilities(&num_types, nullptr, nullptr, nullptr,
+ nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<int32_t> out_types(num_types);
+ error = Hwc2toHwc3Error(
+ display->GetHdrCapabilities(&num_types, out_types.data(),
+ &caps->maxLuminance,
+ &caps->maxAverageLuminance,
+ &caps->minLuminance));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ caps->types.reserve(num_types);
+ for (const auto type : out_types)
+ caps->types.emplace_back(Hwc2HdrTypeToHwc3(type));
+
return ndk::ScopedAStatus::ok();
}
@@ -1325,41 +1326,19 @@
return binder;
}
-hwc3::Error ComposerClient::ImportLayerBuffer(
- int64_t display_id, int64_t layer_id, const Buffer& buffer,
- buffer_handle_t* out_imported_buffer) {
- *out_imported_buffer = nullptr;
-
- auto releaser = composer_resources_->CreateResourceReleaser(true);
+hwc3::Error ComposerClient::ImportLayerBuffer(int64_t display_id,
+ int64_t layer_id,
+ const Buffer& buffer,
+ HwcLayer::Buffer* out_buffer) {
+ auto releaser = ComposerResources::CreateResourceReleaser(true);
auto err = composer_resources_->GetLayerBuffer(display_id, layer_id, buffer,
- out_imported_buffer,
+ &out_buffer->buffer_handle,
releaser.get());
+ out_buffer->acquire_fence = ::android::MakeSharedFd(
+ buffer.fence.dup().release());
return err;
}
-void ComposerClient::ExecuteSetDisplayColorTransform(
- uint64_t display_id, const std::vector<float>& matrix) {
- auto* display = GetDisplay(display_id);
- if (display == nullptr) {
- cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
- return;
- }
-
- auto almost_equal = [](auto a, auto b) {
- const float epsilon = 0.001F;
- return std::abs(a - b) < epsilon;
- };
- const bool is_identity = std::equal(matrix.begin(), matrix.end(),
- kIdentityMatrix.begin(), almost_equal);
-
- const int32_t hint = is_identity ? HAL_COLOR_TRANSFORM_IDENTITY
- : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-
- auto error = Hwc2toHwc3Error(display->SetColorTransform(matrix.data(), hint));
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
- }
-}
void ComposerClient::ExecuteSetDisplayClientTarget(
uint64_t display_id, const ClientTarget& command) {
auto* display = GetDisplay(display_id);
@@ -1378,7 +1357,7 @@
damage_regions.rects = regions.data();
buffer_handle_t imported_buffer = nullptr;
- auto buf_releaser = composer_resources_->CreateResourceReleaser(true);
+ auto buf_releaser = ComposerResources::CreateResourceReleaser(true);
auto error = composer_resources_->GetDisplayClientTarget(display_id,
command.buffer,
@@ -1410,7 +1389,7 @@
}
buffer_handle_t imported_buffer = nullptr;
- auto buf_releaser = composer_resources_->CreateResourceReleaser(true);
+ auto buf_releaser = ComposerResources::CreateResourceReleaser(true);
auto error = composer_resources_->GetDisplayOutputBuffer(display_id, buffer,
&imported_buffer,
@@ -1428,130 +1407,5 @@
return;
}
}
-void ComposerClient::ExecuteValidateDisplay(
- int64_t display_id,
- std::optional<ClockMonotonicTimestamp> /*expected_present_time*/
-) {
- auto* display = GetDisplay(display_id);
- if (display == nullptr) {
- cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
- return;
- }
-
- /* TODO: Handle expectedPresentTime */
- /* This can be implemented in multiple ways. For example, the expected present
- * time property can be implemented by the DRM driver directly as a CRTC
- * property. See:
- * https://cs.android.com/android/platform/superproject/main/+/b8b3b1646e64d0235f77b9e717a3e4082e26f2a8:hardware/google/graphics/common/libhwc2.1/libdrmresource/drm/drmcrtc.cpp;drc=468f6172546ab98983de18210222f231f16b21e1;l=88
- * Unfortunately there doesn't seem to be a standardised way of delaying
- * presentation with a timestamp in the DRM API. What we can do alternatively
- * is to spawn a separate presentation thread that could handle the VBlank
- * events by using DRM_MODE_PAGE_FLIP_EVENT and schedule them appropriately.
- */
-
- std::vector<int64_t> changed_layers;
- std::vector<Composition> composition_types;
- int32_t display_request_mask = 0;
- std::vector<int64_t> requested_layers;
- std::vector<int32_t> request_masks;
-
- const hwc3::Error error = ValidateDisplayInternal(*display, &changed_layers,
- &composition_types,
- &display_request_mask,
- &requested_layers,
- &request_masks, nullptr,
- nullptr);
-
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
- }
-
- // If a CommandError has been been set for the current DisplayCommand, then
- // no other results should be returned besides the error.
- if (cmd_result_writer_->HasError()) {
- return;
- }
-
- DisplayChanges changes{};
- for (size_t i = 0; i < composition_types.size(); i++) {
- changes.AddLayerCompositionChange(display_id, changed_layers[i],
- composition_types[i]);
- }
-
- std::vector<DisplayRequest::LayerRequest> layer_requests;
- for (size_t i = 0; i < requested_layers.size(); i++) {
- layer_requests.push_back({requested_layers[i], request_masks[i]});
- }
-
- const DisplayRequest request_changes{display_id, display_request_mask,
- layer_requests};
- changes.display_request_changes = request_changes;
-
- cmd_result_writer_->AddChanges(changes);
- composer_resources_->SetDisplayMustValidateState(display_id, false);
-}
-
-void ComposerClient::ExecuteAcceptDisplayChanges(int64_t display_id) {
- auto* display = GetDisplay(display_id);
- if (display == nullptr) {
- cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
- return;
- }
-
- auto error = Hwc2toHwc3Error(display->AcceptDisplayChanges());
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
- return;
- }
-}
-
-void ComposerClient::ExecutePresentDisplay(int64_t display_id) {
- auto* display = GetDisplay(display_id);
- if (display == nullptr) {
- cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
- return;
- }
-
- ::android::base::unique_fd display_fence;
- std::unordered_map<int64_t, ::android::base::unique_fd> release_fences;
- auto error = PresentDisplayInternal(display_id, display_fence,
- release_fences);
- if (error != hwc3::Error::kNone) {
- cmd_result_writer_->AddError(error);
- }
- if (cmd_result_writer_->HasError()) {
- return;
- }
-
- cmd_result_writer_->AddPresentFence(display_id, std::move(display_fence));
- cmd_result_writer_->AddReleaseFence(display_id, release_fences);
-}
-
-void ComposerClient::ExecutePresentOrValidateDisplay(
- int64_t display_id,
- std::optional<ClockMonotonicTimestamp> expected_present_time) {
- auto* display = GetDisplay(display_id);
- if (display == nullptr) {
- cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
- return;
- }
-
- /* TODO: Handle expectedPresentTime */
- /* This can be implemented in multiple ways. For example, the expected present
- * time property can be implemented by the DRM driver directly as a CRTC
- * property. See:
- * https://cs.android.com/android/platform/superproject/main/+/b8b3b1646e64d0235f77b9e717a3e4082e26f2a8:hardware/google/graphics/common/libhwc2.1/libdrmresource/drm/drmcrtc.cpp;drc=468f6172546ab98983de18210222f231f16b21e1;l=88
- * Unfortunately there doesn't seem to be a standardised way of delaying
- * presentation with a timestamp in the DRM API. What we can do alternatively
- * is to spawn a separate presentation thread that could handle the VBlank
- * events by using DRM_MODE_PAGE_FLIP_EVENT and schedule them appropriately.
- */
-
- /* TODO: Add check if it's possible to skip display validation */
- ExecuteValidateDisplay(display_id, expected_present_time);
- cmd_result_writer_
- ->AddPresentOrValidateResult(display_id,
- PresentOrValidate::Result::Validated);
-}
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerClient.h b/hwc3/ComposerClient.h
index 2595203..b0d3caa 100644
--- a/hwc3/ComposerClient.h
+++ b/hwc3/ComposerClient.h
@@ -20,6 +20,7 @@
#include "aidl/android/hardware/graphics/composer3/BnComposerClient.h"
#include "aidl/android/hardware/graphics/composer3/LayerCommand.h"
+#include "hwc2_device/HwcLayer.h"
#include "hwc3/CommandResultWriter.h"
#include "hwc3/ComposerResources.h"
#include "hwc3/Utils.h"
@@ -30,10 +31,7 @@
using AidlNativeHandle = aidl::android::hardware::common::NativeHandle;
namespace android {
-
class HwcDisplay;
-class HwcLayer;
-
} // namespace android
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -171,40 +169,16 @@
private:
hwc3::Error ImportLayerBuffer(int64_t display_id, int64_t layer_id,
const Buffer& buffer,
- buffer_handle_t* out_imported_buffer);
+ ::android::HwcLayer::Buffer* out_buffer);
// Layer commands
void DispatchLayerCommand(int64_t display_id, const LayerCommand& command);
// Display commands
void ExecuteDisplayCommand(const DisplayCommand& command);
- void ExecuteSetDisplayColorTransform(uint64_t display_id,
- const std::vector<float>& matrix);
void ExecuteSetDisplayClientTarget(uint64_t display_id,
const ClientTarget& command);
void ExecuteSetDisplayOutputBuffer(uint64_t display_id, const Buffer& buffer);
- void ExecuteValidateDisplay(
- int64_t display_id,
- std::optional<ClockMonotonicTimestamp> expected_present_time);
- void ExecuteAcceptDisplayChanges(int64_t display_id);
- void ExecutePresentDisplay(int64_t display_id);
- void ExecutePresentOrValidateDisplay(
- int64_t display_id,
- std::optional<ClockMonotonicTimestamp> expected_present_time);
-
- static hwc3::Error ValidateDisplayInternal(
- ::android::HwcDisplay& display, std::vector<int64_t>* out_changed_layers,
- std::vector<Composition>* out_composition_types,
- int32_t* out_display_request_mask,
- std::vector<int64_t>* out_requested_layers,
- std::vector<int32_t>* out_request_masks,
- ClientTargetProperty* out_client_target_property,
- DimmingStage* out_dimming_stage);
-
- hwc3::Error PresentDisplayInternal(
- uint64_t display_id, ::android::base::unique_fd& out_display_fence,
- std::unordered_map<int64_t, ::android::base::unique_fd>&
- out_release_fences);
::android::HwcDisplay* GetDisplay(uint64_t display_id);
diff --git a/hwc3/ComposerResources.cpp b/hwc3/ComposerResources.cpp
index ae0edf4..5e19082 100644
--- a/hwc3/ComposerResources.cpp
+++ b/hwc3/ComposerResources.cpp
@@ -25,20 +25,21 @@
#include "hardware/hwcomposer2.h"
#include "hwc3/Utils.h"
+namespace {
+using Hwc2Display = ::android::hardware::graphics::composer::V2_1::Display;
+using Hwc2Layer = ::android::hardware::graphics::composer::V2_1::Layer;
+
+auto ToHwc2Display(uint64_t display_id) -> Hwc2Display {
+ return static_cast<Hwc2Display>(display_id);
+}
+
+auto ToHwc2Layer(int64_t layer_id) -> Hwc2Layer {
+ return static_cast<Hwc2Layer>(layer_id);
+}
+} // namespace
+
namespace aidl::android::hardware::graphics::composer3::impl {
-::android::hardware::graphics::composer::V2_1::Display ToHwc2Display(
- uint64_t display_id) {
- return static_cast<::android::hardware::graphics::composer::V2_1::Display>(
- display_id);
-}
-
-::android::hardware::graphics::composer::V2_1::Layer ToHwc2Layer(
- int64_t layer_id) {
- return static_cast<::android::hardware::graphics::composer::V2_1::Layer>(
- layer_id);
-}
-
std::unique_ptr<ComposerResourceReleaser>
ComposerResources::CreateResourceReleaser(bool is_buffer) {
return std::make_unique<ComposerResourceReleaser>(is_buffer);
diff --git a/hwc3/Utils.h b/hwc3/Utils.h
index b322f5d..642c777 100644
--- a/hwc3/Utils.h
+++ b/hwc3/Utils.h
@@ -16,6 +16,7 @@
#pragma once
+#include <aidl/android/hardware/graphics/common/Hdr.h>
#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
#include <hardware/hwcomposer2.h>
#include <log/log.h>
@@ -165,4 +166,12 @@
return static_cast<int32_t>(dataspace);
}
-}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
+// Values appear to match.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Hdr.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=130;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.2.h;l=12;drc=af7be7616859f8e9e57710b9c37c66cf880a6643
+inline common::Hdr Hwc2HdrTypeToHwc3(int32_t hdr_type) {
+ return static_cast<common::Hdr>(hdr_type);
+}
+
+}; // namespace aidl::android::hardware::graphics::composer3
diff --git a/meson.build b/meson.build
index 97474e2..3d5c9f0 100644
--- a/meson.build
+++ b/meson.build
@@ -16,6 +16,7 @@
'backend/Backend.cpp',
'backend/BackendClient.cpp',
'utils/fd.cpp',
+ 'utils/LibdisplayEdidWrapper.cpp',
'utils/properties.cpp',
)
diff --git a/tests/uevent_print.cpp b/tests/uevent_print.cpp
index 6ffbbfb..cfe2191 100644
--- a/tests/uevent_print.cpp
+++ b/tests/uevent_print.cpp
@@ -7,7 +7,7 @@
int main() {
auto uevent = android::UEvent::CreateInstance();
if (!uevent) {
- std::cout << "Can't initialize UEvent class" << std::endl;
+ std::cout << "Can't initialize UEvent class\n";
return -ENODEV;
}
@@ -18,8 +18,8 @@
continue;
}
- std::cout << "New event #" << number++ << std::endl
- << *msg << std::endl
- << std::endl;
+ std::cout << "New event #" << number++ << '\n'
+ << *msg << '\n'
+ << std::flush;
}
}
diff --git a/utils/EdidWrapper.h b/utils/EdidWrapper.h
new file mode 100644
index 0000000..30124d7
--- /dev/null
+++ b/utils/EdidWrapper.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2025 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
+
+#if HAS_LIBDISPLAY_INFO
+extern "C" {
+#include <libdisplay-info/info.h>
+}
+#endif
+
+#include <ui/GraphicTypes.h>
+
+#include "compositor/DisplayInfo.h"
+#include "drm/DrmUnique.h"
+
+namespace android {
+
+// Stub wrapper class for edid parsing
+class EdidWrapper {
+ public:
+ EdidWrapper() = default;
+ EdidWrapper(const EdidWrapper &) = delete;
+ virtual ~EdidWrapper() = default;
+
+ virtual void GetSupportedHdrTypes(std::vector<ui::Hdr> &types) {
+ types.clear();
+ };
+ virtual void GetHdrCapabilities(std::vector<ui::Hdr> &types,
+ const float * /*max_luminance*/,
+ const float * /*max_average_luminance*/,
+ const float * /*min_luminance*/) {
+ GetSupportedHdrTypes(types);
+ };
+ virtual void GetColorModes(std::vector<Colormode> &color_modes) {
+ color_modes.clear();
+ };
+};
+
+#if HAS_LIBDISPLAY_INFO
+// Wrapper class for that uses libdisplay-info to parse edids
+class LibdisplayEdidWrapper final : public EdidWrapper {
+ public:
+ LibdisplayEdidWrapper() = delete;
+ ~LibdisplayEdidWrapper() override {
+ di_info_destroy(info_);
+ }
+ static auto Create(DrmModePropertyBlobUnique blob)
+ -> std::unique_ptr<LibdisplayEdidWrapper>;
+
+ void GetSupportedHdrTypes(std::vector<ui::Hdr> &types) override;
+
+ void GetHdrCapabilities(std::vector<ui::Hdr> &types,
+ const float *max_luminance,
+ const float *max_average_luminance,
+ const float *min_luminance) override;
+
+ void GetColorModes(std::vector<Colormode> &color_modes) override;
+
+ private:
+ LibdisplayEdidWrapper(di_info *info) : info_(std::move(info)) {
+ }
+
+ di_info *info_{};
+};
+#endif
+
+} // namespace android
diff --git a/utils/LibdisplayEdidWrapper.cpp b/utils/LibdisplayEdidWrapper.cpp
new file mode 100644
index 0000000..d2d2a1c
--- /dev/null
+++ b/utils/LibdisplayEdidWrapper.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "drmhwc"
+
+#if HAS_LIBDISPLAY_INFO
+
+#include "utils/EdidWrapper.h"
+#include "utils/log.h"
+
+namespace android {
+
+auto LibdisplayEdidWrapper::Create(DrmModePropertyBlobUnique blob)
+ -> std::unique_ptr<LibdisplayEdidWrapper> {
+ if (!blob)
+ return nullptr;
+
+ auto *info = di_info_parse_edid(blob->data, blob->length);
+ if (!info) {
+ ALOGW("Failed to parse edid blob.");
+ return nullptr;
+ }
+
+ return std::unique_ptr<LibdisplayEdidWrapper>(
+ new LibdisplayEdidWrapper(std::move(info)));
+}
+
+void LibdisplayEdidWrapper::GetSupportedHdrTypes(std::vector<ui::Hdr> &types) {
+ types.clear();
+
+ const auto *hdr_static_meta = di_info_get_hdr_static_metadata(info_);
+ const auto *colorimetries = di_info_get_supported_signal_colorimetry(info_);
+ if (colorimetries->bt2020_cycc || colorimetries->bt2020_ycc ||
+ colorimetries->bt2020_rgb) {
+ if (hdr_static_meta->pq)
+ types.emplace_back(ui::Hdr::HDR10);
+ if (hdr_static_meta->hlg)
+ types.emplace_back(ui::Hdr::HLG);
+ }
+}
+
+void LibdisplayEdidWrapper::GetHdrCapabilities(
+ std::vector<ui::Hdr> &types, const float *max_luminance,
+ const float *max_average_luminance, const float *min_luminance) {
+ GetSupportedHdrTypes(types);
+
+ const auto *hdr_static_meta = di_info_get_hdr_static_metadata(info_);
+ max_luminance = &hdr_static_meta->desired_content_max_luminance;
+ max_average_luminance = &hdr_static_meta
+ ->desired_content_max_frame_avg_luminance;
+ min_luminance = &hdr_static_meta->desired_content_min_luminance;
+}
+
+void LibdisplayEdidWrapper::GetColorModes(std::vector<Colormode> &color_modes) {
+ color_modes.clear();
+ color_modes.emplace_back(Colormode::kNative);
+
+ const auto *hdr_static_meta = di_info_get_hdr_static_metadata(info_);
+ const auto *colorimetries = di_info_get_supported_signal_colorimetry(info_);
+
+ /* Rec. ITU-R BT.2020 constant luminance YCbCr */
+ /* Rec. ITU-R BT.2020 non-constant luminance YCbCr */
+ if (colorimetries->bt2020_cycc || colorimetries->bt2020_ycc)
+ color_modes.emplace_back(Colormode::kBt2020);
+
+ /* Rec. ITU-R BT.2020 RGB */
+ if (colorimetries->bt2020_rgb)
+ color_modes.emplace_back(Colormode::kDisplayBt2020);
+
+ /* SMPTE ST 2113 RGB: P3D65 and P3DCI */
+ if (colorimetries->st2113_rgb) {
+ color_modes.emplace_back(Colormode::kDciP3);
+ color_modes.emplace_back(Colormode::kDisplayP3);
+ }
+
+ /* Rec. ITU-R BT.2100 ICtCp HDR (with PQ and/or HLG) */
+ if (colorimetries->ictcp) {
+ if (hdr_static_meta->pq)
+ color_modes.emplace_back(Colormode::kBt2100Pq);
+ if (hdr_static_meta->hlg)
+ color_modes.emplace_back(Colormode::kBt2100Hlg);
+ }
+}
+
+} // namespace android
+#endif