aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Stultz <jstultz@google.com>2023-07-12 21:27:56 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-07-12 21:27:56 +0000
commit5365831dfb10183120ae79ae26ce044812c9346c (patch)
tree00306ed4f9d015e1c768b64bcad078bf9069ea04
parentdd74ccbf173a31d24b60ba9ffaf9db10dfa7ab05 (diff)
parent197c32dc5b1164f1837edcea32c12bd2d4cf8e77 (diff)
downloaddrm_hwcomposer-5365831dfb10183120ae79ae26ce044812c9346c.tar.gz
Merge remote-tracking branch 'aosp/upstream-main' into HEAD am: 197c32dc5b
Original change: https://android-review.googlesource.com/c/platform/external/drm_hwcomposer/+/2641990 Change-Id: I19726e1cd7ba3c191e8f0ab484fcce5f94511190 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rwxr-xr-x.ci/.gitlab-ci-checkcommit.sh13
-rw-r--r--.ci/Dockerfile52
-rw-r--r--.ci/Makefile13
-rw-r--r--.gitlab-ci.yml27
-rw-r--r--Android.bp37
-rw-r--r--Makefile95
-rw-r--r--README.md2
-rw-r--r--backend/Backend.cpp60
-rw-r--r--backend/Backend.h5
-rw-r--r--backend/BackendClient.h5
-rw-r--r--backend/BackendManager.cpp2
-rw-r--r--backend/BackendManager.h5
-rw-r--r--bufferinfo/BufferInfoGetter.cpp6
-rw-r--r--bufferinfo/BufferInfoGetter.h4
-rw-r--r--bufferinfo/BufferInfoMapperMetadata.cpp2
-rw-r--r--bufferinfo/BufferInfoMapperMetadata.h5
-rw-r--r--bufferinfo/legacy/BufferInfoImagination.h5
-rw-r--r--bufferinfo/legacy/BufferInfoLibdrm.cpp2
-rw-r--r--bufferinfo/legacy/BufferInfoLibdrm.h5
-rw-r--r--bufferinfo/legacy/BufferInfoMaliHisi.cpp10
-rw-r--r--bufferinfo/legacy/BufferInfoMaliHisi.h5
-rw-r--r--bufferinfo/legacy/BufferInfoMaliMediatek.cpp2
-rw-r--r--bufferinfo/legacy/BufferInfoMaliMediatek.h5
-rw-r--r--bufferinfo/legacy/BufferInfoMaliMeson.cpp2
-rw-r--r--bufferinfo/legacy/BufferInfoMaliMeson.h5
-rw-r--r--bufferinfo/legacy/BufferInfoMinigbm.h5
-rw-r--r--bufferinfo/meson.build5
-rwxr-xr-xbuild_deploy.sh26
-rw-r--r--compositor/DrmKmsPlan.h4
-rw-r--r--compositor/FlatteningController.cpp98
-rw-r--r--compositor/FlatteningController.h71
-rw-r--r--compositor/LayerData.h21
-rw-r--r--drm/DrmAtomicStateManager.cpp131
-rw-r--r--drm/DrmAtomicStateManager.h71
-rw-r--r--drm/DrmConnector.cpp19
-rw-r--r--drm/DrmConnector.h12
-rw-r--r--drm/DrmCrtc.cpp7
-rw-r--r--drm/DrmCrtc.h11
-rw-r--r--drm/DrmDevice.cpp38
-rw-r--r--drm/DrmDevice.h14
-rw-r--r--drm/DrmDisplayPipeline.cpp11
-rw-r--r--drm/DrmDisplayPipeline.h9
-rw-r--r--drm/DrmEncoder.cpp2
-rw-r--r--drm/DrmEncoder.h5
-rw-r--r--drm/DrmFbImporter.cpp18
-rw-r--r--drm/DrmFbImporter.h5
-rw-r--r--drm/DrmMode.cpp113
-rw-r--r--drm/DrmMode.h56
-rw-r--r--drm/DrmPlane.cpp53
-rw-r--r--drm/DrmPlane.h5
-rw-r--r--drm/DrmProperty.cpp75
-rw-r--r--drm/DrmProperty.h45
-rw-r--r--drm/DrmUnique.h5
-rw-r--r--drm/ResourceManager.cpp40
-rw-r--r--drm/ResourceManager.h23
-rw-r--r--drm/UEventListener.cpp36
-rw-r--r--drm/UEventListener.h20
-rw-r--r--drm/VSyncWorker.cpp154
-rw-r--r--drm/VSyncWorker.h51
-rw-r--r--drm/meson.build15
-rw-r--r--hwc2_device/DrmHwcTwo.cpp31
-rw-r--r--hwc2_device/DrmHwcTwo.h9
-rw-r--r--hwc2_device/HwcDisplay.cpp313
-rw-r--r--hwc2_device/HwcDisplay.h52
-rw-r--r--hwc2_device/HwcDisplayConfigs.cpp30
-rw-r--r--hwc2_device/HwcDisplayConfigs.h9
-rw-r--r--hwc2_device/HwcLayer.cpp17
-rw-r--r--hwc2_device/HwcLayer.h10
-rw-r--r--hwc2_device/hwc2_device.cpp22
-rw-r--r--hwc2_device/meson.build19
-rw-r--r--meson.build52
-rwxr-xr-xpresubmit.sh13
-rw-r--r--tests/Android.bp25
-rw-r--r--tests/worker_test.cpp109
-rw-r--r--utils/UEvent.h8
-rw-r--r--utils/UniqueFd.h117
-rw-r--r--utils/Worker.cpp93
-rw-r--r--utils/Worker.h81
-rw-r--r--utils/fd.cpp52
-rw-r--r--utils/fd.h36
-rw-r--r--utils/log.h21
-rw-r--r--utils/properties.h21
82 files changed, 1350 insertions, 1438 deletions
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index c6f7c4e..f854999 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -1,5 +1,13 @@
#! /usr/bin/env bash
+check_tool_installed() {
+ if ! command -v $1 &> /dev/null
+ then
+ echo "Please install '$1' tool"
+ exit 1
+ fi
+}
+
echoerr() {
printf "ERROR: %s\n" "$*" >&2
}
@@ -27,6 +35,9 @@ findtag() {
return 1
}
+check_tool_installed bpfmt
+check_tool_installed clang-format-diff-15
+
git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git
git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do
@@ -50,7 +61,7 @@ git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do
exit 1
fi
- git show "$h" -- | clang-format-diff-14 -p 1 -style=file > /tmp/format-fixup.patch
+ git show "$h" -- | clang-format-diff-15 -p 1 -style=file > /tmp/format-fixup.patch
if [ -s /tmp/format-fixup.patch ]; then
cat /tmp/format-fixup.patch >&2
exit 1
diff --git a/.ci/Dockerfile b/.ci/Dockerfile
new file mode 100644
index 0000000..32c348f
--- /dev/null
+++ b/.ci/Dockerfile
@@ -0,0 +1,52 @@
+FROM ubuntu:22.10
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+ENV PATH="/home/user/bin:${PATH}"
+
+# Taking into account layer structure, everything should be done within one layer.
+RUN apt-get update && apt-get upgrade -y && \
+ apt-get install -y clang-15 clang-tidy-15 clang-format-15 git libdrm-dev blueprint-tools libgtest-dev clang \
+ llvm make python3 python3-pip wget sudo rsync lld pkg-config ninja-build && \
+ pip3 install mako meson jinja2 ply pyyaml
+
+ENV RUN_USER user
+ENV RUN_UID 1000
+
+ENV USER_HOME /home/${RUN_USER}
+
+RUN mkdir -pv ${USER_HOME}
+# Create new user
+RUN adduser \
+ --gecos 'Build User' \
+ --shell '/usr/bin/bash' \
+ --uid ${RUN_UID} \
+ --disabled-login \
+ --disabled-password ${RUN_USER} \
+ && adduser ${RUN_USER} sudo
+
+RUN chown -R ${RUN_USER}:${RUN_USER} ${USER_HOME} && chmod -R 775 ${USER_HOME}
+
+# Ensure sudo group users are not
+# asked for a password when using
+# sudo command by ammending sudoers file
+RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> \
+/etc/sudoers
+
+# Pass control to a newly created user
+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 && \
+ 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
+
+# Create project path
+RUN mkdir -pv ${USER_HOME}/drm_hwcomposer
+WORKDIR ${USER_HOME}/drm_hwcomposer
+
+RUN git config --global user.name "FIRST_NAME LAST_NAME" && git config --global user.email "MY_NAME@example.com"
+
+CMD [ "/bin/bash" ]
diff --git a/.ci/Makefile b/.ci/Makefile
index 581c6d9..9c82fca 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -2,12 +2,12 @@
INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include
SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
-CLANG := clang++-14
-CLANG_TIDY := clang-tidy-14
+CLANG := clang++-15
+CLANG_TIDY := clang-tidy-15
OUT_DIR := /tmp/drm_hwcomposer/build
SRC_DIR := .
-CXXFLAGS := -fPIC -Wall -Wextra -Werror -DPLATFORM_SDK_VERSION=31 -D__ANDROID_API__=31
+CXXFLAGS := -fPIC -Wall -Wextra -Werror -D__ANDROID_API__=31
CXXFLAGS += -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
CXXFLAGS += -fvisibility-inlines-hidden -std=gnu++17 -DHWC2_USE_CPP11 -DHWC2_INCLUDE_STRINGIFICATION -fno-rtti
@@ -22,18 +22,11 @@ TIDY_FILES_OVERRIDE := \
bufferinfo/legacy/BufferInfoMaliMeson.cpp:COARSE \
bufferinfo/legacy/BufferInfoMinigbm.cpp:COARSE \
drm/DrmFbImporter.h:FINE \
- drm/DrmMode.h:COARSE \
- drm/DrmProperty.h:COARSE \
drm/DrmUnique.h:FINE \
- drm/DrmProperty.cpp:COARSE \
- drm/VSyncWorker.cpp:COARSE \
hwc2_device/DrmHwcTwo.cpp:COARSE \
hwc2_device/DrmHwcTwo.h:COARSE \
hwc2_device/HwcDisplay.cpp:COARSE \
hwc2_device/HwcDisplay.h:COARSE \
- tests/worker_test.cpp:COARSE \
- utils/Worker.h:COARSE \
- utils/UniqueFd.h:FINE \
utils/log.h:FINE \
utils/properties.h:FINE \
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eb0c265..bfc4ede 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,23 +1,40 @@
-image: ubuntu:22.04
+image: ubuntu:22.10
variables:
DEBIAN_FRONTEND: noninteractive
before_script:
- apt-get --quiet update --yes >/dev/null
- - apt-get --quiet install --yes clang-14 clang-tidy-14 clang-format-14 git libdrm-dev blueprint-tools libgtest-dev make >/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 python3-pip wget sudo rsync lld pkg-config ninja-build >/dev/null
+ - pip3 install mako meson jinja2 ply pyyaml >/dev/null
stages:
- build
+ - tidy
- style
build:
stage: build
script:
- - make -f .ci/Makefile
+ - mkdir -p install/arm64
+ - cd ..
+ - 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
+
artifacts:
- when: on_failure
- untracked: true
+ paths:
+ - install/
+ expire_in: 1 week
+
+tidy:
+ stage: tidy
+ script:
+ - make -f .ci/Makefile
checkstyle:
stage: style
diff --git a/Android.bp b/Android.bp
index a7a2e94..62c7e0c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,9 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// =====================
-// libdrmhwc_utils.a
-// =====================
package {
default_applicable_licenses: ["external_drm_hwcomposer_license"],
}
@@ -32,20 +29,10 @@ license {
],
}
-cc_library_static {
- name: "libdrmhwc_utils",
-
- srcs: ["utils/Worker.cpp"],
-
- include_dirs: ["external/drm_hwcomposer"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
+cc_library_headers {
+ name: "drm_hwcomposer_headers",
vendor: true,
-
+ export_include_dirs: ["."],
}
// =====================
@@ -65,9 +52,7 @@ cc_defaults {
"libutils",
],
- include_dirs: ["external/drm_hwcomposer"],
-
- static_libs: ["libdrmhwc_utils"],
+ header_libs: ["drm_hwcomposer_headers"],
cflags: [
"-Wall",
@@ -80,23 +65,23 @@ cc_defaults {
"-std=c++17",
],
- product_variables: {
- platform_sdk_version: {
- cflags: ["-DPLATFORM_SDK_VERSION=%d"],
- },
- },
-
relative_install_path: "hw",
vendor: true,
}
filegroup {
+ name: "drm_hwcomposer_fd",
+ srcs: ["utils/fd.cpp"],
+}
+
+filegroup {
name: "drm_hwcomposer_common",
srcs: [
"bufferinfo/BufferInfoGetter.cpp",
"bufferinfo/BufferInfoMapperMetadata.cpp",
"compositor/DrmKmsPlan.cpp",
+ "compositor/FlatteningController.cpp",
"drm/DrmAtomicStateManager.cpp",
"drm/DrmConnector.cpp",
@@ -121,6 +106,8 @@ filegroup {
"hwc2_device/HwcDisplayConfigs.cpp",
"hwc2_device/HwcLayer.cpp",
"hwc2_device/hwc2_device.cpp",
+
+ "utils/fd.cpp",
],
}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..98e33af
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,95 @@
+#!/usr/bin/make
+
+DOCKER_BIN := $(shell command -v docker 2> /dev/null)
+NPROCS:=$(shell grep -c ^processor /proc/cpuinfo)
+
+DOCKERFILE := .ci/Dockerfile
+IMAGE_NAME := drmhwc_ci
+
+# We can't run style and bpfmt check in docker
+# when repo is within AOSP tree, will run it locally.
+GIT_IS_SYMLINK:=$(shell test -L .git && echo true)
+
+define print_no_docker_err
+$(warning Please install docker, e.g. for Ubuntu:)
+$(warning $$ sudo apt install docker.io)
+$(warning $$ sudo usermod -aG docker $$USER)
+$(warning and reboot your PC)
+$(error Aborting...)
+endef
+
+.PHONY : help prepare shell ci_fast ci ci_cleanup build_deploy bd local_presubmit local_cleanup
+.DEFAULT_GOAL := help
+
+help: ## Show this help
+ @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
+
+PREPARE:=.out/prepare_docker.timestamp
+$(PREPARE): $(DOCKERFILE)
+ $(if $(DOCKER_BIN),,$(call print_no_docker_err))
+ mkdir -p $(dir $@)
+ $(DOCKER_BIN) build -t local/build-env -f $(DOCKERFILE) .;
+ $(DOCKER_BIN) stop $(IMAGE_NAME) || true
+ $(DOCKER_BIN) rm $(IMAGE_NAME) || true
+ $(DOCKER_BIN) run -itd --name $(IMAGE_NAME) --network="host" -v $(shell pwd):/home/user/drm_hwcomposer local/build-env
+ @touch $@
+
+prepare: $(PREPARE)
+prepare: ## Build and run Docker image
+
+shell: $(PREPARE)
+shell: ## Start shell into a container
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash
+
+ci_fast: $(PREPARE)
+ci_fast: ## Run meson build for arm64 in docker container
+ @echo "Run meson cross-build for Android:"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+
+ci: $(PREPARE)
+ci: ## Run presubmit within the docker container
+ @echo "Run native build:"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -f .ci/Makefile -j$(NPROCS)"
+ @echo "Run meson cross-build for Android:"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+ @echo "Run style check:"
+ $(if $(GIT_IS_SYMLINK), \
+ ./.ci/.gitlab-ci-checkcommit.sh, \
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "./.ci/.gitlab-ci-checkcommit.sh")
+ @echo "\n\e[32m --- SUCCESS ---\n"
+
+ci_cleanup: ## Cleanup after 'make ci'
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make local_cleanup"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "rm -rf ~/aospless/build"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "rm -rf ~/aospless/install"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "rm -rf ~/aospless/out_src"
+
+build_deploy: $(PREPARE)
+build_deploy: ## Build for Andoid and deploy onto the target device (require active adb device connected)
+ $(if $(filter $(shell adb shell getprop ro.bionic.arch),arm64),,$(error arm64 only is supported at the moment))
+ adb root && adb remount vendor
+ mkdir -p .out/arm64
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "make -C ~/aospless all"
+ $(DOCKER_BIN) exec -it $(IMAGE_NAME) bash -c "cp -r ~/aospless/install/* ~/drm_hwcomposer/.out/arm64"
+ adb push .out/arm64/vendor/lib64/hw/hwcomposer.drm.so /vendor/lib64/hw/hwcomposer.drm.so
+ adb shell stop
+ adb shell stop vendor.hwcomposer-2-1 && adb shell start vendor.hwcomposer-2-1 || true
+ adb shell stop vendor.hwcomposer-2-2 && adb shell start vendor.hwcomposer-2-2 || true
+ adb shell stop vendor.hwcomposer-2-3 && adb shell start vendor.hwcomposer-2-3 || true
+ adb shell stop vendor.hwcomposer-2-4 && adb shell start vendor.hwcomposer-2-4 || true
+ bash -c '[[ "$$HWCLOG" -eq "1" ]] && adb logcat -c || true'
+ adb shell start
+ bash -c '[[ "$$HWCLOG" -eq "1" ]] && adb logcat | grep -i hwc || true'
+
+bd: build_deploy
+bd: ## Alias for build_deploy
+
+local_presubmit: ## Run local presubmit script (requires latest Ubuntu + additional packages). Consider 'make ci' instead
+ @echo "Run native build:"
+ make -f .ci/Makefile -j12
+ @echo "Run style check:"
+ ./.ci/.gitlab-ci-checkcommit.sh
+ @echo "\n\e[32m --- SUCCESS ---\n"
+
+local_cleanup: ## Cleanup after 'make local_presubmit'
+ make -f .ci/Makefile clean
diff --git a/README.md b/README.md
index e98b5ae..5724b36 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ A short list of contribution guidelines:
you with formatting of your patches:
```
- git diff | clang-format-diff-14 -p 1 -style=file
+ git diff | clang-format-diff-15 -p 1 -style=file
```
* Hardware specific changes should be tested on relevant platforms before
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index ba0518a..3ca6e92 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -33,27 +33,36 @@ HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
int client_start = -1;
size_t client_size = 0;
- if (display->ProcessClientFlatteningState(layers.size() <= 1)) {
- display->total_stats().frames_flattened_++;
- client_start = 0;
- client_size = layers.size();
- MarkValidated(layers, client_start, client_size);
- } else {
- std::tie(client_start, client_size) = GetClientLayers(display, layers);
+ auto flatcon = display->GetFlatCon();
+ if (flatcon) {
+ bool should_flatten = false;
+ if (layers.size() <= 1)
+ flatcon->Disable();
+ else
+ should_flatten = flatcon->NewFrame();
+
+ if (should_flatten) {
+ display->total_stats().frames_flattened_++;
+ MarkValidated(layers, 0, layers.size());
+ *num_types = layers.size();
+ return HWC2::Error::HasChanges;
+ }
+ }
- MarkValidated(layers, client_start, client_size);
+ std::tie(client_start, client_size) = GetClientLayers(display, layers);
- bool testing_needed = !(client_start == 0 && client_size == layers.size());
+ MarkValidated(layers, client_start, client_size);
- AtomicCommitArgs a_args = {.test_only = true};
+ auto testing_needed = client_start != 0 || client_size != layers.size();
- if (testing_needed &&
- display->CreateComposition(a_args) != HWC2::Error::None) {
- ++display->total_stats().failed_kms_validate_;
- client_start = 0;
- client_size = layers.size();
- MarkValidated(layers, 0, client_size);
- }
+ AtomicCommitArgs a_args = {.test_only = true};
+
+ if (testing_needed &&
+ display->CreateComposition(a_args) != HWC2::Error::None) {
+ ++display->total_stats().failed_kms_validate_;
+ client_start = 0;
+ client_size = layers.size();
+ MarkValidated(layers, 0, client_size);
}
*num_types = client_size;
@@ -83,8 +92,7 @@ std::tuple<int, size_t> Backend::GetClientLayers(
bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
return !HardwareSupportsLayerType(layer->GetSfType()) ||
- !layer->IsLayerUsableAsDevice() ||
- display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
+ !layer->IsLayerUsableAsDevice() || display->CtmByGpu() ||
(layer->GetLayerData().pi.RequireScalingOrPhasing() &&
display->GetHwc2()->GetResMan().ForcedScalingWithGpu());
}
@@ -99,7 +107,7 @@ uint32_t Backend::CalcPixOps(const std::vector<HwcLayer *> &layers,
uint32_t pixops = 0;
for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
if (z_order >= first_z && z_order < first_z + size) {
- hwc_rect_t &df = layers[z_order]->GetLayerData().pi.display_frame;
+ auto &df = layers[z_order]->GetLayerData().pi.display_frame;
pixops += (df.right - df.left) * (df.bottom - df.top);
}
}
@@ -129,16 +137,16 @@ std::tuple<int, int> Backend::GetExtraClientRange(
if (avail_planes < display->layers().size())
avail_planes--;
- int extra_client = int(layers.size() - client_size) - int(avail_planes);
+ const int extra_client = int(layers.size() - client_size) - int(avail_planes);
if (extra_client > 0) {
int start = 0;
size_t steps = 0;
if (client_size != 0) {
- int prepend = std::min(client_start, extra_client);
- int append = std::min(int(layers.size()) -
- int(client_start + client_size),
- extra_client);
+ const int prepend = std::min(client_start, extra_client);
+ const int append = std::min(int(layers.size()) -
+ int(client_start + client_size),
+ extra_client);
start = client_start - (int)prepend;
client_size += extra_client;
steps = 1 + std::min(std::min(append, prepend),
@@ -150,7 +158,7 @@ std::tuple<int, int> Backend::GetExtraClientRange(
uint32_t gpu_pixops = UINT32_MAX;
for (size_t i = 0; i < steps; i++) {
- uint32_t po = CalcPixOps(layers, start + i, client_size);
+ const uint32_t po = CalcPixOps(layers, start + i, client_size);
if (po < gpu_pixops) {
gpu_pixops = po;
client_start = start + int(i);
diff --git a/backend/Backend.h b/backend/Backend.h
index 82b8fca..c24e818 100644
--- a/backend/Backend.h
+++ b/backend/Backend.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BACKEND_H
-#define ANDROID_BACKEND_H
+#pragma once
#include "hwc2_device/DrmHwcTwo.h"
@@ -41,5 +40,3 @@ class Backend {
int client_start, size_t client_size);
};
} // namespace android
-
-#endif
diff --git a/backend/BackendClient.h b/backend/BackendClient.h
index 95abb0f..1333eca 100644
--- a/backend/BackendClient.h
+++ b/backend/BackendClient.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BACKEND_CLIENT_H
-#define ANDROID_BACKEND_CLIENT_H
+#pragma once
#include "Backend.h"
@@ -27,5 +26,3 @@ class BackendClient : public Backend {
uint32_t *num_requests) override;
};
} // namespace android
-
-#endif
diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp
index 9bf6324..c1bc0f6 100644
--- a/backend/BackendManager.cpp
+++ b/backend/BackendManager.cpp
@@ -42,7 +42,7 @@ int BackendManager::RegisterBackend(const std::string &name,
}
int BackendManager::SetBackendForDisplay(HwcDisplay *display) {
- std::string driver_name(display->GetPipe().device->GetName());
+ auto driver_name(display->GetPipe().device->GetName());
char backend_override[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.backend_override", backend_override,
driver_name.c_str());
diff --git a/backend/BackendManager.h b/backend/BackendManager.h
index 751cb78..4976744 100644
--- a/backend/BackendManager.h
+++ b/backend/BackendManager.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BACKEND_MANAGER_H
-#define ANDROID_BACKEND_MANAGER_H
+#pragma once
#include <functional>
#include <map>
@@ -54,5 +53,3 @@ class BackendManager {
std::map<std::string, BackendConstructorT> available_backends_;
};
} // namespace android
-
-#endif
diff --git a/bufferinfo/BufferInfoGetter.cpp b/bufferinfo/BufferInfoGetter.cpp
index 95c1a23..726b4eb 100644
--- a/bufferinfo/BufferInfoGetter.cpp
+++ b/bufferinfo/BufferInfoGetter.cpp
@@ -18,7 +18,7 @@
#include "BufferInfoGetter.h"
-#if PLATFORM_SDK_VERSION >= 30
+#if __ANDROID_API__ >= 30
#include "BufferInfoMapperMetadata.h"
#endif
@@ -38,7 +38,7 @@ namespace android {
BufferInfoGetter *BufferInfoGetter::GetInstance() {
static std::unique_ptr<BufferInfoGetter> inst;
if (!inst) {
-#if PLATFORM_SDK_VERSION >= 30 && defined(USE_IMAPPER4_METADATA_API)
+#if __ANDROID_API__ >= 30 && defined(USE_IMAPPER4_METADATA_API)
inst.reset(BufferInfoMapperMetadata::CreateInstance());
if (!inst) {
ALOGW(
@@ -68,7 +68,7 @@ std::optional<BufferUniqueId> BufferInfoGetter::GetUniqueId(
}
int LegacyBufferInfoGetter::Init() {
- int ret = hw_get_module(
+ const int ret = hw_get_module(
GRALLOC_HARDWARE_MODULE_ID,
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
reinterpret_cast<const hw_module_t **>(&gralloc_));
diff --git a/bufferinfo/BufferInfoGetter.h b/bufferinfo/BufferInfoGetter.h
index 5591296..5131c37 100644
--- a/bufferinfo/BufferInfoGetter.h
+++ b/bufferinfo/BufferInfoGetter.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_BUFFERINFOGETTER_H_
-#define ANDROID_BUFFERINFOGETTER_H_
+#pragma once
#include <drm/drm_fourcc.h>
#include <hardware/gralloc.h>
@@ -89,4 +88,3 @@ class LegacyBufferInfoGetter : public BufferInfoGetter {
#endif
} // namespace android
-#endif
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index bdacb74..823d28a 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#if PLATFORM_SDK_VERSION >= 30
+#if __ANDROID_API__ >= 30
#define LOG_TAG "hwc-bufferinfo-mappermetadata"
diff --git a/bufferinfo/BufferInfoMapperMetadata.h b/bufferinfo/BufferInfoMapperMetadata.h
index ab269dc..ce66fe5 100644
--- a/bufferinfo/BufferInfoMapperMetadata.h
+++ b/bufferinfo/BufferInfoMapperMetadata.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef PLATFORMIMAGINATION_H
-#define PLATFORMIMAGINATION_H
+#pragma once
#include "bufferinfo/BufferInfoGetter.h"
@@ -32,5 +31,3 @@ class BufferInfoMapperMetadata : public BufferInfoGetter {
static BufferInfoGetter *CreateInstance();
};
} // namespace android
-
-#endif // PLATFORMIMAGINATION_H
diff --git a/bufferinfo/legacy/BufferInfoImagination.h b/bufferinfo/legacy/BufferInfoImagination.h
index 635e3b5..3f4e13a 100644
--- a/bufferinfo/legacy/BufferInfoImagination.h
+++ b/bufferinfo/legacy/BufferInfoImagination.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BUFFERINFOIMAGINATION_H
-#define BUFFERINFOIMAGINATION_H
+#pragma once
#include <hardware/gralloc.h>
@@ -30,5 +29,3 @@ class BufferInfoImagination : public LegacyBufferInfoGetter {
auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
};
} // namespace android
-
-#endif // PLATFORMIMAGINATION_H
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp
index ac71ec0..b314bdc 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.cpp
+++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp
@@ -154,7 +154,7 @@ bool BufferInfoLibdrm::GetYuvPlaneInfo(uint32_t hal_format, int num_fds,
if (num_fds == 1) {
bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0];
} else {
- int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
+ const int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
if (num_fds != expected_planes)
return false;
}
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.h b/bufferinfo/legacy/BufferInfoLibdrm.h
index 7f5b08c..d913d57 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.h
+++ b/bufferinfo/legacy/BufferInfoLibdrm.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BUFFERINFOLIBDRM_H_
-#define BUFFERINFOLIBDRM_H_
+#pragma once
#include <hardware/gralloc.h>
@@ -35,5 +34,3 @@ class BufferInfoLibdrm : public LegacyBufferInfoGetter {
};
} // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.cpp b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
index 1c7f4d0..461e2eb 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.cpp
@@ -77,7 +77,7 @@ auto BufferInfoMaliHisi::GetBoInfo(buffer_handle_t handle)
if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
return {};
- uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+ const uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
if (fmt == DRM_FORMAT_INVALID)
return {};
@@ -100,10 +100,10 @@ auto BufferInfoMaliHisi::GetBoInfo(buffer_handle_t handle)
if (hnd->usage &
(GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK))
align = 16;
- int adjusted_height = MALI_ALIGN(hnd->height, 2);
- int y_size = adjusted_height * hnd->byte_stride;
- int vu_stride = MALI_ALIGN(hnd->byte_stride / 2, align);
- int v_size = vu_stride * (adjusted_height / 2);
+ const int adjusted_height = MALI_ALIGN(hnd->height, 2);
+ const int y_size = adjusted_height * hnd->byte_stride;
+ const int vu_stride = MALI_ALIGN(hnd->byte_stride / 2, align);
+ const int v_size = vu_stride * (adjusted_height / 2);
/* V plane*/
bi.prime_fds[1] = hnd->share_fd;
diff --git a/bufferinfo/legacy/BufferInfoMaliHisi.h b/bufferinfo/legacy/BufferInfoMaliHisi.h
index cc37491..35c7989 100644
--- a/bufferinfo/legacy/BufferInfoMaliHisi.h
+++ b/bufferinfo/legacy/BufferInfoMaliHisi.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BUFFERINFOMALIHISI_H_
-#define BUFFERINFOMALIHISI_H_
+#pragma once
#include <hardware/gralloc.h>
@@ -33,5 +32,3 @@ class BufferInfoMaliHisi : public LegacyBufferInfoGetter {
uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags, bool is_rgb);
};
} // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
index 2e10460..6dac973 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.cpp
@@ -38,7 +38,7 @@ auto BufferInfoMaliMediatek::GetBoInfo(buffer_handle_t handle)
if (!hnd)
return {};
- uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+ const uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
if (fmt == DRM_FORMAT_INVALID)
return {};
diff --git a/bufferinfo/legacy/BufferInfoMaliMediatek.h b/bufferinfo/legacy/BufferInfoMaliMediatek.h
index 43d987a..120a88c 100644
--- a/bufferinfo/legacy/BufferInfoMaliMediatek.h
+++ b/bufferinfo/legacy/BufferInfoMaliMediatek.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BUFFERINFOMALIMTK_H_
-#define BUFFERINFOMALIMTK_H_
+#pragma once
#include <hardware/gralloc.h>
@@ -30,5 +29,3 @@ class BufferInfoMaliMediatek : public LegacyBufferInfoGetter {
auto GetBoInfo(buffer_handle_t handle) -> std::optional<BufferInfo> override;
};
} // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.cpp b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
index 8160296..536e5a6 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.cpp
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.cpp
@@ -70,7 +70,7 @@ auto BufferInfoMaliMeson::GetBoInfo(buffer_handle_t handle)
if (!(hnd->usage & GRALLOC_USAGE_HW_FB))
return {};
- uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+ const uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
if (fmt == DRM_FORMAT_INVALID)
return {};
diff --git a/bufferinfo/legacy/BufferInfoMaliMeson.h b/bufferinfo/legacy/BufferInfoMaliMeson.h
index 3b6fab0..9a484d3 100644
--- a/bufferinfo/legacy/BufferInfoMaliMeson.h
+++ b/bufferinfo/legacy/BufferInfoMaliMeson.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BUFFERINFOMALIHISI_H_
-#define BUFFERINFOMALIHISI_H_
+#pragma once
#include <hardware/gralloc.h>
@@ -32,5 +31,3 @@ class BufferInfoMaliMeson : public LegacyBufferInfoGetter {
uint64_t ConvertGrallocFormatToDrmModifiers(uint64_t flags);
};
} // namespace android
-
-#endif
diff --git a/bufferinfo/legacy/BufferInfoMinigbm.h b/bufferinfo/legacy/BufferInfoMinigbm.h
index 40d9926..5525110 100644
--- a/bufferinfo/legacy/BufferInfoMinigbm.h
+++ b/bufferinfo/legacy/BufferInfoMinigbm.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BUFFERINFOMINIGBM_H_
-#define BUFFERINFOMINIGBM_H_
+#pragma once
#include <hardware/gralloc.h>
@@ -31,5 +30,3 @@ class BufferInfoMinigbm : public LegacyBufferInfoGetter {
};
} // namespace android
-
-#endif
diff --git a/bufferinfo/meson.build b/bufferinfo/meson.build
new file mode 100644
index 0000000..f53d1b9
--- /dev/null
+++ b/bufferinfo/meson.build
@@ -0,0 +1,5 @@
+src_common += files(
+ 'legacy/BufferInfoLibdrm.cpp',
+ 'BufferInfoGetter.cpp',
+ 'BufferInfoMapperMetadata.cpp',
+)
diff --git a/build_deploy.sh b/build_deploy.sh
deleted file mode 100755
index ef25e5c..0000000
--- a/build_deploy.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash -e
-
-# To see logs after deploy run: $ HWCLOG=1 TESTDEV=<DEV> ./build_deploy.sh
-
-[ -z "$TESTDEV" ] && echo "Run $ TESTDEV=<Your lunch target> ./build_deploy.sh" && false
-
-cd ../..
-. build/envsetup.sh
-lunch $TESTDEV
-cd -
-
-mm
-
-adb root && adb remount && adb sync vendor
-
-adb shell stop
-adb shell stop vendor.hwcomposer-2-1 && adb shell start vendor.hwcomposer-2-1 || true
-adb shell stop vendor.hwcomposer-2-2 && adb shell start vendor.hwcomposer-2-2 || true
-adb shell stop vendor.hwcomposer-2-3 && adb shell start vendor.hwcomposer-2-3 || true
-adb shell stop vendor.hwcomposer-2-4 && adb shell start vendor.hwcomposer-2-4 || true
-
-[ $HWCLOG -eq "1" ] && adb logcat -c
-
-adb shell start
-
-[ $HWCLOG -eq "1" ] && adb logcat | grep -i hwc
diff --git a/compositor/DrmKmsPlan.h b/compositor/DrmKmsPlan.h
index 91f636e..054cd93 100644
--- a/compositor/DrmKmsPlan.h
+++ b/compositor/DrmKmsPlan.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_KMS_PLAN_H_
-#define ANDROID_DRM_KMS_PLAN_H_
+#pragma once
#include <memory>
#include <vector>
@@ -41,4 +40,3 @@ struct DrmKmsPlan {
};
} // namespace android
-#endif
diff --git a/compositor/FlatteningController.cpp b/compositor/FlatteningController.cpp
new file mode 100644
index 0000000..257f8a0
--- /dev/null
+++ b/compositor/FlatteningController.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+/*
+ * Usually, display controllers do not use intermediate buffer for composition
+ * results. Instead, they scan-out directly from the input buffers, composing
+ * the planes on the fly every VSYNC.
+ *
+ * Flattening is a technique that reduces memory bandwidth and power consumption
+ * by converting non-updating multi-plane composition into a single-plane.
+ * Additionally, flattening also makes more shared planes available for use by
+ * other CRTCs.
+ *
+ * If the client is not updating layers for 1 second, FlatCon triggers a
+ * callback to refresh the screen. The compositor should mark all layers to be
+ * composed by the client into a single framebuffer using GPU.
+ */
+
+#define LOG_TAG "hwc-flatcon"
+
+#include "FlatteningController.h"
+
+#include "utils/log.h"
+
+namespace android {
+
+auto FlatteningController::CreateInstance(FlatConCallbacks &cbks)
+ -> std::shared_ptr<FlatteningController> {
+ auto fc = std::shared_ptr<FlatteningController>(new FlatteningController());
+
+ fc->cbks_ = cbks;
+
+ std::thread(&FlatteningController::ThreadFn, fc).detach();
+
+ return fc;
+}
+
+/* Compositor should call this every frame */
+bool FlatteningController::NewFrame() {
+ bool wake_it = false;
+ auto lock = std::lock_guard<std::mutex>(mutex_);
+
+ if (flatten_next_frame_) {
+ flatten_next_frame_ = false;
+ return true;
+ }
+
+ sleep_until_ = std::chrono::system_clock::now() + kTimeout;
+ if (disabled_) {
+ wake_it = true;
+ disabled_ = false;
+ }
+
+ if (wake_it)
+ cv_.notify_all();
+
+ return false;
+}
+
+void FlatteningController::ThreadFn(
+ const std::shared_ptr<FlatteningController> &fc) {
+ for (;;) {
+ std::unique_lock<std::mutex> lock(fc->mutex_);
+ if (fc.use_count() == 1 || !fc->cbks_.trigger)
+ break;
+
+ if (fc->sleep_until_ <= std::chrono::system_clock::now() &&
+ !fc->disabled_) {
+ fc->disabled_ = true;
+ fc->flatten_next_frame_ = true;
+ ALOGV("Timeout. Sending an event to compositor");
+ fc->cbks_.trigger();
+ }
+
+ if (fc->disabled_) {
+ ALOGV("Wait");
+ fc->cv_.wait(lock);
+ } else {
+ ALOGV("Wait_until");
+ fc->cv_.wait_until(lock, fc->sleep_until_);
+ }
+ }
+}
+
+} // namespace android
diff --git a/compositor/FlatteningController.h b/compositor/FlatteningController.h
new file mode 100644
index 0000000..2be6ce4
--- /dev/null
+++ b/compositor/FlatteningController.h
@@ -0,0 +1,71 @@
+/*
+ * 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 <chrono>
+#include <condition_variable>
+#include <functional>
+#include <thread>
+
+namespace android {
+
+// NOLINTNEXTLINE(misc-unused-using-decls): False positive
+using std::chrono_literals::operator""s;
+
+struct FlatConCallbacks {
+ std::function<void()> trigger;
+};
+
+class FlatteningController {
+ public:
+ static auto CreateInstance(FlatConCallbacks &cbks)
+ -> std::shared_ptr<FlatteningController>;
+
+ void Disable() {
+ auto lock = std::lock_guard<std::mutex>(mutex_);
+ flatten_next_frame_ = false;
+ disabled_ = true;
+ }
+
+ /* Compositor should call this every frame */
+ bool NewFrame();
+
+ auto ShouldFlatten() const {
+ return flatten_next_frame_;
+ }
+
+ void StopThread() {
+ auto lock = std::lock_guard<std::mutex>(mutex_);
+ cbks_ = {};
+ cv_.notify_all();
+ }
+
+ static constexpr auto kTimeout = 1s;
+
+ private:
+ FlatteningController() = default;
+ static void ThreadFn(const std::shared_ptr<FlatteningController> &fc);
+
+ bool flatten_next_frame_{};
+ bool disabled_{};
+ decltype(std::chrono::system_clock::now()) sleep_until_{};
+ std::mutex mutex_;
+ std::condition_variable cv_;
+ FlatConCallbacks cbks_;
+};
+
+} // namespace android
diff --git a/compositor/LayerData.h b/compositor/LayerData.h
index d04514d..8f4b7aa 100644
--- a/compositor/LayerData.h
+++ b/compositor/LayerData.h
@@ -27,7 +27,7 @@
#include "bufferinfo/BufferInfo.h"
#include "drm/DrmFbImporter.h"
-#include "utils/UniqueFd.h"
+#include "utils/fd.h"
namespace android {
@@ -49,33 +49,24 @@ struct PresentInfo {
hwc_rect_t display_frame{};
bool RequireScalingOrPhasing() const {
- float src_width = source_crop.right - source_crop.left;
- float src_height = source_crop.bottom - source_crop.top;
+ const float src_width = source_crop.right - source_crop.left;
+ const float src_height = source_crop.bottom - source_crop.top;
auto dest_width = float(display_frame.right - display_frame.left);
auto dest_height = float(display_frame.bottom - display_frame.top);
- bool scaling = src_width != dest_width || src_height != dest_height;
- bool phasing = (source_crop.left - std::floor(source_crop.left) != 0) ||
+ auto scaling = src_width != dest_width || src_height != dest_height;
+ auto phasing = (source_crop.left - std::floor(source_crop.left) != 0) ||
(source_crop.top - std::floor(source_crop.top) != 0);
return scaling || phasing;
}
};
struct LayerData {
- auto Clone() {
- LayerData clonned;
- clonned.bi = bi;
- clonned.fb = fb;
- clonned.pi = pi;
- clonned.acquire_fence = std::move(acquire_fence);
- return clonned;
- }
-
std::optional<BufferInfo> bi;
std::shared_ptr<DrmFbIdHandle> fb;
PresentInfo pi;
- UniqueFd acquire_fence;
+ SharedFd acquire_fence;
};
} // namespace android
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
index 5d2eebd..4ff16e2 100644
--- a/drm/DrmAtomicStateManager.cpp
+++ b/drm/DrmAtomicStateManager.cpp
@@ -22,17 +22,10 @@
#include "DrmAtomicStateManager.h"
#include <drm/drm_mode.h>
-#include <pthread.h>
-#include <sched.h>
#include <sync/sync.h>
#include <utils/Trace.h>
-#include <array>
#include <cassert>
-#include <cstdlib>
-#include <ctime>
-#include <sstream>
-#include <vector>
#include "drm/DrmCrtc.h"
#include "drm/DrmDevice.h"
@@ -42,8 +35,20 @@
namespace android {
+auto DrmAtomicStateManager::CreateInstance(DrmDisplayPipeline *pipe)
+ -> std::shared_ptr<DrmAtomicStateManager> {
+ auto dasm = std::shared_ptr<DrmAtomicStateManager>(
+ new DrmAtomicStateManager());
+
+ dasm->pipe_ = pipe;
+ std::thread(&DrmAtomicStateManager::ThreadFn, dasm.get(), dasm).detach();
+
+ return dasm;
+}
+
// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
+ // NOLINTNEXTLINE(misc-const-correctness)
ATRACE_CALL();
if (args.active && *args.active == active_frame_state_.crtc_active_state) {
@@ -102,6 +107,20 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
}
}
+ if (args.color_matrix && crtc->GetCtmProperty()) {
+ auto blob = drm->RegisterUserPropertyBlob(args.color_matrix.get(),
+ sizeof(drm_color_ctm));
+ new_frame_state.ctm_blob = std::move(blob);
+
+ if (!new_frame_state.ctm_blob) {
+ ALOGE("Failed to create CTM blob");
+ return -EINVAL;
+ }
+
+ if (!crtc->GetCtmProperty().AtomicSet(*pset, *new_frame_state.ctm_blob))
+ return -EINVAL;
+ }
+
auto unused_planes = new_frame_state.used_planes;
if (args.composition) {
@@ -136,18 +155,19 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
if (args.test_only) {
- return drmModeAtomicCommit(drm->GetFd(), pset.get(),
+ return drmModeAtomicCommit(*drm->GetFd(), pset.get(),
flags | DRM_MODE_ATOMIC_TEST_ONLY, drm);
}
if (last_present_fence_) {
+ // NOLINTNEXTLINE(misc-const-correctness)
ATRACE_NAME("WaitPriorFramePresented");
constexpr int kTimeoutMs = 500;
- int err = sync_wait(last_present_fence_.Get(), kTimeoutMs);
+ const int err = sync_wait(*last_present_fence_, kTimeoutMs);
if (err != 0) {
- ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)",
- last_present_fence_.Get(), err, errno);
+ ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", *last_present_fence_,
+ err, errno);
}
CleanupPriorFrameResources();
@@ -157,99 +177,86 @@ auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
}
- int err = drmModeAtomicCommit(drm->GetFd(), pset.get(), flags, drm);
+ auto err = drmModeAtomicCommit(*drm->GetFd(), pset.get(), flags, drm);
if (err != 0) {
ALOGE("Failed to commit pset ret=%d\n", err);
return err;
}
+ args.out_fence = MakeSharedFd(out_fence);
+
if (nonblock) {
- last_present_fence_ = UniqueFd::Dup(out_fence);
- staged_frame_state_ = std::move(new_frame_state);
- frames_staged_++;
- ptt_->Notify();
+ {
+ const std::unique_lock lock(mutex_);
+ last_present_fence_ = args.out_fence;
+ staged_frame_state_ = std::move(new_frame_state);
+ frames_staged_++;
+ }
+ cv_.notify_all();
} else {
active_frame_state_ = std::move(new_frame_state);
}
- if (args.display_mode) {
- /* TODO(nobody): we still need this for synthetic vsync, remove after
- * vsync reworked */
- connector->SetActiveMode(*args.display_mode);
- }
-
- args.out_fence = UniqueFd(out_fence);
-
return 0;
}
-PresentTrackerThread::PresentTrackerThread(DrmAtomicStateManager *st_man)
- : st_man_(st_man),
- mutex_(&st_man_->pipe_->device->GetResMan().GetMainLock()) {
- pt_ = std::thread(&PresentTrackerThread::PresentTrackerThreadFn, this);
-}
-
-PresentTrackerThread::~PresentTrackerThread() {
- ALOGI("PresentTrackerThread successfully destroyed");
-}
-
-void PresentTrackerThread::PresentTrackerThreadFn() {
- /* object should be destroyed on thread exit */
- auto self = std::unique_ptr<PresentTrackerThread>(this);
-
+void DrmAtomicStateManager::ThreadFn(
+ const std::shared_ptr<DrmAtomicStateManager> &dasm) {
int tracking_at_the_moment = -1;
+ auto &main_mutex = pipe_->device->GetResMan().GetMainLock();
for (;;) {
- UniqueFd present_fence;
+ SharedFd present_fence;
{
- std::unique_lock lk(*mutex_);
- cv_.wait(lk, [&] {
- return st_man_ == nullptr ||
- st_man_->frames_staged_ > tracking_at_the_moment;
- });
+ std::unique_lock lk(mutex_);
+ cv_.wait(lk);
- if (st_man_ == nullptr) {
+ if (exit_thread_ || dasm.use_count() == 1)
break;
- }
- tracking_at_the_moment = st_man_->frames_staged_;
+ if (frames_staged_ <= tracking_at_the_moment)
+ continue;
+
+ tracking_at_the_moment = frames_staged_;
- present_fence = UniqueFd::Dup(st_man_->last_present_fence_.Get());
- if (!present_fence) {
+ present_fence = last_present_fence_;
+ if (!present_fence)
continue;
- }
}
{
+ // NOLINTNEXTLINE(misc-const-correctness)
ATRACE_NAME("AsyncWaitForBuffersSwap");
constexpr int kTimeoutMs = 500;
- int err = sync_wait(present_fence.Get(), kTimeoutMs);
+ auto err = sync_wait(*present_fence, kTimeoutMs);
if (err != 0) {
- ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", present_fence.Get(),
- err, errno);
+ ALOGE("sync_wait(fd=%i) returned: %i (errno: %i)", *present_fence, err,
+ errno);
}
}
{
- std::unique_lock lk(*mutex_);
- if (st_man_ == nullptr) {
+ const std::unique_lock mlk(main_mutex);
+ const std::unique_lock lk(mutex_);
+ if (exit_thread_)
break;
- }
/* If resources is already cleaned-up by main thread, skip */
- if (tracking_at_the_moment > st_man_->frames_tracked_) {
- st_man_->CleanupPriorFrameResources();
- }
+ if (tracking_at_the_moment > frames_tracked_)
+ CleanupPriorFrameResources();
}
}
+
+ ALOGI("DrmAtomicStateManager thread exit");
}
void DrmAtomicStateManager::CleanupPriorFrameResources() {
assert(frames_staged_ - frames_tracked_ == 1);
assert(last_present_fence_);
+ // NOLINTNEXTLINE(misc-const-correctness)
ATRACE_NAME("CleanupPriorFrameResources");
frames_tracked_++;
active_frame_state_ = std::move(staged_frame_state_);
@@ -257,7 +264,7 @@ void DrmAtomicStateManager::CleanupPriorFrameResources() {
}
auto DrmAtomicStateManager::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
- int err = CommitFrame(args);
+ auto err = CommitFrame(args);
if (!args.test_only) {
if (err != 0) {
@@ -279,11 +286,11 @@ auto DrmAtomicStateManager::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
} // namespace android
auto DrmAtomicStateManager::ActivateDisplayUsingDPMS() -> int {
- return drmModeConnectorSetProperty(pipe_->device->GetFd(),
+ return drmModeConnectorSetProperty(*pipe_->device->GetFd(),
pipe_->connector->Get()->GetId(),
pipe_->connector->Get()
->GetDpmsProperty()
- .id(),
+ .GetId(),
DRM_MODE_DPMS_ON);
}
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index b0b85ac..6e32a37 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -14,16 +14,12 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
-#define ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
+#pragma once
#include <pthread.h>
-#include <functional>
#include <memory>
#include <optional>
-#include <sstream>
-#include <tuple>
#include "compositor/DrmKmsPlan.h"
#include "compositor/LayerData.h"
@@ -39,9 +35,10 @@ struct AtomicCommitArgs {
std::optional<DrmMode> display_mode;
std::optional<bool> active;
std::shared_ptr<DrmKmsPlan> composition;
+ std::shared_ptr<drm_color_ctm> color_matrix;
/* out */
- UniqueFd out_fence;
+ SharedFd out_fence;
/* helpers */
auto HasInputs() -> bool {
@@ -49,50 +46,26 @@ struct AtomicCommitArgs {
}
};
-class PresentTrackerThread {
- public:
- explicit PresentTrackerThread(DrmAtomicStateManager *st_man);
-
- ~PresentTrackerThread();
-
- void Stop() {
- /* Exit thread by signalling that object is no longer valid */
- st_man_ = nullptr;
- Notify();
- pt_.detach();
- }
-
- void Notify() {
- cv_.notify_all();
- }
-
- private:
- DrmAtomicStateManager *st_man_{};
-
- void PresentTrackerThreadFn();
-
- std::condition_variable cv_;
- std::thread pt_;
- std::mutex *mutex_;
-};
-
class DrmAtomicStateManager {
- friend class PresentTrackerThread;
-
public:
- explicit DrmAtomicStateManager(DrmDisplayPipeline *pipe)
- : pipe_(pipe),
- ptt_(std::make_unique<PresentTrackerThread>(this).release()){};
+ static auto CreateInstance(DrmDisplayPipeline *pipe)
+ -> std::shared_ptr<DrmAtomicStateManager>;
- DrmAtomicStateManager(const DrmAtomicStateManager &) = delete;
- ~DrmAtomicStateManager() {
- ptt_->Stop();
- }
+ ~DrmAtomicStateManager() = default;
auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
auto ActivateDisplayUsingDPMS() -> int;
+ void StopThread() {
+ {
+ const std::unique_lock lock(mutex_);
+ exit_thread_ = true;
+ }
+ cv_.notify_all();
+ }
+
private:
+ DrmAtomicStateManager() = default;
auto CommitFrame(AtomicCommitArgs &args) -> int;
struct KmsState {
@@ -103,6 +76,7 @@ class DrmAtomicStateManager {
std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers;
DrmModeUserPropertyBlobUnique mode_blob;
+ DrmModeUserPropertyBlobUnique ctm_blob;
int release_fence_pt_index{};
@@ -118,18 +92,19 @@ class DrmAtomicStateManager {
};
}
- DrmDisplayPipeline *const pipe_;
+ DrmDisplayPipeline *pipe_{};
void CleanupPriorFrameResources();
- /* Present (swap) tracking */
- PresentTrackerThread *ptt_;
KmsState staged_frame_state_;
- UniqueFd last_present_fence_;
+ SharedFd last_present_fence_;
int frames_staged_{};
int frames_tracked_{};
+
+ void ThreadFn(const std::shared_ptr<DrmAtomicStateManager> &dasm);
+ std::condition_variable cv_;
+ std::mutex mutex_;
+ bool exit_thread_{};
};
} // namespace android
-
-#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 4737316..f625563 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -63,7 +63,7 @@ static bool GetConnectorProperty(const DrmDevice &dev,
auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
uint32_t index)
-> std::unique_ptr<DrmConnector> {
- auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
+ auto conn = MakeDrmModeConnectorUnique(*dev.GetFd(), connector_id);
if (!conn) {
ALOGE("Failed to get connector %d", connector_id);
return {};
@@ -99,18 +99,17 @@ int DrmConnector::UpdateEdidProperty() {
}
auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
- uint64_t blob_id = 0;
- int ret = UpdateEdidProperty();
+ auto ret = UpdateEdidProperty();
if (ret != 0) {
return {};
}
- std::tie(ret, blob_id) = GetEdidProperty().value();
- if (ret != 0) {
+ auto blob_id = GetEdidProperty().GetValue();
+ if (!blob_id) {
return {};
}
- return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
+ return MakeDrmModePropertyBlobUnique(*drm_->GetFd(), *blob_id);
}
bool DrmConnector::IsInternal() const {
@@ -159,7 +158,7 @@ std::string DrmConnector::GetName() const {
}
int DrmConnector::UpdateModes() {
- auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
+ auto conn = MakeDrmModeConnectorUnique(*drm_->GetFd(), GetId());
if (!conn) {
ALOGE("Failed to get connector %d", GetId());
return -ENODEV;
@@ -177,15 +176,11 @@ int DrmConnector::UpdateModes() {
}
if (!exists) {
- modes_.emplace_back(DrmMode(&connector_->modes[i]));
+ modes_.emplace_back(&connector_->modes[i]);
}
}
return 0;
}
-void DrmConnector::SetActiveMode(DrmMode &mode) {
- active_mode_ = mode;
-}
-
} // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 629b3cc..f21f598 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_CONNECTOR_H_
-#define ANDROID_DRM_CONNECTOR_H_
+#pragma once
#include <xf86drmMode.h>
@@ -83,12 +82,6 @@ class DrmConnector : public PipelineBindable<DrmConnector> {
return modes_;
}
- auto &GetActiveMode() const {
- return active_mode_;
- }
-
- void SetActiveMode(DrmMode &mode);
-
auto &GetDpmsProperty() const {
return dpms_property_;
}
@@ -124,7 +117,6 @@ class DrmConnector : public PipelineBindable<DrmConnector> {
const uint32_t index_in_res_array_;
- DrmMode active_mode_;
std::vector<DrmMode> modes_;
DrmProperty dpms_property_;
@@ -135,5 +127,3 @@ class DrmConnector : public PipelineBindable<DrmConnector> {
DrmProperty writeback_out_fence_;
};
} // namespace android
-
-#endif // ANDROID_DRM_PLANE_H_
diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp
index b54f14b..948a9ac 100644
--- a/drm/DrmCrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -35,7 +35,7 @@ static int GetCrtcProperty(const DrmDevice &dev, const DrmCrtc &crtc,
auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
-> std::unique_ptr<DrmCrtc> {
- auto crtc = MakeDrmModeCrtcUnique(dev.GetFd(), crtc_id);
+ auto crtc = MakeDrmModeCrtcUnique(*dev.GetFd(), crtc_id);
if (!crtc) {
ALOGE("Failed to get CRTC %d", crtc_id);
return {};
@@ -61,6 +61,11 @@ auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
return {};
}
+ ret = GetCrtcProperty(dev, *c, "CTM", &c->ctm_property_);
+ if (ret != 0) {
+ ALOGV("Missing optional CTM property");
+ }
+
return c;
}
diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h
index ebf0a97..96443cd 100644
--- a/drm/DrmCrtc.h
+++ b/drm/DrmCrtc.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_CRTC_H_
-#define ANDROID_DRM_CRTC_H_
+#pragma once
#include <xf86drmMode.h>
@@ -59,6 +58,10 @@ class DrmCrtc : public PipelineBindable<DrmCrtc> {
return out_fence_ptr_property_;
}
+ auto &GetCtmProperty() const {
+ return ctm_property_;
+ }
+
private:
DrmCrtc(DrmModeCrtcUnique crtc, uint32_t index)
: crtc_(std::move(crtc)), index_in_res_array_(index){};
@@ -67,10 +70,10 @@ class DrmCrtc : public PipelineBindable<DrmCrtc> {
const uint32_t index_in_res_array_;
+ DrmProperty ctm_property_;
+
DrmProperty active_property_;
DrmProperty mode_property_;
DrmProperty out_fence_ptr_property_;
};
} // namespace android
-
-#endif // ANDROID_DRM_CRTC_H_
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 0f73f1f..1d6b62e 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -55,46 +55,46 @@ DrmDevice::DrmDevice(ResourceManager *res_man) : res_man_(res_man) {
auto DrmDevice::Init(const char *path) -> int {
/* TODO: Use drmOpenControl here instead */
- fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+ fd_ = MakeSharedFd(open(path, O_RDWR | O_CLOEXEC));
if (!fd_) {
// NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
ALOGE("Failed to open dri %s: %s", path, strerror(errno));
return -ENODEV;
}
- int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ int ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret != 0) {
ALOGE("Failed to set universal plane cap %d", ret);
return ret;
}
- ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
+ ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
if (ret != 0) {
ALOGE("Failed to set atomic cap %d", ret);
return ret;
}
#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
- ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+ ret = drmSetClientCap(*GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
if (ret != 0) {
ALOGI("Failed to set writeback cap %d", ret);
}
#endif
uint64_t cap_value = 0;
- if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
+ if (drmGetCap(*GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
ALOGW("drmGetCap failed. Fallback to no modifier support.");
cap_value = 0;
}
HasAddFb2ModifiersSupport_ = cap_value != 0;
- drmSetMaster(GetFd());
- if (drmIsMaster(GetFd()) == 0) {
+ drmSetMaster(*GetFd());
+ if (drmIsMaster(*GetFd()) == 0) {
ALOGE("DRM/KMS master access required");
return -EACCES;
}
- auto res = MakeDrmModeResUnique(GetFd());
+ auto res = MakeDrmModeResUnique(*GetFd());
if (!res) {
ALOGE("Failed to get DrmDevice resources");
return -ENODEV;
@@ -136,7 +136,7 @@ auto DrmDevice::Init(const char *path) -> int {
}
}
- auto plane_res = MakeDrmModePlaneResUnique(GetFd());
+ auto plane_res = MakeDrmModePlaneResUnique(*GetFd());
if (!plane_res) {
ALOGE("Failed to get plane resources");
return -ENOENT;
@@ -161,7 +161,7 @@ auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
create_blob.data = (__u64)data;
- int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
+ auto ret = drmIoctl(*GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
if (ret != 0) {
ALOGE("Failed to create mode property blob %d", ret);
return {};
@@ -171,8 +171,8 @@ auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
struct drm_mode_destroy_blob destroy_blob {};
destroy_blob.blob_id = (__u32)*it;
- int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
- &destroy_blob);
+ auto err = drmIoctl(*GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
+ &destroy_blob);
if (err != 0) {
ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
err);
@@ -186,7 +186,7 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
const char *prop_name, DrmProperty *property) const {
drmModeObjectPropertiesPtr props = nullptr;
- props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
+ props = drmModeObjectGetProperties(*GetFd(), obj_id, obj_type);
if (props == nullptr) {
ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
return -ENODEV;
@@ -195,7 +195,7 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
bool found = false;
for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
+ drmModePropertyPtr p = drmModeGetProperty(*GetFd(), props->props[i]);
if (strcmp(p->name, prop_name) == 0) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
property->Init(obj_id, p, props->prop_values[i]);
@@ -209,9 +209,9 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
}
std::string DrmDevice::GetName() const {
- auto *ver = drmGetVersion(GetFd());
+ auto *ver = drmGetVersion(*GetFd());
if (ver == nullptr) {
- ALOGW("Failed to get drm version for fd=%d", GetFd());
+ ALOGW("Failed to get drm version for fd=%d", *GetFd());
return "generic";
}
@@ -221,17 +221,17 @@ std::string DrmDevice::GetName() const {
}
auto DrmDevice::IsKMSDev(const char *path) -> bool {
- auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+ auto fd = MakeUniqueFd(open(path, O_RDWR | O_CLOEXEC));
if (!fd) {
return false;
}
- auto res = MakeDrmModeResUnique(fd.Get());
+ auto res = MakeDrmModeResUnique(*fd);
if (!res) {
return false;
}
- bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
+ auto is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
res->count_encoders > 0;
return is_kms;
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index 4cf0132..39d0c88 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_H_
-#define ANDROID_DRM_H_
+#pragma once
#include <cstdint>
#include <map>
@@ -24,8 +23,7 @@
#include "DrmConnector.h"
#include "DrmCrtc.h"
#include "DrmEncoder.h"
-#include "DrmFbImporter.h"
-#include "utils/UniqueFd.h"
+#include "utils/fd.h"
namespace android {
@@ -40,8 +38,8 @@ class DrmDevice {
static auto CreateInstance(std::string const &path, ResourceManager *res_man)
-> std::unique_ptr<DrmDevice>;
- auto GetFd() const {
- return fd_.Get();
+ auto &GetFd() const {
+ return fd_;
}
auto &GetResMan() {
@@ -103,7 +101,7 @@ class DrmDevice {
static auto IsKMSDev(const char *path) -> bool;
- UniqueFd fd_;
+ SharedFd fd_;
std::vector<std::unique_ptr<DrmConnector>> connectors_;
std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
@@ -121,5 +119,3 @@ class DrmDevice {
ResourceManager *const res_man_;
};
} // namespace android
-
-#endif // ANDROID_DRM_H_
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
index e81544d..1a8ad5b 100644
--- a/drm/DrmDisplayPipeline.cpp
+++ b/drm/DrmDisplayPipeline.cpp
@@ -98,7 +98,7 @@ static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
return {};
}
- pipe->atomic_state_manager = std::make_unique<DrmAtomicStateManager>(
+ pipe->atomic_state_manager = DrmAtomicStateManager::CreateInstance(
pipe.get());
return pipe;
@@ -171,9 +171,9 @@ auto DrmDisplayPipeline::GetUsablePlanes()
std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> planes;
planes.emplace_back(primary_plane);
- static bool use_overlay_planes = ReadUseOverlayProperty();
+ const static bool kUseOverlayPlanes = ReadUseOverlayProperty();
- if (use_overlay_planes) {
+ if (kUseOverlayPlanes) {
for (const auto &plane : device->GetPlanes()) {
if (plane->IsCrtcSupported(*crtc->Get())) {
if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
@@ -189,4 +189,9 @@ auto DrmDisplayPipeline::GetUsablePlanes()
return planes;
}
+DrmDisplayPipeline::~DrmDisplayPipeline() {
+ if (atomic_state_manager)
+ atomic_state_manager->StopThread();
+}
+
} // namespace android
diff --git a/drm/DrmDisplayPipeline.h b/drm/DrmDisplayPipeline.h
index 7ec619e..cf64a36 100644
--- a/drm/DrmDisplayPipeline.h
+++ b/drm/DrmDisplayPipeline.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRMDISPLAYPIPELINE_H_
-#define ANDROID_DRMDISPLAYPIPELINE_H_
+#pragma once
#include <memory>
#include <vector>
@@ -75,6 +74,8 @@ struct DrmDisplayPipeline {
auto GetUsablePlanes()
-> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>>;
+ ~DrmDisplayPipeline();
+
DrmDevice *device;
std::shared_ptr<BindingOwner<DrmConnector>> connector;
@@ -82,9 +83,7 @@ struct DrmDisplayPipeline {
std::shared_ptr<BindingOwner<DrmCrtc>> crtc;
std::shared_ptr<BindingOwner<DrmPlane>> primary_plane;
- std::unique_ptr<DrmAtomicStateManager> atomic_state_manager;
+ std::shared_ptr<DrmAtomicStateManager> atomic_state_manager;
};
} // namespace android
-
-#endif
diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp
index eed5b5f..21ca693 100644
--- a/drm/DrmEncoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -29,7 +29,7 @@ namespace android {
auto DrmEncoder::CreateInstance(DrmDevice &dev, uint32_t encoder_id,
uint32_t index) -> std::unique_ptr<DrmEncoder> {
- auto e = MakeDrmModeEncoderUnique(dev.GetFd(), encoder_id);
+ auto e = MakeDrmModeEncoderUnique(*dev.GetFd(), encoder_id);
if (!e) {
ALOGE("Failed to get encoder %d", encoder_id);
return {};
diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h
index 39a695c..89e664c 100644
--- a/drm/DrmEncoder.h
+++ b/drm/DrmEncoder.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_ENCODER_H_
-#define ANDROID_DRM_ENCODER_H_
+#pragma once
#include <xf86drmMode.h>
@@ -65,5 +64,3 @@ class DrmEncoder : public PipelineBindable<DrmEncoder> {
const uint32_t index_in_res_array_;
};
} // namespace android
-
-#endif // ANDROID_DRM_ENCODER_H_
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index 585b789..a91a52b 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -37,6 +37,7 @@ namespace android {
auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
DrmDevice &drm)
-> std::shared_ptr<DrmFbIdHandle> {
+ // NOLINTNEXTLINE(misc-const-correctness)
ATRACE_NAME("Import dmabufs and register FB");
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
@@ -49,7 +50,7 @@ auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
for (size_t i = 1; i < local->gem_handles_.size(); i++) {
if (bo->prime_fds[i] > 0) {
if (bo->prime_fds[i] != bo->prime_fds[0]) {
- err = drmPrimeFDToHandle(drm.GetFd(), bo->prime_fds[i],
+ err = drmPrimeFDToHandle(*drm.GetFd(), bo->prime_fds[i],
&local->gem_handles_.at(i));
if (err != 0) {
ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
@@ -61,7 +62,7 @@ auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
}
}
- bool has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
+ auto has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
@@ -73,11 +74,11 @@ auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
/* Create framebuffer object */
if (!has_modifiers) {
- err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
+ err = drmModeAddFB2(*drm.GetFd(), bo->width, bo->height, bo->format,
local->gem_handles_.data(), &bo->pitches[0],
&bo->offsets[0], &local->fb_id_, 0);
} else {
- err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
+ err = drmModeAddFB2WithModifiers(*drm.GetFd(), bo->width, bo->height,
bo->format, local->gem_handles_.data(),
&bo->pitches[0], &bo->offsets[0],
&bo->modifiers[0], &local->fb_id_,
@@ -92,10 +93,11 @@ auto DrmFbIdHandle::CreateInstance(BufferInfo *bo, GemHandle first_gem_handle,
}
DrmFbIdHandle::~DrmFbIdHandle() {
+ // NOLINTNEXTLINE(misc-const-correctness)
ATRACE_NAME("Close FB and dmabufs");
/* Destroy framebuffer object */
- if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
+ if (drmModeRmFB(*drm_->GetFd(), fb_id_) != 0) {
ALOGE("Failed to rm fb");
}
@@ -116,7 +118,7 @@ DrmFbIdHandle::~DrmFbIdHandle() {
continue;
}
gem_close.handle = gem_handles_[i];
- int32_t err = drmIoctl(drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+ auto err = drmIoctl(*drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
if (err != 0) {
ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
}
@@ -127,8 +129,8 @@ auto DrmFbImporter::GetOrCreateFbId(BufferInfo *bo)
-> std::shared_ptr<DrmFbIdHandle> {
/* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
GemHandle first_handle = 0;
- int32_t err = drmPrimeFDToHandle(drm_->GetFd(), bo->prime_fds[0],
- &first_handle);
+ auto err = drmPrimeFDToHandle(*drm_->GetFd(), 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 9e94238..9a7c335 100644
--- a/drm/DrmFbImporter.h
+++ b/drm/DrmFbImporter.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef DRM_DRMFBIMPORTER_H_
-#define DRM_DRMFBIMPORTER_H_
+#pragma once
#include <drm/drm_fourcc.h>
#include <hardware/gralloc.h>
@@ -87,5 +86,3 @@ class DrmFbImporter {
};
} // namespace android
-
-#endif
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index 010ea1b..7cbea44 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -22,119 +22,22 @@
namespace android {
-DrmMode::DrmMode(drmModeModeInfoPtr m)
- : clock_(m->clock),
- h_display_(m->hdisplay),
- h_sync_start_(m->hsync_start),
- h_sync_end_(m->hsync_end),
- h_total_(m->htotal),
- h_skew_(m->hskew),
- v_display_(m->vdisplay),
- v_sync_start_(m->vsync_start),
- v_sync_end_(m->vsync_end),
- v_total_(m->vtotal),
- v_scan_(m->vscan),
- v_refresh_(m->vrefresh),
- flags_(m->flags),
- type_(m->type),
- name_(m->name) {
-}
+DrmMode::DrmMode(drmModeModeInfoPtr m) : mode_(*m){};
bool DrmMode::operator==(const drmModeModeInfo &m) const {
- return clock_ == m.clock && h_display_ == m.hdisplay &&
- h_sync_start_ == m.hsync_start && h_sync_end_ == m.hsync_end &&
- h_total_ == m.htotal && h_skew_ == m.hskew &&
- v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start &&
- v_sync_end_ == m.vsync_end && v_total_ == m.vtotal &&
- v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type;
-}
-
-uint32_t DrmMode::clock() const {
- return clock_;
-}
-
-uint16_t DrmMode::h_display() const {
- return h_display_;
-}
-
-uint16_t DrmMode::h_sync_start() const {
- return h_sync_start_;
-}
-
-uint16_t DrmMode::h_sync_end() const {
- return h_sync_end_;
-}
-
-uint16_t DrmMode::h_total() const {
- return h_total_;
-}
-
-uint16_t DrmMode::h_skew() const {
- return h_skew_;
-}
-
-uint16_t DrmMode::v_display() const {
- return v_display_;
-}
-
-uint16_t DrmMode::v_sync_start() const {
- return v_sync_start_;
-}
-
-uint16_t DrmMode::v_sync_end() const {
- return v_sync_end_;
-}
-
-uint16_t DrmMode::v_total() const {
- return v_total_;
-}
-
-uint16_t DrmMode::v_scan() const {
- return v_scan_;
-}
-
-float DrmMode::v_refresh() const {
- if (clock_ == 0) {
- return v_refresh_;
- }
- // Always recalculate refresh to report correct float rate
- return static_cast<float>(clock_) / (float)(v_total_ * h_total_) * 1000.0F;
-}
-
-uint32_t DrmMode::flags() const {
- return flags_;
-}
-
-uint32_t DrmMode::type() const {
- return type_;
-}
-
-std::string DrmMode::name() const {
- return name_ + "@" + std::to_string(v_refresh());
+ return memcmp(&m, &mode_, offsetof(drmModeModeInfo, name)) == 0;
}
auto DrmMode::CreateModeBlob(const DrmDevice &drm)
-> DrmModeUserPropertyBlobUnique {
- struct drm_mode_modeinfo drm_mode = {
- .clock = clock_,
- .hdisplay = h_display_,
- .hsync_start = h_sync_start_,
- .hsync_end = h_sync_end_,
- .htotal = h_total_,
- .hskew = h_skew_,
- .vdisplay = v_display_,
- .vsync_start = v_sync_start_,
- .vsync_end = v_sync_end_,
- .vtotal = v_total_,
- .vscan = v_scan_,
- .vrefresh = v_refresh_,
- .flags = flags_,
- .type = type_,
- };
- strncpy(drm_mode.name, name_.c_str(), DRM_DISPLAY_MODE_LEN);
+ struct drm_mode_modeinfo drm_mode = {};
+ /* drm_mode_modeinfo and drmModeModeInfo should be identical
+ * At least libdrm does the same memcpy in drmModeAttachMode();
+ */
+ memcpy(&drm_mode, &mode_, sizeof(struct drm_mode_modeinfo));
return drm.RegisterUserPropertyBlob(&drm_mode,
- sizeof(struct drm_mode_modeinfo));
+ sizeof(struct drm_mode_modeinfo));
}
} // namespace android
diff --git a/drm/DrmMode.h b/drm/DrmMode.h
index 20515f9..c5790a5 100644
--- a/drm/DrmMode.h
+++ b/drm/DrmMode.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_MODE_H_
-#define ANDROID_DRM_MODE_H_
+#pragma once
#include <xf86drmMode.h>
@@ -36,49 +35,26 @@ class DrmMode {
bool operator==(const drmModeModeInfo &m) const;
- uint32_t clock() const;
+ auto &GetRawMode() const {
+ return mode_;
+ }
- uint16_t h_display() const;
- uint16_t h_sync_start() const;
- uint16_t h_sync_end() const;
- uint16_t h_total() const;
- uint16_t h_skew() const;
+ auto GetVRefresh() const {
+ if (mode_.clock == 0) {
+ return float(mode_.vrefresh);
+ }
+ // Always recalculate refresh to report correct float rate
+ return static_cast<float>(mode_.clock) /
+ (float)(mode_.vtotal * mode_.htotal) * 1000.0F;
+ }
- uint16_t v_display() const;
- uint16_t v_sync_start() const;
- uint16_t v_sync_end() const;
- uint16_t v_total() const;
- uint16_t v_scan() const;
- float v_refresh() const;
-
- uint32_t flags() const;
- uint32_t type() const;
-
- std::string name() const;
+ auto GetName() const {
+ return std::string(mode_.name) + "@" + std::to_string(GetVRefresh());
+ }
auto CreateModeBlob(const DrmDevice &drm) -> DrmModeUserPropertyBlobUnique;
private:
- uint32_t clock_ = 0;
-
- uint16_t h_display_ = 0;
- uint16_t h_sync_start_ = 0;
- uint16_t h_sync_end_ = 0;
- uint16_t h_total_ = 0;
- uint16_t h_skew_ = 0;
-
- uint16_t v_display_ = 0;
- uint16_t v_sync_start_ = 0;
- uint16_t v_sync_end_ = 0;
- uint16_t v_total_ = 0;
- uint16_t v_scan_ = 0;
- uint16_t v_refresh_ = 0;
-
- uint32_t flags_ = 0;
- uint32_t type_ = 0;
-
- std::string name_;
+ drmModeModeInfo mode_;
};
} // namespace android
-
-#endif // ANDROID_DRM_MODE_H_
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 5051d35..228e3dd 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -31,7 +31,7 @@ namespace android {
auto DrmPlane::CreateInstance(DrmDevice &dev, uint32_t plane_id)
-> std::unique_ptr<DrmPlane> {
- auto p = MakeDrmModePlaneUnique(dev.GetFd(), plane_id);
+ auto p = MakeDrmModePlaneUnique(*dev.GetFd(), plane_id);
if (!p) {
ALOGE("Failed to get plane %d", plane_id);
return {};
@@ -57,21 +57,19 @@ int DrmPlane::Init() {
return -ENOTSUP;
}
- int ret = 0;
- uint64_t type = 0;
- std::tie(ret, type) = p.value();
- if (ret != 0) {
+ auto type = p.GetValue();
+ if (!type) {
ALOGE("Failed to get plane type property value");
- return ret;
+ return -EINVAL;
}
- switch (type) {
+ switch (*type) {
case DRM_PLANE_TYPE_OVERLAY:
case DRM_PLANE_TYPE_PRIMARY:
case DRM_PLANE_TYPE_CURSOR:
- type_ = (uint32_t)type;
+ type_ = (uint32_t)*type;
break;
default:
- ALOGE("Invalid plane type %" PRIu64, type);
+ ALOGE("Invalid plane type %" PRIu64, *type);
return -EINVAL;
}
@@ -148,9 +146,10 @@ int DrmPlane::Init() {
}
bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
- unsigned int crtc_property_value = 0;
- std::tie(std::ignore, crtc_property_value) = crtc_property_.value();
- if (crtc_property_value != 0 && crtc_property_value != crtc.GetId() &&
+ auto crtc_prop_optval = crtc_property_.GetValue();
+ auto crtc_prop_val = crtc_prop_optval ? *crtc_prop_optval : 0;
+
+ if (crtc_prop_val != 0 && crtc_prop_val != crtc.GetId() &&
GetType() == DRM_PLANE_TYPE_PRIMARY) {
// Some DRM driver such as omap_drm allows sharing primary plane between
// CRTCs, but the primay plane could not be shared if it has been used by
@@ -158,10 +157,9 @@ bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
// in the kernel drivers/gpu/drm/drm_atomic.c file.
// The current drm_hwc design is not ready to support such scenario yet,
// so adding the CRTC status check here to workaorund for now.
- ALOGW(
- "%s: This Plane(id=%d) is activated for Crtc(id=%d), could not be used "
- "for Crtc (id=%d)",
- __FUNCTION__, GetId(), crtc_property_value, crtc.GetId());
+ ALOGW("%s: This Plane(id=%d) is activated for Crtc(id=%" PRIu64
+ "), could not be used for Crtc (id=%d)",
+ __FUNCTION__, GetId(), crtc_prop_val, crtc.GetId());
return false;
}
@@ -169,6 +167,11 @@ bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
}
bool DrmPlane::IsValidForLayer(LayerData *layer) {
+ if (layer == nullptr || !layer->bi) {
+ ALOGE("%s: Invalid parameters", __func__);
+ return false;
+ }
+
if (!rotation_property_) {
if (layer->pi.transform != LayerTransform::kIdentity) {
ALOGV("No rotation property on plane %d", GetId());
@@ -181,7 +184,7 @@ bool DrmPlane::IsValidForLayer(LayerData *layer) {
}
}
- if (alpha_property_.id() == 0 && layer->pi.alpha != UINT16_MAX) {
+ if (!alpha_property_ && layer->pi.alpha != UINT16_MAX) {
ALOGV("Alpha is not supported on plane %d", GetId());
return false;
}
@@ -193,7 +196,7 @@ bool DrmPlane::IsValidForLayer(LayerData *layer) {
return false;
}
- uint32_t format = layer->bi->format;
+ auto format = layer->bi->format;
if (!IsFormatSupported(format)) {
ALOGV("Plane %d does not supports %c%c%c%c format", GetId(), format,
format >> 8, format >> 16, format >> 24);
@@ -241,16 +244,16 @@ static int To1616FixPt(float in) {
auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, LayerData &layer,
uint32_t zpos, uint32_t crtc_id) -> int {
- if (!layer.fb) {
- ALOGE("Expected a valid framebuffer for pset");
+ if (!layer.fb || !layer.bi) {
+ ALOGE("%s: Invalid arguments", __func__);
return -EINVAL;
}
- if (zpos_property_ && !zpos_property_.is_immutable()) {
+ if (zpos_property_ && !zpos_property_.IsImmutable()) {
uint64_t min_zpos = 0;
// Ignore ret and use min_zpos as 0 by default
- std::tie(std::ignore, min_zpos) = zpos_property_.range_min();
+ std::tie(std::ignore, min_zpos) = zpos_property_.RangeMin();
if (!zpos_property_.AtomicSet(pset, zpos + min_zpos)) {
return -EINVAL;
@@ -258,7 +261,7 @@ auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, LayerData &layer,
}
if (layer.acquire_fence &&
- !in_fence_fd_property_.AtomicSet(pset, layer.acquire_fence.Get())) {
+ !in_fence_fd_property_.AtomicSet(pset, *layer.acquire_fence)) {
return -EINVAL;
}
@@ -317,8 +320,8 @@ auto DrmPlane::AtomicDisablePlane(drmModeAtomicReq &pset) -> int {
auto DrmPlane::GetPlaneProperty(const char *prop_name, DrmProperty &property,
Presence presence) -> bool {
- int err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_PLANE, prop_name,
- &property);
+ auto err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_PLANE, prop_name,
+ &property);
if (err != 0) {
if (presence == Presence::kMandatory) {
ALOGE("Could not get mandatory property \"%s\" from plane %d", prop_name,
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index 31f0a33..c26a3cc 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_PLANE_H_
-#define ANDROID_DRM_PLANE_H_
+#pragma once
#include <xf86drmMode.h>
@@ -100,5 +99,3 @@ class DrmPlane : public PipelineBindable<DrmPlane> {
std::map<LayerTransform, uint64_t> transform_enum_map_;
};
} // namespace android
-
-#endif // ANDROID_DRM_PLANE_H_
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index 32f1c62..938b3ad 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -31,7 +31,7 @@
namespace android {
DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e)
- : value_(e->value), name_(e->name) {
+ : value(e->value), name(e->name) {
}
DrmProperty::DrmProperty(uint32_t obj_id, drmModePropertyPtr p,
@@ -47,70 +47,43 @@ void DrmProperty::Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) {
value_ = value;
for (int i = 0; i < p->count_values; ++i)
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
values_.emplace_back(p->values[i]);
for (int i = 0; i < p->count_enums; ++i)
- enums_.emplace_back(DrmPropertyEnum(&p->enums[i]));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
+ enums_.emplace_back(&p->enums[i]);
for (int i = 0; i < p->count_blobs; ++i)
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic):
blob_ids_.emplace_back(p->blob_ids[i]);
-
- if (flags_ & DRM_MODE_PROP_RANGE)
- type_ = DRM_PROPERTY_TYPE_INT;
- else if (flags_ & DRM_MODE_PROP_ENUM)
- type_ = DRM_PROPERTY_TYPE_ENUM;
- else if (flags_ & DRM_MODE_PROP_OBJECT)
- type_ = DRM_PROPERTY_TYPE_OBJECT;
- else if (flags_ & DRM_MODE_PROP_BLOB)
- type_ = DRM_PROPERTY_TYPE_BLOB;
- else if (flags_ & DRM_MODE_PROP_BITMASK)
- type_ = DRM_PROPERTY_TYPE_BITMASK;
-}
-
-uint32_t DrmProperty::id() const {
- return id_;
-}
-
-std::string DrmProperty::name() const {
- return name_;
}
-std::tuple<int, uint64_t> DrmProperty::value() const {
- if (type_ == DRM_PROPERTY_TYPE_BLOB)
- return std::make_tuple(0, value_);
+std::optional<uint64_t> DrmProperty::GetValue() const {
+ if ((flags_ & DRM_MODE_PROP_BLOB) != 0)
+ return value_;
if (values_.empty())
- return std::make_tuple(-ENOENT, 0);
-
- switch (type_) {
- case DRM_PROPERTY_TYPE_INT:
- return std::make_tuple(0, value_);
-
- case DRM_PROPERTY_TYPE_ENUM:
- if (value_ >= enums_.size())
- return std::make_tuple(-ENOENT, 0);
+ return {};
- return std::make_tuple(0, enums_[value_].value_);
+ if ((flags_ & DRM_MODE_PROP_RANGE) != 0)
+ return value_;
- case DRM_PROPERTY_TYPE_OBJECT:
- return std::make_tuple(0, value_);
+ if ((flags_ & DRM_MODE_PROP_ENUM) != 0) {
+ if (value_ >= enums_.size())
+ return {};
- case DRM_PROPERTY_TYPE_BITMASK:
- default:
- return std::make_tuple(-EINVAL, 0);
+ return enums_[value_].value;
}
-}
-bool DrmProperty::is_immutable() const {
- return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE);
-}
+ if ((flags_ & DRM_MODE_PROP_OBJECT) != 0)
+ return value_;
-bool DrmProperty::is_range() const {
- return id_ && (flags_ & DRM_MODE_PROP_RANGE);
+ return {};
}
-std::tuple<int, uint64_t> DrmProperty::range_min() const {
- if (!is_range())
+std::tuple<int, uint64_t> DrmProperty::RangeMin() const {
+ if (!IsRange())
return std::make_tuple(-EINVAL, 0);
if (values_.empty())
return std::make_tuple(-ENOENT, 0);
@@ -118,8 +91,8 @@ std::tuple<int, uint64_t> DrmProperty::range_min() const {
return std::make_tuple(0, values_[0]);
}
-std::tuple<int, uint64_t> DrmProperty::range_max() const {
- if (!is_range())
+std::tuple<int, uint64_t> DrmProperty::RangeMax() const {
+ if (!IsRange())
return std::make_tuple(-EINVAL, 0);
if (values_.size() < 2)
return std::make_tuple(-ENOENT, 0);
@@ -130,8 +103,8 @@ std::tuple<int, uint64_t> DrmProperty::range_max() const {
std::tuple<uint64_t, int> DrmProperty::GetEnumValueWithName(
const std::string &name) const {
for (const auto &it : enums_) {
- if (it.name_ == name) {
- return std::make_tuple(it.value_, 0);
+ if (it.name == name) {
+ return std::make_tuple(it.value, 0);
}
}
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index 26a7c38..516518b 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -14,27 +14,18 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_PROPERTY_H_
-#define ANDROID_DRM_PROPERTY_H_
+#pragma once
#include <xf86drmMode.h>
#include <cstdint>
#include <map>
+#include <optional>
#include <string>
#include <vector>
namespace android {
-enum DrmPropertyType {
- DRM_PROPERTY_TYPE_INT,
- DRM_PROPERTY_TYPE_ENUM,
- DRM_PROPERTY_TYPE_OBJECT,
- DRM_PROPERTY_TYPE_BLOB,
- DRM_PROPERTY_TYPE_BITMASK,
- DRM_PROPERTY_TYPE_INVALID,
-};
-
class DrmProperty {
public:
DrmProperty() = default;
@@ -45,15 +36,26 @@ class DrmProperty {
auto Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) -> void;
std::tuple<uint64_t, int> GetEnumValueWithName(const std::string &name) const;
- uint32_t id() const;
- std::string name() const;
+ auto GetId() const {
+ return id_;
+ }
+
+ auto GetName() const {
+ return name_;
+ }
+
+ auto GetValue() const -> std::optional<uint64_t>;
- std::tuple<int, uint64_t> value() const;
- bool is_immutable() const;
+ bool IsImmutable() const {
+ return id_ != 0 && (flags_ & DRM_MODE_PROP_IMMUTABLE) != 0;
+ }
- bool is_range() const;
- std::tuple<int, uint64_t> range_min() const;
- std::tuple<int, uint64_t> range_max() const;
+ bool IsRange() const {
+ return id_ != 0 && (flags_ & DRM_MODE_PROP_RANGE) != 0;
+ }
+
+ auto RangeMin() const -> std::tuple<int, uint64_t>;
+ auto RangeMax() const -> std::tuple<int, uint64_t>;
[[nodiscard]] auto AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
-> bool;
@@ -72,14 +74,13 @@ class DrmProperty {
explicit DrmPropertyEnum(drm_mode_property_enum *e);
~DrmPropertyEnum() = default;
- uint64_t value_;
- std::string name_;
+ uint64_t value;
+ std::string name;
};
uint32_t obj_id_ = 0;
uint32_t id_ = 0;
- DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID;
uint32_t flags_ = 0;
std::string name_;
uint64_t value_ = 0;
@@ -104,5 +105,3 @@ auto DrmProperty::AddEnumToMap(const std::string &name, E key,
}
} // namespace android
-
-#endif // ANDROID_DRM_PROPERTY_H_
diff --git a/drm/DrmUnique.h b/drm/DrmUnique.h
index 282528b..2be1eb9 100644
--- a/drm/DrmUnique.h
+++ b/drm/DrmUnique.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef DRM_UNIQUE_H_
-#define DRM_UNIQUE_H_
+#pragma once
#include <xf86drmMode.h>
@@ -83,5 +82,3 @@ auto inline MakeDrmModeResUnique(int fd) {
return DrmModeResUnique(drmModeGetResources(fd),
[](drmModeRes *it) { drmModeFreeResources(it); });
}
-
-#endif
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index dbf0993..577d86c 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -36,13 +36,7 @@ namespace android {
ResourceManager::ResourceManager(
PipelineToFrontendBindingInterface *p2f_bind_interface)
: frontend_interface_(p2f_bind_interface) {
- if (uevent_listener_.Init() != 0) {
- ALOGE("Can't initialize event listener");
- }
-}
-
-ResourceManager::~ResourceManager() {
- uevent_listener_.Exit();
+ uevent_listener_ = UEventListener::CreateInstance();
}
void ResourceManager::Init() {
@@ -54,8 +48,8 @@ void ResourceManager::Init() {
char path_pattern[PROPERTY_VALUE_MAX];
// Could be a valid path or it can have at the end of it the wildcard %
// which means that it will try open all devices until an error is met.
- int path_len = property_get("vendor.hwc.drm.device", path_pattern,
- "/dev/dri/card%");
+ auto path_len = property_get("vendor.hwc.drm.device", path_pattern,
+ "/dev/dri/card%");
if (path_pattern[path_len - 1] != '%') {
auto dev = DrmDevice::CreateInstance(path_pattern, this);
if (dev) {
@@ -78,17 +72,29 @@ void ResourceManager::Init() {
}
}
- char scale_with_gpu[PROPERTY_VALUE_MAX];
- property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0");
- scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1));
+ char proptext[PROPERTY_VALUE_MAX];
+ property_get("vendor.hwc.drm.scale_with_gpu", proptext, "0");
+ scale_with_gpu_ = bool(strncmp(proptext, "0", 1));
+
+ constexpr char kDrmOrGpu[] = "DRM_OR_GPU";
+ constexpr char kDrmOrIgnore[] = "DRM_OR_IGNORE";
+ property_get("vendor.hwc.drm.ctm", proptext, kDrmOrGpu);
+ if (strncmp(proptext, kDrmOrGpu, sizeof(kDrmOrGpu)) == 0) {
+ ctm_handling_ = CtmHandling::kDrmOrGpu;
+ } else if (strncmp(proptext, kDrmOrIgnore, sizeof(kDrmOrIgnore)) == 0) {
+ ctm_handling_ = CtmHandling::kDrmOrIgnore;
+ } else {
+ ALOGE("Invalid value for vendor.hwc.drm.ctm: %s", proptext);
+ ctm_handling_ = CtmHandling::kDrmOrGpu;
+ }
if (BufferInfoGetter::GetInstance() == nullptr) {
ALOGE("Failed to initialize BufferInfoGetter");
return;
}
- uevent_listener_.RegisterHotplugHandler([this] {
- const std::lock_guard<std::mutex> lock(GetMainLock());
+ uevent_listener_->RegisterHotplugHandler([this] {
+ const std::unique_lock lock(GetMainLock());
UpdateFrontendDisplays();
});
@@ -103,7 +109,7 @@ void ResourceManager::DeInit() {
return;
}
- uevent_listener_.RegisterHotplugHandler([] {});
+ uevent_listener_->RegisterHotplugHandler({});
DetachAllFrontendDisplays();
drms_.clear();
@@ -123,8 +129,8 @@ void ResourceManager::UpdateFrontendDisplays() {
for (auto *conn : ordered_connectors) {
conn->UpdateModes();
- bool connected = conn->IsConnected();
- bool attached = attached_pipelines_.count(conn) != 0;
+ auto connected = conn->IsConnected();
+ auto attached = attached_pipelines_.count(conn) != 0;
if (connected != attached) {
ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 144d00e..7fa3fc6 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef RESOURCEMANAGER_H
-#define RESOURCEMANAGER_H
+#pragma once
#include <cstring>
+#include <mutex>
#include "DrmDevice.h"
#include "DrmDisplayPipeline.h"
@@ -26,6 +26,11 @@
namespace android {
+enum class CtmHandling {
+ kDrmOrGpu, /* Handled by DRM is possible, otherwise by GPU */
+ kDrmOrIgnore, /* Handled by DRM is possible, otherwise displayed as is */
+};
+
class PipelineToFrontendBindingInterface {
public:
virtual ~PipelineToFrontendBindingInterface() = default;
@@ -42,7 +47,7 @@ class ResourceManager {
ResourceManager &operator=(const ResourceManager &) = delete;
ResourceManager(const ResourceManager &&) = delete;
ResourceManager &&operator=(const ResourceManager &&) = delete;
- ~ResourceManager();
+ ~ResourceManager() = default;
void Init();
@@ -52,6 +57,10 @@ class ResourceManager {
return scale_with_gpu_;
}
+ auto &GetCtmHandling() const {
+ return ctm_handling_;
+ }
+
auto &GetMainLock() {
return main_lock_;
}
@@ -65,11 +74,13 @@ class ResourceManager {
std::vector<std::unique_ptr<DrmDevice>> drms_;
+ // Android properties:
bool scale_with_gpu_{};
+ CtmHandling ctm_handling_{};
- UEventListener uevent_listener_;
+ std::shared_ptr<UEventListener> uevent_listener_;
- std::mutex main_lock_;
+ std::recursive_mutex main_lock_;
std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>
attached_pipelines_;
@@ -79,5 +90,3 @@ class ResourceManager {
bool initialized_{};
};
} // namespace android
-
-#endif // RESOURCEMANAGER_H
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
index b56b8e1..a05ec65 100644
--- a/drm/UEventListener.cpp
+++ b/drm/UEventListener.cpp
@@ -18,37 +18,37 @@
#include "UEventListener.h"
-#include <cerrno>
+#include <thread>
#include "utils/log.h"
-/* Originally defined in system/core/libsystem/include/system/graphics.h as
- * #define HAL_PRIORITY_URGENT_DISPLAY (-8)*/
-constexpr int kHalPriorityUrgentDisplay = -8;
-
namespace android {
-UEventListener::UEventListener()
- : Worker("uevent-listener", kHalPriorityUrgentDisplay){};
+auto UEventListener::CreateInstance() -> std::shared_ptr<UEventListener> {
+ auto uel = std::shared_ptr<UEventListener>(new UEventListener());
-int UEventListener::Init() {
- uevent_ = UEvent::CreateInstance();
- if (!uevent_) {
- return -ENODEV;
- }
+ uel->uevent_ = UEvent::CreateInstance();
+ if (!uel->uevent_)
+ return {};
+
+ std::thread(&UEventListener::ThreadFn, uel.get(), uel).detach();
- return InitWorker();
+ return uel;
}
-void UEventListener::Routine() {
+void UEventListener::ThreadFn(const std::shared_ptr<UEventListener> &uel) {
+ // TODO(nobody): Rework code to allow stopping the thread (low priority)
while (true) {
- auto uevent_str = uevent_->ReadNext();
+ if (uel.use_count() == 1)
+ break;
+
+ auto uevent_str = uel->uevent_->ReadNext();
if (!hotplug_handler_ || !uevent_str)
continue;
- bool drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
- bool hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
+ auto drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
+ auto hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
if (drm_event && hotplug_event) {
constexpr useconds_t kDelayAfterUeventUs = 200000;
@@ -58,5 +58,7 @@ void UEventListener::Routine() {
hotplug_handler_();
}
}
+
+ ALOGI("UEvent thread exit");
}
} // namespace android
diff --git a/drm/UEventListener.h b/drm/UEventListener.h
index c8b8582..4f2be7c 100644
--- a/drm/UEventListener.h
+++ b/drm/UEventListener.h
@@ -14,35 +14,31 @@
* limitations under the License.
*/
-#ifndef ANDROID_UEVENT_LISTENER_H_
-#define ANDROID_UEVENT_LISTENER_H_
+#pragma once
#include <functional>
#include "utils/UEvent.h"
-#include "utils/Worker.h"
namespace android {
-class UEventListener : public Worker {
+class UEventListener {
public:
- UEventListener();
- ~UEventListener() override = default;
+ ~UEventListener() = default;
- int Init();
+ static auto CreateInstance() -> std::shared_ptr<UEventListener>;
void RegisterHotplugHandler(std::function<void()> hotplug_handler) {
hotplug_handler_ = std::move(hotplug_handler);
}
- protected:
- void Routine() override;
-
private:
+ UEventListener() = default;
+
+ void ThreadFn(const std::shared_ptr<UEventListener> &uel);
+
std::unique_ptr<UEvent> uevent_;
std::function<void()> hotplug_handler_;
};
} // namespace android
-
-#endif
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index ed41189..8a251c7 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -25,28 +25,48 @@
#include <cstring>
#include <ctime>
+#include "drm/ResourceManager.h"
#include "utils/log.h"
namespace android {
-VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY){};
+auto VSyncWorker::CreateInstance(DrmDisplayPipeline *pipe,
+ VSyncWorkerCallbacks &callbacks)
+ -> std::shared_ptr<VSyncWorker> {
+ auto vsw = std::shared_ptr<VSyncWorker>(new VSyncWorker());
-auto VSyncWorker::Init(DrmDisplayPipeline *pipe,
- std::function<void(uint64_t /*timestamp*/)> callback)
- -> int {
- pipe_ = pipe;
- callback_ = std::move(callback);
+ vsw->callbacks_ = callbacks;
- return InitWorker();
+ if (pipe != nullptr) {
+ vsw->high_crtc_ = pipe->crtc->Get()->GetIndexInResArray()
+ << DRM_VBLANK_HIGH_CRTC_SHIFT;
+ vsw->drm_fd_ = pipe->device->GetFd();
+ }
+
+ std::thread(&VSyncWorker::ThreadFn, vsw.get(), vsw).detach();
+
+ return vsw;
}
void VSyncWorker::VSyncControl(bool enabled) {
- Lock();
- enabled_ = enabled;
- last_timestamp_ = -1;
- Unlock();
+ {
+ const std::lock_guard<std::mutex> lock(mutex_);
+ enabled_ = enabled;
+ last_timestamp_ = -1;
+ }
+
+ cv_.notify_all();
+}
+
+void VSyncWorker::StopThread() {
+ {
+ const std::lock_guard<std::mutex> lock(mutex_);
+ thread_exit_ = true;
+ enabled_ = false;
+ callbacks_ = {};
+ }
- Signal();
+ cv_.notify_all();
}
/*
@@ -73,82 +93,86 @@ int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) const {
static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
- struct timespec vsync {};
- int ret = clock_gettime(CLOCK_MONOTONIC, &vsync);
- if (ret)
- return ret;
+ auto time_now = ResourceManager::GetTimeMonotonicNs();
- float refresh = 60.0F; // Default to 60Hz refresh rate
- if (pipe_ != nullptr &&
- pipe_->connector->Get()->GetActiveMode().v_refresh() != 0.0F) {
- refresh = pipe_->connector->Get()->GetActiveMode().v_refresh();
- }
+ // Default to 60Hz refresh rate
+ constexpr uint32_t kDefaultVSPeriodNs = 16666666;
+ auto period_ns = kDefaultVSPeriodNs;
+ if (callbacks_.get_vperiod_ns && callbacks_.get_vperiod_ns() != 0)
+ period_ns = callbacks_.get_vperiod_ns();
- int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs /
- static_cast<int>(refresh),
- vsync.tv_sec * kOneSecondNs +
- vsync.tv_nsec);
- vsync.tv_sec = phased_timestamp / kOneSecondNs;
+ auto phased_timestamp = GetPhasedVSync(period_ns, time_now);
+ struct timespec vsync {};
+ vsync.tv_sec = int(phased_timestamp / kOneSecondNs);
vsync.tv_nsec = int(phased_timestamp - (vsync.tv_sec * kOneSecondNs));
+
+ int ret = 0;
do {
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, nullptr);
} while (ret == EINTR);
- if (ret)
+ if (ret != 0)
return ret;
- *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec;
+ *timestamp = phased_timestamp;
return 0;
}
-void VSyncWorker::Routine() {
+void VSyncWorker::ThreadFn(const std::shared_ptr<VSyncWorker> &vsw) {
int ret = 0;
- Lock();
- if (!enabled_) {
- ret = WaitForSignalOrExitLocked();
- if (ret == -EINTR) {
- Unlock();
- return;
+ for (;;) {
+ {
+ std::unique_lock<std::mutex> lock(vsw->mutex_);
+ if (thread_exit_)
+ break;
+
+ if (!enabled_)
+ vsw->cv_.wait(lock);
+
+ if (!enabled_)
+ continue;
}
- }
- auto *pipe = pipe_;
- Unlock();
+ ret = -EAGAIN;
+ int64_t timestamp = 0;
+ drmVBlank vblank{};
- ret = -EAGAIN;
- int64_t timestamp = 0;
- drmVBlank vblank{};
+ if (drm_fd_) {
+ vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
+ (high_crtc_ &
+ DRM_VBLANK_HIGH_CRTC_MASK));
+ vblank.request.sequence = 1;
- if (pipe != nullptr) {
- uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
- << DRM_VBLANK_HIGH_CRTC_SHIFT);
+ ret = drmWaitVBlank(*drm_fd_, &vblank);
+ if (ret == -EINTR)
+ continue;
+ }
- vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
- (high_crtc &
- DRM_VBLANK_HIGH_CRTC_MASK));
- vblank.request.sequence = 1;
+ if (ret != 0) {
+ ret = SyntheticWaitVBlank(&timestamp);
+ if (ret != 0)
+ continue;
+ } else {
+ constexpr int kUsToNsMul = 1000;
+ timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
+ (int64_t)vblank.reply.tval_usec * kUsToNsMul;
+ }
- ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
- if (ret == -EINTR)
- return;
- }
+ decltype(callbacks_.out_event) callback;
- if (ret) {
- ret = SyntheticWaitVBlank(&timestamp);
- if (ret)
- return;
- } else {
- timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs +
- (int64_t)vblank.reply.tval_usec * 1000;
- }
+ {
+ const std::lock_guard<std::mutex> lock(mutex_);
+ if (!enabled_)
+ continue;
+ callback = callbacks_.out_event;
+ }
- if (!enabled_)
- return;
+ if (callback)
+ callback(timestamp);
- if (callback_) {
- callback_(timestamp);
+ last_timestamp_ = timestamp;
}
- last_timestamp_ = timestamp;
+ ALOGI("VSyncWorker thread exit");
}
} // namespace android
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 1e6d39f..031a561 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -14,46 +14,53 @@
* limitations under the License.
*/
-#ifndef ANDROID_EVENT_WORKER_H_
-#define ANDROID_EVENT_WORKER_H_
+#pragma once
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <hardware/hwcomposer2.h>
-
-#include <atomic>
-#include <cstdint>
+#include <condition_variable>
#include <functional>
#include <map>
+#include <mutex>
+#include <thread>
#include "DrmDevice.h"
-#include "utils/Worker.h"
namespace android {
-class VSyncWorker : public Worker {
+struct VSyncWorkerCallbacks {
+ std::function<void(uint64_t /*timestamp*/)> out_event;
+ std::function<uint32_t()> get_vperiod_ns;
+};
+
+class VSyncWorker {
public:
- VSyncWorker();
- ~VSyncWorker() override = default;
+ ~VSyncWorker() = default;
- auto Init(DrmDisplayPipeline *pipe,
- std::function<void(uint64_t /*timestamp*/)> callback) -> int;
+ auto static CreateInstance(DrmDisplayPipeline *pipe,
+ VSyncWorkerCallbacks &callbacks)
+ -> std::shared_ptr<VSyncWorker>;
void VSyncControl(bool enabled);
-
- protected:
- void Routine() override;
+ void StopThread();
private:
+ VSyncWorker() = default;
+
+ void ThreadFn(const std::shared_ptr<VSyncWorker> &vsw);
+
int64_t GetPhasedVSync(int64_t frame_ns, int64_t current) const;
int SyntheticWaitVBlank(int64_t *timestamp);
- std::function<void(uint64_t /*timestamp*/)> callback_;
+ VSyncWorkerCallbacks callbacks_;
+
+ SharedFd drm_fd_;
+ uint32_t high_crtc_ = 0;
- DrmDisplayPipeline *pipe_ = nullptr;
- std::atomic_bool enabled_ = false;
+ bool enabled_ = false;
+ bool thread_exit_ = false;
int64_t last_timestamp_ = -1;
+
+ std::condition_variable cv_;
+ std::thread vswt_;
+ std::mutex mutex_;
};
} // namespace android
-
-#endif
diff --git a/drm/meson.build b/drm/meson.build
new file mode 100644
index 0000000..7bef11a
--- /dev/null
+++ b/drm/meson.build
@@ -0,0 +1,15 @@
+src_common += files(
+ 'DrmAtomicStateManager.cpp',
+ 'DrmConnector.cpp',
+ 'DrmCrtc.cpp',
+ 'DrmDevice.cpp',
+ 'DrmDisplayPipeline.cpp',
+ 'DrmEncoder.cpp',
+ 'DrmFbImporter.cpp',
+ 'DrmMode.cpp',
+ 'DrmPlane.cpp',
+ 'DrmProperty.cpp',
+ 'ResourceManager.cpp',
+ 'UEventListener.cpp',
+ 'VSyncWorker.cpp',
+)
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index 4accb07..64755c3 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -61,16 +61,9 @@ void DrmHwcTwo::FinalizeDisplayBinding() {
const int kTimeForSFToDisposeDisplayUs = 200000;
usleep(kTimeForSFToDisposeDisplayUs);
mutex.lock();
- std::vector<std::unique_ptr<HwcDisplay>> for_disposal;
for (auto handle : displays_for_removal_list_) {
- for_disposal.emplace_back(
- std::unique_ptr<HwcDisplay>(displays_[handle].release()));
displays_.erase(handle);
}
- /* Destroy HwcDisplays while unlocked to avoid vsyncworker deadlocks */
- mutex.unlock();
- for_disposal.clear();
- mutex.lock();
}
bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
@@ -180,10 +173,7 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
/* Headless display may still be here. Remove it! */
if (displays_.count(kPrimaryDisplay) != 0) {
displays_[kPrimaryDisplay]->Deinit();
- auto &mutex = GetResMan().GetMainLock();
- mutex.unlock();
displays_.erase(kPrimaryDisplay);
- mutex.lock();
}
}
break;
@@ -196,7 +186,7 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
break;
}
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
case HWC2::Callback::Vsync_2_4: {
vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
break;
@@ -214,24 +204,15 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
}
void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
- bool connected) {
- auto &mutex = GetResMan().GetMainLock();
- if (mutex.try_lock()) {
- ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
- mutex.unlock();
- return;
- }
-
+ bool connected) const {
auto hc = hotplug_callback_;
if (hc.first != nullptr && hc.second != nullptr) {
- /* For some reason CLIENT will call HWC2 API in hotplug callback handler,
- * which will cause deadlock . Unlock main mutex to prevent this.
+ /* For some reason HWC Service will call HWC2 API in hotplug callback
+ * handler. This is the reason we're using recursive mutex.
*/
- mutex.unlock();
hc.first(hc.second, displayid,
connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
: HWC2_CONNECTION_DISCONNECTED);
- mutex.lock();
}
}
@@ -239,7 +220,7 @@ void DrmHwcTwo::SendVsyncEventToClient(
hwc2_display_t displayid, int64_t timestamp,
[[maybe_unused]] uint32_t vsync_period) const {
/* vsync callback */
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
if (vsync_2_4_callback_.first != nullptr &&
vsync_2_4_callback_.second != nullptr) {
vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
@@ -255,7 +236,7 @@ void DrmHwcTwo::SendVsyncEventToClient(
void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
[[maybe_unused]] hwc2_display_t displayid,
[[maybe_unused]] int64_t timestamp) const {
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
hwc_vsync_period_change_timeline_t timeline = {
.newVsyncAppliedTimeNanos = timestamp,
.refreshRequired = false,
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index 2b8a74f..81c5155 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_HWC_TWO_H_
-#define ANDROID_DRM_HWC_TWO_H_
+#pragma once
#include <hardware/hwcomposer2.h>
@@ -31,7 +30,7 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface {
std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{};
std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t>
period_timing_changed_callback_{};
@@ -72,7 +71,7 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface {
int64_t timestamp) const;
private:
- void SendHotplugEventToClient(hwc2_display_t displayid, bool connected);
+ void SendHotplugEventToClient(hwc2_display_t displayid, bool connected) const;
ResourceManager resource_manager_;
std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
@@ -86,5 +85,3 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface {
uint32_t last_display_handle_ = kPrimaryDisplay;
};
} // namespace android
-
-#endif
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index d968ab3..efd8c14 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -31,7 +31,7 @@ namespace android {
std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
if (delta.total_pixops_ == 0)
return "No stats yet";
- double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
+ auto ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_);
std::stringstream ss;
ss << " Total frames count: " << delta.total_frames_ << "\n"
@@ -50,32 +50,12 @@ std::string HwcDisplay::DumpDelta(HwcDisplay::Stats delta) {
}
std::string HwcDisplay::Dump() {
- std::string flattening_state_str;
- switch (flattenning_state_) {
- case ClientFlattenningState::Disabled:
- flattening_state_str = "Disabled";
- break;
- case ClientFlattenningState::NotRequired:
- flattening_state_str = "Not needed";
- break;
- case ClientFlattenningState::Flattened:
- flattening_state_str = "Active";
- break;
- case ClientFlattenningState::ClientRefreshRequested:
- flattening_state_str = "Refresh requested";
- break;
- default:
- flattening_state_str = std::to_string(flattenning_state_) +
- " VSync remains";
- }
-
- std::string connector_name = IsInHeadlessMode()
- ? "NULL-DISPLAY"
- : GetPipe().connector->Get()->GetName();
+ auto connector_name = IsInHeadlessMode()
+ ? std::string("NULL-DISPLAY")
+ : GetPipe().connector->Get()->GetName();
std::stringstream ss;
ss << "- Display on: " << connector_name << "\n"
- << " Flattening state: " << flattening_state_str << "\n"
<< "Statistics since system boot:\n"
<< DumpDelta(total_stats_) << "\n\n"
<< "Statistics since last dumpsys request:\n"
@@ -87,17 +67,18 @@ std::string HwcDisplay::Dump() {
HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
DrmHwcTwo *hwc2)
- : hwc2_(hwc2),
- handle_(handle),
- type_(type),
- client_layer_(this),
- color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
- // clang-format off
- color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0};
- // clang-format on
+ : hwc2_(hwc2), handle_(handle), type_(type), client_layer_(this){};
+
+void HwcDisplay::SetColorMarixToIdentity() {
+ color_matrix_ = std::make_shared<drm_color_ctm>();
+ for (int i = 0; i < kCtmCols; i++) {
+ for (int j = 0; j < kCtmRows; j++) {
+ constexpr uint64_t kOne = (1ULL << 32); /* 1.0 in s31.32 format */
+ color_matrix_->matrix[i * kCtmRows + j] = (i == j) ? kOne : 0;
+ }
+ }
+
+ color_transform_hint_ = HAL_COLOR_TRANSFORM_IDENTITY;
}
HwcDisplay::~HwcDisplay() = default;
@@ -137,9 +118,17 @@ void HwcDisplay::Deinit() {
GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
#endif
- vsync_worker_.Init(nullptr, [](int64_t) {});
current_plan_.reset();
backend_.reset();
+ if (flatcon_) {
+ flatcon_->StopThread();
+ flatcon_.reset();
+ }
+ }
+
+ if (vsync_worker_) {
+ vsync_worker_->StopThread();
+ vsync_worker_ = {};
}
SetClientTarget(nullptr, -1, 0, {});
@@ -148,38 +137,54 @@ void HwcDisplay::Deinit() {
HWC2::Error HwcDisplay::Init() {
ChosePreferredConfig();
- int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
- const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
- if (vsync_event_en_) {
- uint32_t period_ns{};
- GetDisplayVsyncPeriod(&period_ns);
- hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
- }
- if (vsync_flattening_en_) {
- ProcessFlatenningVsyncInternal();
- }
- if (vsync_tracking_en_) {
- last_vsync_ts_ = timestamp;
- }
- if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
- vsync_worker_.VSyncControl(false);
- }
- });
- if (ret && ret != -EALREADY) {
- ALOGE("Failed to create event worker for d=%d %d\n", int(handle_), ret);
+ auto vsw_callbacks = (VSyncWorkerCallbacks){
+ .out_event =
+ [this](int64_t timestamp) {
+ const std::unique_lock lock(hwc2_->GetResMan().GetMainLock());
+ if (vsync_event_en_) {
+ uint32_t period_ns{};
+ GetDisplayVsyncPeriod(&period_ns);
+ hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+ }
+ if (vsync_tracking_en_) {
+ last_vsync_ts_ = timestamp;
+ }
+ if (!vsync_event_en_ && !vsync_tracking_en_) {
+ vsync_worker_->VSyncControl(false);
+ }
+ },
+ .get_vperiod_ns = [this]() -> uint32_t {
+ uint32_t outVsyncPeriod = 0;
+ GetDisplayVsyncPeriod(&outVsyncPeriod);
+ return outVsyncPeriod;
+ },
+ };
+
+ vsync_worker_ = VSyncWorker::CreateInstance(pipeline_, vsw_callbacks);
+ if (!vsync_worker_) {
+ ALOGE("Failed to create event worker for d=%d\n", int(handle_));
return HWC2::Error::BadDisplay;
}
if (!IsInHeadlessMode()) {
- ret = BackendManager::GetInstance().SetBackendForDisplay(this);
+ auto ret = BackendManager::GetInstance().SetBackendForDisplay(this);
if (ret) {
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_);
+ }};
+ flatcon_ = FlatteningController::CreateInstance(flatcbk);
}
client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
+ SetColorMarixToIdentity();
+
return HWC2::Error::None;
}
@@ -236,7 +241,7 @@ HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
}
uint32_t num_changes = 0;
- for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
+ for (auto &l : layers_) {
if (l.second.IsTypeChanged()) {
if (layers && num_changes < *num_elements)
layers[num_changes] = l.first;
@@ -257,8 +262,8 @@ HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height,
return HWC2::Error::None;
}
- std::pair<uint32_t, uint32_t> min = pipeline_->device->GetMinResolution();
- std::pair<uint32_t, uint32_t> max = pipeline_->device->GetMaxResolution();
+ auto min = pipeline_->device->GetMinResolution();
+ auto max = pipeline_->device->GetMaxResolution();
if (width < min.first || height < min.second)
return HWC2::Error::Unsupported;
@@ -296,33 +301,33 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
auto &hwc_config = configs_.hwc_configs[conf];
static const int32_t kUmPerInch = 25400;
- uint32_t mm_width = configs_.mm_width;
- uint32_t mm_height = configs_.mm_height;
+ 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:
- *value = static_cast<int>(hwc_config.mode.h_display());
+ *value = static_cast<int>(hwc_config.mode.GetRawMode().hdisplay);
break;
case HWC2::Attribute::Height:
- *value = static_cast<int>(hwc_config.mode.v_display());
+ *value = static_cast<int>(hwc_config.mode.GetRawMode().vdisplay);
break;
case HWC2::Attribute::VsyncPeriod:
// in nanoseconds
- *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh());
+ *value = static_cast<int>(1E9 / hwc_config.mode.GetVRefresh());
break;
case HWC2::Attribute::DpiX:
// Dots per 1000 inches
- *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() *
- kUmPerInch / mm_width)
+ *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 ? static_cast<int>(hwc_config.mode.v_display() *
- kUmPerInch / mm_height)
+ *value = mm_height ? int(hwc_config.mode.GetRawMode().vdisplay *
+ kUmPerInch / mm_height)
: -1;
break;
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
case HWC2::Attribute::ConfigGroup:
/* Dispite ConfigGroup is a part of HWC2.4 API, framework
* able to request it even if service @2.1 is used */
@@ -364,8 +369,8 @@ HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
} else {
stream << "display-" << GetPipe().connector->Get()->GetId();
}
- std::string string = stream.str();
- size_t length = string.length();
+ auto string = stream.str();
+ auto length = string.length();
if (!name) {
*size = length;
return HWC2::Error::None;
@@ -437,7 +442,7 @@ HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
}
layers[num_layers - 1] = l.first;
- fences[num_layers - 1] = UniqueFd::Dup(present_fence_.Get()).Release();
+ fences[num_layers - 1] = DupFd(present_fence_);
}
*num_elements = num_layers;
@@ -450,8 +455,10 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::None;
}
- int PrevModeVsyncPeriodNs = static_cast<int>(
- 1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
+ a_args.color_matrix = color_matrix_;
+
+ uint32_t prev_vperiod_ns = 0;
+ GetDisplayVsyncPeriod(&prev_vperiod_ns);
auto mode_update_commited_ = false;
if (staged_mode_ &&
@@ -459,8 +466,8 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
client_layer_.SetLayerDisplayFrame(
(hwc_rect_t){.left = 0,
.top = 0,
- .right = static_cast<int>(staged_mode_->h_display()),
- .bottom = static_cast<int>(staged_mode_->v_display())});
+ .right = int(staged_mode_->GetRawMode().hdisplay),
+ .bottom = int(staged_mode_->GetRawMode().vdisplay)});
configs_.active_config_id = staged_mode_config_id_;
@@ -477,7 +484,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
switch (l.second.GetValidatedType()) {
case HWC2::Composition::Device:
- z_map.emplace(std::make_pair(l.second.GetZOrder(), &l.second));
+ z_map.emplace(l.second.GetZOrder(), &l.second);
break;
case HWC2::Composition::Client:
// Place it at the z_order of the lowest client layer
@@ -489,7 +496,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
}
}
if (use_client_layer)
- z_map.emplace(std::make_pair(client_z_order, &client_layer_));
+ z_map.emplace(client_z_order, &client_layer_);
if (z_map.empty())
return HWC2::Error::BadLayer;
@@ -498,7 +505,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
/* Import & populate */
for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
- l.second->PopulateLayerData(a_args.test_only);
+ l.second->PopulateLayerData();
}
// now that they're ordered by z, add them to the composition
@@ -513,7 +520,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
*/
return HWC2::Error::BadLayer;
}
- composition_layers.emplace_back(l.second->GetLayerData().Clone());
+ composition_layers.emplace_back(l.second->GetLayerData());
}
/* Store plan to ensure shared planes won't be stolen by other display
@@ -530,7 +537,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
a_args.composition = current_plan_;
- int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+ auto ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
if (ret) {
if (!a_args.test_only)
@@ -542,8 +549,9 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
staged_mode_.reset();
vsync_tracking_en_ = false;
if (last_vsync_ts_ != 0) {
- hwc2_->SendVsyncPeriodTimingChangedEventToClient(
- handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
+ hwc2_->SendVsyncPeriodTimingChangedEventToClient(handle_,
+ last_vsync_ts_ +
+ prev_vperiod_ns);
}
}
@@ -576,8 +584,11 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *out_present_fence) {
if (ret != HWC2::Error::None)
return ret;
- this->present_fence_ = UniqueFd::Dup(a_args.out_fence.Get());
- *out_present_fence = a_args.out_fence.Release();
+ this->present_fence_ = a_args.out_fence;
+ *out_present_fence = DupFd(a_args.out_fence);
+
+ // Reset the color matrix so we don't apply it over and over again.
+ color_matrix_ = {};
++frame_no_;
return HWC2::Error::None;
@@ -625,17 +636,22 @@ HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target,
return HWC2::Error::None;
}
- client_layer_.PopulateLayerData(/*test = */ true);
+ client_layer_.PopulateLayerData();
if (!client_layer_.IsLayerUsableAsDevice()) {
ALOGE("Client layer must be always usable by DRM/KMS");
return HWC2::Error::BadLayer;
}
auto &bi = client_layer_.GetLayerData().bi;
- hwc_frect_t source_crop = {.left = 0.0F,
- .top = 0.0F,
- .right = static_cast<float>(bi->width),
- .bottom = static_cast<float>(bi->height)};
+ if (!bi) {
+ ALOGE("%s: Invalid state", __func__);
+ return HWC2::Error::BadLayer;
+ }
+
+ auto source_crop = (hwc_frect_t){.left = 0.0F,
+ .top = 0.0F,
+ .right = static_cast<float>(bi->width),
+ .bottom = static_cast<float>(bi->height)};
client_layer_.SetLayerSourceCrop(source_crop);
return HWC2::Error::None;
@@ -652,6 +668,8 @@ HWC2::Error HwcDisplay::SetColorMode(int32_t mode) {
return HWC2::Error::None;
}
+#include <xf86drmMode.h>
+
HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
if (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)
@@ -661,12 +679,49 @@ HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) {
return HWC2::Error::BadParameter;
color_transform_hint_ = static_cast<android_color_transform_t>(hint);
- if (color_transform_hint_ == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX)
- std::copy(matrix, matrix + MATRIX_SIZE, color_transform_matrix_.begin());
+
+ if (IsInHeadlessMode())
+ return HWC2::Error::None;
+
+ if (!GetPipe().crtc->Get()->GetCtmProperty())
+ return HWC2::Error::None;
+
+ switch (color_transform_hint_) {
+ case HAL_COLOR_TRANSFORM_IDENTITY:
+ SetColorMarixToIdentity();
+ break;
+ case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+ color_matrix_ = std::make_shared<drm_color_ctm>();
+ /* DRM expects a 3x3 matrix, but the HAL provides a 4x4 matrix. */
+ for (int i = 0; i < kCtmCols; i++) {
+ for (int j = 0; j < kCtmRows; j++) {
+ constexpr int kInCtmRows = 4;
+ /* HAL matrix type is float, but DRM expects a s31.32 fix point */
+ auto value = uint64_t(matrix[i * kInCtmRows + j] * float(1ULL << 32));
+ color_matrix_->matrix[i * kCtmRows + j] = value;
+ }
+ }
+ break;
+ default:
+ return HWC2::Error::Unsupported;
+ }
return HWC2::Error::None;
}
+bool HwcDisplay::CtmByGpu() {
+ if (color_transform_hint_ == HAL_COLOR_TRANSFORM_IDENTITY)
+ return false;
+
+ if (GetPipe().crtc->Get()->GetCtmProperty())
+ return false;
+
+ if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+ return false;
+
+ return true;
+}
+
HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
int32_t /*release_fence*/) {
// TODO(nobody): Need virtual display support
@@ -697,7 +752,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
return HWC2::Error::None;
}
- if (a_args.active) {
+ if (a_args.active && *a_args.active) {
/*
* Setting the display to active before we have a composition
* can break some drivers, so skip setting a_args.active to
@@ -709,7 +764,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
: HWC2::Error::BadParameter;
};
- int err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+ auto err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
if (err) {
ALOGE("Failed to apply the dpms composition err=%d", err);
return HWC2::Error::BadParameter;
@@ -720,7 +775,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
if (vsync_event_en_) {
- vsync_worker_.VSyncControl(true);
+ vsync_worker_->VSyncControl(true);
}
return HWC2::Error::None;
}
@@ -767,7 +822,7 @@ HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
(int32_t *)(outVsyncPeriod));
}
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
if (IsInHeadlessMode()) {
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
@@ -815,7 +870,7 @@ HWC2::Error HwcDisplay::SetActiveConfigWithConstraints(
last_vsync_ts_ = 0;
vsync_tracking_en_ = true;
- vsync_worker_.VSyncControl(true);
+ vsync_worker_->VSyncControl(true);
return HWC2::Error::None;
}
@@ -845,7 +900,7 @@ HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
}
#endif
-#if PLATFORM_SDK_VERSION > 28
+#if __ANDROID_API__ > 28
HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
uint32_t *outDataSize,
uint8_t *outData) {
@@ -871,12 +926,31 @@ HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
}
HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities,
- uint32_t * /*outCapabilities*/) {
+ uint32_t *outCapabilities) {
if (outNumCapabilities == nullptr) {
return HWC2::Error::BadParameter;
}
- *outNumCapabilities = 0;
+ bool skip_ctm = false;
+
+ // Skip client CTM if user requested DRM_OR_IGNORE
+ if (GetHwc2()->GetResMan().GetCtmHandling() == CtmHandling::kDrmOrIgnore)
+ skip_ctm = true;
+
+ // Skip client CTM if DRM can handle it
+ if (!skip_ctm && !IsInHeadlessMode() &&
+ GetPipe().crtc->Get()->GetCtmProperty())
+ skip_ctm = true;
+
+ if (!skip_ctm) {
+ *outNumCapabilities = 0;
+ return HWC2::Error::None;
+ }
+
+ *outNumCapabilities = 1;
+ if (outCapabilities) {
+ outCapabilities[0] = HWC2_DISPLAY_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+ }
return HWC2::Error::None;
}
@@ -890,9 +964,9 @@ HWC2::Error HwcDisplay::SetDisplayBrightness(float /* brightness */) {
return HWC2::Error::Unsupported;
}
-#endif /* PLATFORM_SDK_VERSION > 28 */
+#endif /* __ANDROID_API__ > 28 */
-#if PLATFORM_SDK_VERSION > 27
+#if __ANDROID_API__ > 27
HWC2::Error HwcDisplay::GetRenderIntents(
int32_t mode, uint32_t *outNumIntents,
@@ -928,7 +1002,7 @@ HWC2::Error HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) {
return HWC2::Error::None;
}
-#endif /* PLATFORM_SDK_VERSION > 27 */
+#endif /* __ANDROID_API__ > 27 */
const Backend *HwcDisplay::backend() const {
return backend_.get();
@@ -938,37 +1012,4 @@ void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
backend_ = std::move(backend);
}
-/* returns true if composition should be sent to client */
-bool HwcDisplay::ProcessClientFlatteningState(bool skip) {
- int flattenning_state = flattenning_state_;
- if (flattenning_state == ClientFlattenningState::Disabled) {
- return false;
- }
-
- if (skip) {
- flattenning_state_ = ClientFlattenningState::NotRequired;
- return false;
- }
-
- if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) {
- flattenning_state_ = ClientFlattenningState::Flattened;
- return true;
- }
-
- vsync_flattening_en_ = true;
- vsync_worker_.VSyncControl(true);
- flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
- return false;
-}
-
-void HwcDisplay::ProcessFlatenningVsyncInternal() {
- if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
- --flattenning_state_ == ClientFlattenningState::ClientRefreshRequested &&
- hwc2_->refresh_callback_.first != nullptr &&
- hwc2_->refresh_callback_.second != nullptr) {
- hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
- vsync_flattening_en_ = false;
- }
-}
-
} // namespace android
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index d79efb0..bf95c3e 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_H
-#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_H
+#pragma once
#include <hardware/hwcomposer2.h>
+#include <atomic>
#include <optional>
+#include <sstream>
#include "HwcDisplayConfigs.h"
+#include "compositor/FlatteningController.h"
#include "compositor/LayerData.h"
#include "drm/DrmAtomicStateManager.h"
#include "drm/ResourceManager.h"
@@ -69,12 +71,12 @@ class HwcDisplay {
uint32_t *num_elements, hwc2_layer_t *layers,
int32_t *layer_requests);
HWC2::Error GetDisplayType(int32_t *type);
-#if PLATFORM_SDK_VERSION > 27
+#if __ANDROID_API__ > 27
HWC2::Error GetRenderIntents(int32_t mode, uint32_t *outNumIntents,
int32_t *outIntents);
HWC2::Error SetColorModeWithIntent(int32_t mode, int32_t intent);
#endif
-#if PLATFORM_SDK_VERSION > 28
+#if __ANDROID_API__ > 28
HWC2::Error GetDisplayIdentificationData(uint8_t *outPort,
uint32_t *outDataSize,
uint8_t *outData);
@@ -83,7 +85,7 @@ class HwcDisplay {
HWC2::Error GetDisplayBrightnessSupport(bool *supported);
HWC2::Error SetDisplayBrightness(float);
#endif
-#if PLATFORM_SDK_VERSION > 29
+#if __ANDROID_API__ > 29
HWC2::Error GetDisplayConnectionType(uint32_t *outType);
HWC2::Error SetActiveConfigWithConstraints(
@@ -158,18 +160,12 @@ class HwcDisplay {
return *pipeline_;
}
- android_color_transform_t &color_transform_hint() {
- return color_transform_hint_;
- }
+ bool CtmByGpu();
Stats &total_stats() {
return total_stats_;
}
- /* returns true if composition should be sent to client */
- bool ProcessClientFlatteningState(bool skip);
- void ProcessFlatenningVsyncInternal();
-
/* Headless mode required to keep SurfaceFlinger alive when all display are
* disconnected, Without headless mode Android will continuously crash.
* Only single internal (primary) display is required to be in HEADLESS mode
@@ -182,24 +178,16 @@ class HwcDisplay {
void Deinit();
- private:
- enum ClientFlattenningState : int32_t {
- Disabled = -3,
- NotRequired = -2,
- Flattened = -1,
- ClientRefreshRequested = 0,
- VsyncCountdownMax = 60, /* 1 sec @ 60FPS */
- };
-
- std::atomic_int flattenning_state_{ClientFlattenningState::NotRequired};
-
- constexpr static size_t MATRIX_SIZE = 16;
+ auto GetFlatCon() {
+ return flatcon_;
+ }
+ private:
HwcDisplayConfigs configs_;
DrmHwcTwo *const hwc2_;
- UniqueFd present_fence_;
+ SharedFd present_fence_;
std::optional<DrmMode> staged_mode_;
int64_t staged_mode_change_time_{};
@@ -208,10 +196,10 @@ class HwcDisplay {
DrmDisplayPipeline *pipeline_{};
std::unique_ptr<Backend> backend_;
+ std::shared_ptr<FlatteningController> flatcon_;
- VSyncWorker vsync_worker_;
+ std::shared_ptr<VSyncWorker> vsync_worker_;
bool vsync_event_en_{};
- bool vsync_flattening_en_{};
bool vsync_tracking_en_{};
int64_t last_vsync_ts_{};
@@ -223,8 +211,10 @@ class HwcDisplay {
std::map<hwc2_layer_t, HwcLayer> layers_;
HwcLayer client_layer_;
int32_t color_mode_{};
- std::array<float, MATRIX_SIZE> color_transform_matrix_{};
- android_color_transform_t color_transform_hint_;
+ static constexpr int kCtmRows = 3;
+ static constexpr int kCtmCols = 3;
+ std::shared_ptr<drm_color_ctm> color_matrix_;
+ android_color_transform_t color_transform_hint_{};
std::shared_ptr<DrmKmsPlan> current_plan_;
@@ -233,11 +223,11 @@ class HwcDisplay {
Stats prev_stats_;
std::string DumpDelta(HwcDisplay::Stats delta);
+ void SetColorMarixToIdentity();
+
HWC2::Error Init();
HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
};
} // namespace android
-
-#endif
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index 6a3ed5a..9727989 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -61,7 +61,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
* mode*/
FillHeadless();
/* Read real configs */
- int ret = connector.UpdateModes();
+ auto ret = connector.UpdateModes();
if (ret != 0) {
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::BadDisplay;
@@ -79,7 +79,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
preferred_config_id = 0;
uint32_t preferred_config_group_id = 0;
- uint32_t first_config_id = last_config_id;
+ auto first_config_id = last_config_id;
uint32_t last_group_id = 1;
/* Group modes */
@@ -87,8 +87,10 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
/* Find group for the new mode or create new group */
uint32_t group_found = 0;
for (auto &hwc_config : hwc_configs) {
- if (mode.h_display() == hwc_config.second.mode.h_display() &&
- mode.v_display() == hwc_config.second.mode.v_display()) {
+ if (mode.GetRawMode().hdisplay ==
+ hwc_config.second.mode.GetRawMode().hdisplay &&
+ mode.GetRawMode().vdisplay ==
+ hwc_config.second.mode.GetRawMode().vdisplay) {
group_found = hwc_config.second.group_id;
}
}
@@ -97,9 +99,9 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
}
bool disabled = false;
- if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) {
+ if ((mode.GetRawMode().flags & DRM_MODE_FLAG_3D_MASK) != 0) {
ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
- mode.name().c_str());
+ mode.GetName().c_str());
disabled = true;
}
@@ -112,7 +114,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
};
/* Chwck if the mode is preferred */
- if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
+ if ((mode.GetRawMode().type & DRM_MODE_TYPE_PREFERRED) != 0 &&
preferred_config_id == 0) {
preferred_config_id = last_config_id;
preferred_config_group_id = group_found;
@@ -143,7 +145,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
}
}
- bool has_both = has_interlaced && has_progressive;
+ auto has_both = has_interlaced && has_progressive;
if (!has_both) {
continue;
}
@@ -159,7 +161,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
continue;
}
- bool disable = group_contains_preferred_interlaced
+ auto disable = group_contains_preferred_interlaced
? !hwc_config.second.IsInterlaced()
: hwc_config.second.IsInterlaced();
@@ -167,7 +169,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
ALOGI(
"Group %i: Disabling display mode %s (This group should consist "
"of %s modes)",
- group, hwc_config.second.mode.name().c_str(),
+ group, hwc_config.second.mode.GetName().c_str(),
group_contains_preferred_interlaced ? "interlaced" : "progressive");
hwc_config.second.disabled = true;
@@ -183,13 +185,13 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) {
if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
!hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
- fabsf(hwc_configs[m1].mode.v_refresh() -
- hwc_configs[m2].mode.v_refresh()) < kMinFpsDelta) {
+ fabsf(hwc_configs[m1].mode.GetVRefresh() -
+ hwc_configs[m2].mode.GetVRefresh()) < kMinFpsDelta) {
ALOGI(
"Group %i: Disabling display mode %s (Refresh rate value is "
"too close to existing mode %s)",
- hwc_configs[m2].group_id, hwc_configs[m2].mode.name().c_str(),
- hwc_configs[m1].mode.name().c_str());
+ hwc_configs[m2].group_id, hwc_configs[m2].mode.GetName().c_str(),
+ hwc_configs[m1].mode.GetName().c_str());
hwc_configs[m2].disabled = true;
}
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
index 7c173d6..98067c1 100644
--- a/hwc2_device/HwcDisplayConfigs.h
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
-#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
+#pragma once
#include <hardware/hwcomposer2.h>
@@ -30,11 +29,11 @@ class DrmConnector;
struct HwcDisplayConfig {
uint32_t id{};
uint32_t group_id{};
- DrmMode mode;
+ DrmMode mode{};
bool disabled{};
bool IsInterlaced() const {
- return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0;
+ return (mode.GetRawMode().flags & DRM_MODE_FLAG_INTERLACE) != 0;
}
};
@@ -55,5 +54,3 @@ struct HwcDisplayConfigs {
};
} // namespace android
-
-#endif
diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp
index c278732..dd5359f 100644
--- a/hwc2_device/HwcLayer.cpp
+++ b/hwc2_device/HwcLayer.cpp
@@ -53,7 +53,7 @@ HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) {
*/
HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer,
int32_t acquire_fence) {
- acquire_fence_ = UniqueFd(acquire_fence);
+ layer_data_.acquire_fence = MakeSharedFd(acquire_fence);
buffer_handle_ = buffer;
buffer_handle_updated_ = true;
@@ -202,9 +202,14 @@ void HwcLayer::ImportFb() {
}
}
-void HwcLayer::PopulateLayerData(bool test) {
+void HwcLayer::PopulateLayerData() {
ImportFb();
+ if (!layer_data_.bi) {
+ ALOGE("%s: Invalid state", __func__);
+ return;
+ }
+
if (blend_mode_ != BufferBlendMode::kUndefined) {
layer_data_.bi->blend_mode = blend_mode_;
}
@@ -214,10 +219,6 @@ void HwcLayer::PopulateLayerData(bool test) {
if (sample_range_ != BufferSampleRange::kUndefined) {
layer_data_.bi->sample_range = sample_range_;
}
-
- if (!test) {
- layer_data_.acquire_fence = std::move(acquire_fence_);
- }
}
/* SwapChain Cache */
@@ -227,7 +228,7 @@ bool HwcLayer::SwChainGetBufferFromCache(BufferUniqueId unique_id) {
return false;
}
- int seq = swchain_lookup_table_[unique_id];
+ auto seq = swchain_lookup_table_[unique_id];
if (swchain_cache_.count(seq) == 0) {
return false;
@@ -274,7 +275,7 @@ void HwcLayer::SwChainAddCurrentBuffer(BufferUniqueId unique_id) {
return;
}
- int seq = swchain_lookup_table_[unique_id];
+ auto seq = swchain_lookup_table_[unique_id];
if (swchain_cache_.count(seq) == 0) {
swchain_cache_[seq] = {};
diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h
index 41b3dbb..b69ce5b 100644
--- a/hwc2_device/HwcLayer.h
+++ b/hwc2_device/HwcLayer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_HWC2_DEVICE_HWC_LAYER_H
-#define ANDROID_HWC2_DEVICE_HWC_LAYER_H
+#pragma once
#include <hardware/hwcomposer2.h>
@@ -87,9 +86,6 @@ class HwcLayer {
uint32_t z_order_ = 0;
LayerData layer_data_;
- /* Should be populated to layer_data_.acquire_fence only before presenting */
- UniqueFd acquire_fence_;
-
/* The following buffer data can have 2 sources:
* 1 - Mapper@4 metadata API
* 2 - HWC@2 API
@@ -109,7 +105,7 @@ class HwcLayer {
/* Layer state */
public:
- void PopulateLayerData(bool test);
+ void PopulateLayerData();
bool IsLayerUsableAsDevice() const {
return !bi_get_failed_ && !fb_import_failed_ && buffer_handle_ != nullptr;
@@ -140,5 +136,3 @@ class HwcLayer {
};
} // namespace android
-
-#endif
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index a6dedb4..d4ee10d 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -35,11 +35,11 @@ namespace android {
* to the short "android::HwcLayer::SetLayerBuffer" for better logs readability
*/
static std::string GetFuncName(const char *pretty_function) {
- std::string str(pretty_function);
+ const std::string str(pretty_function);
const char *start = "func = &";
- size_t p1 = str.find(start);
+ auto p1 = str.find(start);
p1 += strlen(start);
- size_t p2 = str.find(',', p1);
+ auto p2 = str.find(',', p1);
return str.substr(p1, p2 - p1);
}
@@ -63,7 +63,7 @@ template <typename T, typename HookType, HookType func, typename... Args>
static T DeviceHook(hwc2_device_t *dev, Args... args) {
ALOGV("Device hook: %s", GetFuncName(__PRETTY_FUNCTION__).c_str());
DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
- const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+ const std::unique_lock lock(hwc->GetResMan().GetMainLock());
return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
}
@@ -73,7 +73,7 @@ static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
ALOGV("Display #%" PRIu64 " hook: %s", display_handle,
GetFuncName(__PRETTY_FUNCTION__).c_str());
DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
- const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+ const std::unique_lock lock(hwc->GetResMan().GetMainLock());
auto *display = hwc->GetDisplay(display_handle);
if (display == nullptr)
return static_cast<int32_t>(HWC2::Error::BadDisplay);
@@ -87,7 +87,7 @@ static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
ALOGV("Display #%" PRIu64 " Layer: #%" PRIu64 " hook: %s", display_handle,
layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str());
DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
- const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+ const std::unique_lock lock(hwc->GetResMan().GetMainLock());
auto *display = hwc->GetDisplay(display_handle);
if (display == nullptr)
return static_cast<int32_t>(HWC2::Error::BadDisplay);
@@ -102,7 +102,7 @@ static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
static int HookDevClose(hw_device_t *dev) {
// NOLINTNEXTLINE (cppcoreguidelines-pro-type-reinterpret-cast): Safe
auto *hwc2_dev = reinterpret_cast<hwc2_device_t *>(dev);
- std::unique_ptr<DrmHwcTwo> ctx(ToDrmHwcTwo(hwc2_dev));
+ const std::unique_ptr<DrmHwcTwo> ctx(ToDrmHwcTwo(hwc2_dev));
return 0;
}
@@ -244,7 +244,7 @@ static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/,
return ToHook<HWC2_PFN_VALIDATE_DISPLAY>(
DisplayHook<decltype(&HwcDisplay::ValidateDisplay),
&HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>);
-#if PLATFORM_SDK_VERSION > 27
+#if __ANDROID_API__ > 27
case HWC2::FunctionDescriptor::GetRenderIntents:
return ToHook<HWC2_PFN_GET_RENDER_INTENTS>(
DisplayHook<decltype(&HwcDisplay::GetRenderIntents),
@@ -255,7 +255,7 @@ static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/,
DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent),
&HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>);
#endif
-#if PLATFORM_SDK_VERSION > 28
+#if __ANDROID_API__ > 28
case HWC2::FunctionDescriptor::GetDisplayIdentificationData:
return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>(
DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData),
@@ -274,8 +274,8 @@ static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/,
return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>(
DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness),
&HwcDisplay::SetDisplayBrightness, float>);
-#endif /* PLATFORM_SDK_VERSION > 28 */
-#if PLATFORM_SDK_VERSION > 29
+#endif /* __ANDROID_API__ > 28 */
+#if __ANDROID_API__ > 29
case HWC2::FunctionDescriptor::GetDisplayConnectionType:
return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>(
DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType),
diff --git a/hwc2_device/meson.build b/hwc2_device/meson.build
new file mode 100644
index 0000000..7e6b8f4
--- /dev/null
+++ b/hwc2_device/meson.build
@@ -0,0 +1,19 @@
+src_hwc2_device = files(
+ 'hwc2_device.cpp',
+ 'DrmHwcTwo.cpp',
+ 'HwcDisplayConfigs.cpp',
+ 'HwcDisplay.cpp',
+ 'HwcLayer.cpp',
+)
+
+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,
+ install_dir : get_option('libdir') / 'hw',
+ include_directories: inc_include,
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..c2e5fb6
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,52 @@
+project(
+ 'drm_hwcomposer',
+ ['c', 'cpp'],
+ version : '2',
+ 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']
+)
+
+inc_include = [include_directories('.')]
+
+src_common = files(
+ 'compositor/DrmKmsPlan.cpp',
+ 'compositor/FlatteningController.cpp',
+ 'backend/BackendManager.cpp',
+ 'backend/Backend.cpp',
+ 'backend/BackendClient.cpp',
+ 'utils/fd.cpp',
+)
+
+deps = [
+ dependency('cutils'),
+ dependency('drm'),
+ dependency('hardware'),
+ dependency('hidlbase'),
+ dependency('log'),
+ dependency('sync'),
+ dependency('ui'),
+ dependency('utils'),
+]
+
+common_cpp_flags = [
+ '-DUSE_IMAPPER4_METADATA_API',
+]
+
+hwc2_cpp_flags = [
+ '-DHWC2_INCLUDE_STRINGIFICATION',
+ '-DHWC2_USE_CPP11',
+]
+
+subdir('drm')
+subdir('bufferinfo')
+
+drmhwc_common = static_library(
+ 'drm_hwcomposer_common',
+ src_common,
+# TODO remove hwc2 flags from common code (backends needs rework)
+ cpp_args : common_cpp_flags + hwc2_cpp_flags,
+ dependencies : deps,
+)
+
+subdir('hwc2_device')
diff --git a/presubmit.sh b/presubmit.sh
deleted file mode 100755
index a551398..0000000
--- a/presubmit.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-set -e
-
-echo "Run native build:"
-
-make -f .ci/Makefile -j12
-
-echo "Run style check:"
-
-./.ci/.gitlab-ci-checkcommit.sh
-
-echo -e "\n\e[32m --- SUCCESS ---"
diff --git a/tests/Android.bp b/tests/Android.bp
index f3ebb71..43fd3fa 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -28,28 +28,19 @@ package {
default_applicable_licenses: ["external_drm_hwcomposer_license"],
}
-cc_test {
- name: "hwc-drm-tests",
-
- srcs: ["worker_test.cpp"],
-
- vendor: true,
- header_libs: ["libhardware_headers"],
- static_libs: ["libdrmhwc_utils"],
- shared_libs: ["hwcomposer.drm"],
- include_dirs: ["external/drm_hwcomposer"],
-}
-
// Tool for listening and dumping uevents
cc_test {
name: "hwc-drm-uevent-print",
- srcs: ["uevent_print.cpp"],
+ srcs: [
+ ":drm_hwcomposer_fd",
+ "uevent_print.cpp",
+ ],
vendor: true,
- header_libs: ["libhardware_headers"],
- shared_libs: ["liblog"],
- include_dirs: [
- "external/drm_hwcomposer",
+ header_libs: [
+ "drm_hwcomposer_headers",
+ "libhardware_headers",
],
+ shared_libs: ["liblog"],
}
diff --git a/tests/worker_test.cpp b/tests/worker_test.cpp
deleted file mode 100644
index d1eb2b3..0000000
--- a/tests/worker_test.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "utils/Worker.h"
-
-#include <gtest/gtest.h>
-#include <hardware/hardware.h>
-
-#include <chrono>
-
-using android::Worker;
-
-struct TestWorker : public Worker {
- TestWorker() : Worker("test-worker", HAL_PRIORITY_URGENT_DISPLAY){};
-
- int Init() {
- return InitWorker();
- }
-
- void Routine() override {
- Lock();
- if (!enabled_) {
- int ret = WaitForSignalOrExitLocked();
- if (ret == -EINTR) {
- Unlock();
- return;
- }
- // should only reached here if it was enabled
- if (!enabled_)
- printf("Shouldn't reach here while disabled %d %d\n", value, ret);
- }
- value++;
- Unlock();
- }
-
- void Control(bool enable) {
- bool changed = false;
- Lock();
- if (enabled_ != enable) {
- enabled_ = enable;
- changed = true;
- }
- Unlock();
-
- if (enable && changed)
- Signal();
- }
-
- // NOLINTNEXTLINE: should not be public
- int value{};
-
- private:
- bool enabled_{};
-};
-
-struct WorkerTest : public testing::Test {
- TestWorker worker;
-
- void SetUp() override {
- worker.Init();
- }
-
- void small_delay() {
- std::this_thread::sleep_for(std::chrono::milliseconds(20));
- }
-};
-
-// NOLINTNEXTLINE: required by gtest macros
-TEST_F(WorkerTest, TestWorker) {
- // already isInitialized so should succeed
- ASSERT_TRUE(worker.initialized());
-
- int val = worker.value;
- small_delay();
-
- // value shouldn't change when isInitialized
- ASSERT_EQ(val, worker.value);
-
- worker.Control(true);
- small_delay();
-
- // while locked, value shouldn't be changing
- worker.Lock();
- val = worker.value;
- small_delay();
- ASSERT_EQ(val, worker.value);
- worker.Unlock();
-
- small_delay();
- // value should be different now
- ASSERT_NE(val, worker.value);
-
- worker.Control(false);
- worker.Lock();
- val = worker.value;
- worker.Unlock();
- small_delay();
-
- // value should be same
- ASSERT_EQ(val, worker.value);
-
- worker.Exit();
- ASSERT_FALSE(worker.initialized());
-}
-
-// NOLINTNEXTLINE: required by gtest macros
-TEST_F(WorkerTest, ExitWhileRunning) {
- worker.Control(true);
-
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
- worker.Exit();
-}
diff --git a/utils/UEvent.h b/utils/UEvent.h
index 17b3cab..5b9ecea 100644
--- a/utils/UEvent.h
+++ b/utils/UEvent.h
@@ -24,7 +24,7 @@
#include <optional>
#include <string>
-#include "UniqueFd.h"
+#include "fd.h"
#include "log.h"
namespace android {
@@ -32,7 +32,7 @@ namespace android {
class UEvent {
public:
static auto CreateInstance() -> std::unique_ptr<UEvent> {
- auto fd = UniqueFd(
+ auto fd = MakeUniqueFd(
socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT));
if (!fd) {
@@ -46,7 +46,7 @@ class UEvent {
addr.nl_groups = UINT32_MAX;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
- int ret = bind(fd.Get(), (struct sockaddr *)&addr, sizeof(addr));
+ const int ret = bind(*fd, (struct sockaddr *)&addr, sizeof(addr));
if (ret != 0) {
ALOGE("Failed to bind uevent socket: errno=%i", errno);
return {};
@@ -59,7 +59,7 @@ class UEvent {
constexpr int kUEventBufferSize = 1024;
char buffer[kUEventBufferSize];
ssize_t ret = 0;
- ret = read(fd_.Get(), &buffer, sizeof(buffer));
+ ret = read(*fd_, &buffer, sizeof(buffer));
if (ret == 0)
return {};
diff --git a/utils/UniqueFd.h b/utils/UniqueFd.h
deleted file mode 100644
index d747a7f..0000000
--- a/utils/UniqueFd.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015, 2021 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.
- */
-
-#ifndef UNIQUEFD_H_
-#define UNIQUEFD_H_
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <memory>
-
-namespace android {
-
-/*
- * Using UniqueFd:
- * 1. Create UniqueFd object:
- * auto fd_obj = UniqueFd(open("SomeFile", xxx));
- *
- * 2. Check whether the fd_obj is empty:
- * if (!fd_obj) { return -errno; }
- *
- * 3. Accessing the file descriptor:
- * int ret = read(fd_obj.Get(), buf, buf_size);
- *
- * 4. Closing the file:
- * FD will be closed once execution leaves fd_obj scope (on any return,
- * exception, destruction of class/struct where object is member, etc.).
- * User can also force closing the fd_obj by calling:
- * fd_obj = UniqueFd();
- * // fd is closed and fd_obj is empty now.
- *
- * 5. File descriptor may be transferred to the code, which will close it after
- * using. This can be done in 2 ways:
- * a. Duplicate the fd, in this case both fds should be closed separately:
- * int out_fd = dup(fd_obj.Get();
- * ...
- * close(out_fd);
- * b. Transfer ownership, use this method if you do not need the fd anymore.
- * int out_fd = fd_obj.Release();
- * // fd_obj is empty now.
- * ...
- * close(out_fd);
- *
- * 6. Transferring fd into another UniqueFD object:
- * UniqueFd fd_obj_2 = std::move(fd_obj);
- * // fd_obj empty now
- */
-
-constexpr int kEmptyFd = -1;
-
-class UniqueFd {
- public:
- UniqueFd() = default;
- explicit UniqueFd(int fd) : fd_(fd){};
-
- auto Release [[nodiscard]] () -> int {
- return std::exchange(fd_, kEmptyFd);
- }
-
- auto Get [[nodiscard]] () const -> int {
- return fd_;
- }
-
- static auto Dup(int fd) {
- // NOLINTNEXTLINE(android-cloexec-dup): fcntl has issue (see issue #63)
- return UniqueFd(dup(fd));
- }
-
- explicit operator bool() const {
- return fd_ != kEmptyFd;
- }
-
- ~UniqueFd() {
- Set(kEmptyFd);
- }
-
- /* Allow move semantics */
- UniqueFd(UniqueFd &&rhs) noexcept {
- Set(rhs.Release());
- }
-
- auto operator=(UniqueFd &&rhs) noexcept -> UniqueFd & {
- Set(rhs.Release());
- return *this;
- }
-
- /* Disable copy semantics */
- UniqueFd(const UniqueFd &) = delete;
- auto operator=(const UniqueFd &) = delete;
-
- private:
- void Set(int new_fd) {
- if (fd_ != kEmptyFd) {
- close(fd_);
- }
- fd_ = new_fd;
- }
-
- int fd_ = kEmptyFd;
-};
-
-} // namespace android
-
-#endif
diff --git a/utils/Worker.cpp b/utils/Worker.cpp
deleted file mode 100644
index d2b60c8..0000000
--- a/utils/Worker.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "Worker.h"
-
-#include <sys/prctl.h>
-#include <sys/resource.h>
-
-namespace android {
-
-Worker::Worker(const char *name, int priority)
- : name_(name), priority_(priority), exit_(false), initialized_(false) {
-}
-
-Worker::~Worker() {
- Exit();
-}
-
-int Worker::InitWorker() {
- std::lock_guard<std::mutex> lk(mutex_);
- if (initialized())
- return -EALREADY;
-
- thread_ = std::make_unique<std::thread>(&Worker::InternalRoutine, this);
- initialized_ = true;
- exit_ = false;
-
- return 0;
-}
-
-void Worker::Exit() {
- std::unique_lock<std::mutex> lk(mutex_);
- exit_ = true;
- if (initialized()) {
- lk.unlock();
- cond_.notify_all();
- thread_->join();
- initialized_ = false;
- }
-}
-
-int Worker::WaitForSignalOrExitLocked(int64_t max_nanoseconds) {
- int ret = 0;
- if (should_exit())
- return -EINTR;
-
- std::unique_lock<std::mutex> lk(mutex_, std::adopt_lock);
- if (max_nanoseconds < 0) {
- cond_.wait(lk);
- } else if (std::cv_status::timeout ==
- cond_.wait_for(lk, std::chrono::nanoseconds(max_nanoseconds))) {
- ret = -ETIMEDOUT;
- }
-
- // exit takes precedence on timeout
- if (should_exit())
- ret = -EINTR;
-
- // release leaves mutex locked when going out of scope
- lk.release();
-
- return ret;
-}
-
-void Worker::InternalRoutine() {
- setpriority(PRIO_PROCESS, 0, priority_);
- prctl(PR_SET_NAME, name_.c_str());
-
- std::unique_lock<std::mutex> lk(mutex_, std::defer_lock);
-
- while (true) {
- lk.lock();
- if (should_exit())
- return;
- lk.unlock();
-
- Routine();
- }
-}
-} // namespace android
diff --git a/utils/Worker.h b/utils/Worker.h
deleted file mode 100644
index 74cfdc4..0000000
--- a/utils/Worker.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef ANDROID_WORKER_H_
-#define ANDROID_WORKER_H_
-
-#include <condition_variable>
-#include <cstdint>
-#include <cstdlib>
-#include <mutex>
-#include <string>
-#include <thread>
-
-namespace android {
-
-class Worker {
- public:
- void Lock() {
- mutex_.lock();
- }
- void Unlock() {
- mutex_.unlock();
- }
-
- void Signal() {
- cond_.notify_all();
- }
- void Exit();
-
- bool initialized() const {
- return initialized_;
- }
-
- virtual ~Worker();
-
- protected:
- Worker(const char *name, int priority);
-
- int InitWorker();
- virtual void Routine() = 0;
-
- /*
- * Must be called with the lock acquired. max_nanoseconds may be negative to
- * indicate infinite timeout, otherwise it indicates the maximum time span to
- * wait for a signal before returning.
- * Returns -EINTR if interrupted by exit request, or -ETIMEDOUT if timed out
- */
- int WaitForSignalOrExitLocked(int64_t max_nanoseconds = -1);
-
- bool should_exit() const {
- return exit_;
- }
-
- std::mutex mutex_;
- std::condition_variable cond_;
-
- private:
- void InternalRoutine();
-
- std::string name_;
- int priority_;
-
- std::unique_ptr<std::thread> thread_;
- bool exit_;
- bool initialized_;
-};
-} // namespace android
-#endif
diff --git a/utils/fd.cpp b/utils/fd.cpp
new file mode 100644
index 0000000..395d3b2
--- /dev/null
+++ b/utils/fd.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include "fd.h"
+
+namespace android {
+
+static void CloseFd(const int *fd) {
+ if (fd != nullptr) {
+ if (*fd >= 0)
+ close(*fd);
+
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+ delete fd;
+ }
+}
+
+auto MakeUniqueFd(int fd) -> UniqueFd {
+ if (fd < 0)
+ return {nullptr, CloseFd};
+
+ return {new int(fd), CloseFd};
+}
+
+auto MakeSharedFd(int fd) -> SharedFd {
+ if (fd < 0)
+ return {};
+
+ return {new int(fd), CloseFd};
+}
+
+auto DupFd(SharedFd const &fd) -> int {
+ if (!fd)
+ return -1;
+
+ return fcntl(*fd, F_DUPFD_CLOEXEC, 0);
+}
+
+} // namespace android
diff --git a/utils/fd.h b/utils/fd.h
new file mode 100644
index 0000000..6bfd0fa
--- /dev/null
+++ b/utils/fd.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 - 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 <fcntl.h>
+#include <unistd.h>
+
+#include <memory>
+#include <utility>
+
+namespace android {
+
+using UniqueFd = std::unique_ptr<int, void (*)(const int *)>;
+using SharedFd = std::shared_ptr<int>;
+
+auto MakeUniqueFd(int fd) -> UniqueFd;
+
+auto MakeSharedFd(int fd) -> SharedFd;
+
+auto DupFd(SharedFd const &fd) -> int;
+
+} // namespace android
diff --git a/utils/log.h b/utils/log.h
index a48d2e7..22200df 100644
--- a/utils/log.h
+++ b/utils/log.h
@@ -1,5 +1,20 @@
-#ifndef UTILS_LOG_H_
-#define UTILS_LOG_H_
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
#ifdef ANDROID
@@ -22,5 +37,3 @@
#define ALOGV(args...) printf("VERBOSE: " args)
#endif
-
-#endif \ No newline at end of file
diff --git a/utils/properties.h b/utils/properties.h
index 0b49c61..e400236 100644
--- a/utils/properties.h
+++ b/utils/properties.h
@@ -1,5 +1,20 @@
-#ifndef UTILS_PROPERTIES_H_
-#define UTILS_PROPERTIES_H_
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
#ifdef ANDROID
@@ -25,5 +40,3 @@ auto inline property_get(const char *name, char *value,
}
#endif
-
-#endif \ No newline at end of file