Upgrade drm_hwcomposer to 851ea4dc268c4da612c65a5dfedbd3ed85960405 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 Test: TreeHugger Change-Id: I532539ae7080fd19cbe7bd4cd714b3ee04db5f39
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 5366943..ff3d42e 100644 --- a/hwc3/ComposerClient.cpp +++ b/hwc3/ComposerClient.cpp
@@ -60,8 +60,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, @@ -89,12 +93,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): @@ -116,13 +116,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): @@ -137,6 +141,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) { @@ -161,6 +173,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; @@ -169,6 +202,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) { @@ -278,28 +324,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 @@ -319,7 +353,7 @@ ComposerClient::~ComposerClient() { DEBUG_FUNC(); - { + if (hwc_) { const std::unique_lock lock(hwc_->GetResMan().GetMainLock()); hwc_->DeinitDisplays(); hwc_.reset(); @@ -410,113 +444,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); } @@ -553,13 +480,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); } @@ -593,7 +518,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; } @@ -604,14 +530,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); } @@ -619,18 +553,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); } } @@ -960,8 +941,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(); } @@ -1305,41 +1306,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); @@ -1358,7 +1337,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, @@ -1390,7 +1369,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, @@ -1408,130 +1387,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 20d15b4..37cb8ab 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" @@ -29,10 +30,7 @@ using AidlNativeHandle = aidl::android::hardware::common::NativeHandle; namespace android { - class HwcDisplay; -class HwcLayer; - } // namespace android namespace aidl::android::hardware::graphics::composer3::impl { @@ -163,40 +161,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