diff options
author | John Stultz <jstultz@google.com> | 2023-07-12 21:27:56 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-07-12 21:27:56 +0000 |
commit | 5365831dfb10183120ae79ae26ce044812c9346c (patch) | |
tree | 00306ed4f9d015e1c768b64bcad078bf9069ea04 | |
parent | dd74ccbf173a31d24b60ba9ffaf9db10dfa7ab05 (diff) | |
parent | 197c32dc5b1164f1837edcea32c12bd2d4cf8e77 (diff) | |
download | drm_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>
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 @@ -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 @@ -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(×tamp); + 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(×tamp); - 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 |