Merge tag 'android-15.0.0_r6' of https://android.googlesource.com/platform/external/drm_hwcomposer into HEAD
Android 15.0.0 Release 6 (AP4A.241205.013)
Change-Id: I6ab6337d41a05d3bdcebb5f0a0dc6794146e6278
# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ1IssQAKCRDorT+BmrEO
# eEqZAJ47wH2WMDie95nGXgjopsELBJTJywCfTbM6HvC5vAt7c36u/uRfSadkRi0=
# =72LX
# -----END PGP SIGNATURE-----
# gpg: Signature faite le jeu 05 déc 2024 17:44:01 EST
# gpg: avec la clef DSA 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Impossible de vérifier la signature : Pas de clef publique
diff --git a/.ci/Dockerfile b/.ci/Dockerfile
index 2158d7a..c42c8b6 100644
--- a/.ci/Dockerfile
+++ b/.ci/Dockerfile
@@ -41,11 +41,11 @@
USER ${RUN_USER}
# Install aospless package (produced by GloDroid/aospext)
-RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/uploads/28ef9379b1a0ec1ee19a17825b0f3f3f/aospless_drm_hwcomposer_arm64.tar.xz && \
+RUN wget -P ${USER_HOME} https://gitlab.freedesktop.org/-/project/5/uploads/d66764aa71f9f1235b92d44a652cd3c3/aospless_drm_hwcomposer_arm64.tar.xz && \
cd ${USER_HOME} && \
- (echo 96b2148d04c50cf36d4151ae022e665764b8ca3317712e9467a433b62c545a43 aospless_drm_hwcomposer_arm64.tar.xz | sha256sum --check) && \
- tar xf aospless_drm_hwcomposer_arm64.tar.xz && \
- rm -r ${USER_HOME}/aospless/src && ln -s ../drm_hwcomposer/ ${USER_HOME}/aospless/src
+ sha256sum aospless_drm_hwcomposer_arm64.tar.xz && \
+ (echo 00ff288f184111dd35143c462e82fd5f8f31a1417d5eb9a11e8798695abcc141 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
RUN mkdir -pv ${USER_HOME}/drm_hwcomposer
diff --git a/.ci/Makefile b/.ci/Makefile
index a30414c..325e0b5 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -1,5 +1,5 @@
-BASE_DIR:=../aospless
+BASE_DIR ?=../aospless
SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
@@ -40,8 +40,10 @@
-llvmlibc* -fuchsia-* -altera-* \
-llvm-header-guard \
-cppcoreguidelines-pro-type-vararg \
+ -google-readability-todo \
-hicpp-vararg \
-hicpp-signed-bitwise \
+ -misc-const-correctness \
-readability-identifier-length \
TIDY_CHECKS_NORMAL := \
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bdbb8be..da052c3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,3 @@
-image: ubuntu:23.04
-
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
@@ -7,31 +5,38 @@
variables:
DEBIAN_FRONTEND: noninteractive
-
-before_script:
- - apt-get --quiet update --yes >/dev/null
- - apt-get --quiet install --yes clang-15 clang-tidy-15 clang-format-15 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
- - apt-get --quiet install --yes clang llvm make python3 wget sudo rsync lld pkg-config ninja-build meson >/dev/null
- - apt-get --quiet install --yes python3-mako python3-jinja2 python3-ply python3-yaml >/dev/null
+ DOCKER_IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
stages:
+ - build-container
- build
- tidy
- style
+build-container:
+ stage: build-container
+ image: docker:27.0.3
+ services:
+ - docker:27.0.3-dind
+ variables:
+ DOCKER_TLS_CERTDIR: ""
+ before_script:
+ - echo "$CI_JOB_TOKEN" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
+ script:
+ - docker build -t $DOCKER_IMAGE_TAG -f .ci/Dockerfile .
+ - docker push $DOCKER_IMAGE_TAG
+ after_script:
+ - docker logout
+
build:
stage: build
+ image: $DOCKER_IMAGE_TAG
script:
- mkdir -p install/arm64
- - cd ..
- - rm -f aospless_drm_hwcomposer_arm64.tar.xz
- - rm -rf aospless/*
- - wget https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/uploads/28ef9379b1a0ec1ee19a17825b0f3f3f/aospless_drm_hwcomposer_arm64.tar.xz
- - tar xf aospless_drm_hwcomposer_arm64.tar.xz
- - rm -r aospless/src
- - ln -s ../drm-hwcomposer/ aospless/src
- - make -C ./aospless all
- - cp -r aospless/install/* drm-hwcomposer/install/arm64
+ - rm ${HOME}/aospless/src
+ - ln -s ${PWD} ${HOME}/aospless/src
+ - make -C ${HOME}/aospless all
+ - cp -r ${HOME}/aospless/install/* install/arm64
artifacts:
paths:
@@ -40,17 +45,16 @@
tidy:
stage: tidy
+ image: $DOCKER_IMAGE_TAG
script:
- - cd ..
- - rm -f aospless_drm_hwcomposer_arm64.tar.xz
- - rm -rf aospless/*
- - wget https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/uploads/28ef9379b1a0ec1ee19a17825b0f3f3f/aospless_drm_hwcomposer_arm64.tar.xz
- - tar xf aospless_drm_hwcomposer_arm64.tar.xz
- - cd -
- - make -f .ci/Makefile
+ - rm ${HOME}/aospless/src
+ - ln -s ${PWD} ${HOME}/aospless/src
+ - BASE_DIR=${HOME}/aospless make -j$(nproc) -k -f .ci/Makefile
+ timeout: 2h
checkstyle:
stage: style
+ image: $DOCKER_IMAGE_TAG
script: "./.ci/.gitlab-ci-checkcommit.sh"
artifacts:
when: on_failure
diff --git a/Android.bp b/Android.bp
index 62c7e0c..7d014dc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,6 +42,8 @@
name: "hwcomposer.drm_defaults",
shared_libs: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2-resources",
"libcutils",
"libdrm",
"libhardware",
@@ -52,7 +54,13 @@
"libutils",
],
- header_libs: ["drm_hwcomposer_headers"],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+
+ header_libs: [
+ "drm_hwcomposer_headers",
+ ],
cflags: [
"-Wall",
@@ -62,7 +70,6 @@
cppflags: [
"-DHWC2_INCLUDE_STRINGIFICATION",
"-DHWC2_USE_CPP11",
- "-std=c++17",
],
relative_install_path: "hw",
@@ -96,6 +103,7 @@
"drm/ResourceManager.cpp",
"drm/UEventListener.cpp",
"drm/VSyncWorker.cpp",
+ "drm/DrmHwc.cpp",
"backend/Backend.cpp",
"backend/BackendClient.cpp",
@@ -111,6 +119,38 @@
],
}
+filegroup {
+ name: "drm_hwcomposer_hwc3",
+ srcs: [
+ "hwc3/Composer.cpp",
+ "hwc3/ComposerClient.cpp",
+ "hwc3/ComposerResources.cpp",
+ "hwc3/DrmHwcThree.cpp",
+ "hwc3/Utils.cpp",
+ ],
+}
+
+filegroup {
+ name: "drm_hwcomposer_service",
+ srcs: [
+ "hwc3/service.cpp",
+ ],
+}
+
+filegroup {
+ name: "drm_hwcomposer_init_rc",
+ srcs: [
+ "hwc3/hwc3-drm.rc",
+ ],
+}
+
+filegroup {
+ name: "drm_hwcomposer_vintf_manifest",
+ srcs: [
+ "hwc3/hwc3-drm.xml",
+ ],
+}
+
// Kept only for compatibility with older Android version. Please do not use!
cc_library_static {
name: "drm_hwcomposer",
@@ -137,6 +177,48 @@
],
}
+cc_binary {
+ name: "android.hardware.composer.hwc3-service.drm",
+
+ srcs: [
+ ":drm_hwcomposer_hwc3",
+ ":drm_hwcomposer_service",
+ ":drm_hwcomposer_common",
+ "bufferinfo/legacy/BufferInfoLibdrm.cpp",
+ ],
+
+ defaults: [
+ "hwcomposer.drm_defaults",
+ ],
+
+ shared_libs: [
+ "android.hardware.graphics.composer3-V3-ndk",
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ "liblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+
+ "-DUSE_IMAPPER4_METADATA_API",
+ ],
+
+ cppflags: [
+ "-DHWC2_INCLUDE_STRINGIFICATION",
+ "-DHWC2_USE_CPP11",
+ ],
+
+ relative_install_path: "hw",
+ vendor: true,
+
+ vintf_fragments: [":drm_hwcomposer_vintf_manifest"],
+ init_rc: [":drm_hwcomposer_init_rc"],
+}
+
// Used by hwcomposer.drm_imagination
filegroup {
name: "drm_hwcomposer_platformimagination",
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index 3ca6e92..91cb84d 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -94,7 +94,7 @@
return !HardwareSupportsLayerType(layer->GetSfType()) ||
!layer->IsLayerUsableAsDevice() || display->CtmByGpu() ||
(layer->GetLayerData().pi.RequireScalingOrPhasing() &&
- display->GetHwc2()->GetResMan().ForcedScalingWithGpu());
+ display->GetHwc()->GetResMan().ForcedScalingWithGpu());
}
bool Backend::HardwareSupportsLayerType(HWC2::Composition comp_type) {
diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp
index 4e2532a..23fe270 100644
--- a/backend/BackendManager.cpp
+++ b/backend/BackendManager.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-backend"
+#define LOG_TAG "drmhwc"
#include "BackendManager.h"
diff --git a/bufferinfo/BufferInfoGetter.cpp b/bufferinfo/BufferInfoGetter.cpp
index 726b4eb..f12db22 100644
--- a/bufferinfo/BufferInfoGetter.cpp
+++ b/bufferinfo/BufferInfoGetter.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-buffer-info-getter"
+#define LOG_TAG "drmhwc"
#include "BufferInfoGetter.h"
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index 823d28a..dc1b906 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -16,7 +16,7 @@
#if __ANDROID_API__ >= 30
-#define LOG_TAG "hwc-bufferinfo-mappermetadata"
+#define LOG_TAG "drmhwc"
#include "BufferInfoMapperMetadata.h"
diff --git a/bufferinfo/legacy/BufferInfoImagination.cpp b/bufferinfo/legacy/BufferInfoImagination.cpp
index 6d917c2..0bb0aaa 100644
--- a/bufferinfo/legacy/BufferInfoImagination.cpp
+++ b/bufferinfo/legacy/BufferInfoImagination.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-bufferinfo-imagination"
+#define LOG_TAG "drmhwc"
#include "BufferInfoImagination.h"
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp
index b314bdc..6978b08 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.cpp
+++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-bufferinfo-libdrm"
+#define LOG_TAG "drmhwc"
#include "BufferInfoLibdrm.h"
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.cpp b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
index 461e2eb..bfb2e7b 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-bufferinfo-mali-hisi"
+#define LOG_TAG "drmhwc"
#include "BufferInfoMaliHisi.h"
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
index 6dac973..4493c98 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-bufferinfo-mali-mediatek"
+#define LOG_TAG "drmhwc"
#include "BufferInfoMaliMediatek.h"
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.cpp b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
index 536e5a6..aa77529 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-bufferinfo-mali-meson"
+#define LOG_TAG "drmhwc"
#include "BufferInfoMaliMeson.h"
diff --git a/bufferinfo/legacy/BufferInfoMinigbm.cpp b/bufferinfo/legacy/BufferInfoMinigbm.cpp
index c5a9e98..4bc4358 100644
--- a/bufferinfo/legacy/BufferInfoMinigbm.cpp
+++ b/bufferinfo/legacy/BufferInfoMinigbm.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-bufferinfo-minigbm"
+#define LOG_TAG "drmhwc"
#include "BufferInfoMinigbm.h"
diff --git a/compositor/DrmKmsPlan.cpp b/compositor/DrmKmsPlan.cpp
index 6289b84..4f75e89 100644
--- a/compositor/DrmKmsPlan.cpp
+++ b/compositor/DrmKmsPlan.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-composition-drm-kms-plan"
+#define LOG_TAG "drmhwc"
#include "DrmKmsPlan.h"
diff --git a/compositor/FlatteningController.cpp b/compositor/FlatteningController.cpp
index 257f8a0..efd7ad0 100644
--- a/compositor/FlatteningController.cpp
+++ b/compositor/FlatteningController.cpp
@@ -29,7 +29,7 @@
* composed by the client into a single framebuffer using GPU.
*/
-#define LOG_TAG "hwc-flatcon"
+#define LOG_TAG "drmhwc"
#include "FlatteningController.h"
@@ -41,6 +41,12 @@
-> std::shared_ptr<FlatteningController> {
auto fc = std::shared_ptr<FlatteningController>(new FlatteningController());
+ /* Disable the controller by default as it can cause refresh event to be
+ * issued at creation time, even when it is not required. This can fail VTS
+ * tests at teardown that check for this behaviour. See:
+ * https://cs.android.com/android/platform/superproject/main/+/cedca652b903e4f4e584e457b5a7038e0825fb94:hardware/interfaces/graphics/composer/aidl/vts/VtsComposerClient.cpp;drc=a2a6deaf5036e081f48379b6573db4465538b5ac;l=604
+ */
+ fc->Disable();
fc->cbks_ = cbks;
std::thread(&FlatteningController::ThreadFn, fc).detach();
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index b1f8257..537f819 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -17,7 +17,7 @@
#undef NDEBUG /* Required for assert to work */
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwc-drm-atomic-state-manager"
+#define LOG_TAG "drmhwc"
#include "DrmAtomicStateManager.h"
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index b396487..e459fe7 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-connector"
+#define LOG_TAG "drmhwc"
#include "DrmConnector.h"
diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp
index 948a9ac..ecee9e2 100644
--- a/drm/DrmCrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-crtc"
+#define LOG_TAG "drmhwc"
#include "DrmCrtc.h"
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index f6f0b01..4534104 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-device"
+#define LOG_TAG "drmhwc"
#include "DrmDevice.h"
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
index 1a8ad5b..2d81578 100644
--- a/drm/DrmDisplayPipeline.cpp
+++ b/drm/DrmDisplayPipeline.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-display-pipeline"
+#define LOG_TAG "drmhwc"
#include "DrmDisplayPipeline.h"
diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp
index 21ca693..7480ce6 100644
--- a/drm/DrmEncoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-encoder"
+#define LOG_TAG "drmhwc"
#include "DrmEncoder.h"
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index a91a52b..fe80891 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -17,7 +17,7 @@
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
-#define LOG_TAG "hwc-platform-drm-generic"
+#define LOG_TAG "drmhwc"
#include "DrmFbImporter.h"
@@ -97,7 +97,7 @@
ATRACE_NAME("Close FB and dmabufs");
/* Destroy framebuffer object */
- if (drmModeRmFB(*drm_->GetFd(), fb_id_) != 0) {
+ if (drmModeRmFB(*drm_fd_, fb_id_) != 0) {
ALOGE("Failed to rm fb");
}
@@ -118,7 +118,7 @@
continue;
}
gem_close.handle = gem_handles_[i];
- auto err = drmIoctl(*drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+ auto err = drmIoctl(*drm_fd_, DRM_IOCTL_GEM_CLOSE, &gem_close);
if (err != 0) {
ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
}
@@ -127,10 +127,21 @@
auto DrmFbImporter::GetOrCreateFbId(BufferInfo *bo)
-> std::shared_ptr<DrmFbIdHandle> {
+ /* TODO: Clean up DrmDevices and DrmFbImporter inter-dependency.
+ *
+ * DrmFbImporter can outlive DrmDevice which will cause issues when resources
+ * are released. Addressing this would require a restructure on how
+ * ResourceManager stores DrmDevices and DrmFbImporter to make sure they
+ * depend on each other. For now, just acquire the DRM fd from the DrmDevice
+ * to make sure it is not closed.
+ */
+ if (drm_fd_ == nullptr) {
+ drm_fd_ = drm_->GetFd();
+ }
+
/* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
GemHandle first_handle = 0;
- auto err = drmPrimeFDToHandle(*drm_->GetFd(), bo->prime_fds[0],
- &first_handle);
+ auto err = drmPrimeFDToHandle(*drm_fd_, bo->prime_fds[0], &first_handle);
if (err != 0) {
ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
diff --git a/drm/DrmFbImporter.h b/drm/DrmFbImporter.h
index 9a7c335..30f57ba 100644
--- a/drm/DrmFbImporter.h
+++ b/drm/DrmFbImporter.h
@@ -24,6 +24,7 @@
#include "bufferinfo/BufferInfo.h"
#include "drm/DrmDevice.h"
+#include "utils/fd.h"
#ifndef DRM_FORMAT_INVALID
#define DRM_FORMAT_INVALID 0
@@ -49,9 +50,9 @@
}
private:
- explicit DrmFbIdHandle(DrmDevice &drm) : drm_(&drm){};
+ explicit DrmFbIdHandle(DrmDevice &drm) : drm_fd_(drm.GetFd()) {};
- DrmDevice *const drm_;
+ SharedFd drm_fd_;
uint32_t fb_id_{};
std::array<GemHandle, kBufferMaxPlanes> gem_handles_{};
@@ -81,6 +82,7 @@
}
DrmDevice *const drm_;
+ SharedFd drm_fd_;
std::map<GemHandle, std::weak_ptr<DrmFbIdHandle>> drm_fb_id_handle_cache_;
};
diff --git a/drm/DrmHwc.cpp b/drm/DrmHwc.cpp
new file mode 100644
index 0000000..df3eb56
--- /dev/null
+++ b/drm/DrmHwc.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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"
+
+#include "DrmHwc.h"
+
+#include <cinttypes>
+
+#include "backend/Backend.h"
+#include "utils/log.h"
+
+namespace android {
+
+DrmHwc::DrmHwc() : resource_manager_(this) {};
+
+/* Must be called after every display attach/detach cycle */
+void DrmHwc::FinalizeDisplayBinding() {
+ if (displays_.count(kPrimaryDisplay) == 0) {
+ /* Primary display MUST always exist */
+ ALOGI("No pipelines available. Creating null-display for headless mode");
+ displays_[kPrimaryDisplay] = std::make_unique<
+ HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
+ /* Initializes null-display */
+ displays_[kPrimaryDisplay]->SetPipeline({});
+ }
+
+ if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
+ !display_handles_.empty()) {
+ /* Reattach first secondary display to take place of the primary */
+ auto pipe = display_handles_.begin()->first;
+ ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
+ pipe->connector->Get()->GetName().c_str());
+ UnbindDisplay(pipe);
+ BindDisplay(pipe);
+ }
+
+ // Finally, send hotplug events to the client
+ for (auto &dhe : deferred_hotplug_events_) {
+ SendHotplugEventToClient(dhe.first, dhe.second);
+ }
+ deferred_hotplug_events_.clear();
+
+ /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
+ */
+ auto &mutex = GetResMan().GetMainLock();
+ mutex.unlock();
+ const int time_for_sf_to_dispose_display_us = 200000;
+ usleep(time_for_sf_to_dispose_display_us);
+ mutex.lock();
+ for (auto handle : displays_for_removal_list_) {
+ displays_.erase(handle);
+ }
+}
+
+bool DrmHwc::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
+ if (display_handles_.count(pipeline) != 0) {
+ ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
+ __func__, pipeline.get());
+ return false;
+ }
+
+ uint32_t disp_handle = kPrimaryDisplay;
+
+ if (displays_.count(kPrimaryDisplay) != 0 &&
+ !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
+ disp_handle = ++last_display_handle_;
+ }
+
+ if (displays_.count(disp_handle) == 0) {
+ auto disp = std::make_unique<HwcDisplay>(disp_handle,
+ HWC2::DisplayType::Physical, this);
+ displays_[disp_handle] = std::move(disp);
+ }
+
+ ALOGI("Attaching pipeline '%s' to the display #%d%s",
+ pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
+ disp_handle == kPrimaryDisplay ? " (Primary)" : "");
+
+ displays_[disp_handle]->SetPipeline(pipeline);
+ display_handles_[pipeline] = disp_handle;
+
+ return true;
+}
+
+bool DrmHwc::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
+ if (display_handles_.count(pipeline) == 0) {
+ ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
+ return false;
+ }
+ auto handle = display_handles_[pipeline];
+ display_handles_.erase(pipeline);
+
+ ALOGI("Detaching the pipeline '%s' from the display #%i%s",
+ pipeline->connector->Get()->GetName().c_str(), (int)handle,
+ handle == kPrimaryDisplay ? " (Primary)" : "");
+
+ if (displays_.count(handle) == 0) {
+ ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
+ return false;
+ }
+ displays_[handle]->SetPipeline({});
+
+ /* We must defer display disposal and removal, since it may still have pending
+ * HWC_API calls scheduled and waiting until ueventlistener thread releases
+ * main lock, otherwise transaction may fail and SF may crash
+ */
+ if (handle != kPrimaryDisplay) {
+ displays_for_removal_list_.emplace_back(handle);
+ }
+ return true;
+}
+
+HWC2::Error DrmHwc::CreateVirtualDisplay(
+ uint32_t width, uint32_t height,
+ int32_t *format, // NOLINT(readability-non-const-parameter)
+ hwc2_display_t *display) {
+ ALOGI("Creating virtual display %dx%d format %d", width, height, *format);
+
+ auto virtual_pipeline = resource_manager_.GetVirtualDisplayPipeline();
+ if (!virtual_pipeline)
+ return HWC2::Error::Unsupported;
+
+ *display = ++last_display_handle_;
+ auto disp = std::make_unique<HwcDisplay>(*display, HWC2::DisplayType::Virtual,
+ this);
+
+ disp->SetVirtualDisplayResolution(width, height);
+ disp->SetPipeline(virtual_pipeline);
+ displays_[*display] = std::move(disp);
+ return HWC2::Error::None;
+}
+
+HWC2::Error DrmHwc::DestroyVirtualDisplay(hwc2_display_t display) {
+ ALOGI("Destroying virtual display %" PRIu64, display);
+
+ if (displays_.count(display) == 0) {
+ ALOGE("Trying to destroy non-existent display %" PRIu64, display);
+ return HWC2::Error::BadDisplay;
+ }
+
+ displays_[display]->SetPipeline({});
+
+ /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
+ */
+ auto &mutex = GetResMan().GetMainLock();
+ mutex.unlock();
+ const int time_for_sf_to_dispose_display_us = 200000;
+ usleep(time_for_sf_to_dispose_display_us);
+ mutex.lock();
+
+ displays_.erase(display);
+
+ return HWC2::Error::None;
+}
+
+void DrmHwc::Dump(uint32_t *out_size, char *out_buffer) {
+ if (out_buffer != nullptr) {
+ auto copied_bytes = dump_string_.copy(out_buffer, *out_size);
+ *out_size = static_cast<uint32_t>(copied_bytes);
+ return;
+ }
+
+ std::stringstream output;
+
+ output << "-- drm_hwcomposer --\n\n";
+
+ for (auto &disp : displays_)
+ output << disp.second->Dump();
+
+ dump_string_ = output.str();
+ *out_size = static_cast<uint32_t>(dump_string_.size());
+}
+
+uint32_t DrmHwc::GetMaxVirtualDisplayCount() {
+ auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
+ writeback_count = std::min(writeback_count, 1U);
+ /* Currently, only 1 virtual display is supported. Other cases need testing */
+ ALOGI("Max virtual display count: %d", writeback_count);
+ return writeback_count;
+}
+
+void DrmHwc::DeinitDisplays() {
+ for (auto &pair : Displays()) {
+ pair.second->SetPipeline(nullptr);
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/DrmHwc.h b/drm/DrmHwc.h
new file mode 100644
index 0000000..44dc276
--- /dev/null
+++ b/drm/DrmHwc.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "drm/ResourceManager.h"
+#include "hwc2_device/HwcDisplay.h"
+
+namespace android {
+
+class DrmHwc : public PipelineToFrontendBindingInterface {
+ public:
+ DrmHwc();
+ ~DrmHwc() override = default;
+
+ // Client Callback functions.:
+ virtual void SendVsyncEventToClient(hwc2_display_t displayid,
+ int64_t timestamp,
+ uint32_t vsync_period) const = 0;
+ virtual void SendVsyncPeriodTimingChangedEventToClient(
+ hwc2_display_t displayid, int64_t timestamp) const = 0;
+ virtual void SendRefreshEventToClient(uint64_t displayid) = 0;
+ virtual void SendHotplugEventToClient(hwc2_display_t displayid,
+ bool connected) = 0;
+
+ // Device functions
+ HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
+ int32_t *format, hwc2_display_t *display);
+ HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
+ void Dump(uint32_t *out_size, char *out_buffer);
+ uint32_t GetMaxVirtualDisplayCount();
+
+ auto GetDisplay(hwc2_display_t display_handle) {
+ return displays_.count(display_handle) != 0
+ ? displays_[display_handle].get()
+ : nullptr;
+ }
+
+ auto &GetResMan() {
+ return resource_manager_;
+ }
+
+ void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
+ deferred_hotplug_events_[displayid] = connected;
+ }
+
+ void DeinitDisplays();
+
+ // PipelineToFrontendBindingInterface
+ bool BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
+ bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
+ void FinalizeDisplayBinding() override;
+
+ protected:
+ auto& Displays() { return displays_; }
+
+ private:
+ ResourceManager resource_manager_;
+ std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
+ std::map<std::shared_ptr<DrmDisplayPipeline>, hwc2_display_t>
+ display_handles_;
+
+ std::string dump_string_;
+
+ std::map<hwc2_display_t, bool> deferred_hotplug_events_;
+ std::vector<hwc2_display_t> displays_for_removal_list_;
+
+ uint32_t last_display_handle_ = kPrimaryDisplay;
+};
+} // namespace android
\ No newline at end of file
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 19b7609..310e67b 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-plane"
+#define LOG_TAG "drmhwc"
#include "DrmPlane.h"
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index 938b3ad..031918a 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -15,7 +15,7 @@
*/
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
-#define LOG_TAG "hwc-drm-property"
+#define LOG_TAG "drmhwc"
#include "DrmProperty.h"
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index a6e9fc2..5ac80c4 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-resource-manager"
+#define LOG_TAG "drmhwc"
#include "ResourceManager.h"
@@ -39,6 +39,10 @@
uevent_listener_ = UEventListener::CreateInstance();
}
+ResourceManager::~ResourceManager() {
+ uevent_listener_->StopThread();
+}
+
void ResourceManager::Init() {
if (initialized_) {
ALOGE("Already initialized");
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 20e84a9..9a2652c 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -34,9 +34,9 @@
class PipelineToFrontendBindingInterface {
public:
virtual ~PipelineToFrontendBindingInterface() = default;
- virtual bool BindDisplay(std::shared_ptr<DrmDisplayPipeline>);
- virtual bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline>);
- virtual void FinalizeDisplayBinding();
+ virtual bool BindDisplay(std::shared_ptr<DrmDisplayPipeline>) = 0;
+ virtual bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline>) = 0;
+ virtual void FinalizeDisplayBinding() = 0;
};
class ResourceManager {
@@ -47,7 +47,7 @@
ResourceManager &operator=(const ResourceManager &) = delete;
ResourceManager(const ResourceManager &&) = delete;
ResourceManager &&operator=(const ResourceManager &&) = delete;
- ~ResourceManager() = default;
+ ~ResourceManager();
void Init();
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
index a05ec65..f69481a 100644
--- a/drm/UEventListener.cpp
+++ b/drm/UEventListener.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-uevent-listener"
+#define LOG_TAG "drmhwc"
#include "UEventListener.h"
@@ -24,6 +24,10 @@
namespace android {
+void UEventListener::StopThread() {
+ uevent_->Stop();
+}
+
auto UEventListener::CreateInstance() -> std::shared_ptr<UEventListener> {
auto uel = std::shared_ptr<UEventListener>(new UEventListener());
@@ -61,4 +65,5 @@
ALOGI("UEvent thread exit");
}
+
} // namespace android
diff --git a/drm/UEventListener.h b/drm/UEventListener.h
index 4f2be7c..f26c465 100644
--- a/drm/UEventListener.h
+++ b/drm/UEventListener.h
@@ -32,6 +32,8 @@
hotplug_handler_ = std::move(hotplug_handler);
}
+ void StopThread();
+
private:
UEventListener() = default;
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 10d48e3..963a37b 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-vsync-worker"
+#define LOG_TAG "drmhwc"
#include "VSyncWorker.h"
diff --git a/drm/meson.build b/drm/meson.build
index 7bef11a..47a45cc 100644
--- a/drm/meson.build
+++ b/drm/meson.build
@@ -6,6 +6,7 @@
'DrmDisplayPipeline.cpp',
'DrmEncoder.cpp',
'DrmFbImporter.cpp',
+ 'DrmHwc.cpp',
'DrmMode.cpp',
'DrmPlane.cpp',
'DrmProperty.cpp',
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index b151155..c120b63 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-drm-two"
+#define LOG_TAG "drmhwc"
#include "DrmHwcTwo.h"
@@ -25,174 +25,6 @@
namespace android {
-DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){};
-
-/* Must be called after every display attach/detach cycle */
-void DrmHwcTwo::FinalizeDisplayBinding() {
- if (displays_.count(kPrimaryDisplay) == 0) {
- /* Primary display MUST always exist */
- ALOGI("No pipelines available. Creating null-display for headless mode");
- displays_[kPrimaryDisplay] = std::make_unique<
- HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
- /* Initializes null-display */
- displays_[kPrimaryDisplay]->SetPipeline({});
- }
-
- if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
- !display_handles_.empty()) {
- /* Reattach first secondary display to take place of the primary */
- auto pipe = display_handles_.begin()->first;
- ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
- pipe->connector->Get()->GetName().c_str());
- UnbindDisplay(pipe);
- BindDisplay(pipe);
- }
-
- // Finally, send hotplug events to the client
- for (auto &dhe : deferred_hotplug_events_) {
- SendHotplugEventToClient(dhe.first, dhe.second);
- }
- deferred_hotplug_events_.clear();
-
- /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
- */
- auto &mutex = GetResMan().GetMainLock();
- mutex.unlock();
- const int kTimeForSFToDisposeDisplayUs = 200000;
- usleep(kTimeForSFToDisposeDisplayUs);
- mutex.lock();
- for (auto handle : displays_for_removal_list_) {
- displays_.erase(handle);
- }
-}
-
-bool DrmHwcTwo::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
- if (display_handles_.count(pipeline) != 0) {
- ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
- __func__, pipeline.get());
- return false;
- }
-
- uint32_t disp_handle = kPrimaryDisplay;
-
- if (displays_.count(kPrimaryDisplay) != 0 &&
- !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
- disp_handle = ++last_display_handle_;
- }
-
- if (displays_.count(disp_handle) == 0) {
- auto disp = std::make_unique<HwcDisplay>(disp_handle,
- HWC2::DisplayType::Physical, this);
- displays_[disp_handle] = std::move(disp);
- }
-
- ALOGI("Attaching pipeline '%s' to the display #%d%s",
- pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
- disp_handle == kPrimaryDisplay ? " (Primary)" : "");
-
- displays_[disp_handle]->SetPipeline(pipeline);
- display_handles_[pipeline] = disp_handle;
-
- return true;
-}
-
-bool DrmHwcTwo::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
- if (display_handles_.count(pipeline) == 0) {
- ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
- return false;
- }
- auto handle = display_handles_[pipeline];
- display_handles_.erase(pipeline);
-
- ALOGI("Detaching the pipeline '%s' from the display #%i%s",
- pipeline->connector->Get()->GetName().c_str(), (int)handle,
- handle == kPrimaryDisplay ? " (Primary)" : "");
-
- if (displays_.count(handle) == 0) {
- ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
- return false;
- }
- displays_[handle]->SetPipeline({});
-
- /* We must defer display disposal and removal, since it may still have pending
- * HWC_API calls scheduled and waiting until ueventlistener thread releases
- * main lock, otherwise transaction may fail and SF may crash
- */
- if (handle != kPrimaryDisplay) {
- displays_for_removal_list_.emplace_back(handle);
- }
- return true;
-}
-
-HWC2::Error DrmHwcTwo::CreateVirtualDisplay(
- uint32_t width, uint32_t height,
- int32_t *format, // NOLINT(readability-non-const-parameter)
- hwc2_display_t *display) {
- ALOGI("Creating virtual display %dx%d format %d", width, height, *format);
-
- auto virtual_pipeline = resource_manager_.GetVirtualDisplayPipeline();
- if (!virtual_pipeline)
- return HWC2::Error::Unsupported;
-
- *display = ++last_display_handle_;
- auto disp = std::make_unique<HwcDisplay>(*display, HWC2::DisplayType::Virtual,
- this);
-
- disp->SetVirtualDisplayResolution(width, height);
- disp->SetPipeline(virtual_pipeline);
- displays_[*display] = std::move(disp);
- return HWC2::Error::None;
-}
-
-HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) {
- ALOGI("Destroying virtual display %" PRIu64, display);
-
- if (displays_.count(display) == 0) {
- ALOGE("Trying to destroy non-existent display %" PRIu64, display);
- return HWC2::Error::BadDisplay;
- }
-
- displays_[display]->SetPipeline({});
-
- /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
- */
- auto &mutex = GetResMan().GetMainLock();
- mutex.unlock();
- const int kTimeForSFToDisposeDisplayUs = 200000;
- usleep(kTimeForSFToDisposeDisplayUs);
- mutex.lock();
-
- displays_.erase(display);
-
- return HWC2::Error::None;
-}
-
-void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
- if (outBuffer != nullptr) {
- auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
- *outSize = static_cast<uint32_t>(copied_bytes);
- return;
- }
-
- std::stringstream output;
-
- output << "-- drm_hwcomposer --\n\n";
-
- for (auto &disp : displays_)
- output << disp.second->Dump();
-
- mDumpString = output.str();
- *outSize = static_cast<uint32_t>(mDumpString.size());
-}
-
-uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
- auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
- writeback_count = std::min(writeback_count, 1U);
- /* Currently, only 1 virtual display is supported. Other cases need testing */
- ALOGI("Max virtual display count: %d", writeback_count);
- return writeback_count;
-}
-
HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
hwc2_callback_data_t data,
hwc2_function_pointer_t function) {
@@ -200,13 +32,13 @@
case HWC2::Callback::Hotplug: {
hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
if (function != nullptr) {
- resource_manager_.Init();
+ GetResMan().Init();
} else {
- resource_manager_.DeInit();
+ GetResMan().DeInit();
/* Headless display may still be here. Remove it! */
- if (displays_.count(kPrimaryDisplay) != 0) {
- displays_[kPrimaryDisplay]->Deinit();
- displays_.erase(kPrimaryDisplay);
+ if (Displays().count(kPrimaryDisplay) != 0) {
+ Displays()[kPrimaryDisplay]->Deinit();
+ Displays().erase(kPrimaryDisplay);
}
}
break;
@@ -237,15 +69,15 @@
}
void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
- bool connected) const {
+ bool connected) {
auto hc = hotplug_callback_;
if (hc.first != nullptr && hc.second != nullptr) {
/* For some reason HWC Service will call HWC2 API in hotplug callback
* handler. This is the reason we're using recursive mutex.
*/
hc.first(hc.second, displayid,
- connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
- : HWC2_CONNECTION_DISCONNECTED);
+ connected ? HWC2_CONNECTION_CONNECTED
+ : HWC2_CONNECTION_DISCONNECTED);
}
}
@@ -283,4 +115,11 @@
#endif
}
+void DrmHwcTwo::SendRefreshEventToClient(hwc2_display_t displayid) {
+ if (refresh_callback_.first != nullptr &&
+ refresh_callback_.second != nullptr) {
+ refresh_callback_.first(refresh_callback_.second, displayid);
+ }
+}
+
} // namespace android
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index 8701feb..b3ca0f8 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -18,16 +18,28 @@
#include <hardware/hwcomposer2.h>
-#include "drm/ResourceManager.h"
-#include "hwc2_device/HwcDisplay.h"
+#include "drm/DrmHwc.h"
namespace android {
-class DrmHwcTwo : public PipelineToFrontendBindingInterface {
+class DrmHwcTwo : public DrmHwc {
public:
- DrmHwcTwo();
+ DrmHwcTwo() = default;
~DrmHwcTwo() override = default;
+ HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
+ hwc2_function_pointer_t function);
+
+ // DrmHwc
+ void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
+ uint32_t vsync_period) const override;
+ void SendVsyncPeriodTimingChangedEventToClient(
+ hwc2_display_t displayid, int64_t timestamp) const override;
+ void SendRefreshEventToClient(uint64_t displayid) override;
+ void SendHotplugEventToClient(hwc2_display_t displayid,
+ bool connected) override;
+
+ private:
std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
#if __ANDROID_API__ > 29
@@ -36,53 +48,5 @@
period_timing_changed_callback_{};
#endif
std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
-
- // Device functions
- HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
- int32_t *format, hwc2_display_t *display);
- HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
- void Dump(uint32_t *outSize, char *outBuffer);
- uint32_t GetMaxVirtualDisplayCount();
- HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
- hwc2_function_pointer_t function);
-
- auto GetDisplay(hwc2_display_t display_handle) {
- return displays_.count(display_handle) != 0
- ? displays_[display_handle].get()
- : nullptr;
- }
-
- auto &GetResMan() {
- return resource_manager_;
- }
-
- void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
- deferred_hotplug_events_[displayid] = connected;
- }
-
- // PipelineToFrontendBindingInterface
- bool BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
- bool UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) override;
- void FinalizeDisplayBinding() override;
-
- void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
- uint32_t vsync_period) const;
- void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,
- int64_t timestamp) const;
-
- private:
- void SendHotplugEventToClient(hwc2_display_t displayid, bool connected) const;
-
- ResourceManager resource_manager_;
- std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
- std::map<std::shared_ptr<DrmDisplayPipeline>, hwc2_display_t>
- display_handles_;
-
- std::string mDumpString;
-
- std::map<hwc2_display_t, bool> deferred_hotplug_events_;
- std::vector<hwc2_display_t> displays_for_removal_list_;
-
- uint32_t last_display_handle_ = kPrimaryDisplay;
};
} // namespace android
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 6f08c33..36333d2 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-display"
+#define LOG_TAG "drmhwc"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "HwcDisplay.h"
-#include "DrmHwcTwo.h"
#include "backend/Backend.h"
#include "backend/BackendManager.h"
#include "bufferinfo/BufferInfoGetter.h"
+#include "drm/DrmHwc.h"
#include "utils/log.h"
#include "utils/properties.h"
@@ -66,8 +66,8 @@
}
HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
- DrmHwcTwo *hwc2)
- : hwc2_(hwc2), handle_(handle), type_(type), client_layer_(this) {
+ DrmHwc *hwc)
+ : hwc_(hwc), handle_(handle), type_(type), client_layer_(this) {
if (type_ == HWC2::DisplayType::Virtual) {
writeback_layer_ = std::make_unique<HwcLayer>(this);
}
@@ -85,7 +85,9 @@
color_transform_hint_ = HAL_COLOR_TRANSFORM_IDENTITY;
}
-HwcDisplay::~HwcDisplay() = default;
+HwcDisplay::~HwcDisplay() {
+ Deinit();
+};
void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
Deinit();
@@ -94,9 +96,9 @@
if (pipeline_ != nullptr || handle_ == kPrimaryDisplay) {
Init();
- hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
+ hwc_->ScheduleHotplugEvent(handle_, /*connected = */ true);
} else {
- hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
+ hwc_->ScheduleHotplugEvent(handle_, /*connected = */ false);
}
}
@@ -131,6 +133,8 @@
}
if (vsync_worker_) {
+ // TODO: There should be a mechanism to wait for this worker to complete,
+ // otherwise there is a race condition while destructing the HwcDisplay.
vsync_worker_->StopThread();
vsync_worker_ = {};
}
@@ -144,11 +148,11 @@
auto vsw_callbacks = (VSyncWorkerCallbacks){
.out_event =
[this](int64_t timestamp) {
- const std::unique_lock lock(hwc2_->GetResMan().GetMainLock());
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
if (vsync_event_en_) {
uint32_t period_ns{};
GetDisplayVsyncPeriod(&period_ns);
- hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+ hwc_->SendVsyncEventToClient(handle_, timestamp, period_ns);
}
if (vsync_tracking_en_) {
last_vsync_ts_ = timestamp;
@@ -178,12 +182,8 @@
ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
return HWC2::Error::BadDisplay;
}
- auto flatcbk = (struct FlatConCallbacks){.trigger = [this]() {
- if (hwc2_->refresh_callback_.first != nullptr &&
- hwc2_->refresh_callback_.second != nullptr)
- hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second,
- handle_);
- }};
+ auto flatcbk = (struct FlatConCallbacks){
+ .trigger = [this]() { hwc_->SendRefreshEventToClient(handle_); }};
flatcon_ = FlatteningController::CreateInstance(flatcbk);
}
@@ -310,7 +310,6 @@
static const int32_t kUmPerInch = 25400;
auto mm_width = configs_.mm_width;
- auto mm_height = configs_.mm_height;
auto attribute = static_cast<HWC2::Attribute>(attribute_in);
switch (attribute) {
case HWC2::Attribute::Width:
@@ -323,18 +322,17 @@
// in nanoseconds
*value = static_cast<int>(1E9 / hwc_config.mode.GetVRefresh());
break;
+ case HWC2::Attribute::DpiY:
+ // ideally this should be vdisplay/mm_heigth, however mm_height
+ // comes from edid parsing and is highly unreliable. Viewing the
+ // rarity of anisotropic displays, falling back to a single value
+ // for dpi yield more correct output.
case HWC2::Attribute::DpiX:
// Dots per 1000 inches
*value = mm_width ? int(hwc_config.mode.GetRawMode().hdisplay *
kUmPerInch / mm_width)
: -1;
break;
- case HWC2::Attribute::DpiY:
- // Dots per 1000 inches
- *value = mm_height ? int(hwc_config.mode.GetRawMode().vdisplay *
- kUmPerInch / mm_height)
- : -1;
- break;
#if __ANDROID_API__ > 29
case HWC2::Attribute::ConfigGroup:
/* Dispite ConfigGroup is a part of HWC2.4 API, framework
@@ -349,8 +347,8 @@
return HWC2::Error::None;
}
-HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
- hwc2_config_t *configs) {
+HWC2::Error HwcDisplay::LegacyGetDisplayConfigs(uint32_t *num_configs,
+ hwc2_config_t *configs) {
uint32_t idx = 0;
for (auto &hwc_config : configs_.hwc_configs) {
if (hwc_config.second.disabled) {
@@ -564,9 +562,9 @@
staged_mode_.reset();
vsync_tracking_en_ = false;
if (last_vsync_ts_ != 0) {
- hwc2_->SendVsyncPeriodTimingChangedEventToClient(handle_,
- last_vsync_ts_ +
- prev_vperiod_ns);
+ hwc_->SendVsyncPeriodTimingChangedEventToClient(handle_,
+ last_vsync_ts_ +
+ prev_vperiod_ns);
}
}
@@ -731,7 +729,7 @@
if (GetPipe().crtc->Get()->GetCtmProperty())
return false;
- if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+ if (GetHwc()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
return false;
return true;
@@ -963,7 +961,7 @@
bool skip_ctm = false;
// Skip client CTM if user requested DRM_OR_IGNORE
- if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+ if (GetHwc()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
skip_ctm = true;
// Skip client CTM if DRM can handle it
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 13d4328..87d2da7 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -33,14 +33,14 @@
namespace android {
class Backend;
-class DrmHwcTwo;
+class DrmHwc;
inline constexpr uint32_t kPrimaryDisplay = 0;
// NOLINTNEXTLINE
class HwcDisplay {
public:
- HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
+ HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
HwcDisplay(const HwcDisplay &) = delete;
~HwcDisplay();
@@ -54,6 +54,10 @@
std::string Dump();
+ const HwcDisplayConfigs &GetDisplayConfigs() const {
+ return configs_;
+ }
+
// HWC Hooks
HWC2::Error AcceptDisplayChanges();
HWC2::Error CreateLayer(hwc2_layer_t *layer);
@@ -66,7 +70,8 @@
HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes);
HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute,
int32_t *value);
- HWC2::Error GetDisplayConfigs(uint32_t *num_configs, hwc2_config_t *configs);
+ HWC2::Error LegacyGetDisplayConfigs(uint32_t *num_configs,
+ hwc2_config_t *configs);
HWC2::Error GetDisplayName(uint32_t *size, char *name);
HWC2::Error GetDisplayRequests(int32_t *display_requests,
uint32_t *num_elements, hwc2_layer_t *layers,
@@ -149,8 +154,8 @@
const Backend *backend() const;
void set_backend(std::unique_ptr<Backend> backend);
- auto GetHwc2() {
- return hwc2_;
+ auto GetHwc() {
+ return hwc_;
}
std::map<hwc2_layer_t, HwcLayer> &layers() {
@@ -195,7 +200,7 @@
private:
HwcDisplayConfigs configs_;
- DrmHwcTwo *const hwc2_;
+ DrmHwc *const hwc_;
SharedFd present_fence_;
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index f6bf4a1..3645356 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-display-configs"
+#define LOG_TAG "drmhwc"
#include "HwcDisplayConfigs.h"
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index 12da418..da4ce7c 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "hwc-layer"
+#define LOG_TAG "drmhwc"
#include "HwcLayer.h"
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index d4ee10d..28b6963 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -17,7 +17,7 @@
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
// #define LOG_NDEBUG 0 // Uncomment to see HWC2 API calls in logcat
-#define LOG_TAG "hwc2-device"
+#define LOG_TAG "drmhwc"
#include <cinttypes>
@@ -177,8 +177,8 @@
int32_t *>);
case HWC2::FunctionDescriptor::GetDisplayConfigs:
return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>(
- DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs),
- &HwcDisplay::GetDisplayConfigs, uint32_t *,
+ DisplayHook<decltype(&HwcDisplay::LegacyGetDisplayConfigs),
+ &HwcDisplay::LegacyGetDisplayConfigs, uint32_t *,
hwc2_config_t *>);
case HWC2::FunctionDescriptor::GetDisplayName:
return ToHook<HWC2_PFN_GET_DISPLAY_NAME>(
diff --git a/hwc2_device/meson.build b/hwc2_device/meson.build
index 7e6b8f4..6a9a93a 100644
--- a/hwc2_device/meson.build
+++ b/hwc2_device/meson.build
@@ -6,14 +6,23 @@
'HwcLayer.cpp',
)
+drmhwc_hwc2_common = static_library(
+ 'drm_hwc2',
+ src_hwc2_device,
+# TODO remove hwc2 flags from common code (backends needs rework)
+ cpp_args : common_cpp_flags + hwc2_cpp_flags,
+ dependencies : deps,
+ link_with: drmhwc_common,
+ include_directories: inc_include,
+)
+
shared_library(
'hwcomposer.drm',
- src_hwc2_device,
name_prefix : '',
cpp_args : common_cpp_flags + hwc2_cpp_flags,
dependencies : deps,
install : true,
- link_whole: drmhwc_common,
+ link_whole: [drmhwc_common, drmhwc_hwc2_common],
install_dir : get_option('libdir') / 'hw',
include_directories: inc_include,
-)
+)
\ No newline at end of file
diff --git a/hwc3/CommandResultWriter.h b/hwc3/CommandResultWriter.h
new file mode 100644
index 0000000..fa96f33
--- /dev/null
+++ b/hwc3/CommandResultWriter.h
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include <unordered_map>
+#include <vector>
+
+#include "Utils.h"
+#include "aidl/android/hardware/graphics/composer3/CommandError.h"
+#include "aidl/android/hardware/graphics/composer3/CommandResultPayload.h"
+#include "aidl/android/hardware/graphics/composer3/PresentFence.h"
+#include "aidl/android/hardware/graphics/composer3/PresentOrValidate.h"
+#include "aidl/android/hardware/graphics/composer3/ReleaseFences.h"
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+struct DisplayChanges {
+ std::optional<ChangedCompositionTypes> composition_changes;
+ std::optional<DisplayRequest> display_request_changes;
+
+ void AddLayerCompositionChange(int64_t display_id, int64_t layer_id,
+ Composition layer_composition) {
+ if (!composition_changes) {
+ composition_changes.emplace();
+ composition_changes->display = display_id;
+ }
+
+ ChangedCompositionLayer composition_change;
+ composition_change.layer = layer_id;
+ composition_change.composition = layer_composition;
+ composition_changes->layers.emplace_back(composition_change);
+ }
+
+ void ClearLayerCompositionChanges() {
+ composition_changes.reset();
+ }
+
+ bool HasAnyChanges() const {
+ return composition_changes.has_value() ||
+ display_request_changes.has_value();
+ }
+
+ void Reset() {
+ composition_changes.reset();
+ display_request_changes.reset();
+ }
+};
+
+class CommandResultWriter {
+ public:
+ explicit CommandResultWriter(std::vector<CommandResultPayload>* results)
+ : results_(results) {
+ }
+
+ bool HasError() const {
+ return has_error_;
+ }
+
+ void IncrementCommand() {
+ index_++;
+ has_error_ = false;
+ }
+
+ void AddError(hwc3::Error error) {
+ CommandError command_error;
+ command_error.errorCode = static_cast<int32_t>(error);
+ command_error.commandIndex = static_cast<int32_t>(index_);
+
+ results_->emplace_back(command_error);
+ has_error_ = true;
+ }
+
+ void AddPresentFence(int64_t display_id, ::android::base::unique_fd fence) {
+ if (!fence.ok()) {
+ return;
+ }
+
+ PresentFence present_fence;
+ present_fence.fence = ::ndk::ScopedFileDescriptor(fence.release());
+ present_fence.display = display_id;
+ results_->emplace_back(std::move(present_fence));
+ }
+
+ void AddReleaseFence(
+ int64_t display_id,
+ std::unordered_map<int64_t, ::android::base::unique_fd>& layer_fences) {
+ ReleaseFences release_fences;
+ release_fences.display = display_id;
+ for (auto& [layer, fence] : layer_fences) {
+ if (!fence.ok()) {
+ continue;
+ }
+
+ ReleaseFences::Layer layer_result;
+ layer_result.layer = layer;
+ layer_result.fence = ::ndk::ScopedFileDescriptor(fence.release());
+
+ release_fences.layers.emplace_back(std::move(layer_result));
+ }
+
+ results_->emplace_back(std::move(release_fences));
+ }
+
+ void AddChanges(const DisplayChanges& changes) {
+ if (changes.composition_changes) {
+ results_->emplace_back(*changes.composition_changes);
+ }
+ if (changes.display_request_changes) {
+ results_->emplace_back(*changes.display_request_changes);
+ }
+ }
+
+ void AddPresentOrValidateResult(int64_t display_id,
+ const PresentOrValidate::Result& pov_result) {
+ PresentOrValidate pov_command;
+ pov_command.display = display_id;
+ pov_command.result = pov_result;
+
+ results_->emplace_back(pov_command);
+ }
+
+ private:
+ size_t index_{0};
+ bool has_error_{false};
+ std::vector<CommandResultPayload>* results_{nullptr};
+};
+}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/Composer.cpp b/hwc3/Composer.cpp
new file mode 100644
index 0000000..4977a14
--- /dev/null
+++ b/hwc3/Composer.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "Composer.h"
+
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+
+#include "hwc3/ComposerClient.h"
+#include "hwc3/Utils.h"
+#include "utils/log.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+ndk::ScopedAStatus Composer::createClient(
+ std::shared_ptr<IComposerClient>* out_client) {
+ DEBUG_FUNC();
+
+ if (!client_.expired()) {
+ return ToBinderStatus(hwc3::Error::kNoResources);
+ }
+
+ auto client = ndk::SharedRefBase::make<ComposerClient>();
+ if (!client || !client->Init()) {
+ *out_client = nullptr;
+ return ToBinderStatus(hwc3::Error::kNoResources);
+ }
+
+ *out_client = client;
+ client_ = client;
+
+ return ndk::ScopedAStatus::ok();
+}
+
+binder_status_t Composer::dump(int fd, const char** /*args*/,
+ uint32_t /*numArgs*/) {
+ std::stringstream output;
+ output << "hwc3-drm\n\n";
+
+ auto client_instance = client_.lock();
+ if (!client_instance) {
+ return STATUS_OK;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
+ auto* client = static_cast<ComposerClient*>(client_instance.get());
+ output << client->Dump();
+
+ auto output_str = output.str();
+ write(fd, output_str.c_str(), output_str.size());
+ return STATUS_OK;
+}
+
+ndk::ScopedAStatus Composer::getCapabilities(std::vector<Capability>* caps) {
+ DEBUG_FUNC();
+ /* No capabilities advertised */
+ caps->clear();
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::SpAIBinder Composer::createBinder() {
+ auto binder = BnComposer::createBinder();
+ AIBinder_setInheritRt(binder.get(), true);
+ return binder;
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/Composer.h b/hwc3/Composer.h
new file mode 100644
index 0000000..f6c2536
--- /dev/null
+++ b/hwc3/Composer.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/composer3/BnComposer.h>
+#include <utils/Mutex.h>
+
+#include <memory>
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class Composer : public BnComposer {
+ public:
+ Composer() = default;
+
+ binder_status_t dump(int fd, const char** args, uint32_t num_args) override;
+
+ // compser3 api
+ ndk::ScopedAStatus createClient(
+ std::shared_ptr<IComposerClient>* client) override;
+ ndk::ScopedAStatus getCapabilities(std::vector<Capability>* caps) override;
+
+ protected:
+ ::ndk::SpAIBinder createBinder() override;
+
+ private:
+ std::weak_ptr<IComposerClient> client_;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
new file mode 100644
index 0000000..f353abb
--- /dev/null
+++ b/hwc3/ComposerClient.cpp
@@ -0,0 +1,1366 @@
+/*
+ * 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"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "ComposerClient.h"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <hardware/hwcomposer2.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "aidl/android/hardware/graphics/common/Transform.h"
+#include "aidl/android/hardware/graphics/composer3/ClientTarget.h"
+#include "aidl/android/hardware/graphics/composer3/Composition.h"
+#include "aidl/android/hardware/graphics/composer3/DisplayRequest.h"
+#include "aidl/android/hardware/graphics/composer3/IComposerClient.h"
+#include "aidl/android/hardware/graphics/composer3/PowerMode.h"
+#include "aidl/android/hardware/graphics/composer3/PresentOrValidate.h"
+#include "aidl/android/hardware/graphics/composer3/RenderIntent.h"
+#include "android/binder_auto_utils.h"
+#include "cutils/native_handle.h"
+#include "hardware/hwcomposer_defs.h"
+#include "hwc2_device/HwcDisplay.h"
+#include "hwc2_device/HwcDisplayConfigs.h"
+#include "hwc2_device/HwcLayer.h"
+#include "hwc3/DrmHwcThree.h"
+#include "hwc3/Utils.h"
+
+using ::android::HwcDisplay;
+using ::android::HwcDisplayConfigs;
+
+#include "utils/log.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+namespace {
+
+// clang-format off
+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,
+};
+// clang-format on
+
+} // namespace
+
+ComposerClient::ComposerClient() {
+ DEBUG_FUNC();
+}
+
+bool ComposerClient::Init() {
+ DEBUG_FUNC();
+ composer_resources_ = ComposerResources::Create();
+ if (composer_resources_) {
+ hwc_ = std::make_unique<DrmHwcThree>(composer_resources_.get());
+ }
+ return composer_resources_ != nullptr;
+}
+
+ComposerClient::~ComposerClient() {
+ DEBUG_FUNC();
+ {
+ // First Deinit the displays to start shutting down the Display's dependent
+ // threads such as VSyncWorker.
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ hwc_->DeinitDisplays();
+ }
+ // Sleep to wait for threads to complete and exit.
+ const int time_for_threads_to_exit_us = 200000;
+ usleep(time_for_threads_to_exit_us);
+ {
+ // Hold the lock while destructing the hwc_ and the objects that it owns.
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ hwc_.reset();
+ }
+ LOG(DEBUG) << "removed composer client";
+}
+
+ndk::ScopedAStatus ComposerClient::createLayer(int64_t display_id,
+ int32_t buffer_slot_count,
+ int64_t* layer_id) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ hwc2_layer_t hwc2_layer_id = 0;
+ auto err = Hwc2toHwc3Error(display->CreateLayer(&hwc2_layer_id));
+ if (err != hwc3::Error::kNone) {
+ return ToBinderStatus(err);
+ }
+
+ const int64_t created_layer_id = Hwc2LayerToHwc3(hwc2_layer_id);
+ err = composer_resources_->AddLayer(display_id, created_layer_id,
+ buffer_slot_count);
+ if (err != hwc3::Error::kNone) {
+ destroyLayer(display_id, created_layer_id);
+ return ToBinderStatus(err);
+ }
+
+ *layer_id = created_layer_id;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::createVirtualDisplay(
+ int32_t width, int32_t height, AidlPixelFormat format_hint,
+ int32_t output_buffer_slot_count, VirtualDisplay* out_display) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+
+ hwc2_display_t hwc2_display_id = 0;
+ // TODO: Format is currently not used in drm_hwcomposer.
+ int32_t hwc2_format = 0;
+ auto err = Hwc2toHwc3Error(hwc_->CreateVirtualDisplay(width, height,
+ &hwc2_format,
+ &hwc2_display_id));
+ if (err != hwc3::Error::kNone) {
+ return ToBinderStatus(err);
+ }
+
+ const int64_t created_display_id = Hwc2DisplayToHwc3(hwc2_display_id);
+ err = composer_resources_->AddVirtualDisplay(hwc2_display_id,
+ output_buffer_slot_count);
+ if (err != hwc3::Error::kNone) {
+ hwc_->DestroyVirtualDisplay(hwc2_display_id);
+ return ToBinderStatus(err);
+ }
+
+ out_display->display = created_display_id;
+ out_display->format = format_hint;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::destroyLayer(int64_t display_id,
+ int64_t layer_id) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto err = Hwc2toHwc3Error(display->DestroyLayer(Hwc3LayerToHwc2(layer_id)));
+ if (err != hwc3::Error::kNone) {
+ return ToBinderStatus(err);
+ }
+
+ err = composer_resources_->RemoveLayer(display_id, layer_id);
+ return ToBinderStatus(err);
+}
+
+ndk::ScopedAStatus ComposerClient::destroyVirtualDisplay(int64_t display_id) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ auto err = Hwc2toHwc3Error(hwc_->DestroyVirtualDisplay(display_id));
+ 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);
+ }
+
+ std::vector<hwc2_layer_t> hwc_changed_layers(num_types);
+ std::vector<int32_t> hwc_composition_types(num_types);
+ hwc3::Error 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);
+}
+
+void ComposerClient::DispatchLayerCommand(int64_t display_id,
+ const LayerCommand& command) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ auto* layer = display->get_layer(command.layer);
+ if (layer == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadLayer);
+ return;
+ }
+
+ HwcLayerWrapper layer_wrapper{command.layer, layer};
+ if (command.buffer) {
+ ExecuteSetLayerBuffer(display_id, layer_wrapper, *command.buffer);
+ }
+ if (command.blendMode) {
+ ExecuteSetLayerBlendMode(display_id, layer_wrapper, *command.blendMode);
+ }
+ if (command.composition) {
+ ExecuteSetLayerComposition(display_id, layer_wrapper, *command.composition);
+ }
+ if (command.dataspace) {
+ ExecuteSetLayerDataspace(display_id, layer_wrapper, *command.dataspace);
+ }
+ if (command.displayFrame) {
+ ExecuteSetLayerDisplayFrame(display_id, layer_wrapper,
+ *command.displayFrame);
+ }
+ if (command.planeAlpha) {
+ ExecuteSetLayerPlaneAlpha(display_id, layer_wrapper, *command.planeAlpha);
+ }
+ if (command.sourceCrop) {
+ ExecuteSetLayerSourceCrop(display_id, layer_wrapper, *command.sourceCrop);
+ }
+ if (command.transform) {
+ ExecuteSetLayerTransform(display_id, layer_wrapper, *command.transform);
+ }
+ if (command.z) {
+ ExecuteSetLayerZOrder(display_id, layer_wrapper, *command.z);
+ }
+ if (command.brightness) {
+ ExecuteSetLayerBrightness(display_id, layer_wrapper, *command.brightness);
+ }
+
+ // Some unsupported functionality returns kUnsupported, and others
+ // are just a no-op.
+ // TODO: Audit whether some of these should actually return kUnsupported
+ // instead.
+ if (command.sidebandStream) {
+ cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
+ }
+ // TODO: Blocking region handling missing.
+ // TODO: Layer surface damage.
+ // TODO: Layer visible region.
+ // TODO: Per-frame metadata.
+ // TODO: Layer color transform.
+ // TODO: Layer cursor position.
+ // TODO: Layer color.
+}
+
+void ComposerClient::ExecuteDisplayCommand(const DisplayCommand& command) {
+ const int64_t display_id = command.display;
+ if (hwc_->GetDisplay(display_id) == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ for (const auto& layer_cmd : command.layers) {
+ DispatchLayerCommand(command.display, layer_cmd);
+ }
+
+ if (command.brightness) {
+ ExecuteSetDisplayBrightness(command.display, *command.brightness);
+ }
+ if (command.colorTransformMatrix) {
+ ExecuteSetDisplayColorTransform(command.display,
+ *command.colorTransformMatrix);
+ }
+ if (command.clientTarget) {
+ ExecuteSetDisplayClientTarget(command.display, *command.clientTarget);
+ }
+ if (command.virtualDisplayOutputBuffer) {
+ ExecuteSetDisplayOutputBuffer(command.display,
+ *command.virtualDisplayOutputBuffer);
+ }
+ if (command.validateDisplay) {
+ ExecuteValidateDisplay(command.display, command.expectedPresentTime);
+ }
+ if (command.acceptDisplayChanges) {
+ ExecuteAcceptDisplayChanges(command.display);
+ }
+ if (command.presentDisplay) {
+ ExecutePresentDisplay(command.display);
+ }
+ if (command.presentOrValidateDisplay) {
+ ExecutePresentOrValidateDisplay(command.display,
+ command.expectedPresentTime);
+ }
+}
+
+ndk::ScopedAStatus ComposerClient::executeCommands(
+ const std::vector<DisplayCommand>& commands,
+ std::vector<CommandResultPayload>* results) {
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ DEBUG_FUNC();
+ cmd_result_writer_ = std::make_unique<CommandResultWriter>(results);
+ for (const auto& cmd : commands) {
+ ExecuteDisplayCommand(cmd);
+ cmd_result_writer_->IncrementCommand();
+ }
+ cmd_result_writer_.reset();
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t display_id,
+ int32_t* config) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t hwc2_config = 0;
+ const hwc3::Error error = Hwc2toHwc3Error(
+ display->GetActiveConfig(&hwc2_config));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+ *config = Hwc2ConfigIdToHwc3(hwc2_config);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getColorModes(
+ int64_t display_id, std::vector<ColorMode>* color_modes) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t num_modes = 0;
+ auto error = Hwc2toHwc3Error(display->GetColorModes(&num_modes, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<int32_t> hwc2_color_modes(num_modes);
+ error = Hwc2toHwc3Error(
+ display->GetColorModes(&num_modes, hwc2_color_modes.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ for (const auto& mode : hwc2_color_modes) {
+ color_modes->push_back(Hwc2ColorModeToHwc3(mode));
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDataspaceSaturationMatrix(
+ common::Dataspace dataspace, std::vector<float>* matrix) {
+ DEBUG_FUNC();
+ if (dataspace != common::Dataspace::SRGB_LINEAR) {
+ return ToBinderStatus(hwc3::Error::kBadParameter);
+ }
+
+ matrix->clear();
+ matrix->insert(matrix->begin(), kIdentityMatrix.begin(),
+ kIdentityMatrix.end());
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayAttribute(
+ int64_t display_id, int32_t config, DisplayAttribute attribute,
+ int32_t* value) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ const hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayAttribute(Hwc3ConfigIdToHwc2(config),
+ Hwc3DisplayAttributeToHwc2(attribute),
+ value));
+ return ToBinderStatus(error);
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayCapabilities(
+ int64_t display_id, std::vector<DisplayCapability>* caps) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t num_capabilities = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayCapabilities(&num_capabilities, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<uint32_t> out_caps(num_capabilities);
+ error = Hwc2toHwc3Error(
+ display->GetDisplayCapabilities(&num_capabilities, out_caps.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ caps->reserve(num_capabilities);
+ for (const auto cap : out_caps) {
+ caps->emplace_back(Hwc2DisplayCapabilityToHwc3(cap));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayConfigs(
+ int64_t display_id, std::vector<int32_t>* configs) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t num_configs = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->LegacyGetDisplayConfigs(&num_configs, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<hwc2_config_t> out_configs(num_configs);
+ error = Hwc2toHwc3Error(
+ display->LegacyGetDisplayConfigs(&num_configs, out_configs.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ configs->reserve(num_configs);
+ for (const auto config : out_configs) {
+ configs->emplace_back(Hwc2ConfigIdToHwc3(config));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayConnectionType(
+ int64_t display_id, DisplayConnectionType* type) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t out_type = 0;
+ const hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayConnectionType(&out_type));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ *type = Hwc2DisplayConnectionTypeToHwc3(out_type);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayIdentificationData(
+ int64_t display_id, DisplayIdentification* id) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint8_t port = 0;
+ uint32_t data_size = 0;
+ hwc3::Error error = Hwc2toHwc3Error(
+ display->GetDisplayIdentificationData(&port, &data_size, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ id->data.resize(data_size);
+ error = Hwc2toHwc3Error(
+ display->GetDisplayIdentificationData(&port, &data_size,
+ id->data.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ id->port = static_cast<int8_t>(port);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayName(int64_t display_id,
+ std::string* name) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t size = 0;
+ auto error = Hwc2toHwc3Error(display->GetDisplayName(&size, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ name->resize(size);
+ error = Hwc2toHwc3Error(display->GetDisplayName(&size, name->data()));
+ return ToBinderStatus(error);
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayVsyncPeriod(
+ int64_t display_id, int32_t* vsync_period) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t hwc2_vsync_period = 0;
+ auto error = Hwc2toHwc3Error(
+ display->GetDisplayVsyncPeriod(&hwc2_vsync_period));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ *vsync_period = static_cast<int32_t>(hwc2_vsync_period);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayedContentSample(
+ int64_t /*display_id*/, int64_t /*max_frames*/, int64_t /*timestamp*/,
+ DisplayContentSample* /*samples*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayedContentSamplingAttributes(
+ int64_t /*display_id*/, DisplayContentSamplingAttributes* /*attrs*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayPhysicalOrientation(
+ int64_t display_id, common::Transform* orientation) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ *orientation = common::Transform::NONE;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getHdrCapabilities(int64_t display_id,
+ HdrCapabilities* caps) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ /* No HDR capabilities */
+ caps->types.clear();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getMaxVirtualDisplayCount(int32_t* count) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ *count = static_cast<int32_t>(hwc_->GetMaxVirtualDisplayCount());
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getPerFrameMetadataKeys(
+ int64_t /*display_id*/, std::vector<PerFrameMetadataKey>* /*keys*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getReadbackBufferAttributes(
+ int64_t /*display_id*/, ReadbackBufferAttributes* /*attrs*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getReadbackBufferFence(
+ int64_t /*display_id*/, ndk::ScopedFileDescriptor* /*acquireFence*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getRenderIntents(
+ int64_t display_id, ColorMode mode, std::vector<RenderIntent>* intents) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ const int32_t hwc2_color_mode = Hwc3ColorModeToHwc2(mode);
+ uint32_t out_num_intents = 0;
+ auto error = Hwc2toHwc3Error(
+ display->GetRenderIntents(hwc2_color_mode, &out_num_intents, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<int32_t> out_intents(out_num_intents);
+ error = Hwc2toHwc3Error(display->GetRenderIntents(hwc2_color_mode,
+ &out_num_intents,
+ out_intents.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ intents->reserve(out_num_intents);
+ for (const auto intent : out_intents) {
+ intents->emplace_back(Hwc2RenderIntentToHwc3(intent));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getSupportedContentTypes(
+ int64_t display_id, std::vector<ContentType>* types) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ uint32_t out_num_supported_types = 0;
+ auto error = Hwc2toHwc3Error(
+ display->GetSupportedContentTypes(&out_num_supported_types, nullptr));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ std::vector<uint32_t> out_supported_types(out_num_supported_types);
+ error = Hwc2toHwc3Error(
+ display->GetSupportedContentTypes(&out_num_supported_types,
+ out_supported_types.data()));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ for (const auto type : out_supported_types) {
+ types->push_back(Hwc2ContentTypeToHwc3(type));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayDecorationSupport(
+ int64_t /*display_id*/,
+ std::optional<common::DisplayDecorationSupport>* /*support_struct*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::registerCallback(
+ const std::shared_ptr<IComposerCallback>& callback) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ // This function is specified to be called exactly once.
+ hwc_->Init(callback);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display_id,
+ int32_t config) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ return ToBinderStatus(Hwc2toHwc3Error(display->SetActiveConfig(config)));
+}
+
+ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
+ int64_t display_id, int32_t config,
+ const VsyncPeriodChangeConstraints& constraints,
+ VsyncPeriodChangeTimeline* timeline) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ hwc_vsync_period_change_constraints_t hwc2_constraints;
+ hwc2_constraints.desiredTimeNanos = constraints.desiredTimeNanos;
+ hwc2_constraints.seamlessRequired = static_cast<uint8_t>(
+ constraints.seamlessRequired);
+
+ hwc_vsync_period_change_timeline_t hwc2_timeline{};
+ auto error = Hwc2toHwc3Error(
+ display->SetActiveConfigWithConstraints(config, &hwc2_constraints,
+ &hwc2_timeline));
+ if (error != hwc3::Error::kNone) {
+ return ToBinderStatus(error);
+ }
+
+ timeline->refreshTimeNanos = hwc2_timeline.refreshTimeNanos;
+ timeline->newVsyncAppliedTimeNanos = hwc2_timeline.newVsyncAppliedTimeNanos;
+ timeline->refreshRequired = static_cast<bool>(hwc2_timeline.refreshRequired);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t /*display_id*/,
+ int32_t /*config*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::clearBootDisplayConfig(
+ int64_t /*display_id*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getPreferredBootDisplayConfig(
+ int64_t /*display_id*/, int32_t* /*config*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::setAutoLowLatencyMode(int64_t display_id,
+ bool on) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = Hwc2toHwc3Error(display->SetAutoLowLatencyMode(on));
+ return ToBinderStatus(error);
+}
+
+ndk::ScopedAStatus ComposerClient::setClientTargetSlotCount(int64_t display_id,
+ int32_t count) {
+ DEBUG_FUNC();
+ return ToBinderStatus(
+ composer_resources_->SetDisplayClientTargetCacheSize(display_id, count));
+}
+
+ndk::ScopedAStatus ComposerClient::setColorMode(int64_t display_id,
+ ColorMode mode,
+ RenderIntent intent) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetColorModeWithIntent(Hwc3ColorModeToHwc2(mode),
+ Hwc3RenderIntentToHwc2(intent));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
+}
+
+ndk::ScopedAStatus ComposerClient::setContentType(int64_t display_id,
+ ContentType type) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetContentType(Hwc3ContentTypeToHwc2(type));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
+}
+
+ndk::ScopedAStatus ComposerClient::setDisplayedContentSamplingEnabled(
+ int64_t /*display_id*/, bool /*enable*/,
+ FormatColorComponent /*componentMask*/, int64_t /*maxFrames*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::setPowerMode(int64_t display_id,
+ PowerMode mode) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ if (mode == PowerMode::ON_SUSPEND) {
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+ }
+
+ auto error = display->SetPowerMode(Hwc3PowerModeToHwc2(mode));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
+}
+
+ndk::ScopedAStatus ComposerClient::setReadbackBuffer(
+ int64_t /*display_id*/, const AidlNativeHandle& /*aidlBuffer*/,
+ const ndk::ScopedFileDescriptor& /*releaseFence*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::setVsyncEnabled(int64_t display_id,
+ bool enabled) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ auto error = display->SetVsyncEnabled(static_cast<int32_t>(enabled));
+ return ToBinderStatus(Hwc2toHwc3Error(error));
+}
+
+ndk::ScopedAStatus ComposerClient::setIdleTimerEnabled(int64_t /*display_id*/,
+ int32_t /*timeout*/) {
+ DEBUG_FUNC();
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getOverlaySupport(
+ OverlayProperties* /*out_overlay_properties*/) {
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getHdrConversionCapabilities(
+ std::vector<common::HdrConversionCapability>* /*out_capabilities*/) {
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::setHdrConversionStrategy(
+ const common::HdrConversionStrategy& /*conversion_strategy*/,
+ common::Hdr* /*out_hdr*/) {
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::setRefreshRateChangedCallbackDebugEnabled(
+ int64_t /*display*/, bool /*enabled*/) {
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+ndk::ScopedAStatus ComposerClient::getDisplayConfigurations(
+ int64_t display_id, int32_t /*max_frame_interval_ns*/,
+ std::vector<DisplayConfiguration>* configurations) {
+ DEBUG_FUNC();
+ const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadDisplay);
+ }
+
+ const HwcDisplayConfigs& configs = display->GetDisplayConfigs();
+ for (const auto& [id, config] : configs.hwc_configs) {
+ static const int kNanosecondsPerSecond = 1E9;
+ configurations->emplace_back(
+ DisplayConfiguration{.configId = static_cast<int32_t>(config.id),
+ .width = config.mode.GetRawMode().hdisplay,
+ .height = config.mode.GetRawMode().vdisplay,
+ .configGroup = static_cast<int32_t>(
+ config.group_id),
+ .vsyncPeriod = static_cast<int>(kNanosecondsPerSecond * double(
+ 1 / config.mode.GetVRefresh()))});
+
+ if (configs.mm_width != 0) {
+ // ideally this should be vdisplay/mm_heigth, however mm_height
+ // comes from edid parsing and is highly unreliable. Viewing the
+ // rarity of anisotropic displays, falling back to a single value
+ // for dpi yield more correct output.
+ static const float kMmPerInch = 25.4;
+ float dpi = float(config.mode.GetRawMode().hdisplay) * kMmPerInch /
+ float(configs.mm_width);
+ configurations->back().dpi = {.x = dpi, .y = dpi};
+ }
+
+ // TODO: Populate vrrConfig.
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ComposerClient::notifyExpectedPresent(
+ int64_t /*display*/, const ClockMonotonicTimestamp& /*expected_present_time*/,
+ int32_t /*frame_interval_ns*/) {
+ return ToBinderStatus(hwc3::Error::kUnsupported);
+}
+
+std::string ComposerClient::Dump() {
+ uint32_t size = 0;
+ hwc_->Dump(&size, nullptr);
+
+ std::string buffer(size, '\0');
+ hwc_->Dump(&size, &buffer.front());
+ return buffer;
+}
+
+::ndk::SpAIBinder ComposerClient::createBinder() {
+ auto binder = BnComposerClient::createBinder();
+ AIBinder_setInheritRt(binder.get(), true);
+ return binder;
+}
+
+void ComposerClient::ExecuteSetLayerBuffer(int64_t display_id,
+ HwcLayerWrapper& layer,
+ const Buffer& buffer) {
+ buffer_handle_t imported_buffer = nullptr;
+
+ auto releaser = composer_resources_->CreateResourceReleaser(true);
+ auto err = composer_resources_->GetLayerBuffer(display_id, layer.layer_id,
+ buffer, &imported_buffer,
+ releaser.get());
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence_fd = const_cast<ndk::ScopedFileDescriptor&>(buffer.fence)
+ .release();
+ err = Hwc2toHwc3Error(layer.layer->SetLayerBuffer(imported_buffer, fence_fd));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerBlendMode(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableBlendMode& blend_mode) {
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerBlendMode(
+ Hwc3BlendModeToHwc2(blend_mode.blendMode)));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerComposition(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableComposition& composition) {
+ hwc3::Error error = hwc3::Error::kNone;
+ switch (composition.composition) {
+ // Unsupported composition types should set an error for the current
+ // DisplayCommand.
+ case Composition::DISPLAY_DECORATION:
+ case Composition::SIDEBAND:
+ error = hwc3::Error::kUnsupported;
+ break;
+ default:
+ error = Hwc2toHwc3Error(layer.layer->SetLayerCompositionType(
+ Hwc3CompositionToHwc2(composition.composition)));
+ }
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerDataspace(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableDataspace& dataspace) {
+ auto err = Hwc2toHwc3Error(
+ layer.layer->SetLayerDataspace(Hwc3DataspaceToHwc2(dataspace.dataspace)));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerDisplayFrame(int64_t /*display_id*/,
+ HwcLayerWrapper& layer,
+ const common::Rect& rect) {
+ const hwc_rect_t hwc2_rect{rect.left, rect.top, rect.right, rect.bottom};
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerDisplayFrame(hwc2_rect));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+void ComposerClient::ExecuteSetLayerPlaneAlpha(int64_t /*display_id*/,
+ HwcLayerWrapper& layer,
+ const PlaneAlpha& plane_alpha) {
+ auto err = Hwc2toHwc3Error(
+ layer.layer->SetLayerPlaneAlpha(plane_alpha.alpha));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerSourceCrop(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const common::FRect& source_crop) {
+ const hwc_frect_t rect{source_crop.left, source_crop.top, source_crop.right,
+ source_crop.bottom};
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerSourceCrop(rect));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+void ComposerClient::ExecuteSetLayerTransform(
+ int64_t /*display_id*/, HwcLayerWrapper& layer,
+ const ParcelableTransform& transform) {
+ auto err = Hwc2toHwc3Error(
+ layer.layer->SetLayerTransform(Hwc3TransformToHwc2(transform.transform)));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+void ComposerClient::ExecuteSetLayerZOrder(int64_t /*display_id*/,
+ HwcLayerWrapper& layer,
+ const ZOrder& z_order) {
+ auto err = Hwc2toHwc3Error(layer.layer->SetLayerZOrder(z_order.z));
+ if (err != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(err);
+ }
+}
+
+void ComposerClient::ExecuteSetLayerBrightness(
+ int64_t /*display_id*/, HwcLayerWrapper& /*layer*/,
+ const LayerBrightness& brightness) {
+ if (std::signbit(brightness.brightness) ||
+ std::isnan(brightness.brightness)) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadParameter);
+ }
+}
+
+void ComposerClient::ExecuteSetDisplayBrightness(
+ uint64_t display_id, const DisplayBrightness& command) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ auto error = Hwc2toHwc3Error(
+ display->SetDisplayBrightness(command.brightness));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+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);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ hwc_region_t damage_regions;
+ damage_regions.numRects = command.damage.size();
+
+ std::vector<hwc_rect_t> regions(command.damage.size());
+ for (const auto& region : command.damage) {
+ regions.push_back({region.left, region.top, region.right, region.bottom});
+ }
+ damage_regions.rects = regions.data();
+
+ buffer_handle_t imported_buffer = nullptr;
+ auto buf_releaser = composer_resources_->CreateResourceReleaser(true);
+
+ auto error = composer_resources_->GetDisplayClientTarget(display_id,
+ command.buffer,
+ &imported_buffer,
+ buf_releaser.get());
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence = const_cast<::ndk::ScopedFileDescriptor&>(command.buffer.fence)
+ .release();
+ error = Hwc2toHwc3Error(
+ display->SetClientTarget(imported_buffer, fence,
+ Hwc3DataspaceToHwc2(command.dataspace),
+ damage_regions));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ }
+}
+
+void ComposerClient::ExecuteSetDisplayOutputBuffer(uint64_t display_id,
+ const Buffer& buffer) {
+ auto* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
+ return;
+ }
+
+ buffer_handle_t imported_buffer = nullptr;
+ auto buf_releaser = composer_resources_->CreateResourceReleaser(true);
+
+ auto error = composer_resources_->GetDisplayOutputBuffer(display_id, buffer,
+ &imported_buffer,
+ buf_releaser.get());
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ return;
+ }
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ auto fence = const_cast<::ndk::ScopedFileDescriptor&>(buffer.fence).release();
+ error = Hwc2toHwc3Error(display->SetOutputBuffer(imported_buffer, fence));
+ if (error != hwc3::Error::kNone) {
+ cmd_result_writer_->AddError(error);
+ 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
new file mode 100644
index 0000000..f6362ad
--- /dev/null
+++ b/hwc3/ComposerClient.h
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "aidl/android/hardware/graphics/composer3/BnComposerClient.h"
+#include "aidl/android/hardware/graphics/composer3/LayerCommand.h"
+#include "hwc3/CommandResultWriter.h"
+#include "hwc3/ComposerResources.h"
+#include "hwc3/Utils.h"
+#include "utils/Mutex.h"
+
+using AidlPixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
+using AidlNativeHandle = aidl::android::hardware::common::NativeHandle;
+
+namespace android {
+
+class HwcDisplay;
+class HwcLayer;
+
+} // namespace android
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmHwcThree;
+
+struct HwcLayerWrapper {
+ int64_t layer_id;
+ ::android::HwcLayer* layer;
+};
+
+class ComposerClient : public BnComposerClient {
+ public:
+ ComposerClient();
+ ~ComposerClient() override;
+
+ bool Init();
+ std::string Dump();
+
+ // composer3 interface
+ ndk::ScopedAStatus createLayer(int64_t display, int32_t buffer_slot_count,
+ int64_t* layer) override;
+ ndk::ScopedAStatus createVirtualDisplay(int32_t width, int32_t height,
+ AidlPixelFormat format_hint,
+ int32_t output_buffer_slot_count,
+ VirtualDisplay* display) override;
+ ndk::ScopedAStatus destroyLayer(int64_t display, int64_t layer) override;
+ ndk::ScopedAStatus destroyVirtualDisplay(int64_t display) override;
+ ndk::ScopedAStatus executeCommands(
+ const std::vector<DisplayCommand>& commands,
+ std::vector<CommandResultPayload>* results) override;
+ ndk::ScopedAStatus getActiveConfig(int64_t display, int32_t* config) override;
+ ndk::ScopedAStatus getColorModes(
+ int64_t display, std::vector<ColorMode>* color_modes) override;
+ ndk::ScopedAStatus getDataspaceSaturationMatrix(
+ common::Dataspace dataspace, std::vector<float>* matrix) override;
+ ndk::ScopedAStatus getDisplayAttribute(int64_t display, int32_t config,
+ DisplayAttribute attribute,
+ int32_t* value) override;
+ ndk::ScopedAStatus getDisplayCapabilities(
+ int64_t display, std::vector<DisplayCapability>* caps) override;
+ ndk::ScopedAStatus getDisplayConfigs(int64_t display,
+ std::vector<int32_t>* configs) override;
+ ndk::ScopedAStatus getDisplayConnectionType(
+ int64_t display, DisplayConnectionType* type) override;
+ ndk::ScopedAStatus getDisplayIdentificationData(
+ int64_t display, DisplayIdentification* id) override;
+ ndk::ScopedAStatus getDisplayName(int64_t display,
+ std::string* name) override;
+ ndk::ScopedAStatus getDisplayVsyncPeriod(int64_t display,
+ int32_t* vsync_period) override;
+ ndk::ScopedAStatus getDisplayedContentSample(
+ int64_t display, int64_t max_frames, int64_t timestamp,
+ DisplayContentSample* samples) override;
+ ndk::ScopedAStatus getDisplayedContentSamplingAttributes(
+ int64_t display, DisplayContentSamplingAttributes* attrs) override;
+ ndk::ScopedAStatus getDisplayPhysicalOrientation(
+ int64_t display, common::Transform* orientation) override;
+ ndk::ScopedAStatus getHdrCapabilities(int64_t display,
+ HdrCapabilities* caps) override;
+ ndk::ScopedAStatus getMaxVirtualDisplayCount(int32_t* count) override;
+ ndk::ScopedAStatus getPerFrameMetadataKeys(
+ int64_t display, std::vector<PerFrameMetadataKey>* keys) override;
+ ndk::ScopedAStatus getReadbackBufferAttributes(
+ int64_t display, ReadbackBufferAttributes* attrs) override;
+ ndk::ScopedAStatus getReadbackBufferFence(
+ int64_t display, ndk::ScopedFileDescriptor* acquire_fence) override;
+ ndk::ScopedAStatus getRenderIntents(
+ int64_t display, ColorMode mode,
+ std::vector<RenderIntent>* intents) override;
+ ndk::ScopedAStatus getSupportedContentTypes(
+ int64_t display, std::vector<ContentType>* types) override;
+ ndk::ScopedAStatus getDisplayDecorationSupport(
+ int64_t display,
+ std::optional<common::DisplayDecorationSupport>* support) override;
+ ndk::ScopedAStatus registerCallback(
+ const std::shared_ptr<IComposerCallback>& callback) override;
+ ndk::ScopedAStatus setActiveConfig(int64_t display, int32_t config) override;
+ ndk::ScopedAStatus setActiveConfigWithConstraints(
+ int64_t display, int32_t config,
+ const VsyncPeriodChangeConstraints& constraints,
+ VsyncPeriodChangeTimeline* timeline) override;
+ ndk::ScopedAStatus setBootDisplayConfig(int64_t display,
+ int32_t config) override;
+ ndk::ScopedAStatus clearBootDisplayConfig(int64_t display) override;
+ ndk::ScopedAStatus getPreferredBootDisplayConfig(int64_t display,
+ int32_t* config) override;
+ ndk::ScopedAStatus setAutoLowLatencyMode(int64_t display, bool on) override;
+ ndk::ScopedAStatus setClientTargetSlotCount(int64_t display,
+ int32_t count) override;
+ ndk::ScopedAStatus setColorMode(int64_t display, ColorMode mode,
+ RenderIntent intent) override;
+ ndk::ScopedAStatus setContentType(int64_t display, ContentType type) override;
+ ndk::ScopedAStatus setDisplayedContentSamplingEnabled(
+ int64_t display, bool enable, FormatColorComponent component_mask,
+ int64_t max_frames) override;
+ ndk::ScopedAStatus setPowerMode(int64_t display, PowerMode mode) override;
+ ndk::ScopedAStatus setReadbackBuffer(
+ int64_t display, const AidlNativeHandle& buffer,
+ const ndk::ScopedFileDescriptor& release_fence) override;
+ ndk::ScopedAStatus setVsyncEnabled(int64_t display, bool enabled) override;
+ ndk::ScopedAStatus setIdleTimerEnabled(int64_t display,
+ int32_t timeout) override;
+ ndk::ScopedAStatus getOverlaySupport(
+ OverlayProperties* out_overlay_properties) override;
+ ndk::ScopedAStatus getHdrConversionCapabilities(
+ std::vector<common::HdrConversionCapability>* out_capabilities) override;
+ ndk::ScopedAStatus setHdrConversionStrategy(
+ const common::HdrConversionStrategy& conversion_strategy,
+ common::Hdr* out_hdr) override;
+ ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(
+ int64_t display, bool enabled) override;
+ ndk::ScopedAStatus getDisplayConfigurations(
+ int64_t display, int32_t max_frame_interval_ns,
+ std::vector<DisplayConfiguration>* configurations) override;
+ ndk::ScopedAStatus notifyExpectedPresent(
+ int64_t display, const ClockMonotonicTimestamp& expected_present_time,
+ int32_t frame_interval_ns) override;
+
+ protected:
+ ::ndk::SpAIBinder createBinder() override;
+
+ private:
+ // Layer commands
+ void DispatchLayerCommand(int64_t display_id, const LayerCommand& command);
+ void ExecuteSetLayerBuffer(int64_t display_id, HwcLayerWrapper& layer_id,
+ const Buffer& buffer);
+ void ExecuteSetLayerBlendMode(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableBlendMode& blend_mode);
+ void ExecuteSetLayerComposition(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableComposition& composition);
+ void ExecuteSetLayerDataspace(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableDataspace& dataspace);
+ void ExecuteSetLayerDisplayFrame(int64_t display_id, HwcLayerWrapper& layer,
+ const common::Rect& rect);
+ void ExecuteSetLayerPlaneAlpha(int64_t display_id, HwcLayerWrapper& layer,
+ const PlaneAlpha& plane_alpha);
+ void ExecuteSetLayerSourceCrop(int64_t display_id, HwcLayerWrapper& layer,
+ const common::FRect& source_crop);
+ void ExecuteSetLayerTransform(int64_t display_id, HwcLayerWrapper& layer,
+ const ParcelableTransform& transform);
+ void ExecuteSetLayerZOrder(int64_t display_id, HwcLayerWrapper& layer,
+ const ZOrder& z_order);
+ void ExecuteSetLayerBrightness(int64_t display_id, HwcLayerWrapper& layer,
+ const LayerBrightness& brightness);
+
+ // Display commands
+ void ExecuteDisplayCommand(const DisplayCommand& command);
+ void ExecuteSetDisplayBrightness(uint64_t display_id,
+ const DisplayBrightness& 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);
+
+ std::unique_ptr<CommandResultWriter> cmd_result_writer_;
+
+ // Manages importing and caching gralloc buffers for displays and layers.
+ std::unique_ptr<ComposerResources> composer_resources_;
+
+ std::unique_ptr<DrmHwcThree> hwc_;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/ComposerResources.cpp b/hwc3/ComposerResources.cpp
new file mode 100644
index 0000000..ae0edf4
--- /dev/null
+++ b/hwc3/ComposerResources.cpp
@@ -0,0 +1,202 @@
+
+/*
+ * 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"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "ComposerResources.h"
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+#include "hardware/hwcomposer2.h"
+#include "hwc3/Utils.h"
+
+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);
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::Create() {
+ auto instance = std::unique_ptr<ComposerResources>(new ComposerResources);
+ if (instance->resources_ == nullptr) {
+ ALOGE("%s: Failed to initialise ComposerResources", __func__);
+ return nullptr;
+ }
+
+ return instance;
+}
+
+hwc3::Error ComposerResources::GetLayerBuffer(
+ uint64_t display_id, int64_t layer_id, const Buffer& buffer,
+ buffer_handle_t* out_buffer_handle,
+ ComposerResourceReleaser* buf_releaser) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ const bool use_cache = !buffer.handle.has_value();
+ buffer_handle_t buffer_handle = nullptr;
+ if (buffer.handle.has_value()) {
+ buffer_handle = ::android::makeFromAidl(*buffer.handle);
+ }
+
+ auto err = resources_->getLayerBuffer(display, layer, buffer.slot, use_cache,
+ buffer_handle, out_buffer_handle,
+ buf_releaser->GetReplacedHandle());
+
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetLayerSidebandStream(
+ uint64_t display_id, int64_t layer_id,
+ const aidl::android::hardware::common::NativeHandle& handle,
+ buffer_handle_t* out_handle, ComposerResourceReleaser* releaser) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ auto err = resources_->getLayerSidebandStream(display, layer,
+ ::android::makeFromAidl(handle),
+ out_handle,
+ releaser->GetReplacedHandle());
+
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::AddLayer(uint64_t display_id, int64_t layer_id,
+ uint32_t buffer_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ auto err = resources_->addLayer(display, layer, buffer_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::RemoveLayer(uint64_t display_id,
+ int64_t layer_id) {
+ auto display = ToHwc2Display(display_id);
+ auto layer = ToHwc2Layer(layer_id);
+
+ auto err = resources_->removeLayer(display, layer);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+bool ComposerResources::HasDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ return resources_->hasDisplay(display);
+}
+
+hwc3::Error ComposerResources::AddPhysicalDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->addPhysicalDisplay(display);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::AddVirtualDisplay(
+ uint64_t display, uint32_t output_buffer_cache_size) {
+ auto err = resources_->addVirtualDisplay(display, output_buffer_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::RemoveDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->removeDisplay(display);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+void ComposerResources::SetDisplayMustValidateState(uint64_t display_id,
+ bool must_validate) {
+ auto display = ToHwc2Display(display_id);
+ resources_->setDisplayMustValidateState(display, must_validate);
+}
+
+bool ComposerResources::MustValidateDisplay(uint64_t display_id) {
+ auto display = ToHwc2Display(display_id);
+ return resources_->mustValidateDisplay(display);
+}
+
+hwc3::Error ComposerResources::GetDisplayClientTarget(
+ uint64_t display_id, const Buffer& buffer, buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser) {
+ auto display = ToHwc2Display(display_id);
+
+ const bool use_cache = !buffer.handle.has_value();
+ buffer_handle_t buffer_handle = nullptr;
+ if (buffer.handle.has_value()) {
+ buffer_handle = ::android::makeFromAidl(*buffer.handle);
+ }
+
+ auto err = resources_->getDisplayClientTarget(display, buffer.slot, use_cache,
+ buffer_handle, out_handle,
+ releaser->GetReplacedHandle());
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::SetDisplayClientTargetCacheSize(
+ uint64_t display_id, uint32_t client_target_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_
+ ->setDisplayClientTargetCacheSize(display,
+ client_target_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetDisplayClientTargetCacheSize(
+ uint64_t display_id, size_t* out_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->getDisplayClientTargetCacheSize(display,
+ out_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetDisplayOutputBufferCacheSize(
+ uint64_t display_id, size_t* out_cache_size) {
+ auto display = ToHwc2Display(display_id);
+ auto err = resources_->getDisplayOutputBufferCacheSize(display,
+ out_cache_size);
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+
+hwc3::Error ComposerResources::GetDisplayOutputBuffer(
+ uint64_t display_id, const Buffer& buffer, buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser) {
+ auto display = ToHwc2Display(display_id);
+ const bool use_cache = !buffer.handle.has_value();
+
+ buffer_handle_t buffer_handle = nullptr;
+ if (buffer.handle.has_value()) {
+ buffer_handle = ::android::makeFromAidl(*buffer.handle);
+ }
+
+ auto err = resources_->getDisplayOutputBuffer(display, buffer.slot, use_cache,
+ buffer_handle, out_handle,
+ releaser->GetReplacedHandle());
+ return Hwc2toHwc3Error(static_cast<HWC2::Error>(err));
+}
+} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/hwc3/ComposerResources.h b/hwc3/ComposerResources.h
new file mode 100644
index 0000000..6f4eee7
--- /dev/null
+++ b/hwc3/ComposerResources.h
@@ -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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "aidl/android/hardware/graphics/composer3/IComposerClient.h"
+#include "composer-resources/2.2/ComposerResources.h"
+#include "cutils/native_handle.h"
+#include "hwc3/Utils.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class ComposerResourceReleaser {
+ public:
+ explicit ComposerResourceReleaser(bool is_buffer)
+ : replaced_handle_(is_buffer) {
+ }
+ virtual ~ComposerResourceReleaser() = default;
+
+ ::android::hardware::graphics::composer::V2_2::hal::ComposerResources::
+ ReplacedHandle*
+ GetReplacedHandle() {
+ return &replaced_handle_;
+ }
+
+ private:
+ ::android::hardware::graphics::composer::V2_2::hal::ComposerResources::
+ ReplacedHandle replaced_handle_;
+};
+
+class ComposerResources {
+ public:
+ static std::unique_ptr<ComposerResources> Create();
+ ~ComposerResources() = default;
+
+ hwc3::Error GetLayerBuffer(uint64_t display_id, int64_t layer_id,
+ const Buffer& buffer,
+ buffer_handle_t* out_buffer_handle,
+ ComposerResourceReleaser* releaser);
+ hwc3::Error GetLayerSidebandStream(
+ uint64_t display_id, int64_t layer_id,
+ const aidl::android::hardware::common::NativeHandle& handle,
+ buffer_handle_t* out_handle, ComposerResourceReleaser* releaser);
+
+ hwc3::Error AddLayer(uint64_t display, int64_t layer,
+ uint32_t buffer_cache_size);
+ hwc3::Error RemoveLayer(uint64_t display, int64_t layer);
+
+ bool HasDisplay(uint64_t display);
+ hwc3::Error AddPhysicalDisplay(uint64_t display);
+ hwc3::Error AddVirtualDisplay(uint64_t display,
+ uint32_t output_buffer_cache_size);
+ hwc3::Error RemoveDisplay(uint64_t display);
+
+ void SetDisplayMustValidateState(uint64_t display_id, bool must_validate);
+ bool MustValidateDisplay(uint64_t display_id);
+
+ hwc3::Error GetDisplayClientTarget(uint64_t display_id, const Buffer& buffer,
+ buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser);
+
+ hwc3::Error SetDisplayClientTargetCacheSize(
+ uint64_t display_id, uint32_t client_target_cache_size);
+ hwc3::Error GetDisplayClientTargetCacheSize(uint64_t display_id,
+ size_t* out_cache_size);
+ hwc3::Error GetDisplayOutputBufferCacheSize(uint64_t display,
+ size_t* out_cache_size);
+ hwc3::Error GetDisplayOutputBuffer(uint64_t display_id, const Buffer& buffer,
+ buffer_handle_t* out_handle,
+ ComposerResourceReleaser* releaser);
+
+ static std::unique_ptr<ComposerResourceReleaser> CreateResourceReleaser(
+ bool is_buffer);
+
+ private:
+ ComposerResources() = default;
+
+ std::unique_ptr<
+ ::android::hardware::graphics::composer::V2_2::hal::ComposerResources>
+ resources_ = ::android::hardware::graphics::composer::V2_2::hal::
+ ComposerResources::create();
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/hwc3/DrmHwcThree.cpp b/hwc3/DrmHwcThree.cpp
new file mode 100644
index 0000000..d758865
--- /dev/null
+++ b/hwc3/DrmHwcThree.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#include "DrmHwcThree.h"
+
+#include <cinttypes>
+
+#include "Utils.h"
+#include "aidl/android/hardware/graphics/common/Dataspace.h"
+#include "aidl/android/hardware/graphics/common/DisplayHotplugEvent.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+using ::android::HwcDisplay;
+
+DrmHwcThree::~DrmHwcThree() {
+ /* Display deinit routine is handled by resource manager */
+ GetResMan().DeInit();
+}
+
+void DrmHwcThree::Init(std::shared_ptr<IComposerCallback> callback) {
+ composer_callback_ = std::move(callback);
+ GetResMan().Init();
+}
+
+void DrmHwcThree::SendVsyncPeriodTimingChangedEventToClient(
+ uint64_t display_id, int64_t timestamp) const {
+ VsyncPeriodChangeTimeline timeline;
+ timeline.newVsyncAppliedTimeNanos = timestamp;
+ timeline.refreshRequired = false;
+ timeline.refreshTimeNanos = 0;
+
+ composer_callback_->onVsyncPeriodTimingChanged(static_cast<int64_t>(
+ display_id),
+ timeline);
+}
+
+void DrmHwcThree::SendRefreshEventToClient(uint64_t display_id) {
+ composer_resources_->SetDisplayMustValidateState(display_id, true);
+ composer_callback_->onRefresh(static_cast<int64_t>(display_id));
+}
+
+void DrmHwcThree::SendVsyncEventToClient(uint64_t display_id, int64_t timestamp,
+ uint32_t vsync_period) const {
+ composer_callback_->onVsync(static_cast<int64_t>(display_id), timestamp,
+ static_cast<int32_t>(vsync_period));
+}
+
+void DrmHwcThree::SendHotplugEventToClient(hwc2_display_t display_id,
+ bool connected) {
+ HandleDisplayHotplugEvent(static_cast<uint64_t>(display_id), connected);
+ common::DisplayHotplugEvent event = connected ? common::DisplayHotplugEvent::CONNECTED : common::DisplayHotplugEvent::DISCONNECTED;
+ composer_callback_->onHotplugEvent(static_cast<int64_t>(display_id), event);
+}
+
+void DrmHwcThree::CleanDisplayResources(uint64_t display_id) {
+ DEBUG_FUNC();
+ HwcDisplay* display = GetDisplay(display_id);
+ if (display == nullptr) {
+ return;
+ }
+
+ display->SetPowerMode(static_cast<int32_t>(PowerMode::OFF));
+
+ size_t cache_size = 0;
+ auto err = composer_resources_->GetDisplayClientTargetCacheSize(display_id,
+ &cache_size);
+ if (err != hwc3::Error::kNone) {
+ ALOGE("%s: Could not clear target buffer cache for display: %" PRIu64,
+ __func__, display_id);
+ return;
+ }
+
+ for (size_t slot = 0; slot < cache_size; slot++) {
+ buffer_handle_t buffer_handle = nullptr;
+ auto buf_releaser = ComposerResources::CreateResourceReleaser(true);
+
+ Buffer buf{};
+ buf.slot = static_cast<int32_t>(slot);
+ err = composer_resources_->GetDisplayClientTarget(display_id, buf,
+ &buffer_handle,
+ buf_releaser.get());
+ if (err != hwc3::Error::kNone) {
+ continue;
+ }
+
+ err = Hwc2toHwc3Error(
+ display->SetClientTarget(buffer_handle, -1,
+ static_cast<int32_t>(
+ common::Dataspace::UNKNOWN),
+ {}));
+ if (err != hwc3::Error::kNone) {
+ ALOGE(
+ "%s: Could not clear slot %zu of the target buffer cache for "
+ "display %" PRIu64,
+ __func__, slot, display_id);
+ }
+ }
+}
+
+void DrmHwcThree::HandleDisplayHotplugEvent(uint64_t display_id,
+ bool connected) {
+ DEBUG_FUNC();
+ if (!connected) {
+ composer_resources_->RemoveDisplay(display_id);
+ Displays().erase(display_id);
+ return;
+ }
+
+ if (composer_resources_->HasDisplay(display_id)) {
+ /* Cleanup existing display resources */
+ CleanDisplayResources(display_id);
+ composer_resources_->RemoveDisplay(display_id);
+ Displays().erase(display_id);
+ }
+ composer_resources_->AddPhysicalDisplay(display_id);
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/DrmHwcThree.h b/hwc3/DrmHwcThree.h
new file mode 100644
index 0000000..8ba96c6
--- /dev/null
+++ b/hwc3/DrmHwcThree.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
+
+#include "drm/DrmHwc.h"
+#include "hwc3/ComposerResources.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmHwcThree : public ::android::DrmHwc {
+ public:
+ explicit DrmHwcThree(ComposerResources* composer_resources)
+ : composer_resources_(composer_resources) {
+ }
+ ~DrmHwcThree() override;
+
+ void Init(std::shared_ptr<IComposerCallback> callback);
+
+ // DrmHwcInterface
+ void SendVsyncEventToClient(hwc2_display_t display_id, int64_t timestamp,
+ uint32_t vsync_period) const override;
+ void SendVsyncPeriodTimingChangedEventToClient(
+ hwc2_display_t display_id, int64_t timestamp) const override;
+ void SendRefreshEventToClient(uint64_t display_id) override;
+ void SendHotplugEventToClient(hwc2_display_t display_id,
+ bool connected) override;
+
+ private:
+ void CleanDisplayResources(uint64_t display_id);
+ void HandleDisplayHotplugEvent(uint64_t display_id, bool connected);
+
+ std::shared_ptr<IComposerCallback> composer_callback_;
+ ComposerResources* composer_resources_;
+};
+} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/hwc3/Utils.cpp b/hwc3/Utils.cpp
new file mode 100644
index 0000000..adbd2fb
--- /dev/null
+++ b/hwc3/Utils.cpp
@@ -0,0 +1,58 @@
+
+/*
+ * 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"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include "Utils.h"
+
+#include <hardware/hwcomposer2.h>
+
+#include "utils/log.h"
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+hwc3::Error Hwc2toHwc3Error(HWC2::Error error) {
+ switch (error) {
+ case HWC2::Error::None:
+ return hwc3::Error::kNone;
+ case HWC2::Error::BadConfig:
+ return hwc3::Error::kBadConfig;
+ case HWC2::Error::BadDisplay:
+ return hwc3::Error::kBadDisplay;
+ case HWC2::Error::BadLayer:
+ return hwc3::Error::kBadLayer;
+ case HWC2::Error::BadParameter:
+ return hwc3::Error::kBadParameter;
+ case HWC2::Error::NoResources:
+ return hwc3::Error::kNoResources;
+ case HWC2::Error::NotValidated:
+ return hwc3::Error::kNotValidated;
+ case HWC2::Error::Unsupported:
+ return hwc3::Error::kUnsupported;
+ case HWC2::Error::SeamlessNotAllowed:
+ return hwc3::Error::kSeamlessNotAllowed;
+ case HWC2::Error::SeamlessNotPossible:
+ return hwc3::Error::kSeamlessNotPossible;
+ default:
+ ALOGE("Unknown HWC2 error. Could not translate to HWC3 error: %d",
+ static_cast<int32_t>(error));
+ return hwc3::Error::kUnsupported;
+ }
+}
+
+}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/Utils.h b/hwc3/Utils.h
new file mode 100644
index 0000000..23d6bdc
--- /dev/null
+++ b/hwc3/Utils.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <hardware/hwcomposer2.h>
+
+#include <cstdint>
+
+// NOLINTNEXTLINE
+#define DEBUG_FUNC() ALOGV("%s", __func__)
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+namespace hwc3 {
+enum class Error : int32_t {
+ kNone = 0,
+ kBadConfig = IComposerClient::EX_BAD_CONFIG,
+ kBadDisplay = IComposerClient::EX_BAD_DISPLAY,
+ kBadLayer = IComposerClient::EX_BAD_LAYER,
+ kBadParameter = IComposerClient::EX_BAD_PARAMETER,
+ kNoResources = IComposerClient::EX_NO_RESOURCES,
+ kNotValidated = IComposerClient::EX_NOT_VALIDATED,
+ kUnsupported = IComposerClient::EX_UNSUPPORTED,
+ kSeamlessNotAllowed = IComposerClient::EX_SEAMLESS_NOT_ALLOWED,
+ kSeamlessNotPossible = IComposerClient::EX_SEAMLESS_NOT_POSSIBLE,
+};
+} // namespace hwc3
+
+hwc3::Error Hwc2toHwc3Error(HWC2::Error error);
+
+inline ndk::ScopedAStatus ToBinderStatus(hwc3::Error error) {
+ if (error != hwc3::Error::kNone) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(error));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+inline ndk::ScopedAStatus ToBinderStatus(HWC2::Error error) {
+ return ToBinderStatus(Hwc2toHwc3Error(error));
+}
+
+// ID conversion. HWC2 uses typedef'd unsigned integer types while HWC3 uses
+// signed integer types. static_cast in between these.
+inline int64_t Hwc2LayerToHwc3(hwc2_layer_t layer) {
+ return static_cast<int64_t>(layer);
+}
+
+inline int64_t Hwc2DisplayToHwc3(hwc2_display_t display) {
+ return static_cast<int64_t>(display);
+}
+
+inline int32_t Hwc2ConfigIdToHwc3(hwc2_config_t config_id) {
+ return static_cast<int32_t>(config_id);
+}
+
+inline hwc2_layer_t Hwc3LayerToHwc2(int64_t layer) {
+ return static_cast<hwc2_layer_t>(layer);
+}
+
+inline hwc2_display_t Hwc3DisplayToHwc2(int64_t display) {
+ return static_cast<hwc2_display_t>(display);
+}
+
+inline hwc2_config_t Hwc3ConfigIdToHwc2(int32_t config_id) {
+ return static_cast<hwc2_config_t>(config_id);
+}
+
+// Values match up to HWC2_COMPOSITION_SIDEBAND, with HWC2 not supporting
+// newer values. static_cast in between shared values.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24;l=826
+inline Composition Hwc2CompositionTypeToHwc3(int32_t composition_type) {
+ if (composition_type < HWC2_COMPOSITION_INVALID ||
+ composition_type > HWC2_COMPOSITION_SIDEBAND) {
+ return Composition::INVALID;
+ }
+ return static_cast<Composition>(composition_type);
+}
+
+inline int32_t Hwc3CompositionToHwc2(Composition composition_type) {
+ if (composition_type > Composition::SIDEBAND) {
+ return HWC2_COMPOSITION_INVALID;
+ }
+ return static_cast<int32_t>(composition_type);
+}
+
+// Values for color modes match across HWC versions, so static cast is safe:
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/ColorMode.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=118
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.1.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=35
+inline ColorMode Hwc2ColorModeToHwc3(int32_t color_mode) {
+ return static_cast<ColorMode>(color_mode);
+}
+
+inline int32_t Hwc3ColorModeToHwc2(ColorMode color_mode) {
+ return static_cast<int32_t>(color_mode);
+}
+
+// Capabilities match up to DisplayCapability::AUTO_LOW_LATENCY_MODE, with hwc2
+// not defining capabilities beyond that.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl#28
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e;l=418
+inline DisplayCapability Hwc2DisplayCapabilityToHwc3(
+ uint32_t display_capability) {
+ if (display_capability > HWC2_DISPLAY_CAPABILITY_AUTO_LOW_LATENCY_MODE) {
+ return DisplayCapability::INVALID;
+ }
+ return static_cast<DisplayCapability>(display_capability);
+}
+
+// Values match between hwc versions, so static cast is safe.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConnectionType.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=216;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24;bpv=0;bpt=1
+inline DisplayConnectionType Hwc2DisplayConnectionTypeToHwc3(uint32_t type) {
+ if (type > HWC2_DISPLAY_CONNECTION_TYPE_EXTERNAL) {
+ // Arbitrarily return EXTERNAL in this case, which shouldn't happen.
+ // TODO: This will be cleaned up once hwc2<->hwc3 conversion is removed.
+ ALOGE("Unknown HWC2 connection type. Could not translate: %d", type);
+ return DisplayConnectionType::EXTERNAL;
+ }
+ return static_cast<DisplayConnectionType>(type);
+}
+
+// Values match, so static_cast is safe.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/RenderIntent.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.1.h;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2;l=37
+inline RenderIntent Hwc2RenderIntentToHwc3(int32_t intent) {
+ if (intent < HAL_RENDER_INTENT_COLORIMETRIC ||
+ intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE) {
+ ALOGE("Unknown HWC2 render intent. Could not translate: %d", intent);
+ return RenderIntent::COLORIMETRIC;
+ }
+ return static_cast<RenderIntent>(intent);
+}
+inline int32_t Hwc3RenderIntentToHwc2(RenderIntent render_intent) {
+ return static_cast<int32_t>(render_intent);
+}
+
+// Content type matches, so static_cast is safe.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/ContentType.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=350;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e
+inline ContentType Hwc2ContentTypeToHwc3(uint32_t content_type) {
+ if (content_type > HWC2_CONTENT_TYPE_GAME) {
+ ALOGE("Unknown HWC2 content type. Could not translate: %d", content_type);
+ return ContentType::NONE;
+ }
+ return static_cast<ContentType>(content_type);
+}
+inline int32_t Hwc3ContentTypeToHwc2(ContentType content_type) {
+ return static_cast<int32_t>(content_type);
+}
+
+// Values match, so it's safe to do static_cast.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayAttribute.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=58;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24
+inline int32_t Hwc3DisplayAttributeToHwc2(DisplayAttribute display_attribute) {
+ return static_cast<int32_t>(display_attribute);
+}
+
+// Values match up to DOZE_SUSPEND.
+// https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/main/graphics/composer/aidl/android/hardware/graphics/composer3/PowerMode.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=348;drc=d783cabd4d9bddb4b83f2dd38300b7598bb58b24
+inline int32_t Hwc3PowerModeToHwc2(PowerMode power_mode) {
+ if (power_mode > PowerMode::DOZE_SUSPEND) {
+ ALOGE("Unsupported HWC2 power mode. Could not translate: %d", power_mode);
+ return HWC2_POWER_MODE_ON;
+ }
+ return static_cast<int32_t>(power_mode);
+}
+
+// Values match, so static_cast is okay.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/BlendMode.aidl;drc=bab1ba54ede32520a5042d616a3af46ad4f55d5f;l=25
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/libhardware/include_all/hardware/hwcomposer2.h;l=72;drc=1a0e4a1698c7b080d6763cef9e16592bce75967e
+inline int32_t Hwc3BlendModeToHwc2(common::BlendMode blend_mode) {
+ return static_cast<int32_t>(blend_mode);
+}
+
+// Values appear to match.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=43
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.1.h;l=22;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2
+inline int32_t Hwc3DataspaceToHwc2(common::Dataspace dataspace) {
+ return static_cast<int32_t>(dataspace);
+}
+
+// Values match, so static_cast is okay.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Transform.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=41
+inline int32_t Hwc3TransformToHwc2(common::Transform transform) {
+ return static_cast<int32_t>(transform);
+}
+
+}; // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
diff --git a/hwc3/hwc3-drm.rc b/hwc3/hwc3-drm.rc
new file mode 100644
index 0000000..425dd24
--- /dev/null
+++ b/hwc3/hwc3-drm.rc
@@ -0,0 +1,8 @@
+service vendor.hwcomposer-3 /vendor/bin/hw/android.hardware.composer.hwc3-service.drm
+ class hal animation
+ interface aidl android.hardware.graphics.composer3.IComposer/default
+ user system
+ group graphics drmrpc
+ capabilities SYS_NICE
+ onrestart restart surfaceflinger
+ task_profiles ServiceCapacityLow
diff --git a/hwc3/hwc3-drm.xml b/hwc3/hwc3-drm.xml
new file mode 100644
index 0000000..911f7f8
--- /dev/null
+++ b/hwc3/hwc3-drm.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.graphics.composer3</name>
+ <version>3</version>
+ <interface>
+ <name>IComposer</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/hwc3/meson.build b/hwc3/meson.build
new file mode 100644
index 0000000..2486212
--- /dev/null
+++ b/hwc3/meson.build
@@ -0,0 +1,34 @@
+
+src_hwc3 = files(
+ 'ComposerClient.cpp',
+ 'Composer.cpp',
+ 'DrmHwcThree.cpp',
+ 'service.cpp',
+ 'ComposerResources.cpp',
+ 'Utils.cpp',
+)
+
+executable(
+ 'android.hardware.composer.hwc3-service.drm',
+ src_hwc3,
+ cpp_args : common_cpp_flags + hwc2_cpp_flags,
+ dependencies : deps,
+ install : true,
+ link_with: [drmhwc_common, drmhwc_hwc2_common],
+ install_dir : get_option('bindir') / 'hw',
+ include_directories: inc_include,
+)
+
+configure_file(
+ input: 'hwc3-drm.rc',
+ output: '@PLAINNAME@',
+ copy: true,
+ install_dir: get_option('sysconfdir') / 'init',
+)
+
+configure_file(
+ input: 'hwc3-drm.xml',
+ output: '@PLAINNAME@',
+ copy: true,
+ install_dir: get_option('sysconfdir') / 'vintf' / 'manifest',
+)
diff --git a/hwc3/service.cpp b/hwc3/service.cpp
new file mode 100644
index 0000000..920260a
--- /dev/null
+++ b/hwc3/service.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 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"
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/ProcessState.h>
+#include <sched.h>
+
+#include "Composer.h"
+#include "utils/log.h"
+
+using aidl::android::hardware::graphics::composer3::impl::Composer;
+
+int main(int /*argc*/, char* argv[]) {
+ (void)argv;
+ ALOGI("hwc3-drm starting up");
+
+ // same as SF main thread
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+ }
+
+ auto composer = ndk::SharedRefBase::make<Composer>();
+ if (!composer) {
+ ALOGE("Failed to create composer");
+ return -ENOMEM;
+ }
+
+ const std::string instance = std::string() + Composer::descriptor +
+ "/default";
+ ALOGI("HWC3 service name %s", instance.c_str());
+ auto status = AServiceManager_addServiceWithFlags(
+ composer->asBinder().get(), instance.c_str(),
+ AServiceManager_AddServiceFlag::ADD_SERVICE_ALLOW_ISOLATED);
+ if (status != STATUS_OK) {
+ ALOGE("Failed to register service. Error %d", (int)status);
+ return -EINVAL;
+ }
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/meson.build b/meson.build
index c2e5fb6..e9a86ec 100644
--- a/meson.build
+++ b/meson.build
@@ -1,7 +1,7 @@
project(
'drm_hwcomposer',
['c', 'cpp'],
- version : '2',
+ version : '3',
license : 'APACHE-2.0',
meson_version : '>= 0.56',
default_options : ['buildtype=debugoptimized', 'b_ndebug=if-release', 'c_std=c11', 'cpp_std=c++17', 'cpp_rtti=false']
@@ -18,6 +18,14 @@
'utils/fd.cpp',
)
+srcs_hwc2_device = [
+ 'hwc2_device/hwc2_device.cpp',
+ 'hwc2_device/DrmHwcTwo.cpp',
+ 'hwc2_device/HwcDisplayConfigs.cpp',
+ 'hwc2_device/HwcDisplay.cpp',
+ 'hwc2_device/HwcLayer.cpp',
+]
+
deps = [
dependency('cutils'),
dependency('drm'),
@@ -27,6 +35,9 @@
dependency('sync'),
dependency('ui'),
dependency('utils'),
+ dependency('aidlcommonsupport'),
+ dependency('android.hardware.graphics.composer@2.1-resources'),
+ dependency('android.hardware.graphics.composer@2.2-resources'),
]
common_cpp_flags = [
@@ -50,3 +61,4 @@
)
subdir('hwc2_device')
+subdir('hwc3')
diff --git a/utils/UEvent.h b/utils/UEvent.h
index 5b9ecea..051b1fc 100644
--- a/utils/UEvent.h
+++ b/utils/UEvent.h
@@ -17,6 +17,8 @@
#pragma once
#include <linux/netlink.h>
+#include <poll.h>
+#include <sys/eventfd.h>
#include <sys/socket.h>
#include <cerrno>
@@ -52,12 +54,23 @@
return {};
}
- return std::unique_ptr<UEvent>(new UEvent(fd));
+ auto stop_event_fd = MakeUniqueFd(eventfd(0, EFD_CLOEXEC));
+ if (!stop_event_fd) {
+ ALOGE("Failed to create eventfd: errno=%i", errno);
+ return {};
+ }
+
+ return std::unique_ptr<UEvent>(new UEvent(fd, stop_event_fd));
}
auto ReadNext() -> std::optional<std::string> {
constexpr int kUEventBufferSize = 1024;
char buffer[kUEventBufferSize];
+
+ if (!WaitForData()) {
+ return {};
+ }
+
ssize_t ret = 0;
ret = read(*fd_, &buffer, sizeof(buffer));
if (ret == 0)
@@ -77,9 +90,57 @@
return std::string(buffer);
}
+ void Stop() {
+ // Increment the eventfd by writing 1. All subsequent calls to ReadNext will
+ // return false.
+ const uint64_t value = 1;
+ const ssize_t ret = write(*stop_event_fd_, &value, sizeof(value));
+ if (ret == -1) {
+ ALOGE("Error writing to eventfd. errno: %d", errno);
+ } else if (ret != sizeof(value)) {
+ ALOGE("Wrote fewer bytes to eventfd than expected: %zd vs %zd", ret,
+ sizeof(value));
+ }
+ }
+
private:
- explicit UEvent(UniqueFd &fd) : fd_(std::move(fd)){};
+ enum { kFdIdx = 0, kStopEventFdIdx, kNumFds };
+
+ UEvent(UniqueFd &fd, UniqueFd &stop_event_fd)
+ : fd_(std::move(fd)), stop_event_fd_(std::move(stop_event_fd)) {};
+
+ // Returns true if there is data to be read off of fd_.
+ bool WaitForData() {
+ struct pollfd poll_fds[kNumFds];
+ poll_fds[kFdIdx].fd = *fd_;
+ poll_fds[kFdIdx].events = POLLIN;
+ poll_fds[kStopEventFdIdx].fd = *stop_event_fd_;
+ poll_fds[kStopEventFdIdx].events = POLLIN;
+
+ const int ret = poll(poll_fds, kNumFds, -1);
+ if (ret == 0) {
+ // Timeout shouldn't happen, but return here anyways.
+ ALOGE("Timed out polling uevent.");
+ return false;
+ }
+ if (ret < 1) {
+ ALOGE("Error polling uevent. errno: %d", errno);
+ return false;
+ }
+
+ if ((poll_fds[kStopEventFdIdx].revents & POLLIN) != 0) {
+ // Stop event has been signalled. Return without reading from the fd to
+ // ensure that this fd stays in a readable state.
+ ALOGI("Stop event signalled.");
+ return false;
+ }
+
+ // Return true if there is data to read.
+ return (poll_fds[kFdIdx].revents & POLLIN) != 0;
+ }
+
UniqueFd fd_;
+ UniqueFd stop_event_fd_;
};
} // namespace android