diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2022-01-20 21:07:22 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-01-20 21:07:22 +0000 |
commit | 09ba88048789e588df23c04f6326d18824ea3aee (patch) | |
tree | 7db9ed847f6dc958acad6d8e7dec6a0f7922b069 | |
parent | 14aec06fcc6c5a46ba1e953c4c07d3cdc4c207f1 (diff) | |
parent | fb30bcf225af16f208012a41bb4dbea2a3b201af (diff) | |
download | drm_hwcomposer-09ba88048789e588df23c04f6326d18824ea3aee.tar.gz |
Merge "drm_hwcomposer: Merge remote-tracking branch 'aosp/upstream-main' into HEAD" am: 6ca311696d am: cdf90f5669 am: fb30bcf225
Original change: https://android-review.googlesource.com/c/platform/external/drm_hwcomposer/+/1949446
Change-Id: I47e757287b79d8a4524db06f0e3ab3715f20eef4
62 files changed, 2766 insertions, 2685 deletions
diff --git a/.ci/.common.sh b/.ci/.common.sh deleted file mode 100644 index 48cc594..0000000 --- a/.ci/.common.sh +++ /dev/null @@ -1,42 +0,0 @@ -INCLUDE_DIRS="-I. -I../libdrm/include/drm -Iinclude -I/usr/include/libdrm -I./.ci/android_headers -I./tests/test_include" - -CLANG="clang++-12" -CLANG_TIDY="clang-tidy-12" - -CXXARGS="-fPIC -Wall -Werror -DPLATFORM_SDK_VERSION=30 -D__ANDROID_API__=30 -Wsign-promo -Wimplicit-fallthrough" -CXXARGS+=" -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -Wno-gnu-include-next -Wsign-compare" -CXXARGS+=" -fvisibility-inlines-hidden -std=gnu++17 -DHWC2_USE_CPP11 -DHWC2_INCLUDE_STRINGIFICATION -fno-rtti" - -BUILD_FILES=( -backend/BackendClient.cpp -backend/Backend.cpp -backend/BackendManager.cpp -backend/BackendRCarDu.cpp -bufferinfo/BufferInfoGetter.cpp -#bufferinfo/BufferInfoMapperMetadata.cpp -bufferinfo/legacy/BufferInfoImagination.cpp -bufferinfo/legacy/BufferInfoLibdrm.cpp -bufferinfo/legacy/BufferInfoMaliHisi.cpp -bufferinfo/legacy/BufferInfoMaliMediatek.cpp -bufferinfo/legacy/BufferInfoMaliMeson.cpp -bufferinfo/legacy/BufferInfoMinigbm.cpp -compositor/DrmDisplayComposition.cpp -compositor/DrmDisplayCompositor.cpp -compositor/Planner.cpp -drm/DrmConnector.cpp -drm/DrmCrtc.cpp -drm/DrmDevice.cpp -drm/DrmEncoder.cpp -drm/DrmFbImporter.cpp -drm/DrmMode.cpp -drm/DrmPlane.cpp -drm/DrmProperty.cpp -DrmHwcTwo.cpp -drm/ResourceManager.cpp -drm/UEventListener.cpp -drm/VSyncWorker.cpp -tests/worker_test.cpp -utils/autolock.cpp -#utils/hwcutils.cpp -utils/Worker.cpp -) diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh index 817afa7..e59ad9f 100755 --- a/.ci/.gitlab-ci-checkcommit.sh +++ b/.ci/.gitlab-ci-checkcommit.sh @@ -50,7 +50,7 @@ git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do exit 1 fi - git show "$h" -- | clang-format-diff-11 -p 1 -style=file > /tmp/format-fixup.patch + git show "$h" -- | clang-format-diff-12 -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/.gitlab-ci-clang-build.sh b/.ci/.gitlab-ci-clang-build.sh deleted file mode 100755 index 1070365..0000000 --- a/.ci/.gitlab-ci-clang-build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -. ./.ci/.common.sh - -set -xe - -for source in "${BUILD_FILES[@]}" -do - filename=$(basename -- "$source") - $CLANG $source $INCLUDE_DIRS $CXXARGS -c -o /tmp/"${filename%.*}.o" -done diff --git a/.ci/.gitlab-ci-clang-tidy-coarse.sh b/.ci/.gitlab-ci-clang-tidy-coarse.sh deleted file mode 100755 index a3afeb9..0000000 --- a/.ci/.gitlab-ci-clang-tidy-coarse.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -. ./.ci/.common.sh - -TIDY_COARSE_CHECKS="-*,android-*,bugprone-*,cert-*,clang-analyzer-*," -TIDY_COARSE_CHECKS+="cppcoreguidelines-*," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-bounds-array-to-pointer-decay," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-bounds-constant-array-index," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-bounds-pointer-arithmetic," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-type-cstyle-cast," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-type-union-access," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-pro-type-vararg," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-avoid-magic-numbers," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-macro-usage," -TIDY_COARSE_CHECKS+="-cppcoreguidelines-avoid-c-arrays," -TIDY_COARSE_CHECKS+="google-*," -TIDY_COARSE_CHECKS+="-google-readability-braces-around-statements," -TIDY_COARSE_CHECKS+="-google-readability-casting," -TIDY_COARSE_CHECKS+="misc-*," -TIDY_COARSE_CHECKS+="-misc-non-private-member-variables-in-classes", -TIDY_COARSE_CHECKS+="modernize-*," -TIDY_COARSE_CHECKS+="-modernize-avoid-c-arrays," -TIDY_COARSE_CHECKS+="-modernize-use-trailing-return-type," -TIDY_COARSE_CHECKS+="performance-*," -TIDY_COARSE_CHECKS+="portability-*," -TIDY_COARSE_CHECKS+="readability-*," -TIDY_COARSE_CHECKS+="-readability-braces-around-statements," -TIDY_COARSE_CHECKS+="-readability-function-cognitive-complexity," -TIDY_COARSE_CHECKS+="-readability-convert-member-functions-to-static," -TIDY_COARSE_CHECKS+="-readability-implicit-bool-conversion," -TIDY_COARSE_CHECKS+="-readability-identifier-naming," -TIDY_COARSE_CHECKS+="-readability-magic-numbers," -TIDY_COARSE_CHECKS+="-readability-use-anyofallof" - -TIDY_FILES=( "${BUILD_FILES[@]}" ) - -set -xe - -for source in "${TIDY_FILES[@]}" -do - $CLANG_TIDY $source --checks=$TIDY_COARSE_CHECKS -- -x c++ $INCLUDE_DIRS $CXXARGS -done diff --git a/.ci/.gitlab-ci-clang-tidy-fine.sh b/.ci/.gitlab-ci-clang-tidy-fine.sh deleted file mode 100755 index 0e3e35b..0000000 --- a/.ci/.gitlab-ci-clang-tidy-fine.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -. ./.ci/.common.sh - -TIDY_FILES=( -drm/DrmFbImporter.h -drm/DrmUnique.h -utils/UniqueFd.h -utils/log.h -utils/properties.h -) - -set -xe - -for source in "${TIDY_FILES[@]}" -do - $CLANG_TIDY $source -- -x c++ $INCLUDE_DIRS $CXXARGS -done diff --git a/.ci/Makefile b/.ci/Makefile new file mode 100644 index 0000000..4ca14d6 --- /dev/null +++ b/.ci/Makefile @@ -0,0 +1,167 @@ + +INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include +SYSTEM_INCLUDE_DIRS := /usr/include/libdrm + +CLANG := clang++-12 +CLANG_TIDY := clang-tidy-12 +OUT_DIR := /tmp/drm_hwcomposer/build +SRC_DIR := . + +CXXFLAGS := -fPIC -Wall -Wextra -Werror -DPLATFORM_SDK_VERSION=31 -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 + +SKIP_FILES := \ + bufferinfo/BufferInfoMapperMetadata.cpp + +TIDY_FILES_OVERRIDE := \ + bufferinfo/legacy/BufferInfoImagination.cpp:COARSE \ + bufferinfo/legacy/BufferInfoLibdrm.cpp:COARSE \ + bufferinfo/legacy/BufferInfoMaliHisi.cpp:COARSE \ + bufferinfo/legacy/BufferInfoMaliMediatek.cpp:COARSE \ + bufferinfo/legacy/BufferInfoMaliMeson.cpp:COARSE \ + bufferinfo/legacy/BufferInfoMinigbm.cpp:COARSE \ + compositor/DrmDisplayComposition.cpp:COARSE \ + compositor/DrmDisplayComposition.h:COARSE \ + compositor/DrmDisplayCompositor.cpp:COARSE \ + drm/DrmFbImporter.h:FINE \ + drm/DrmMode.h:COARSE \ + drm/DrmDevice.h:COARSE \ + drm/DrmProperty.h:COARSE \ + drm/DrmConnector.h:COARSE \ + drm/DrmCrtc.h:COARSE \ + drm/DrmUnique.h:FINE \ + drm/DrmEncoder.h:COARSE \ + drm/DrmConnector.cpp:COARSE \ + drm/DrmDevice.cpp:COARSE \ + drm/DrmProperty.cpp:COARSE \ + drm/UEventListener.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 \ + +TIDY_CHECKS_FINE := * \ + -llvmlibc* -fuchsia-* -altera-* \ + -llvm-header-guard \ + -cppcoreguidelines-pro-type-vararg \ + -hicpp-vararg \ + -hicpp-signed-bitwise \ + +TIDY_CHECKS_NORMAL := \ + $(TIDY_CHECKS_FINE) \ + -hicpp* \ + -cppcoreguidelines-special-member-functions \ + -cppcoreguidelines-avoid-c-arrays \ + -cppcoreguidelines-pro-bounds-array-to-pointer-decay \ + -cppcoreguidelines-pro-bounds-constant-array-index \ + -cppcoreguidelines-avoid-magic-numbers \ + -google-readability-braces-around-statements \ + -google-readability-casting \ + -misc-non-private-member-variables-in-classes \ + -modernize-avoid-c-arrays \ + -modernize-use-nodiscard \ + -modernize-use-trailing-return-type \ + -readability-braces-around-statements \ + +TIDY_CHECKS_COARSE := \ + $(TIDY_CHECKS_NORMAL) \ + -cppcoreguidelines-non-private-member-variables-in-classes \ + -cppcoreguidelines-pro-bounds-pointer-arithmetic \ + -cppcoreguidelines-pro-type-cstyle-cast \ + -cppcoreguidelines-pro-type-reinterpret-cast \ + -cppcoreguidelines-pro-type-static-cast-downcast \ + -cppcoreguidelines-pro-type-union-access \ + -cppcoreguidelines-macro-usage \ + -readability-convert-member-functions-to-static \ + -readability-implicit-bool-conversion \ + -readability-identifier-naming \ + -readability-magic-numbers \ + +.PHONY: all build tidy clean + +all: build tidy + +clean: + rm -rf $(OUT_DIR)/ + +# Build + +BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/*' -path '*.cpp') +SKIP_FILES_path := $(foreach file,$(SKIP_FILES),$(SRC_DIR)/$(file)) + +BUILD_FILES := $(subst ./,,$(filter-out $(SKIP_FILES_path),$(BUILD_FILES_AUTO))) + +_OBJ := $(BUILD_FILES:.cpp=.o) +OBJ := $(patsubst %,$(OUT_DIR)/%,$(_OBJ)) + +DEPS := $(patsubst %.cpp,$(OUT_DIR)/%.d,$(BUILD_FILES)) + +build: $(OBJ) + +CXXARGS := $(foreach dir,$(INCLUDE_DIRS),-I$(SRC_DIR)/$(dir)) $(foreach dir,$(SYSTEM_INCLUDE_DIRS),-I$(dir)) $(CXXFLAGS) + +$(OUT_DIR)/%.o: $(SRC_DIR)/%.cpp + mkdir -p $(dir $@) + $(CLANG) $< $(CXXARGS) -c -o $@ + +$(OUT_DIR)/%.d: $(SRC_DIR)/%.cpp + mkdir -p $(dir $@) + $(CLANG) $(CXXARGS) $< -MM -MT $(OUT_DIR)/$(patsubst %.cpp,%.o,$<) -o $@ + +# TIDY +TIDY_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/*' \( -path '*.cpp' -o -path '*.h' \)) + +TIDY_FILES_AUTO_filtered := $(filter-out $(SKIP_FILES_path),$(TIDY_FILES_AUTO)) + +TIDY_FILES_OVERRIDE_path := $(foreach pair,$(TIDY_FILES_OVERRIDE),$(SRC_DIR)/$(pair)) + +TIDY_FILES_OVERRIDE_name_only := $(foreach pair,$(TIDY_FILES_OVERRIDE_path),$(word 1, $(subst :, ,$(pair)))) + +TIDY_FILES := $(sort $(TIDY_FILES_AUTO_filtered) $(TIDY_FILES_OVERRIDE_name_only)) + +space := $(subst ,, ) +comma := , + +TIDY_ARGS_NONE := --checks="-*,llvm-include-order" +TIDY_ARGS_ := --checks="-*,llvm-include-order" +TIDY_ARGS_FINE := --checks="$(subst $(space),$(comma),$(strip $(TIDY_CHECKS_FINE)))" +TIDY_ARGS_NORMAL := --checks="$(subst $(space),$(comma),$(strip $(TIDY_CHECKS_NORMAL)))" +TIDY_ARGS_COARSE := --checks="$(subst $(space),$(comma),$(strip $(TIDY_CHECKS_COARSE)))" + +define process-tidy + +_TARG := $(OUT_DIR)/$1.tidy.ts +_DEP := $(SRC_DIR)/$1 + +TIDY_DEPS += $(_TARG) + +TIDY_LEVEL_1 := $$(strip $$(foreach pair,$$(TIDY_FILES_OVERRIDE_path),$$(if $$(filter $$(word 1, $$(subst :, ,$$(pair))),$1),$$(word 2, $$(subst :, ,$$(pair))),))) + +TIDY_LEVEL_2 := $$(if $$(TIDY_LEVEL_1),$$(TIDY_LEVEL_1),NORMAL) + +TIDY_ARGS := $$(TIDY_ARGS_$$(TIDY_LEVEL_2)) + +$$(_TARG): _DEP := $$(_DEP) +$$(_TARG): _TARG := $$(_TARG) +$$(_TARG): TIDY_ARGS := $$(TIDY_ARGS) +$$(_TARG): $$(_DEP) + mkdir -p $$(dir $$(_TARG)) + $$(CLANG_TIDY) $$(_DEP) $$(TIDY_ARGS) -- -x c++ $$(CXXARGS) + touch $$(_TARG) + +endef + +$(foreach file,$(TIDY_FILES),$(eval $(call process-tidy,$(file)))) + +tidy: $(TIDY_DEPS) + +ifneq ($(MAKECMDGOALS), clean) +-include $(DEPS) +endif diff --git a/.clang-tidy b/.clang-tidy index 221c030..3731a29 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,15 +1,3 @@ -# fuchsia: Conflicts with other checks -# llvm-header-guard: Does not match drm_hwc header gusrd style -# Allow using ALOGE - -Checks: > - *, - -fuchsia*, - -llvm*, - -concurrency-mt-unsafe, - -cppcoreguidelines-pro-type-vararg, -hicpp-vararg, - -hicpp-signed-bitwise, - # Turn all the warnings from the checks above into errors. WarningsAsErrors: "*" @@ -50,8 +38,10 @@ CheckOptions: value: '^[A-Z]+(_[A-Z]+)*_$' - key: readability-identifier-naming.MemberCase value: lower_case - - key: readability-identifier-naming.MemberSuffix + - key: readability-identifier-naming.PrivateMemberSuffix value: _ + - key: readability-identifier-naming.PublicMemberSuffix + value: '' - key: readability-identifier-naming.NamespaceCase value: lower_case - key: readability-identifier-naming.ParameterCase @@ -64,3 +54,7 @@ CheckOptions: value: lower_case - key: readability-identifier-naming.IgnoreMainLikeFunctions value: 1 + - key: cppcoreguidelines-macro-usage.AllowedRegexp + value: "LOG_TAG|ATRACE_TAG" + - key: readability-magic-numbers.IgnoredFloatingPointValues + value: '1000.0' diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 41d38ba..9a54b44 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ variables: before_script: - apt-get --quiet update --yes >/dev/null - - apt-get --quiet install --yes clang-12 clang-tidy-12 clang-format-12 git libdrm-dev blueprint-tools libgtest-dev >/dev/null + - apt-get --quiet install --yes clang-12 clang-tidy-12 clang-format-12 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null stages: - build @@ -13,7 +13,8 @@ stages: build: stage: build - script: "./.ci/.gitlab-ci-clang-build.sh" + script: + - make -f .ci/Makefile artifacts: when: on_failure untracked: true @@ -24,17 +25,3 @@ checkstyle: artifacts: when: on_failure untracked: true - -tidy-coarse: - stage: style - script: "./.ci/.gitlab-ci-clang-tidy-coarse.sh" - artifacts: - when: on_failure - untracked: true - -tidy-fine: - stage: style - script: "./.ci/.gitlab-ci-clang-tidy-fine.sh" - artifacts: - when: on_failure - untracked: true @@ -98,8 +98,6 @@ cc_defaults { filegroup { name: "drm_hwcomposer_common", srcs: [ - "DrmHwcTwo.cpp", - "bufferinfo/BufferInfoGetter.cpp", "bufferinfo/BufferInfoMapperMetadata.cpp", @@ -126,6 +124,12 @@ filegroup { "backend/BackendClient.cpp", "backend/BackendManager.cpp", "backend/BackendRCarDu.cpp", + + "hwc2_device/DrmHwcTwo.cpp", + "hwc2_device/HwcDisplay.cpp", + "hwc2_device/HwcDisplayConfigs.cpp", + "hwc2_device/HwcLayer.cpp", + "hwc2_device/hwc2_device.cpp", ], } diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp deleted file mode 100644 index 9bf1327..0000000 --- a/DrmHwcTwo.cpp +++ /dev/null @@ -1,1679 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_TAG "hwc-drm-two" - -#include "DrmHwcTwo.h" - -#include <fcntl.h> -#include <hardware/hardware.h> -#include <hardware/hwcomposer2.h> -#include <sync/sync.h> -#include <unistd.h> - -#include <cinttypes> -#include <iostream> -#include <sstream> -#include <string> - -#include "backend/BackendManager.h" -#include "bufferinfo/BufferInfoGetter.h" -#include "compositor/DrmDisplayComposition.h" -#include "utils/log.h" -#include "utils/properties.h" - -namespace android { - -DrmHwcTwo::DrmHwcTwo() : hwc2_device() { - common.tag = HARDWARE_DEVICE_TAG; - common.version = HWC_DEVICE_API_VERSION_2_0; - common.close = HookDevClose; - getCapabilities = HookDevGetCapabilities; - getFunction = HookDevGetFunction; -} - -HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ, - HWC2::DisplayType type) { - DrmDevice *drm = resource_manager_.GetDrmDevice(static_cast<int>(displ)); - if (!drm) { - ALOGE("Failed to get a valid drmresource"); - return HWC2::Error::NoResources; - } - displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ), - std::forward_as_tuple(&resource_manager_, drm, displ, type, - this)); - - DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ)); - if (!crtc) { - ALOGE("Failed to get crtc for display %d", static_cast<int>(displ)); - return HWC2::Error::BadDisplay; - } - auto display_planes = std::vector<DrmPlane *>(); - for (const auto &plane : drm->planes()) { - if (plane->GetCrtcSupported(*crtc)) - display_planes.push_back(plane.get()); - } - displays_.at(displ).Init(&display_planes); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::Init() { - int rv = resource_manager_.Init(); - if (rv) { - ALOGE("Can't initialize the resource manager %d", rv); - return HWC2::Error::NoResources; - } - - HWC2::Error ret = HWC2::Error::None; - for (int i = 0; i < resource_manager_.getDisplayCount(); i++) { - ret = CreateDisplay(i, HWC2::DisplayType::Physical); - if (ret != HWC2::Error::None) { - ALOGE("Failed to create display %d with error %d", i, ret); - return ret; - } - } - - resource_manager_.GetUEventListener()->RegisterHotplugHandler( - [this] { HandleHotplugUEvent(); }); - - return ret; -} - -template <typename... Args> -static inline HWC2::Error unsupported(char const *func, Args... /*args*/) { - ALOGV("Unsupported function: %s", func); - return HWC2::Error::Unsupported; -} - -static inline void supported(char const *func) { - ALOGV("Supported function: %s", func); -} - -HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t width, uint32_t height, - int32_t *format, - hwc2_display_t *display) { - // TODO(nobody): Implement virtual display - return unsupported(__func__, width, height, format, display); -} - -HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) { - // TODO(nobody): Implement virtual display - return unsupported(__func__, display); -} - -std::string DrmHwcTwo::HwcDisplay::DumpDelta( - DrmHwcTwo::HwcDisplay::Stats delta) { - if (delta.total_pixops_ == 0) - return "No stats yet"; - double ratio = 1.0 - double(delta.gpu_pixops_) / double(delta.total_pixops_); - - std::stringstream ss; - ss << " Total frames count: " << delta.total_frames_ << "\n" - << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n" - << " Failed to commit frames: " << delta.failed_kms_present_ << "\n" - << ((delta.failed_kms_present_ > 0) - ? " !!! Internal failure, FIX it please\n" - : "") - << " Flattened frames: " << delta.frames_flattened_ << "\n" - << " Pixel operations (free units)" - << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_ - << "]\n" - << " Composition efficiency: " << ratio; - - return ss.str(); -} - -std::string DrmHwcTwo::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::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" - << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n"; - - memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); - return ss.str(); -} - -void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { - supported(__func__); - - if (outBuffer != nullptr) { - auto copied_bytes = mDumpString.copy(outBuffer, *outSize); - *outSize = static_cast<uint32_t>(copied_bytes); - return; - } - - std::stringstream output; - - output << "-- drm_hwcomposer --\n\n"; - - for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &dp : displays_) - output << dp.second.Dump(); - - mDumpString = output.str(); - *outSize = static_cast<uint32_t>(mDumpString.size()); -} - -uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() { - // TODO(nobody): Implement virtual display - unsupported(__func__); - return 0; -} - -HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, - hwc2_callback_data_t data, - hwc2_function_pointer_t function) { - supported(__func__); - - std::unique_lock<std::mutex> lock(callback_lock_); - - switch (static_cast<HWC2::Callback>(descriptor)) { - case HWC2::Callback::Hotplug: { - hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data); - lock.unlock(); - const auto &drm_devices = resource_manager_.getDrmDevices(); - for (const auto &device : drm_devices) - HandleInitialHotplugState(device.get()); - break; - } - case HWC2::Callback::Refresh: { - refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data); - break; - } - case HWC2::Callback::Vsync: { - vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data); - break; - } -#if PLATFORM_SDK_VERSION > 29 - case HWC2::Callback::Vsync_2_4: { - vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data); - break; - } -#endif - default: - break; - } - return HWC2::Error::None; -} - -DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager, - DrmDevice *drm, hwc2_display_t handle, - HWC2::DisplayType type, DrmHwcTwo *hwc2) - : hwc2_(hwc2), - resource_manager_(resource_manager), - drm_(drm), - handle_(handle), - type_(type), - color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) { - supported(__func__); - - // 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 -} - -void DrmHwcTwo::HwcDisplay::ClearDisplay() { - AtomicCommitArgs a_args = {.clear_active_composition = true}; - compositor_.ExecuteAtomicCommit(a_args); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) { - supported(__func__); - planner_ = Planner::CreateInstance(drm_); - if (!planner_) { - ALOGE("Failed to create planner instance for composition"); - return HWC2::Error::NoResources; - } - - int display = static_cast<int>(handle_); - int ret = compositor_.Init(resource_manager_, display); - if (ret) { - ALOGE("Failed display compositor init for display %d (%d)", display, ret); - return HWC2::Error::NoResources; - } - - // Split up the given display planes into primary and overlay to properly - // interface with the composition - char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; - property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop, - "1"); - bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10); - for (auto &plane : *planes) { - if (plane->type() == DRM_PLANE_TYPE_PRIMARY) - primary_planes_.push_back(plane); - else if (use_overlay_planes && (plane)->type() == DRM_PLANE_TYPE_OVERLAY) - overlay_planes_.push_back(plane); - } - - crtc_ = drm_->GetCrtcForDisplay(display); - if (!crtc_) { - ALOGE("Failed to get crtc for display %d", display); - return HWC2::Error::BadDisplay; - } - - connector_ = drm_->GetConnectorForDisplay(display); - if (!connector_) { - ALOGE("Failed to get connector for display %d", display); - return HWC2::Error::BadDisplay; - } - - ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) { - const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_); - /* vsync callback */ -#if PLATFORM_SDK_VERSION > 29 - if (hwc2_->vsync_2_4_callback_.first != nullptr && - hwc2_->vsync_2_4_callback_.second != nullptr) { - hwc2_vsync_period_t period_ns{}; - GetDisplayVsyncPeriod(&period_ns); - hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second, - handle_, timestamp, period_ns); - } else -#endif - if (hwc2_->vsync_callback_.first != nullptr && - hwc2_->vsync_callback_.second != nullptr) { - hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_, - timestamp); - } - }); - if (ret) { - ALOGE("Failed to create event worker for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - ret = flattening_vsync_worker_.Init(drm_, display, [this](int64_t /*timestamp*/) { - const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_); - /* Frontend flattening */ - 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_); - flattening_vsync_worker_.VSyncControl(false); - } - }); - if (ret) { - ALOGE("Failed to create event worker for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - ret = BackendManager::GetInstance().SetBackendForDisplay(this); - if (ret) { - ALOGE("Failed to set backend for d=%d %d\n", display, ret); - return HWC2::Error::BadDisplay; - } - - client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED); - - return ChosePreferredConfig(); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() { - // Fetch the number of modes from the display - uint32_t num_configs = 0; - HWC2::Error err = GetDisplayConfigs(&num_configs, nullptr); - if (err != HWC2::Error::None || !num_configs) - return HWC2::Error::BadDisplay; - - return SetActiveConfig(preferred_config_id_); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() { - supported(__func__); - for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) - l.second.accept_type_change(); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::CreateLayer(hwc2_layer_t *layer) { - supported(__func__); - layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer()); - *layer = static_cast<hwc2_layer_t>(layer_idx_); - ++layer_idx_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::DestroyLayer(hwc2_layer_t layer) { - supported(__func__); - if (!get_layer(layer)) - return HWC2::Error::BadLayer; - - layers_.erase(layer); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetActiveConfig( - hwc2_config_t *config) const { - supported(__func__); - if (hwc_configs_.count(active_config_id_) == 0) - return HWC2::Error::BadConfig; - - *config = active_config_id_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetChangedCompositionTypes( - uint32_t *num_elements, hwc2_layer_t *layers, int32_t *types) { - supported(__func__); - uint32_t num_changes = 0; - for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { - if (l.second.type_changed()) { - if (layers && num_changes < *num_elements) - layers[num_changes] = l.first; - if (types && num_changes < *num_elements) - types[num_changes] = static_cast<int32_t>(l.second.validated_type()); - ++num_changes; - } - } - if (!layers && !types) - *num_elements = num_changes; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetClientTargetSupport(uint32_t width, - uint32_t height, - int32_t /*format*/, - int32_t dataspace) { - supported(__func__); - std::pair<uint32_t, uint32_t> min = drm_->min_resolution(); - std::pair<uint32_t, uint32_t> max = drm_->max_resolution(); - - if (width < min.first || height < min.second) - return HWC2::Error::Unsupported; - - if (width > max.first || height > max.second) - return HWC2::Error::Unsupported; - - if (dataspace != HAL_DATASPACE_UNKNOWN) - return HWC2::Error::Unsupported; - - // TODO(nobody): Validate format can be handled by either GL or planes - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetColorModes(uint32_t *num_modes, - int32_t *modes) { - supported(__func__); - if (!modes) - *num_modes = 1; - - if (modes) - *modes = HAL_COLOR_MODE_NATIVE; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayAttribute(hwc2_config_t config, - int32_t attribute_in, - int32_t *value) { - supported(__func__); - int conf = static_cast<int>(config); - - if (hwc_configs_.count(conf) == 0) { - ALOGE("Could not find active mode for %d", conf); - return HWC2::Error::BadConfig; - } - - auto &hwc_config = hwc_configs_[conf]; - - static const int32_t kUmPerInch = 25400; - uint32_t mm_width = connector_->mm_width(); - uint32_t mm_height = connector_->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()); - break; - case HWC2::Attribute::Height: - *value = static_cast<int>(hwc_config.mode.v_display()); - break; - case HWC2::Attribute::VsyncPeriod: - // in nanoseconds - *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh()); - break; - case HWC2::Attribute::DpiX: - // Dots per 1000 inches - *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() * - 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) - : -1; - break; -#if PLATFORM_SDK_VERSION > 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 */ - *value = hwc_config.group_id; - break; -#endif - default: - *value = -1; - return HWC2::Error::BadConfig; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs) { - supported(__func__); - // Since this callback is normally invoked twice (once to get the count, and - // once to populate configs), we don't really want to read the edid - // redundantly. Instead, only update the modes on the first invocation. While - // it's possible this will result in stale modes, it'll all come out in the - // wash when we try to set the active config later. - if (!configs) { - int ret = connector_->UpdateModes(); - if (ret) { - ALOGE("Failed to update display modes %d", ret); - return HWC2::Error::BadDisplay; - } - - hwc_configs_.clear(); - preferred_config_id_ = 0; - int preferred_config_group_id_ = 0; - - if (connector_->modes().empty()) { - ALOGE("No modes reported by KMS"); - return HWC2::Error::BadDisplay; - } - - int last_config_id = 1; - int last_group_id = 1; - - /* Group modes */ - for (const auto &mode : connector_->modes()) { - /* Find group for the new mode or create new group */ - int 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()) { - group_found = hwc_config.second.group_id; - } - } - if (group_found == 0) { - group_found = last_group_id++; - } - - bool disabled = false; - if (mode.flags() & DRM_MODE_FLAG_3D_MASK) { - ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)", - mode.name().c_str()); - disabled = true; - } - - /* Add config */ - hwc_configs_[last_config_id] = { - .id = last_config_id, - .group_id = group_found, - .mode = mode, - .disabled = disabled, - }; - - /* Chwck if the mode is preferred */ - if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 && - preferred_config_id_ == 0) { - preferred_config_id_ = last_config_id; - preferred_config_group_id_ = group_found; - } - - last_config_id++; - } - - /* We must have preferred mode. Set first mode as preferred - * in case KMS haven't reported anything. */ - if (preferred_config_id_ == 0) { - preferred_config_id_ = 1; - preferred_config_group_id_ = 1; - } - - for (int group = 1; group < last_group_id; group++) { - bool has_interlaced = false; - bool has_progressive = false; - for (auto &hwc_config : hwc_configs_) { - if (hwc_config.second.group_id != group || hwc_config.second.disabled) { - continue; - } - - if (hwc_config.second.IsInterlaced()) { - has_interlaced = true; - } else { - has_progressive = true; - } - } - - bool has_both = has_interlaced && has_progressive; - if (!has_both) { - continue; - } - - bool group_contains_preferred_interlaced = false; - if (group == preferred_config_group_id_ && - hwc_configs_[preferred_config_id_].IsInterlaced()) { - group_contains_preferred_interlaced = true; - } - - for (auto &hwc_config : hwc_configs_) { - if (hwc_config.second.group_id != group || hwc_config.second.disabled) { - continue; - } - - bool disable = group_contains_preferred_interlaced - ? !hwc_config.second.IsInterlaced() - : hwc_config.second.IsInterlaced(); - - if (disable) { - ALOGI( - "Group %i: Disabling display mode %s (This group should consist " - "of %s modes)", - group, hwc_config.second.mode.name().c_str(), - group_contains_preferred_interlaced ? "interlaced" - : "progressive"); - - hwc_config.second.disabled = true; - } - } - } - - /* Group should not contain 2 modes with FPS delta less than ~1HZ - * otherwise android.graphics.cts.SetFrameRateTest CTS will fail - */ - for (int m1 = 1; m1 < last_config_id; m1++) { - for (int m2 = 1; 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()) < 1.0) { - 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].disabled = true; - } - } - } - } - - uint32_t idx = 0; - for (auto &hwc_config : hwc_configs_) { - if (hwc_config.second.disabled) { - continue; - } - - if (configs != nullptr) { - if (idx >= *num_configs) { - break; - } - configs[idx] = hwc_config.second.id; - } - - idx++; - } - *num_configs = idx; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayName(uint32_t *size, char *name) { - supported(__func__); - std::ostringstream stream; - stream << "display-" << connector_->id(); - std::string string = stream.str(); - size_t length = string.length(); - if (!name) { - *size = length; - return HWC2::Error::None; - } - - *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size); - strncpy(name, string.c_str(), *size); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayRequests(int32_t *display_requests, - uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *layer_requests) { - supported(__func__); - // TODO(nobody): I think virtual display should request - // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here - unsupported(__func__, display_requests, num_elements, layers, layer_requests); - *num_elements = 0; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayType(int32_t *type) { - supported(__func__); - *type = static_cast<int32_t>(type_); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDozeSupport(int32_t *support) { - supported(__func__); - *support = 0; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetHdrCapabilities( - uint32_t *num_types, int32_t * /*types*/, float * /*max_luminance*/, - float * /*max_average_luminance*/, float * /*min_luminance*/) { - supported(__func__); - *num_types = 0; - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767 - */ -HWC2::Error DrmHwcTwo::HwcDisplay::GetReleaseFences(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *fences) { - supported(__func__); - uint32_t num_layers = 0; - - for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { - ++num_layers; - if (layers == nullptr || fences == nullptr) - continue; - - if (num_layers > *num_elements) { - ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements); - return HWC2::Error::None; - } - - layers[num_layers - 1] = l.first; - fences[num_layers - 1] = l.second.release_fence_.Release(); - } - *num_elements = num_layers; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { - // order the layers by z-order - bool use_client_layer = false; - uint32_t client_z_order = UINT32_MAX; - std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map; - for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { - switch (l.second.validated_type()) { - case HWC2::Composition::Device: - z_map.emplace(std::make_pair(l.second.z_order(), &l.second)); - break; - case HWC2::Composition::Client: - // Place it at the z_order of the lowest client layer - use_client_layer = true; - client_z_order = std::min(client_z_order, l.second.z_order()); - break; - default: - continue; - } - } - if (use_client_layer) - z_map.emplace(std::make_pair(client_z_order, &client_layer_)); - - if (z_map.empty()) - return HWC2::Error::BadLayer; - - std::vector<DrmHwcLayer> composition_layers; - - // now that they're ordered by z, add them to the composition - for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { - DrmHwcLayer layer; - l.second->PopulateDrmLayer(&layer); - int ret = layer.ImportBuffer(drm_); - if (ret) { - ALOGE("Failed to import layer, ret=%d", ret); - return HWC2::Error::NoResources; - } - composition_layers.emplace_back(std::move(layer)); - } - - auto composition = std::make_shared<DrmDisplayComposition>(crtc_, - planner_.get()); - - // TODO(nobody): Don't always assume geometry changed - int ret = composition->SetLayers(composition_layers.data(), - composition_layers.size()); - if (ret) { - ALOGE("Failed to set layers in the composition ret=%d", ret); - return HWC2::Error::BadLayer; - } - - std::vector<DrmPlane *> primary_planes(primary_planes_); - std::vector<DrmPlane *> overlay_planes(overlay_planes_); - ret = composition->Plan(&primary_planes, &overlay_planes); - if (ret) { - ALOGV("Failed to plan the composition ret=%d", ret); - return HWC2::Error::BadConfig; - } - - // Disable the planes we're not using - for (auto i = primary_planes.begin(); i != primary_planes.end();) { - composition->AddPlaneDisable(*i); - i = primary_planes.erase(i); - } - for (auto i = overlay_planes.begin(); i != overlay_planes.end();) { - composition->AddPlaneDisable(*i); - i = overlay_planes.erase(i); - } - - a_args.composition = composition; - ret = compositor_.ExecuteAtomicCommit(a_args); - - if (ret) { - if (!a_args.test_only) - ALOGE("Failed to apply the frame composition ret=%d", ret); - return HWC2::Error::BadParameter; - } - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805 - */ -HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *present_fence) { - supported(__func__); - HWC2::Error ret; - - ++total_stats_.total_frames_; - - AtomicCommitArgs a_args{}; - ret = CreateComposition(a_args); - - if (ret != HWC2::Error::None) - ++total_stats_.failed_kms_present_; - - if (ret == HWC2::Error::BadLayer) { - // Can we really have no client or device layers? - *present_fence = -1; - return HWC2::Error::None; - } - if (ret != HWC2::Error::None) - return ret; - - *present_fence = a_args.out_fence.Release(); - - ++frame_no_; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) { - supported(__func__); - - int conf = static_cast<int>(config); - - if (hwc_configs_.count(conf) == 0) { - ALOGE("Could not find active mode for %d", conf); - return HWC2::Error::BadConfig; - } - - auto &mode = hwc_configs_[conf].mode; - - AtomicCommitArgs a_args = { - .display_mode = mode, - .clear_active_composition = true, - }; - - int err = compositor_.ExecuteAtomicCommit(a_args); - if (err != 0) { - ALOGE("Failed to queue mode changing commit %d", err); - return HWC2::Error::BadConfig; - } - - active_config_id_ = conf; - - // Setup the client layer's dimensions - hwc_rect_t display_frame = {.left = 0, - .top = 0, - .right = static_cast<int>(mode.h_display()), - .bottom = static_cast<int>(mode.v_display())}; - client_layer_.SetLayerDisplayFrame(display_frame); - - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861 - */ -HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target, - int32_t acquire_fence, - int32_t dataspace, - hwc_region_t /*damage*/) { - supported(__func__); - - client_layer_.set_buffer(target); - client_layer_.acquire_fence_ = UniqueFd(acquire_fence); - client_layer_.SetLayerDataspace(dataspace); - - /* TODO: Do not update source_crop every call. - * It makes sense to do it once after every hotplug event. */ - hwc_drm_bo bo{}; - BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo); - - hwc_frect_t source_crop = {.left = 0.0F, - .top = 0.0F, - .right = static_cast<float>(bo.width), - .bottom = static_cast<float>(bo.height)}; - client_layer_.SetLayerSourceCrop(source_crop); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorMode(int32_t mode) { - supported(__func__); - - if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) - return HWC2::Error::BadParameter; - - if (mode != HAL_COLOR_MODE_NATIVE) - return HWC2::Error::Unsupported; - - color_mode_ = mode; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorTransform(const float *matrix, - int32_t hint) { - supported(__func__); - if (hint < HAL_COLOR_TRANSFORM_IDENTITY || - hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) - return HWC2::Error::BadParameter; - - if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) - 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()); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetOutputBuffer(buffer_handle_t buffer, - int32_t release_fence) { - supported(__func__); - // TODO(nobody): Need virtual display support - return unsupported(__func__, buffer, release_fence); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetPowerMode(int32_t mode_in) { - supported(__func__); - auto mode = static_cast<HWC2::PowerMode>(mode_in); - AtomicCommitArgs a_args{}; - - switch (mode) { - case HWC2::PowerMode::Off: - a_args.active = false; - break; - case HWC2::PowerMode::On: - a_args.active = true; - break; - case HWC2::PowerMode::Doze: - case HWC2::PowerMode::DozeSuspend: - return HWC2::Error::Unsupported; - default: - ALOGI("Power mode %d is unsupported\n", mode); - return HWC2::Error::BadParameter; - }; - - int err = compositor_.ExecuteAtomicCommit(a_args); - if (err) { - ALOGE("Failed to apply the dpms composition err=%d", err); - return HWC2::Error::BadParameter; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { - supported(__func__); - vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, - uint32_t *num_requests) { - supported(__func__); - - return backend_->ValidateDisplay(this, num_types, num_requests); -} - -std::vector<DrmHwcTwo::HwcLayer *> -DrmHwcTwo::HwcDisplay::GetOrderLayersByZPos() { - std::vector<DrmHwcTwo::HwcLayer *> ordered_layers; - ordered_layers.reserve(layers_.size()); - - for (auto &[handle, layer] : layers_) { - ordered_layers.emplace_back(&layer); - } - - std::sort(std::begin(ordered_layers), std::end(ordered_layers), - [](const DrmHwcTwo::HwcLayer *lhs, const DrmHwcTwo::HwcLayer *rhs) { - return lhs->z_order() < rhs->z_order(); - }); - - return ordered_layers; -} - -#if PLATFORM_SDK_VERSION > 29 -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayConnectionType(uint32_t *outType) { - if (connector_->internal()) - *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal); - else if (connector_->external()) - *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External); - else - return HWC2::Error::BadConfig; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayVsyncPeriod( - hwc2_vsync_period_t *outVsyncPeriod /* ns */) { - supported(__func__); - return GetDisplayAttribute(active_config_id_, HWC2_ATTRIBUTE_VSYNC_PERIOD, - (int32_t *)(outVsyncPeriod)); -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfigWithConstraints( - hwc2_config_t /*config*/, - hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, - hwc_vsync_period_change_timeline_t *outTimeline) { - supported(__func__); - - if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) { - return HWC2::Error::BadParameter; - } - - return HWC2::Error::BadConfig; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) { - return HWC2::Error::Unsupported; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetSupportedContentTypes( - uint32_t *outNumSupportedContentTypes, - const uint32_t *outSupportedContentTypes) { - if (outSupportedContentTypes == nullptr) - *outNumSupportedContentTypes = 0; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetContentType(int32_t contentType) { - supported(__func__); - - if (contentType != HWC2_CONTENT_TYPE_NONE) - return HWC2::Error::Unsupported; - - /* TODO: Map to the DRM Connector property: - * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809 - */ - - return HWC2::Error::None; -} -#endif - -#if PLATFORM_SDK_VERSION > 28 -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayIdentificationData( - uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) { - supported(__func__); - - auto blob = connector_->GetEdidBlob(); - - if (!blob) { - ALOGE("Failed to get edid property value."); - return HWC2::Error::Unsupported; - } - - if (outData) { - *outDataSize = std::min(*outDataSize, blob->length); - memcpy(outData, blob->data, *outDataSize); - } else { - *outDataSize = blob->length; - } - *outPort = connector_->id(); - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayCapabilities( - uint32_t *outNumCapabilities, uint32_t *outCapabilities) { - unsupported(__func__, outCapabilities); - - if (outNumCapabilities == nullptr) { - return HWC2::Error::BadParameter; - } - - *outNumCapabilities = 0; - - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::GetDisplayBrightnessSupport( - bool *supported) { - *supported = false; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetDisplayBrightness( - float /* brightness */) { - return HWC2::Error::Unsupported; -} - -#endif /* PLATFORM_SDK_VERSION > 28 */ - -#if PLATFORM_SDK_VERSION > 27 - -HWC2::Error DrmHwcTwo::HwcDisplay::GetRenderIntents( - int32_t mode, uint32_t *outNumIntents, - int32_t * /*android_render_intent_v1_1_t*/ outIntents) { - if (mode != HAL_COLOR_MODE_NATIVE) { - return HWC2::Error::BadParameter; - } - - if (outIntents == nullptr) { - *outNumIntents = 1; - return HWC2::Error::None; - } - *outNumIntents = 1; - outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcDisplay::SetColorModeWithIntent(int32_t mode, - int32_t intent) { - if (intent < HAL_RENDER_INTENT_COLORIMETRIC || - intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE) - return HWC2::Error::BadParameter; - - if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) - return HWC2::Error::BadParameter; - - if (mode != HAL_COLOR_MODE_NATIVE) - return HWC2::Error::Unsupported; - - if (intent != HAL_RENDER_INTENT_COLORIMETRIC) - return HWC2::Error::Unsupported; - - color_mode_ = mode; - return HWC2::Error::None; -} - -#endif /* PLATFORM_SDK_VERSION > 27 */ - -HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t /*x*/, - int32_t /*y*/) { - supported(__func__); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) { - supported(__func__); - switch (static_cast<HWC2::BlendMode>(mode)) { - case HWC2::BlendMode::None: - blending_ = DrmHwcBlending::kNone; - break; - case HWC2::BlendMode::Premultiplied: - blending_ = DrmHwcBlending::kPreMult; - break; - case HWC2::BlendMode::Coverage: - blending_ = DrmHwcBlending::kCoverage; - break; - default: - ALOGE("Unknown blending mode b=%d", blending_); - blending_ = DrmHwcBlending::kNone; - break; - } - return HWC2::Error::None; -} - -/* Find API details at: - * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=2314 - */ -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBuffer(buffer_handle_t buffer, - int32_t acquire_fence) { - supported(__func__); - - set_buffer(buffer); - acquire_fence_ = UniqueFd(acquire_fence); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t /*color*/) { - // TODO(nobody): Put to client composition here? - supported(__func__); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerCompositionType(int32_t type) { - sf_type_ = static_cast<HWC2::Composition>(type); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) { - supported(__func__); - switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { - case HAL_DATASPACE_STANDARD_BT709: - color_space_ = DrmHwcColorSpace::kItuRec709; - break; - case HAL_DATASPACE_STANDARD_BT601_625: - case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED: - case HAL_DATASPACE_STANDARD_BT601_525: - case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED: - color_space_ = DrmHwcColorSpace::kItuRec601; - break; - case HAL_DATASPACE_STANDARD_BT2020: - case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE: - color_space_ = DrmHwcColorSpace::kItuRec2020; - break; - default: - color_space_ = DrmHwcColorSpace::kUndefined; - } - - switch (dataspace & HAL_DATASPACE_RANGE_MASK) { - case HAL_DATASPACE_RANGE_FULL: - sample_range_ = DrmHwcSampleRange::kFullRange; - break; - case HAL_DATASPACE_RANGE_LIMITED: - sample_range_ = DrmHwcSampleRange::kLimitedRange; - break; - default: - sample_range_ = DrmHwcSampleRange::kUndefined; - } - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) { - supported(__func__); - display_frame_ = frame; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerPlaneAlpha(float alpha) { - supported(__func__); - alpha_ = alpha; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSidebandStream( - const native_handle_t *stream) { - supported(__func__); - // TODO(nobody): We don't support sideband - return unsupported(__func__, stream); -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) { - supported(__func__); - source_crop_ = crop; - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerSurfaceDamage(hwc_region_t damage) { - supported(__func__); - // TODO(nobody): We don't use surface damage, marking as unsupported - unsupported(__func__, damage); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) { - supported(__func__); - - uint32_t l_transform = 0; - - // 270* and 180* cannot be combined with flips. More specifically, they - // already contain both horizontal and vertical flips, so those fields are - // redundant in this case. 90* rotation can be combined with either horizontal - // flip or vertical flip, so treat it differently - if (transform == HWC_TRANSFORM_ROT_270) { - l_transform = DrmHwcTransform::kRotate270; - } else if (transform == HWC_TRANSFORM_ROT_180) { - l_transform = DrmHwcTransform::kRotate180; - } else { - if (transform & HWC_TRANSFORM_FLIP_H) - l_transform |= DrmHwcTransform::kFlipH; - if (transform & HWC_TRANSFORM_FLIP_V) - l_transform |= DrmHwcTransform::kFlipV; - if (transform & HWC_TRANSFORM_ROT_90) - l_transform |= DrmHwcTransform::kRotate90; - } - - transform_ = static_cast<DrmHwcTransform>(l_transform); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerVisibleRegion(hwc_region_t visible) { - supported(__func__); - // TODO(nobody): We don't use this information, marking as unsupported - unsupported(__func__, visible); - return HWC2::Error::None; -} - -HWC2::Error DrmHwcTwo::HwcLayer::SetLayerZOrder(uint32_t order) { - supported(__func__); - z_order_ = order; - return HWC2::Error::None; -} - -void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) { - supported(__func__); - layer->sf_handle = buffer_; - // TODO(rsglobal): Avoid extra fd duplication - layer->acquire_fence = UniqueFd(fcntl(acquire_fence_.Get(), F_DUPFD_CLOEXEC)); - layer->display_frame = display_frame_; - layer->alpha = lround(65535.0F * alpha_); - layer->blending = blending_; - layer->source_crop = source_crop_; - layer->transform = transform_; - layer->color_space = color_space_; - layer->sample_range = sample_range_; -} - -void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) { - const std::lock_guard<std::mutex> lock(callback_lock_); - - if (hotplug_callback_.first != nullptr && - hotplug_callback_.second != nullptr) { - hotplug_callback_.first(hotplug_callback_.second, displayid, - state == DRM_MODE_CONNECTED - ? HWC2_CONNECTION_CONNECTED - : HWC2_CONNECTION_DISCONNECTED); - } -} - -void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) { - for (const auto &conn : drmDevice->connectors()) { - if (conn->state() != DRM_MODE_CONNECTED) - continue; - HandleDisplayHotplug(conn->display(), conn->state()); - } -} - -void DrmHwcTwo::HandleHotplugUEvent() { - for (const auto &drm : resource_manager_.getDrmDevices()) { - for (const auto &conn : drm->connectors()) { - drmModeConnection old_state = conn->state(); - drmModeConnection cur_state = conn->UpdateModes() - ? DRM_MODE_UNKNOWNCONNECTION - : conn->state(); - - if (cur_state == old_state) - continue; - - ALOGI("%s event for connector %u on display %d", - cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(), - conn->display()); - - int display_id = conn->display(); - if (cur_state == DRM_MODE_CONNECTED) { - auto &display = displays_.at(display_id); - display.ChosePreferredConfig(); - } else { - auto &display = displays_.at(display_id); - display.ClearDisplay(); - } - - HandleDisplayHotplug(display_id, cur_state); - } - } -} - -// static -int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) { - unsupported(__func__); - return 0; -} - -// static -void DrmHwcTwo::HookDevGetCapabilities(hwc2_device_t * /*dev*/, - uint32_t *out_count, - int32_t * /*out_capabilities*/) { - supported(__func__); - *out_count = 0; -} - -// static -hwc2_function_pointer_t DrmHwcTwo::HookDevGetFunction( - struct hwc2_device * /*dev*/, int32_t descriptor) { - supported(__func__); - auto func = static_cast<HWC2::FunctionDescriptor>(descriptor); - switch (func) { - // Device functions - case HWC2::FunctionDescriptor::CreateVirtualDisplay: - return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>( - DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay), - &DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t, - int32_t *, hwc2_display_t *>); - case HWC2::FunctionDescriptor::DestroyVirtualDisplay: - return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>( - DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay), - &DrmHwcTwo::DestroyVirtualDisplay, hwc2_display_t>); - case HWC2::FunctionDescriptor::Dump: - return ToHook<HWC2_PFN_DUMP>( - DeviceHook<void, decltype(&DrmHwcTwo::Dump), &DrmHwcTwo::Dump, - uint32_t *, char *>); - case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: - return ToHook<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>( - DeviceHook<uint32_t, decltype(&DrmHwcTwo::GetMaxVirtualDisplayCount), - &DrmHwcTwo::GetMaxVirtualDisplayCount>); - case HWC2::FunctionDescriptor::RegisterCallback: - return ToHook<HWC2_PFN_REGISTER_CALLBACK>( - DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback), - &DrmHwcTwo::RegisterCallback, int32_t, - hwc2_callback_data_t, hwc2_function_pointer_t>); - - // Display functions - case HWC2::FunctionDescriptor::AcceptDisplayChanges: - return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>( - DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges), - &HwcDisplay::AcceptDisplayChanges>); - case HWC2::FunctionDescriptor::CreateLayer: - return ToHook<HWC2_PFN_CREATE_LAYER>( - DisplayHook<decltype(&HwcDisplay::CreateLayer), - &HwcDisplay::CreateLayer, hwc2_layer_t *>); - case HWC2::FunctionDescriptor::DestroyLayer: - return ToHook<HWC2_PFN_DESTROY_LAYER>( - DisplayHook<decltype(&HwcDisplay::DestroyLayer), - &HwcDisplay::DestroyLayer, hwc2_layer_t>); - case HWC2::FunctionDescriptor::GetActiveConfig: - return ToHook<HWC2_PFN_GET_ACTIVE_CONFIG>( - DisplayHook<decltype(&HwcDisplay::GetActiveConfig), - &HwcDisplay::GetActiveConfig, hwc2_config_t *>); - case HWC2::FunctionDescriptor::GetChangedCompositionTypes: - return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>( - DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes), - &HwcDisplay::GetChangedCompositionTypes, uint32_t *, - hwc2_layer_t *, int32_t *>); - case HWC2::FunctionDescriptor::GetClientTargetSupport: - return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>( - DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport), - &HwcDisplay::GetClientTargetSupport, uint32_t, uint32_t, - int32_t, int32_t>); - case HWC2::FunctionDescriptor::GetColorModes: - return ToHook<HWC2_PFN_GET_COLOR_MODES>( - DisplayHook<decltype(&HwcDisplay::GetColorModes), - &HwcDisplay::GetColorModes, uint32_t *, int32_t *>); - case HWC2::FunctionDescriptor::GetDisplayAttribute: - return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>( - DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute), - &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t, - int32_t *>); - case HWC2::FunctionDescriptor::GetDisplayConfigs: - return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>( - DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs), - &HwcDisplay::GetDisplayConfigs, uint32_t *, - hwc2_config_t *>); - case HWC2::FunctionDescriptor::GetDisplayName: - return ToHook<HWC2_PFN_GET_DISPLAY_NAME>( - DisplayHook<decltype(&HwcDisplay::GetDisplayName), - &HwcDisplay::GetDisplayName, uint32_t *, char *>); - case HWC2::FunctionDescriptor::GetDisplayRequests: - return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>( - DisplayHook<decltype(&HwcDisplay::GetDisplayRequests), - &HwcDisplay::GetDisplayRequests, int32_t *, uint32_t *, - hwc2_layer_t *, int32_t *>); - case HWC2::FunctionDescriptor::GetDisplayType: - return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>( - DisplayHook<decltype(&HwcDisplay::GetDisplayType), - &HwcDisplay::GetDisplayType, int32_t *>); - case HWC2::FunctionDescriptor::GetDozeSupport: - return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>( - DisplayHook<decltype(&HwcDisplay::GetDozeSupport), - &HwcDisplay::GetDozeSupport, int32_t *>); - case HWC2::FunctionDescriptor::GetHdrCapabilities: - return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>( - DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities), - &HwcDisplay::GetHdrCapabilities, uint32_t *, int32_t *, - float *, float *, float *>); - case HWC2::FunctionDescriptor::GetReleaseFences: - return ToHook<HWC2_PFN_GET_RELEASE_FENCES>( - DisplayHook<decltype(&HwcDisplay::GetReleaseFences), - &HwcDisplay::GetReleaseFences, uint32_t *, hwc2_layer_t *, - int32_t *>); - case HWC2::FunctionDescriptor::PresentDisplay: - return ToHook<HWC2_PFN_PRESENT_DISPLAY>( - DisplayHook<decltype(&HwcDisplay::PresentDisplay), - &HwcDisplay::PresentDisplay, int32_t *>); - case HWC2::FunctionDescriptor::SetActiveConfig: - return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>( - DisplayHook<decltype(&HwcDisplay::SetActiveConfig), - &HwcDisplay::SetActiveConfig, hwc2_config_t>); - case HWC2::FunctionDescriptor::SetClientTarget: - return ToHook<HWC2_PFN_SET_CLIENT_TARGET>( - DisplayHook<decltype(&HwcDisplay::SetClientTarget), - &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t, - int32_t, hwc_region_t>); - case HWC2::FunctionDescriptor::SetColorMode: - return ToHook<HWC2_PFN_SET_COLOR_MODE>( - DisplayHook<decltype(&HwcDisplay::SetColorMode), - &HwcDisplay::SetColorMode, int32_t>); - case HWC2::FunctionDescriptor::SetColorTransform: - return ToHook<HWC2_PFN_SET_COLOR_TRANSFORM>( - DisplayHook<decltype(&HwcDisplay::SetColorTransform), - &HwcDisplay::SetColorTransform, const float *, int32_t>); - case HWC2::FunctionDescriptor::SetOutputBuffer: - return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>( - DisplayHook<decltype(&HwcDisplay::SetOutputBuffer), - &HwcDisplay::SetOutputBuffer, buffer_handle_t, int32_t>); - case HWC2::FunctionDescriptor::SetPowerMode: - return ToHook<HWC2_PFN_SET_POWER_MODE>( - DisplayHook<decltype(&HwcDisplay::SetPowerMode), - &HwcDisplay::SetPowerMode, int32_t>); - case HWC2::FunctionDescriptor::SetVsyncEnabled: - return ToHook<HWC2_PFN_SET_VSYNC_ENABLED>( - DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled), - &HwcDisplay::SetVsyncEnabled, int32_t>); - case HWC2::FunctionDescriptor::ValidateDisplay: - return ToHook<HWC2_PFN_VALIDATE_DISPLAY>( - DisplayHook<decltype(&HwcDisplay::ValidateDisplay), - &HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>); -#if PLATFORM_SDK_VERSION > 27 - case HWC2::FunctionDescriptor::GetRenderIntents: - return ToHook<HWC2_PFN_GET_RENDER_INTENTS>( - DisplayHook<decltype(&HwcDisplay::GetRenderIntents), - &HwcDisplay::GetRenderIntents, int32_t, uint32_t *, - int32_t *>); - case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: - return ToHook<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>( - DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent), - &HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>); -#endif -#if PLATFORM_SDK_VERSION > 28 - case HWC2::FunctionDescriptor::GetDisplayIdentificationData: - return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>( - DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData), - &HwcDisplay::GetDisplayIdentificationData, uint8_t *, - uint32_t *, uint8_t *>); - case HWC2::FunctionDescriptor::GetDisplayCapabilities: - return ToHook<HWC2_PFN_GET_DISPLAY_CAPABILITIES>( - DisplayHook<decltype(&HwcDisplay::GetDisplayCapabilities), - &HwcDisplay::GetDisplayCapabilities, uint32_t *, - uint32_t *>); - case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: - return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>( - DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport), - &HwcDisplay::GetDisplayBrightnessSupport, bool *>); - case HWC2::FunctionDescriptor::SetDisplayBrightness: - return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>( - DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness), - &HwcDisplay::SetDisplayBrightness, float>); -#endif /* PLATFORM_SDK_VERSION > 28 */ -#if PLATFORM_SDK_VERSION > 29 - case HWC2::FunctionDescriptor::GetDisplayConnectionType: - return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>( - DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType), - &HwcDisplay::GetDisplayConnectionType, uint32_t *>); - case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod: - return ToHook<HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD>( - DisplayHook<decltype(&HwcDisplay::GetDisplayVsyncPeriod), - &HwcDisplay::GetDisplayVsyncPeriod, - hwc2_vsync_period_t *>); - case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints: - return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS>( - DisplayHook<decltype(&HwcDisplay::SetActiveConfigWithConstraints), - &HwcDisplay::SetActiveConfigWithConstraints, - hwc2_config_t, hwc_vsync_period_change_constraints_t *, - hwc_vsync_period_change_timeline_t *>); - case HWC2::FunctionDescriptor::SetAutoLowLatencyMode: - return ToHook<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>( - DisplayHook<decltype(&HwcDisplay::SetAutoLowLatencyMode), - &HwcDisplay::SetAutoLowLatencyMode, bool>); - case HWC2::FunctionDescriptor::GetSupportedContentTypes: - return ToHook<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>( - DisplayHook<decltype(&HwcDisplay::GetSupportedContentTypes), - &HwcDisplay::GetSupportedContentTypes, uint32_t *, - uint32_t *>); - case HWC2::FunctionDescriptor::SetContentType: - return ToHook<HWC2_PFN_SET_CONTENT_TYPE>( - DisplayHook<decltype(&HwcDisplay::SetContentType), - &HwcDisplay::SetContentType, int32_t>); -#endif - // Layer functions - case HWC2::FunctionDescriptor::SetCursorPosition: - return ToHook<HWC2_PFN_SET_CURSOR_POSITION>( - LayerHook<decltype(&HwcLayer::SetCursorPosition), - &HwcLayer::SetCursorPosition, int32_t, int32_t>); - case HWC2::FunctionDescriptor::SetLayerBlendMode: - return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>( - LayerHook<decltype(&HwcLayer::SetLayerBlendMode), - &HwcLayer::SetLayerBlendMode, int32_t>); - case HWC2::FunctionDescriptor::SetLayerBuffer: - return ToHook<HWC2_PFN_SET_LAYER_BUFFER>( - LayerHook<decltype(&HwcLayer::SetLayerBuffer), - &HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>); - case HWC2::FunctionDescriptor::SetLayerColor: - return ToHook<HWC2_PFN_SET_LAYER_COLOR>( - LayerHook<decltype(&HwcLayer::SetLayerColor), - &HwcLayer::SetLayerColor, hwc_color_t>); - case HWC2::FunctionDescriptor::SetLayerCompositionType: - return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>( - LayerHook<decltype(&HwcLayer::SetLayerCompositionType), - &HwcLayer::SetLayerCompositionType, int32_t>); - case HWC2::FunctionDescriptor::SetLayerDataspace: - return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>( - LayerHook<decltype(&HwcLayer::SetLayerDataspace), - &HwcLayer::SetLayerDataspace, int32_t>); - case HWC2::FunctionDescriptor::SetLayerDisplayFrame: - return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>( - LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame), - &HwcLayer::SetLayerDisplayFrame, hwc_rect_t>); - case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: - return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>( - LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha), - &HwcLayer::SetLayerPlaneAlpha, float>); - case HWC2::FunctionDescriptor::SetLayerSidebandStream: - return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>( - LayerHook<decltype(&HwcLayer::SetLayerSidebandStream), - &HwcLayer::SetLayerSidebandStream, - const native_handle_t *>); - case HWC2::FunctionDescriptor::SetLayerSourceCrop: - return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>( - LayerHook<decltype(&HwcLayer::SetLayerSourceCrop), - &HwcLayer::SetLayerSourceCrop, hwc_frect_t>); - case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: - return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>( - LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage), - &HwcLayer::SetLayerSurfaceDamage, hwc_region_t>); - case HWC2::FunctionDescriptor::SetLayerTransform: - return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>( - LayerHook<decltype(&HwcLayer::SetLayerTransform), - &HwcLayer::SetLayerTransform, int32_t>); - case HWC2::FunctionDescriptor::SetLayerVisibleRegion: - return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>( - LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion), - &HwcLayer::SetLayerVisibleRegion, hwc_region_t>); - case HWC2::FunctionDescriptor::SetLayerZOrder: - return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>( - LayerHook<decltype(&HwcLayer::SetLayerZOrder), - &HwcLayer::SetLayerZOrder, uint32_t>); - case HWC2::FunctionDescriptor::Invalid: - default: - return nullptr; - } -} - -// static -int DrmHwcTwo::HookDevOpen(const struct hw_module_t *module, const char *name, - struct hw_device_t **dev) { - supported(__func__); - if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) { - ALOGE("Invalid module name- %s", name); - return -EINVAL; - } - - std::unique_ptr<DrmHwcTwo> ctx(new DrmHwcTwo()); - if (!ctx) { - ALOGE("Failed to allocate DrmHwcTwo"); - return -ENOMEM; - } - - HWC2::Error err = ctx->Init(); - if (err != HWC2::Error::None) { - ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err); - return -EINVAL; - } - - ctx->common.module = (hw_module_t *)module; - *dev = &ctx->common; - ctx.release(); // NOLINT(bugprone-unused-return-value) - return 0; -} -} // namespace android - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -static struct hw_module_methods_t hwc2_module_methods = { - .open = android::DrmHwcTwo::HookDevOpen, -}; - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -hw_module_t HAL_MODULE_INFO_SYM = { - .tag = HARDWARE_MODULE_TAG, - .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0), - .id = HWC_HARDWARE_MODULE_ID, - .name = "DrmHwcTwo module", - .author = "The Android Open Source Project", - .methods = &hwc2_module_methods, - .dso = nullptr, - .reserved = {0}, -}; diff --git a/DrmHwcTwo.h b/DrmHwcTwo.h deleted file mode 100644 index 7fd4fbd..0000000 --- a/DrmHwcTwo.h +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Copyright (C) 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_DRM_HWC_TWO_H_ -#define ANDROID_DRM_HWC_TWO_H_ - -#include <hardware/hwcomposer2.h> -#include <math.h> - -#include <array> -#include <map> - -#include "compositor/DrmDisplayCompositor.h" -#include "compositor/Planner.h" -#include "drm/ResourceManager.h" -#include "drm/VSyncWorker.h" -#include "drmhwcomposer.h" - -namespace android { - -class Backend; - -class DrmHwcTwo : public hwc2_device_t { - public: - static int HookDevOpen(const struct hw_module_t *module, const char *name, - struct hw_device_t **dev); - - DrmHwcTwo(); - - HWC2::Error Init(); - - 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 - std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{}; -#endif - std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{}; - - std::mutex callback_lock_; - - class HwcLayer { - public: - HWC2::Composition sf_type() const { - return sf_type_; - } - HWC2::Composition validated_type() const { - return validated_type_; - } - void accept_type_change() { - sf_type_ = validated_type_; - } - void set_validated_type(HWC2::Composition type) { - validated_type_ = type; - } - bool type_changed() const { - return sf_type_ != validated_type_; - } - - uint32_t z_order() const { - return z_order_; - } - - buffer_handle_t buffer() { - return buffer_; - } - void set_buffer(buffer_handle_t buffer) { - buffer_ = buffer; - } - - hwc_rect_t display_frame() { - return display_frame_; - } - - void PopulateDrmLayer(DrmHwcLayer *layer); - - bool RequireScalingOrPhasing() { - float src_width = source_crop_.right - source_crop_.left; - float src_height = source_crop_.bottom - source_crop_.top; - - float dest_width = display_frame_.right - display_frame_.left; - float dest_height = display_frame_.bottom - display_frame_.top; - - bool scaling = src_width != dest_width || src_height != dest_height; - bool phasing = (source_crop_.left - floor(source_crop_.left) != 0) || - (source_crop_.top - floor(source_crop_.top) != 0); - return scaling || phasing; - } - - // Layer hooks - HWC2::Error SetCursorPosition(int32_t /*x*/, int32_t /*y*/); - HWC2::Error SetLayerBlendMode(int32_t mode); - HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence); - HWC2::Error SetLayerColor(hwc_color_t /*color*/); - HWC2::Error SetLayerCompositionType(int32_t type); - HWC2::Error SetLayerDataspace(int32_t dataspace); - HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame); - HWC2::Error SetLayerPlaneAlpha(float alpha); - HWC2::Error SetLayerSidebandStream(const native_handle_t *stream); - HWC2::Error SetLayerSourceCrop(hwc_frect_t crop); - HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage); - HWC2::Error SetLayerTransform(int32_t transform); - HWC2::Error SetLayerVisibleRegion(hwc_region_t visible); - HWC2::Error SetLayerZOrder(uint32_t order); - - UniqueFd acquire_fence_; - - /* - * Release fence is not used. - * There is no release fence support available in the DRM/KMS. In case no - * release fence provided application will use this buffer for writing when - * the next frame present fence is signaled. - */ - UniqueFd release_fence_; - - private: - // sf_type_ stores the initial type given to us by surfaceflinger, - // validated_type_ stores the type after running ValidateDisplay - HWC2::Composition sf_type_ = HWC2::Composition::Invalid; - HWC2::Composition validated_type_ = HWC2::Composition::Invalid; - - buffer_handle_t buffer_ = NULL; - hwc_rect_t display_frame_; - float alpha_ = 1.0f; - hwc_frect_t source_crop_; - DrmHwcTransform transform_ = DrmHwcTransform::kIdentity; - uint32_t z_order_ = 0; - DrmHwcBlending blending_ = DrmHwcBlending::kNone; - DrmHwcColorSpace color_space_ = DrmHwcColorSpace::kUndefined; - DrmHwcSampleRange sample_range_ = DrmHwcSampleRange::kUndefined; - }; - - class HwcDisplay { - public: - HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm, - hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2); - HwcDisplay(const HwcDisplay &) = delete; - HWC2::Error Init(std::vector<DrmPlane *> *planes); - - HWC2::Error CreateComposition(AtomicCommitArgs &a_args); - std::vector<DrmHwcTwo::HwcLayer *> GetOrderLayersByZPos(); - - void ClearDisplay(); - - std::string Dump(); - - // HWC Hooks - HWC2::Error AcceptDisplayChanges(); - HWC2::Error CreateLayer(hwc2_layer_t *layer); - HWC2::Error DestroyLayer(hwc2_layer_t layer); - HWC2::Error GetActiveConfig(hwc2_config_t *config) const; - HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, - hwc2_layer_t *layers, - int32_t *types); - HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, - int32_t format, int32_t dataspace); - HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); - HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, - int32_t *value); - HWC2::Error GetDisplayConfigs(uint32_t *num_configs, - hwc2_config_t *configs); - HWC2::Error GetDisplayName(uint32_t *size, char *name); - HWC2::Error GetDisplayRequests(int32_t *display_requests, - uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *layer_requests); - HWC2::Error GetDisplayType(int32_t *type); -#if PLATFORM_SDK_VERSION > 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 - HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, - uint32_t *outDataSize, - uint8_t *outData); - HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, - uint32_t *outCapabilities); - HWC2::Error GetDisplayBrightnessSupport(bool *supported); - HWC2::Error SetDisplayBrightness(float); -#endif -#if PLATFORM_SDK_VERSION > 29 - HWC2::Error GetDisplayConnectionType(uint32_t *outType); - HWC2::Error GetDisplayVsyncPeriod(hwc2_vsync_period_t *outVsyncPeriod); - - HWC2::Error SetActiveConfigWithConstraints( - hwc2_config_t config, - hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, - hwc_vsync_period_change_timeline_t *outTimeline); - HWC2::Error SetAutoLowLatencyMode(bool on); - HWC2::Error GetSupportedContentTypes( - uint32_t *outNumSupportedContentTypes, - const uint32_t *outSupportedContentTypes); - - HWC2::Error SetContentType(int32_t contentType); -#endif - - HWC2::Error GetDozeSupport(int32_t *support); - HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, - float *max_luminance, - float *max_average_luminance, - float *min_luminance); - HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, - int32_t *fences); - HWC2::Error PresentDisplay(int32_t *present_fence); - HWC2::Error SetActiveConfig(hwc2_config_t config); - HWC2::Error ChosePreferredConfig(); - HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, - int32_t dataspace, hwc_region_t damage); - HWC2::Error SetColorMode(int32_t mode); - HWC2::Error SetColorTransform(const float *matrix, int32_t hint); - HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); - HWC2::Error SetPowerMode(int32_t mode); - HWC2::Error SetVsyncEnabled(int32_t enabled); - HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); - HwcLayer *get_layer(hwc2_layer_t layer) { - auto it = layers_.find(layer); - if (it == layers_.end()) - return nullptr; - return &it->second; - } - - /* Statistics */ - struct Stats { - Stats minus(Stats b) { - return {total_frames_ - b.total_frames_, - total_pixops_ - b.total_pixops_, - gpu_pixops_ - b.gpu_pixops_, - failed_kms_validate_ - b.failed_kms_validate_, - failed_kms_present_ - b.failed_kms_present_, - frames_flattened_ - b.frames_flattened_}; - } - - uint32_t total_frames_ = 0; - uint64_t total_pixops_ = 0; - uint64_t gpu_pixops_ = 0; - uint32_t failed_kms_validate_ = 0; - uint32_t failed_kms_present_ = 0; - uint32_t frames_flattened_ = 0; - }; - - struct HwcDisplayConfig { - int id{}; - int group_id{}; - DrmMode mode; - bool disabled{}; - - bool IsInterlaced() { - return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0; - } - }; - - std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs_; - - int active_config_id_ = 0; - int preferred_config_id_ = 0; - - const Backend *backend() const { - return backend_.get(); - } - void set_backend(std::unique_ptr<Backend> backend) { - backend_ = std::move(backend); - } - - const std::vector<DrmPlane *> &primary_planes() const { - return primary_planes_; - } - - const std::vector<DrmPlane *> &overlay_planes() const { - return overlay_planes_; - } - - std::map<hwc2_layer_t, HwcLayer> &layers() { - return layers_; - } - - const DrmDisplayCompositor &compositor() const { - return compositor_; - } - - const DrmDevice *drm() const { - return drm_; - } - - const DrmConnector *connector() const { - return connector_; - } - - ResourceManager *resource_manager() const { - return resource_manager_; - } - - android_color_transform_t &color_transform_hint() { - return color_transform_hint_; - } - - Stats &total_stats() { - return total_stats_; - } - - /* returns true if composition should be sent to client */ - bool 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; - } - - flattening_vsync_worker_.VSyncControl(true); - flattenning_state_ = ClientFlattenningState::VsyncCountdownMax; - return false; - } - - 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}; - VSyncWorker flattening_vsync_worker_; - - constexpr static size_t MATRIX_SIZE = 16; - - DrmHwcTwo *hwc2_; - - ResourceManager *resource_manager_; - DrmDevice *drm_; - DrmDisplayCompositor compositor_; - std::unique_ptr<Planner> planner_; - - std::vector<DrmPlane *> primary_planes_; - std::vector<DrmPlane *> overlay_planes_; - - std::unique_ptr<Backend> backend_; - - VSyncWorker vsync_worker_; - DrmConnector *connector_ = NULL; - DrmCrtc *crtc_ = NULL; - hwc2_display_t handle_; - HWC2::DisplayType type_; - uint32_t layer_idx_ = 0; - 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_; - - uint32_t frame_no_ = 0; - Stats total_stats_; - Stats prev_stats_; - std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta); - }; - - private: - static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) { - return static_cast<DrmHwcTwo *>(dev); - } - - template <typename PFN, typename T> - static hwc2_function_pointer_t ToHook(T function) { - static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer"); - return reinterpret_cast<hwc2_function_pointer_t>(function); - } - - template <typename T, typename HookType, HookType func, typename... Args> - static T DeviceHook(hwc2_device_t *dev, Args... args) { - DrmHwcTwo *hwc = toDrmHwcTwo(dev); - return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...)); - } - - static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { - auto it = hwc->displays_.find(display_handle); - if (it == hwc->displays_.end()) - return nullptr; - - return &it->second; - } - - template <typename HookType, HookType func, typename... Args> - static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, - Args... args) { - HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); - if (!display) - return static_cast<int32_t>(HWC2::Error::BadDisplay); - - return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...)); - } - - template <typename HookType, HookType func, typename... Args> - static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, - hwc2_layer_t layer_handle, Args... args) { - HwcDisplay *display = GetDisplay(toDrmHwcTwo(dev), display_handle); - if (!display) - return static_cast<int32_t>(HWC2::Error::BadDisplay); - - HwcLayer *layer = display->get_layer(layer_handle); - if (!layer) - return static_cast<int32_t>(HWC2::Error::BadLayer); - - return static_cast<int32_t>((layer->*func)(std::forward<Args>(args)...)); - } - - // hwc2_device_t hooks - static int HookDevClose(hw_device_t *dev); - static void HookDevGetCapabilities(hwc2_device_t *dev, uint32_t *out_count, - int32_t *out_capabilities); - static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device *device, - int32_t descriptor); - - // Device functions - HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height, - int32_t *format, hwc2_display_t *display); - HWC2::Error DestroyVirtualDisplay(hwc2_display_t display); - void Dump(uint32_t *outSize, char *outBuffer); - uint32_t GetMaxVirtualDisplayCount(); - HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, - hwc2_function_pointer_t function); - HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type); - void HandleDisplayHotplug(hwc2_display_t displayid, int state); - void HandleInitialHotplugState(DrmDevice *drmDevice); - - void HandleHotplugUEvent(); - - ResourceManager resource_manager_; - std::map<hwc2_display_t, HwcDisplay> displays_; - - std::string mDumpString; -}; -} // namespace android - -#endif diff --git a/backend/Backend.cpp b/backend/Backend.cpp index ce606dd..98862ba 100644 --- a/backend/Backend.cpp +++ b/backend/Backend.cpp @@ -23,8 +23,7 @@ namespace android { -HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, +HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t *num_requests) { *num_types = 0; *num_requests = 0; @@ -63,12 +62,11 @@ HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, client_size); display->total_stats().total_pixops_ += CalcPixOps(layers, 0, layers.size()); - return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None; + return *num_types != 0 ? HWC2::Error::HasChanges : HWC2::Error::None; } std::tuple<int, size_t> Backend::GetClientLayers( - DrmHwcTwo::HwcDisplay *display, - const std::vector<DrmHwcTwo::HwcLayer *> &layers) { + HwcDisplay *display, const std::vector<HwcLayer *> &layers) { int client_start = -1; size_t client_size = 0; @@ -83,10 +81,9 @@ std::tuple<int, size_t> Backend::GetClientLayers( return GetExtraClientRange(display, layers, client_start, client_size); } -bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) { - return !HardwareSupportsLayerType(layer->sf_type()) || - !BufferInfoGetter::GetInstance()->IsHandleUsable(layer->buffer()) || +bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) { + return !HardwareSupportsLayerType(layer->GetSfType()) || + !BufferInfoGetter::GetInstance()->IsHandleUsable(layer->GetBuffer()) || display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY || (layer->RequireScalingOrPhasing() && display->resource_manager()->ForcedScalingWithGpu()); @@ -97,32 +94,31 @@ bool Backend::HardwareSupportsLayerType(HWC2::Composition comp_type) { comp_type == HWC2::Composition::Cursor; } -uint32_t Backend::CalcPixOps(const std::vector<DrmHwcTwo::HwcLayer *> &layers, +uint32_t Backend::CalcPixOps(const std::vector<HwcLayer *> &layers, size_t first_z, size_t size) { 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]->display_frame(); + hwc_rect_t df = layers[z_order]->GetDisplayFrame(); pixops += (df.right - df.left) * (df.bottom - df.top); } } return pixops; } -void Backend::MarkValidated(std::vector<DrmHwcTwo::HwcLayer *> &layers, +void Backend::MarkValidated(std::vector<HwcLayer *> &layers, size_t client_first_z, size_t client_size) { for (size_t z_order = 0; z_order < layers.size(); ++z_order) { if (z_order >= client_first_z && z_order < client_first_z + client_size) - layers[z_order]->set_validated_type(HWC2::Composition::Client); + layers[z_order]->SetValidatedType(HWC2::Composition::Client); else - layers[z_order]->set_validated_type(HWC2::Composition::Device); + layers[z_order]->SetValidatedType(HWC2::Composition::Device); } } std::tuple<int, int> Backend::GetExtraClientRange( - DrmHwcTwo::HwcDisplay *display, - const std::vector<DrmHwcTwo::HwcLayer *> &layers, int client_start, - size_t client_size) { + HwcDisplay *display, const std::vector<HwcLayer *> &layers, + int client_start, size_t client_size) { size_t avail_planes = display->primary_planes().size() + display->overlay_planes().size(); diff --git a/backend/Backend.h b/backend/Backend.h index fc9a733..82b8fca 100644 --- a/backend/Backend.h +++ b/backend/Backend.h @@ -17,32 +17,28 @@ #ifndef ANDROID_BACKEND_H #define ANDROID_BACKEND_H -#include "DrmHwcTwo.h" +#include "hwc2_device/DrmHwcTwo.h" namespace android { class Backend { public: virtual ~Backend() = default; - virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, + virtual HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t *num_requests); virtual std::tuple<int, size_t> GetClientLayers( - DrmHwcTwo::HwcDisplay *display, - const std::vector<DrmHwcTwo::HwcLayer *> &layers); - virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer); + HwcDisplay *display, const std::vector<HwcLayer *> &layers); + virtual bool IsClientLayer(HwcDisplay *display, HwcLayer *layer); protected: - bool HardwareSupportsLayerType(HWC2::Composition comp_type); - uint32_t CalcPixOps(const std::vector<DrmHwcTwo::HwcLayer *> &layers, - size_t first_z, size_t size); - void MarkValidated(std::vector<DrmHwcTwo::HwcLayer *> &layers, - size_t client_first_z, size_t client_size); - std::tuple<int, int> GetExtraClientRange( - DrmHwcTwo::HwcDisplay *display, - const std::vector<DrmHwcTwo::HwcLayer *> &layers, int client_start, - size_t client_size); + static bool HardwareSupportsLayerType(HWC2::Composition comp_type); + static uint32_t CalcPixOps(const std::vector<HwcLayer *> &layers, + size_t first_z, size_t size); + static void MarkValidated(std::vector<HwcLayer *> &layers, + size_t client_first_z, size_t client_size); + static std::tuple<int, int> GetExtraClientRange( + HwcDisplay *display, const std::vector<HwcLayer *> &layers, + int client_start, size_t client_size); }; } // namespace android diff --git a/backend/BackendClient.cpp b/backend/BackendClient.cpp index 49963b8..606dca2 100644 --- a/backend/BackendClient.cpp +++ b/backend/BackendClient.cpp @@ -20,11 +20,11 @@ namespace android { -HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display, +HWC2::Error BackendClient::ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t * /*num_requests*/) { - for (auto & [ layer_handle, layer ] : display->layers()) { - layer.set_validated_type(HWC2::Composition::Client); + for (auto &[layer_handle, layer] : display->layers()) { + layer.SetValidatedType(HWC2::Composition::Client); ++*num_types; } return HWC2::Error::HasChanges; diff --git a/backend/BackendClient.h b/backend/BackendClient.h index 13543f1..95abb0f 100644 --- a/backend/BackendClient.h +++ b/backend/BackendClient.h @@ -23,8 +23,7 @@ namespace android { class BackendClient : public Backend { public: - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, + HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types, uint32_t *num_requests) override; }; } // namespace android diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp index 7b89761..aadef36 100644 --- a/backend/BackendManager.cpp +++ b/backend/BackendManager.cpp @@ -36,12 +36,12 @@ BackendManager &BackendManager::GetInstance() { } int BackendManager::RegisterBackend(const std::string &name, - backend_constructor_t backend_constructor) { + BackendConstructorT backend_constructor) { available_backends_[name] = std::move(backend_constructor); return 0; } -int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) { +int BackendManager::SetBackendForDisplay(HwcDisplay *display) { std::string driver_name(display->drm()->GetName()); char backend_override[PROPERTY_VALUE_MAX]; property_get("vendor.hwc.backend_override", backend_override, @@ -49,7 +49,7 @@ int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) { std::string backend_name(backend_override); display->set_backend(GetBackendByName(backend_name)); - if (!display->backend()) { + if (display->backend() == nullptr) { ALOGE("Failed to set backend '%s' for '%s' and driver '%s'", backend_name.c_str(), display->connector()->name().c_str(), driver_name.c_str()); diff --git a/backend/BackendManager.h b/backend/BackendManager.h index 9b314db..751cb78 100644 --- a/backend/BackendManager.h +++ b/backend/BackendManager.h @@ -24,6 +24,7 @@ #include "Backend.h" +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define REGISTER_BACKEND(name_str_, backend_) \ static int \ backend = BackendManager::GetInstance() \ @@ -36,21 +37,21 @@ namespace android { class BackendManager { public: - using backend_constructor_t = std::function<std::unique_ptr<Backend>()>; + using BackendConstructorT = std::function<std::unique_ptr<Backend>()>; static BackendManager &GetInstance(); int RegisterBackend(const std::string &name, - backend_constructor_t backend_constructor); - int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display); + BackendConstructorT backend_constructor); + int SetBackendForDisplay(HwcDisplay *display); std::unique_ptr<Backend> GetBackendByName(std::string &name); - HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display, - uint32_t *num_types, uint32_t *num_requests); + HWC2::Error ValidateDisplay(HwcDisplay *display, uint32_t *num_types, + uint32_t *num_requests); private: BackendManager() = default; static const std::vector<std::string> kClientDevices; - std::map<std::string, backend_constructor_t> available_backends_; + std::map<std::string, BackendConstructorT> available_backends_; }; } // namespace android diff --git a/backend/BackendRCarDu.cpp b/backend/BackendRCarDu.cpp index b012797..0750ee4 100644 --- a/backend/BackendRCarDu.cpp +++ b/backend/BackendRCarDu.cpp @@ -22,13 +22,12 @@ namespace android { -bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) { +bool BackendRCarDu::IsClientLayer(HwcDisplay *display, HwcLayer *layer) { hwc_drm_bo_t bo; - int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(layer->buffer(), + int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(layer->GetBuffer(), &bo); - if (ret) + if (ret != 0) return true; if (bo.format == DRM_FORMAT_ABGR8888) diff --git a/backend/BackendRCarDu.h b/backend/BackendRCarDu.h index 8a1011a..1259c9f 100644 --- a/backend/BackendRCarDu.h +++ b/backend/BackendRCarDu.h @@ -23,8 +23,7 @@ namespace android { class BackendRCarDu : public Backend { public: - bool IsClientLayer(DrmHwcTwo::HwcDisplay *display, - DrmHwcTwo::HwcLayer *layer) override; + bool IsClientLayer(HwcDisplay *display, HwcLayer *layer) override; }; } // namespace android diff --git a/bufferinfo/BufferInfoGetter.cpp b/bufferinfo/BufferInfoGetter.cpp index c284365..0cfd7e5 100644 --- a/bufferinfo/BufferInfoGetter.cpp +++ b/bufferinfo/BufferInfoGetter.cpp @@ -62,9 +62,11 @@ bool BufferInfoGetter::IsHandleUsable(buffer_handle_t handle) { } int LegacyBufferInfoGetter::Init() { - int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, - (const hw_module_t **)&gralloc_); - if (ret) { + int ret = hw_get_module( + GRALLOC_HARDWARE_MODULE_ID, + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + reinterpret_cast<const hw_module_t **>(&gralloc_)); + if (ret != 0) { ALOGE("Failed to open gralloc module"); return ret; } diff --git a/bufferinfo/BufferInfoGetter.h b/bufferinfo/BufferInfoGetter.h index 7b088df..59184a4 100644 --- a/bufferinfo/BufferInfoGetter.h +++ b/bufferinfo/BufferInfoGetter.h @@ -31,8 +31,7 @@ namespace android { class BufferInfoGetter { public: - virtual ~BufferInfoGetter() { - } + virtual ~BufferInfoGetter() = default; virtual int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) = 0; @@ -53,17 +52,18 @@ class LegacyBufferInfoGetter : public BufferInfoGetter { return 0; } - int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override = 0; - static std::unique_ptr<LegacyBufferInfoGetter> CreateInstance(); static uint32_t ConvertHalFormatToDrm(uint32_t hal_format); + + // NOLINTNEXTLINE:(readability-identifier-naming) const gralloc_module_t *gralloc_; }; #ifdef DISABLE_LEGACY_GETTERS #define LEGACY_BUFFER_INFO_GETTER(getter_) #else +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define LEGACY_BUFFER_INFO_GETTER(getter_) \ std::unique_ptr<LegacyBufferInfoGetter> \ LegacyBufferInfoGetter::CreateInstance() { \ diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp index a8e95e7..2f08a76 100644 --- a/bufferinfo/BufferInfoMapperMetadata.cpp +++ b/bufferinfo/BufferInfoMapperMetadata.cpp @@ -54,7 +54,7 @@ BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) { return android::BAD_VALUE; } - for (int i = 0; i < HWC_DRM_BO_MAX_PLANES; i++) { + for (int i = 0; i < kHwcDrmBoMaxPlanes; i++) { /* If no size, we're out of usable planes */ if (bo->sizes[i] <= 0) { if (i == 0) { @@ -89,12 +89,12 @@ BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) { int BufferInfoMapperMetadata::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) { GraphicBufferMapper &mapper = GraphicBufferMapper::getInstance(); - if (!handle) + if (handle == nullptr) return -EINVAL; uint64_t usage = 0; int err = mapper.getUsage(handle, &usage); - if (err) { + if (err != 0) { ALOGE("Failed to get usage err=%d", err); return err; } @@ -102,27 +102,27 @@ int BufferInfoMapperMetadata::ConvertBoInfo(buffer_handle_t handle, ui::PixelFormat hal_format; err = mapper.getPixelFormatRequested(handle, &hal_format); - if (err) { + if (err != 0) { ALOGE("Failed to get HAL Pixel Format err=%d", err); return err; } bo->hal_format = static_cast<uint32_t>(hal_format); err = mapper.getPixelFormatFourCC(handle, &bo->format); - if (err) { + if (err != 0) { ALOGE("Failed to get FourCC format err=%d", err); return err; } err = mapper.getPixelFormatModifier(handle, &bo->modifiers[0]); - if (err) { + if (err != 0) { ALOGE("Failed to get DRM Modifier err=%d", err); return err; } uint64_t width = 0; err = mapper.getWidth(handle, &width); - if (err) { + if (err != 0) { ALOGE("Failed to get Width err=%d", err); return err; } @@ -130,7 +130,7 @@ int BufferInfoMapperMetadata::ConvertBoInfo(buffer_handle_t handle, uint64_t height = 0; err = mapper.getHeight(handle, &height); - if (err) { + if (err != 0) { ALOGE("Failed to get Height err=%d", err); return err; } @@ -138,7 +138,7 @@ int BufferInfoMapperMetadata::ConvertBoInfo(buffer_handle_t handle, std::vector<ui::PlaneLayout> layouts; err = mapper.getPlaneLayouts(handle, &layouts); - if (err) { + if (err != 0) { ALOGE("Failed to get Plane Layouts err=%d", err); return err; } diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp index 47481b2..4f942fe 100644 --- a/bufferinfo/legacy/BufferInfoLibdrm.cpp +++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp @@ -78,6 +78,7 @@ static uint32_t get_fourcc_yuv(uint32_t native, enum chroma_order chroma_order, } static bool is_yuv(uint32_t native) { + // NOLINTNEXTLINE(readability-use-anyofallof) for (auto droid_yuv_format : kDroidYuvFormats) if (droid_yuv_format.native == native) return true; diff --git a/compositor/DrmDisplayComposition.cpp b/compositor/DrmDisplayComposition.cpp index cd95267..e571b26 100644 --- a/compositor/DrmDisplayComposition.cpp +++ b/compositor/DrmDisplayComposition.cpp @@ -32,9 +32,9 @@ namespace android { -DrmDisplayComposition::DrmDisplayComposition(DrmCrtc *crtc, Planner *planner) - : crtc_(crtc), // Can be NULL if we haven't modeset yet - planner_(planner) { +DrmDisplayComposition::DrmDisplayComposition(DrmCrtc *crtc) + : crtc_(crtc) // Can be NULL if we haven't modeset yet +{ } int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers) { @@ -45,11 +45,6 @@ int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers) { return 0; } -int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { - composition_planes_.emplace_back(DrmCompositionPlane::Type::kDisable, plane); - return 0; -} - int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) { composition_planes_.emplace_back(std::move(plane)); return 0; @@ -63,10 +58,10 @@ int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes, to_composite.emplace(std::make_pair(i, &layers_[i])); int ret = 0; - std::tie(ret, - composition_planes_) = planner_->ProvisionPlanes(to_composite, crtc_, - primary_planes, - overlay_planes); + std::tie(ret, composition_planes_) = Planner::ProvisionPlanes(to_composite, + crtc_, + primary_planes, + overlay_planes); if (ret) { ALOGV("Planner failed provisioning planes ret=%d", ret); return ret; @@ -78,11 +73,8 @@ int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes, if (!i.plane()) continue; - // make sure that source layers are ordered based on zorder - std::sort(i.source_layers().begin(), i.source_layers().end()); - std::vector<DrmPlane *> *container = nullptr; - if (i.plane()->type() == DRM_PLANE_TYPE_PRIMARY) + if (i.plane()->GetType() == DRM_PLANE_TYPE_PRIMARY) container = primary_planes; else container = overlay_planes; diff --git a/compositor/DrmDisplayComposition.h b/compositor/DrmDisplayComposition.h index f1958d7..dcfd96e 100644 --- a/compositor/DrmDisplayComposition.h +++ b/compositor/DrmDisplayComposition.h @@ -30,58 +30,39 @@ namespace android { class Importer; -class Planner; + +constexpr size_t kUndefinedSourceLayer = UINT16_MAX; class DrmCompositionPlane { public: - enum class Type : int32_t { - kDisable, - kLayer, - }; - DrmCompositionPlane() = default; DrmCompositionPlane(DrmCompositionPlane &&rhs) = default; DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default; - DrmCompositionPlane(Type type, DrmPlane *plane) : type_(type), plane_(plane) { - } - DrmCompositionPlane(Type type, DrmPlane *plane, size_t source_layer) - : type_(type), plane_(plane), source_layers_(1, source_layer) { - } - - Type type() const { - return type_; + DrmCompositionPlane(DrmPlane *plane, size_t source_layer) + : plane_(plane), source_layer_(source_layer) { } DrmPlane *plane() const { return plane_; } - void set_plane(DrmPlane *plane) { - plane_ = plane; - } - - std::vector<size_t> &source_layers() { - return source_layers_; - } - const std::vector<size_t> &source_layers() const { - return source_layers_; + size_t source_layer() const { + return source_layer_; } private: - Type type_ = Type::kDisable; - DrmPlane *plane_ = NULL; - std::vector<size_t> source_layers_; + DrmPlane *plane_ = nullptr; + size_t source_layer_ = kUndefinedSourceLayer; }; class DrmDisplayComposition { public: DrmDisplayComposition(const DrmDisplayComposition &) = delete; - DrmDisplayComposition(DrmCrtc *crtc, Planner *planner); + explicit DrmDisplayComposition(DrmCrtc *crtc); ~DrmDisplayComposition() = default; int SetLayers(DrmHwcLayer *layers, size_t num_layers); int AddPlaneComposition(DrmCompositionPlane plane); - int AddPlaneDisable(DrmPlane *plane); int Plan(std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes); @@ -98,13 +79,8 @@ class DrmDisplayComposition { return crtc_; } - Planner *planner() const { - return planner_; - } - private: - DrmCrtc *crtc_ = NULL; - Planner *planner_ = NULL; + DrmCrtc *crtc_ = nullptr; std::vector<DrmHwcLayer> layers_; std::vector<DrmCompositionPlane> composition_planes_; diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp index 447d75e..89e7f2d 100644 --- a/compositor/DrmDisplayCompositor.cpp +++ b/compositor/DrmDisplayCompositor.cpp @@ -49,7 +49,6 @@ auto DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display) ALOGE("Could not find drmdevice for display"); return -EINVAL; } - planner_ = Planner::CreateInstance(drm); initialized_ = true; return 0; @@ -64,13 +63,14 @@ DrmDisplayCompositor::CreateInitializedComposition() const { return std::unique_ptr<DrmDisplayComposition>(); } - return std::make_unique<DrmDisplayComposition>(crtc, planner_.get()); + return std::make_unique<DrmDisplayComposition>(crtc); } +// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int { ATRACE_CALL(); - if (args.active && *args.active == active_kms_data.active_state) { + if (args.active && *args.active == active_frame_state_.crtc_active_state) { /* Don't set the same state twice */ args.active.reset(); } @@ -80,7 +80,7 @@ auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int { return 0; } - if (!active_kms_data.active_state) { + if (!active_frame_state_.crtc_active_state) { /* Force activate display */ args.active = true; } @@ -90,6 +90,8 @@ auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int { return -EINVAL; } + auto new_frame_state = NewFrameState(); + DrmDevice *drm = resource_manager_->GetDrmDevice(display_); DrmConnector *connector = drm->GetConnectorForDisplay(display_); @@ -115,9 +117,8 @@ auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int { return -EINVAL; } - DrmModeUserPropertyBlobUnique mode_blob; - if (args.active) { + new_frame_state.crtc_active_state = *args.active; if (!crtc->active_property().AtomicSet(*pset, *args.active) || !connector->crtc_id_property().AtomicSet(*pset, crtc->id())) { return -EINVAL; @@ -125,58 +126,61 @@ auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int { } if (args.display_mode) { - mode_blob = args.display_mode.value().CreateModeBlob( + new_frame_state.mode_blob = args.display_mode.value().CreateModeBlob( *resource_manager_->GetDrmDevice(display_)); - if (!mode_blob) { + if (!new_frame_state.mode_blob) { ALOGE("Failed to create mode_blob"); return -EINVAL; } - if (!crtc->mode_property().AtomicSet(*pset, *mode_blob)) { + if (!crtc->mode_property().AtomicSet(*pset, *new_frame_state.mode_blob)) { return -EINVAL; } } + auto unused_planes = new_frame_state.used_planes; + if (args.composition) { + new_frame_state.used_framebuffers.clear(); + new_frame_state.used_planes.clear(); + std::vector<DrmHwcLayer> &layers = args.composition->layers(); std::vector<DrmCompositionPlane> &comp_planes = args.composition ->composition_planes(); for (DrmCompositionPlane &comp_plane : comp_planes) { DrmPlane *plane = comp_plane.plane(); - std::vector<size_t> &source_layers = comp_plane.source_layers(); - - if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) { - if (source_layers.size() > 1) { - ALOGE("Can't handle more than one source layer sz=%zu type=%d", - source_layers.size(), comp_plane.type()); - continue; - } - - if (source_layers.empty() || source_layers.front() >= layers.size()) { - ALOGE("Source layer index %zu out of bounds %zu type=%d", - source_layers.front(), layers.size(), comp_plane.type()); - return -EINVAL; - } - DrmHwcLayer &layer = layers[source_layers.front()]; - - if (plane->AtomicSetState(*pset, layer, source_layers.front(), - crtc->id()) != 0) { - return -EINVAL; - } - } else { - if (plane->AtomicDisablePlane(*pset) != 0) { - return -EINVAL; - } + size_t source_layer = comp_plane.source_layer(); + + if (source_layer >= layers.size()) { + ALOGE("Source layer index %zu out of bounds %zu", source_layer, + layers.size()); + return -EINVAL; + } + DrmHwcLayer &layer = layers[source_layer]; + + new_frame_state.used_framebuffers.emplace_back(layer.fb_id_handle); + new_frame_state.used_planes.emplace_back(plane); + + /* Remove from 'unused' list, since plane is re-used */ + auto &v = unused_planes; + v.erase(std::remove(v.begin(), v.end(), plane), v.end()); + + if (plane->AtomicSetState(*pset, layer, source_layer, crtc->id()) != 0) { + return -EINVAL; } } } - if (args.clear_active_composition && active_kms_data.composition) { - auto &comp_planes = active_kms_data.composition->composition_planes(); - for (auto &comp_plane : comp_planes) { - if (comp_plane.plane()->AtomicDisablePlane(*pset) != 0) { + if (args.clear_active_composition) { + new_frame_state.used_framebuffers.clear(); + new_frame_state.used_planes.clear(); + } + + if (args.clear_active_composition || args.composition) { + for (auto *plane : unused_planes) { + if (plane->AtomicDisablePlane(*pset) != 0) { return -EINVAL; } } @@ -195,21 +199,12 @@ auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int { if (!args.test_only) { if (args.display_mode) { + /* TODO(nobody): we still need this for synthetic vsync, remove after + * vsync reworked */ connector->set_active_mode(*args.display_mode); - active_kms_data.mode_blob = std::move(mode_blob); } - if (args.clear_active_composition) { - active_kms_data.composition.reset(); - } - - if (args.composition) { - active_kms_data.composition = args.composition; - } - - if (args.active) { - active_kms_data.active_state = *args.active; - } + active_frame_state_ = std::move(new_frame_state); if (crtc->out_fence_ptr_property()) { args.out_fence = UniqueFd((int)out_fence); @@ -238,4 +233,20 @@ auto DrmDisplayCompositor::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int { return err; } // namespace android +auto DrmDisplayCompositor::ActivateDisplayUsingDPMS() -> int { + auto *drm = resource_manager_->GetDrmDevice(display_); + auto *connector = drm->GetConnectorForDisplay(display_); + if (connector == nullptr) { + ALOGE("Could not locate connector for display %d", display_); + return -ENODEV; + } + + if (connector->dpms_property()) { + drmModeConnectorSetProperty(drm->fd(), connector->id(), + connector->dpms_property().id(), + DRM_MODE_DPMS_ON); + } + return 0; +} + } // namespace android diff --git a/compositor/DrmDisplayCompositor.h b/compositor/DrmDisplayCompositor.h index 55fe77d..e7899ed 100644 --- a/compositor/DrmDisplayCompositor.h +++ b/compositor/DrmDisplayCompositor.h @@ -23,11 +23,11 @@ #include <functional> #include <memory> +#include <optional> #include <sstream> #include <tuple> #include "DrmDisplayComposition.h" -#include "Planner.h" #include "drm/ResourceManager.h" #include "drm/VSyncWorker.h" #include "drmhwcomposer.h" @@ -62,19 +62,35 @@ class DrmDisplayCompositor { auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int; - private: DrmDisplayCompositor(const DrmDisplayCompositor &) = delete; + auto ActivateDisplayUsingDPMS() -> int; + + private: auto CommitFrame(AtomicCommitArgs &args) -> int; - struct { - std::shared_ptr<DrmDisplayComposition> composition; + struct KmsState { + /* Required to cleanup unused planes */ + std::vector<DrmPlane *> used_planes; + /* We have to hold a reference to framebuffer while displaying it , + * otherwise picture will blink */ + std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers; + DrmModeUserPropertyBlobUnique mode_blob; - bool active_state{}; - } active_kms_data; + + /* To avoid setting the inactive state twice, which will fail the commit */ + bool crtc_active_state{}; + } active_frame_state_; + + auto NewFrameState() -> KmsState { + return (KmsState){ + .used_planes = active_frame_state_.used_planes, + .used_framebuffers = active_frame_state_.used_framebuffers, + .crtc_active_state = active_frame_state_.crtc_active_state, + }; + } ResourceManager *resource_manager_ = nullptr; - std::unique_ptr<Planner> planner_; bool initialized_{}; int display_ = -1; }; diff --git a/compositor/Planner.cpp b/compositor/Planner.cpp index 9db03c3..f43e314 100644 --- a/compositor/Planner.cpp +++ b/compositor/Planner.cpp @@ -25,12 +25,6 @@ namespace android { -std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice * /*device*/) { - std::unique_ptr<Planner> planner(new Planner); - planner->AddStage<PlanStageGreedy>(); - return planner; -} - std::vector<DrmPlane *> Planner::GetUsablePlanes( DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes) { @@ -57,54 +51,26 @@ std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes( } // Go through the provisioning stages and provision planes - for (auto &i : stages_) { - int ret = i->ProvisionPlanes(&composition, layers, &planes); - if (ret) { - ALOGV("Failed provision stage with ret %d", ret); - return std::make_tuple(ret, std::vector<DrmCompositionPlane>()); - } + int ret = ProvisionPlanesInternal(&composition, layers, &planes); + if (ret != 0) { + ALOGV("Failed provision stage with ret %d", ret); + return std::make_tuple(ret, std::vector<DrmCompositionPlane>()); } return std::make_tuple(0, std::move(composition)); } -int PlanStageProtected::ProvisionPlanes( - std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, - std::vector<DrmPlane *> *planes) { - int ret = 0; - for (auto i = layers.begin(); i != layers.end();) { - if (!i->second->protected_usage()) { - ++i; - continue; - } - - ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, - std::make_pair(i->first, i->second)); - if (ret) { - ALOGE("Failed to dedicate protected layer! Dropping it."); - return ret; - } - - i = layers.erase(i); - } - - return 0; -} - -int PlanStageGreedy::ProvisionPlanes( +int Planner::ProvisionPlanesInternal( std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, - std::vector<DrmPlane *> *planes) { + std::map<size_t, DrmHwcLayer *> &layers, std::vector<DrmPlane *> *planes) { // Fill up the remaining planes for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) { - int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, - std::make_pair(i->first, i->second)); + int ret = Emplace(composition, planes, std::make_pair(i->first, i->second)); // We don't have any planes left if (ret == -ENOENT) break; - if (ret) { + if (ret != 0) { ALOGV("Failed to emplace layer %zu, dropping it", i->first); return ret; } diff --git a/compositor/Planner.h b/compositor/Planner.h index 3390acb..7802d0c 100644 --- a/compositor/Planner.h +++ b/compositor/Planner.h @@ -32,56 +32,46 @@ namespace android { class DrmDevice; class Planner { - public: - class PlanStage { - public: - virtual ~PlanStage() { - } - - virtual int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, - std::vector<DrmPlane *> *planes) = 0; + private: + // Removes and returns the next available plane from planes + static DrmPlane *PopPlane(std::vector<DrmPlane *> *planes) { + if (planes->empty()) + return nullptr; + DrmPlane *plane = planes->front(); + planes->erase(planes->begin()); + return plane; + } - protected: - // Removes and returns the next available plane from planes - static DrmPlane *PopPlane(std::vector<DrmPlane *> *planes) { - if (planes->empty()) - return NULL; - DrmPlane *plane = planes->front(); - planes->erase(planes->begin()); - return plane; + // Inserts the given layer:plane in the composition at the back + static int Emplace(std::vector<DrmCompositionPlane> *composition, + std::vector<DrmPlane *> *planes, + std::pair<size_t, DrmHwcLayer *> layer) { + DrmPlane *plane = PopPlane(planes); + std::vector<DrmPlane *> unused_planes; + int ret = -ENOENT; + while (plane != nullptr) { + ret = plane->IsValidForLayer(layer.second) ? 0 : -EINVAL; + if (ret == 0) + break; + if (!plane->GetZPosProperty().is_immutable()) + unused_planes.push_back(plane); + plane = PopPlane(planes); } - // Inserts the given layer:plane in the composition at the back - static int Emplace(std::vector<DrmCompositionPlane> *composition, - std::vector<DrmPlane *> *planes, - DrmCompositionPlane::Type type, - std::pair<size_t, DrmHwcLayer *> layer) { - DrmPlane *plane = PopPlane(planes); - std::vector<DrmPlane *> unused_planes; - int ret = -ENOENT; - while (plane) { - ret = plane->IsValidForLayer(layer.second) ? 0 : -EINVAL; - if (!ret) - break; - if (!plane->zpos_property().is_immutable()) - unused_planes.push_back(plane); - plane = PopPlane(planes); - } - - if (!ret) { - composition->emplace_back(type, plane, layer.first); - planes->insert(planes->begin(), unused_planes.begin(), - unused_planes.end()); - } - - return ret; + if (ret == 0) { + composition->emplace_back(plane, layer.first); + planes->insert(planes->begin(), unused_planes.begin(), + unused_planes.end()); } - }; - // Creates a planner instance with platform-specific planning stages - static std::unique_ptr<Planner> CreateInstance(DrmDevice *drm); + return ret; + } + static int ProvisionPlanesInternal( + std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, std::vector<DrmPlane *> *planes); + + public: // Takes a stack of layers and provisions hardware planes for them. If the // entire stack can't fit in hardware, FIXME // @@ -91,42 +81,15 @@ class Planner { // // Returns: A tuple with the status of the operation (0 for success) and // a vector of the resulting plan (ie: layer->plane mapping). - std::tuple<int, std::vector<DrmCompositionPlane>> ProvisionPlanes( + static std::tuple<int, std::vector<DrmCompositionPlane>> ProvisionPlanes( std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes); - template <typename T, typename... A> - void AddStage(A &&...args) { - stages_.emplace_back( - std::unique_ptr<PlanStage>(new T(std::forward(args)...))); - } - private: - std::vector<DrmPlane *> GetUsablePlanes( + static std::vector<DrmPlane *> GetUsablePlanes( DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes); - - std::vector<std::unique_ptr<PlanStage>> stages_; -}; - -// This plan stage extracts all protected layers and places them on dedicated -// planes. -class PlanStageProtected : public Planner::PlanStage { - public: - int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, - std::vector<DrmPlane *> *planes); -}; - -// This plan stage places as many layers on dedicated planes as possible (first -// come first serve), and then sticks the rest in a precomposition plane (if -// needed). -class PlanStageGreedy : public Planner::PlanStage { - public: - int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, - std::vector<DrmPlane *> *planes); }; } // namespace android #endif diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp index 5b3c697..32b6d24 100644 --- a/drm/DrmConnector.cpp +++ b/drm/DrmConnector.cpp @@ -28,9 +28,17 @@ #include "DrmDevice.h" #include "utils/log.h" +#ifndef DRM_MODE_CONNECTOR_SPI +#define DRM_MODE_CONNECTOR_SPI 19 +#endif + +#ifndef DRM_MODE_CONNECTOR_USB +#define DRM_MODE_CONNECTOR_USB 20 +#endif + namespace android { -constexpr size_t kTypesCount = 17; +constexpr size_t kTypesCount = 21; DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, DrmEncoder *current_encoder, @@ -120,14 +128,15 @@ void DrmConnector::set_display(int display) { bool DrmConnector::internal() const { return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP || type_ == DRM_MODE_CONNECTOR_DSI || - type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI; + type_ == DRM_MODE_CONNECTOR_VIRTUAL || + type_ == DRM_MODE_CONNECTOR_DPI || type_ == DRM_MODE_CONNECTOR_SPI; } bool DrmConnector::external() const { return type_ == DRM_MODE_CONNECTOR_HDMIA || type_ == DRM_MODE_CONNECTOR_DisplayPort || type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII || - type_ == DRM_MODE_CONNECTOR_VGA; + type_ == DRM_MODE_CONNECTOR_VGA || type_ == DRM_MODE_CONNECTOR_USB; } bool DrmConnector::writeback() const { @@ -144,9 +153,10 @@ bool DrmConnector::valid_type() const { std::string DrmConnector::name() const { constexpr std::array<const char *, kTypesCount> kNames = - {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", - "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A", - "HDMI-B", "TV", "eDP", "Virtual", "DSI"}; + {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", + "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A", + "HDMI-B", "TV", "eDP", "Virtual", "DSI", "DPI", + "Writeback", "SPI", "USB"}; if (type_ < kTypesCount) { std::ostringstream name_buf; diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h index f2305aa..2bcb543 100644 --- a/drm/DrmConnector.h +++ b/drm/DrmConnector.h @@ -17,9 +17,9 @@ #ifndef ANDROID_DRM_CONNECTOR_H_ #define ANDROID_DRM_CONNECTOR_H_ -#include <stdint.h> #include <xf86drmMode.h> +#include <cstdint> #include <string> #include <vector> diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp index 4da08fe..08a1922 100644 --- a/drm/DrmCrtc.cpp +++ b/drm/DrmCrtc.cpp @@ -33,19 +33,19 @@ DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe) int DrmCrtc::Init() { int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_); - if (ret) { + if (ret != 0) { ALOGE("Failed to get ACTIVE property"); return ret; } ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_); - if (ret) { + if (ret != 0) { ALOGE("Failed to get MODE_ID property"); return ret; } ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_); - if (ret) { + if (ret != 0) { ALOGE("Failed to get OUT_FENCE_PTR property"); return ret; } diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h index 7972bef..85e067a 100644 --- a/drm/DrmCrtc.h +++ b/drm/DrmCrtc.h @@ -17,9 +17,10 @@ #ifndef ANDROID_DRM_CRTC_H_ #define ANDROID_DRM_CRTC_H_ -#include <stdint.h> #include <xf86drmMode.h> +#include <cstdint> + #include "DrmMode.h" #include "DrmProperty.h" diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp index 0f5f581..a679bf5 100644 --- a/drm/DrmDevice.cpp +++ b/drm/DrmDevice.cpp @@ -30,6 +30,7 @@ #include <sstream> #include <string> +#include "drm/DrmPlane.h" #include "utils/log.h" #include "utils/properties.h" @@ -116,10 +117,12 @@ DrmDevice::DrmDevice() { mDrmFbImporter = std::make_unique<DrmFbImporter>(self); } +// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) { /* TODO: Use drmOpenControl here instead */ fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC)); if (fd() < 0) { + // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme ALOGE("Failed to open dri %s: %s", path, strerror(errno)); return std::make_tuple(-ENODEV, 0); } @@ -388,14 +391,6 @@ DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const { return nullptr; } -DrmPlane *DrmDevice::GetPlane(uint32_t id) const { - for (const auto &plane : planes_) { - if (plane->id() == id) - return plane.get(); - } - return nullptr; -} - const std::vector<std::unique_ptr<DrmCrtc>> &DrmDevice::crtcs() const { return crtcs_; } diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h index c08c766..d3effc2 100644 --- a/drm/DrmDevice.h +++ b/drm/DrmDevice.h @@ -17,8 +17,7 @@ #ifndef ANDROID_DRM_H_ #define ANDROID_DRM_H_ -#include <stdint.h> - +#include <cstdint> #include <map> #include <tuple> @@ -26,7 +25,6 @@ #include "DrmCrtc.h" #include "DrmEncoder.h" #include "DrmFbImporter.h" -#include "DrmPlane.h" #include "utils/UniqueFd.h" namespace android { @@ -65,7 +63,6 @@ class DrmDevice { DrmConnector *GetWritebackConnectorForDisplay(int display) const; DrmConnector *AvailableWritebackConnector(int display) const; DrmCrtc *GetCrtcForDisplay(int display) const; - DrmPlane *GetPlane(uint32_t id) const; int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, DrmProperty *property) const; @@ -87,7 +84,7 @@ class DrmDevice { } DrmFbImporter &GetDrmFbImporter() { - return *mDrmFbImporter.get(); + return *mDrmFbImporter; } static auto IsKMSDev(const char *path) -> bool; diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h index 4c01bc1..b130b7d 100644 --- a/drm/DrmEncoder.h +++ b/drm/DrmEncoder.h @@ -17,9 +17,9 @@ #ifndef ANDROID_DRM_ENCODER_H_ #define ANDROID_DRM_ENCODER_H_ -#include <stdint.h> #include <xf86drmMode.h> +#include <cstdint> #include <set> #include <vector> diff --git a/drm/DrmFbImporter.h b/drm/DrmFbImporter.h index 167aa60..efeb457 100644 --- a/drm/DrmFbImporter.h +++ b/drm/DrmFbImporter.h @@ -57,7 +57,7 @@ class DrmFbIdHandle { const std::shared_ptr<DrmDevice> drm_; uint32_t fb_id_{}; - std::array<GemHandle, HWC_DRM_BO_MAX_PLANES> gem_handles_{}; + std::array<GemHandle, kHwcDrmBoMaxPlanes> gem_handles_{}; }; class DrmFbImporter { diff --git a/drm/DrmMode.h b/drm/DrmMode.h index 41b9e15..20515f9 100644 --- a/drm/DrmMode.h +++ b/drm/DrmMode.h @@ -17,10 +17,10 @@ #ifndef ANDROID_DRM_MODE_H_ #define ANDROID_DRM_MODE_H_ -#include <stdio.h> #include <xf86drmMode.h> #include <cstdint> +#include <cstdio> #include <string> #include "DrmUnique.h" @@ -32,7 +32,7 @@ class DrmDevice; class DrmMode { public: DrmMode() = default; - DrmMode(drmModeModeInfoPtr m); + explicit DrmMode(drmModeModeInfoPtr m); bool operator==(const drmModeModeInfo &m) const; diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp index f6ddad2..25a4902 100644 --- a/drm/DrmPlane.cpp +++ b/drm/DrmPlane.cpp @@ -33,6 +33,7 @@ DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p) : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs), + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) formats_(p->formats, p->formats + p->count_formats) { } @@ -46,7 +47,7 @@ int DrmPlane::Init() { int ret = 0; uint64_t type = 0; std::tie(ret, type) = p.value(); - if (ret) { + if (ret != 0) { ALOGE("Failed to get plane type property value"); return ret; } @@ -133,10 +134,6 @@ int DrmPlane::Init() { return 0; } -uint32_t DrmPlane::id() const { - return id_; -} - bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const { return ((1 << crtc.pipe()) & possible_crtc_mask_) != 0; } @@ -154,7 +151,7 @@ bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) { } } - if (alpha_property_.id() == 0 && layer->alpha != 0xffff) { + if (alpha_property_.id() == 0 && layer->alpha != UINT16_MAX) { ALOGV("Alpha is not supported on plane %d", id_); return false; } @@ -176,7 +173,7 @@ bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) { return true; } -uint32_t DrmPlane::type() const { +uint32_t DrmPlane::GetType() const { return type_; } @@ -194,15 +191,15 @@ bool DrmPlane::HasNonRgbFormat() const { static uint64_t ToDrmRotation(DrmHwcTransform transform) { uint64_t rotation = 0; - if (transform & DrmHwcTransform::kFlipH) + if ((transform & DrmHwcTransform::kFlipH) != 0) rotation |= DRM_MODE_REFLECT_X; - if (transform & DrmHwcTransform::kFlipV) + if ((transform & DrmHwcTransform::kFlipV) != 0) rotation |= DRM_MODE_REFLECT_Y; - if (transform & DrmHwcTransform::kRotate90) + if ((transform & DrmHwcTransform::kRotate90) != 0) rotation |= DRM_MODE_ROTATE_90; - else if (transform & DrmHwcTransform::kRotate180) + else if ((transform & DrmHwcTransform::kRotate180) != 0) rotation |= DRM_MODE_ROTATE_180; - else if (transform & DrmHwcTransform::kRotate270) + else if ((transform & DrmHwcTransform::kRotate270) != 0) rotation |= DRM_MODE_ROTATE_270; else rotation |= DRM_MODE_ROTATE_0; @@ -210,9 +207,15 @@ static uint64_t ToDrmRotation(DrmHwcTransform transform) { return rotation; } +/* Convert float to 16.16 fixed point */ +static int To1616FixPt(float in) { + constexpr int kBitShift = 16; + return int(in * (1 << kBitShift)); +} + auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos, uint32_t crtc_id) -> int { - if (!layer.FbIdHandle) { + if (!layer.fb_id_handle) { ALOGE("Expected a valid framebuffer for pset"); return -EINVAL; } @@ -234,21 +237,19 @@ auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, } if (!crtc_property_.AtomicSet(pset, crtc_id) || - !fb_property_.AtomicSet(pset, layer.FbIdHandle->GetFbId()) || + !fb_property_.AtomicSet(pset, layer.fb_id_handle->GetFbId()) || !crtc_x_property_.AtomicSet(pset, layer.display_frame.left) || !crtc_y_property_.AtomicSet(pset, layer.display_frame.top) || !crtc_w_property_.AtomicSet(pset, layer.display_frame.right - layer.display_frame.left) || !crtc_h_property_.AtomicSet(pset, layer.display_frame.bottom - layer.display_frame.top) || - !src_x_property_.AtomicSet(pset, (int)(layer.source_crop.left) << 16) || - !src_y_property_.AtomicSet(pset, (int)(layer.source_crop.top) << 16) || - !src_w_property_.AtomicSet(pset, (int)(layer.source_crop.right - - layer.source_crop.left) - << 16) || - !src_h_property_.AtomicSet(pset, (int)(layer.source_crop.bottom - - layer.source_crop.top) - << 16)) { + !src_x_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.left)) || + !src_y_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.top)) || + !src_w_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.right - + layer.source_crop.left)) || + !src_h_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.bottom - + layer.source_crop.top))) { return -EINVAL; } @@ -289,7 +290,7 @@ auto DrmPlane::AtomicDisablePlane(drmModeAtomicReq &pset) -> int { return 0; } -const DrmProperty &DrmPlane::zpos_property() const { +const DrmProperty &DrmPlane::GetZPosProperty() const { return zpos_property_; } diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h index 34bba56..e1ee920 100644 --- a/drm/DrmPlane.h +++ b/drm/DrmPlane.h @@ -17,9 +17,9 @@ #ifndef ANDROID_DRM_PLANE_H_ #define ANDROID_DRM_PLANE_H_ -#include <stdint.h> #include <xf86drmMode.h> +#include <cstdint> #include <vector> #include "DrmCrtc.h" @@ -29,6 +29,7 @@ namespace android { class DrmDevice; +struct DrmHwcLayer; class DrmPlane { public: @@ -38,12 +39,10 @@ class DrmPlane { int Init(); - uint32_t id() const; - bool GetCrtcSupported(const DrmCrtc &crtc) const; bool IsValidForLayer(DrmHwcLayer *layer); - uint32_t type() const; + uint32_t GetType() const; bool IsFormatSupported(uint32_t format) const; bool HasNonRgbFormat() const; @@ -51,7 +50,7 @@ class DrmPlane { auto AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos, uint32_t crtc_id) -> int; auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int; - const DrmProperty &zpos_property() const; + const DrmProperty &GetZPosProperty() const; private: DrmDevice *drm_; diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h index 68f300f..26a7c38 100644 --- a/drm/DrmProperty.h +++ b/drm/DrmProperty.h @@ -17,9 +17,9 @@ #ifndef ANDROID_DRM_PROPERTY_H_ #define ANDROID_DRM_PROPERTY_H_ -#include <stdint.h> #include <xf86drmMode.h> +#include <cstdint> #include <map> #include <string> #include <vector> @@ -62,14 +62,14 @@ class DrmProperty { auto AddEnumToMap(const std::string &name, E key, std::map<E, uint64_t> &map) -> bool; - operator bool() const { + explicit operator bool() const { return id_ != 0; } private: class DrmPropertyEnum { public: - DrmPropertyEnum(drm_mode_property_enum *e); + explicit DrmPropertyEnum(drm_mode_property_enum *e); ~DrmPropertyEnum() = default; uint64_t value_; diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp index 8baa4cb..46f77e4 100644 --- a/drm/ResourceManager.cpp +++ b/drm/ResourceManager.cpp @@ -24,6 +24,8 @@ #include <sstream> #include "bufferinfo/BufferInfoGetter.h" +#include "drm/DrmDevice.h" +#include "drm/DrmPlane.h" #include "utils/log.h" #include "utils/properties.h" @@ -32,6 +34,10 @@ namespace android { ResourceManager::ResourceManager() : num_displays_(0) { } +ResourceManager::~ResourceManager() { + uevent_listener_.Exit(); +} + int ResourceManager::Init() { char path_pattern[PROPERTY_VALUE_MAX]; // Could be a valid path or it can have at the end of it the wildcard % @@ -43,12 +49,12 @@ int ResourceManager::Init() { ret = AddDrmDevice(std::string(path_pattern)); } else { path_pattern[path_len - 1] = '\0'; - for (int idx = 0; !ret; ++idx) { + for (int idx = 0; ret == 0; ++idx) { std::ostringstream path; path << path_pattern << idx; struct stat buf {}; - if (stat(path.str().c_str(), &buf)) + if (stat(path.str().c_str(), &buf) != 0) break; if (DrmDevice::IsKMSDev(path.str().c_str())) @@ -56,22 +62,22 @@ int ResourceManager::Init() { } } - if (!num_displays_) { + if (num_displays_ == 0) { ALOGE("Failed to initialize any displays"); - return ret ? -EINVAL : ret; + return ret != 0 ? -EINVAL : ret; } 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)); - if (!BufferInfoGetter::GetInstance()) { + if (BufferInfoGetter::GetInstance() == nullptr) { ALOGE("Failed to initialize BufferInfoGetter"); return -EINVAL; } ret = uevent_listener_.Init(); - if (ret) { + if (ret != 0) { ALOGE("Can't initialize event listener %d", ret); return ret; } diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h index 5ffe92c..773b350 100644 --- a/drm/ResourceManager.h +++ b/drm/ResourceManager.h @@ -17,11 +17,11 @@ #ifndef RESOURCEMANAGER_H #define RESOURCEMANAGER_H -#include <string.h> +#include <cstring> #include "DrmDevice.h" -#include "UEventListener.h" #include "DrmFbImporter.h" +#include "UEventListener.h" namespace android { @@ -30,19 +30,17 @@ class ResourceManager { ResourceManager(); ResourceManager(const ResourceManager &) = delete; ResourceManager &operator=(const ResourceManager &) = delete; - ~ResourceManager() { - uevent_listener_.Exit(); - } + ~ResourceManager(); int Init(); DrmDevice *GetDrmDevice(int display); - const std::vector<std::unique_ptr<DrmDevice>> &getDrmDevices() const { + const std::vector<std::unique_ptr<DrmDevice>> &GetDrmDevices() const { return drms_; } - int getDisplayCount() const { + int GetDisplayCount() const { return num_displays_; } - bool ForcedScalingWithGpu() { + bool ForcedScalingWithGpu() const { return scale_with_gpu_; } diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp index eae0608..470e89a 100644 --- a/drm/UEventListener.cpp +++ b/drm/UEventListener.cpp @@ -40,6 +40,7 @@ int UEventListener::Init() { uevent_fd_ = UniqueFd( socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)); if (!uevent_fd_) { + // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme ALOGE("Failed to open uevent socket: %s", strerror(errno)); return -errno; } @@ -51,6 +52,7 @@ int UEventListener::Init() { int ret = bind(uevent_fd_.Get(), (struct sockaddr *)&addr, sizeof(addr)); if (ret) { + // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme ALOGE("Failed to bind uevent socket: %s", strerror(errno)); return -errno; } diff --git a/drm/UEventListener.h b/drm/UEventListener.h index 048eb40..0724443 100644 --- a/drm/UEventListener.h +++ b/drm/UEventListener.h @@ -27,16 +27,16 @@ namespace android { class UEventListener : public Worker { public: UEventListener(); - virtual ~UEventListener() = default; + ~UEventListener() override = default; int Init(); void RegisterHotplugHandler(std::function<void()> hotplug_handler) { - hotplug_handler_ = hotplug_handler; + hotplug_handler_ = std::move(hotplug_handler); } protected: - virtual void Routine(); + void Routine() override; private: UniqueFd uevent_fd_; diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h index 74ff487..67aaa16 100644 --- a/drm/VSyncWorker.h +++ b/drm/VSyncWorker.h @@ -20,9 +20,9 @@ #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include <hardware/hwcomposer2.h> -#include <stdint.h> #include <atomic> +#include <cstdint> #include <functional> #include <map> diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp new file mode 100644 index 0000000..5bbb48a --- /dev/null +++ b/hwc2_device/DrmHwcTwo.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 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. + */ + +#define LOG_TAG "hwc-drm-two" + +#include "DrmHwcTwo.h" + +#include "backend/Backend.h" +#include "utils/log.h" + +namespace android { + +DrmHwcTwo::DrmHwcTwo() = default; + +HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ, + HWC2::DisplayType type) { + DrmDevice *drm = resource_manager_.GetDrmDevice(static_cast<int>(displ)); + if (!drm) { + ALOGE("Failed to get a valid drmresource"); + return HWC2::Error::NoResources; + } + displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ), + std::forward_as_tuple(&resource_manager_, drm, displ, type, + this)); + + DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ)); + if (!crtc) { + ALOGE("Failed to get crtc for display %d", static_cast<int>(displ)); + return HWC2::Error::BadDisplay; + } + auto display_planes = std::vector<DrmPlane *>(); + for (const auto &plane : drm->planes()) { + if (plane->GetCrtcSupported(*crtc)) + display_planes.push_back(plane.get()); + } + displays_.at(displ).Init(&display_planes); + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::Init() { + int rv = resource_manager_.Init(); + if (rv) { + ALOGE("Can't initialize the resource manager %d", rv); + return HWC2::Error::NoResources; + } + + HWC2::Error ret = HWC2::Error::None; + for (int i = 0; i < resource_manager_.GetDisplayCount(); i++) { + ret = CreateDisplay(i, HWC2::DisplayType::Physical); + if (ret != HWC2::Error::None) { + ALOGE("Failed to create display %d with error %d", i, ret); + return ret; + } + } + + resource_manager_.GetUEventListener()->RegisterHotplugHandler( + [this] { HandleHotplugUEvent(); }); + + return ret; +} + +HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t /*width*/, + uint32_t /*height*/, + int32_t * /*format*/, + hwc2_display_t * /*display*/) { + // TODO(nobody): Implement virtual display + return HWC2::Error::Unsupported; +} + +HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t /*display*/) { + // TODO(nobody): Implement virtual display + return HWC2::Error::Unsupported; +} + +void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) { + if (outBuffer != nullptr) { + auto copied_bytes = mDumpString.copy(outBuffer, *outSize); + *outSize = static_cast<uint32_t>(copied_bytes); + return; + } + + std::stringstream output; + + output << "-- drm_hwcomposer --\n\n"; + + for (std::pair<const hwc2_display_t, HwcDisplay> &dp : displays_) + output << dp.second.Dump(); + + mDumpString = output.str(); + *outSize = static_cast<uint32_t>(mDumpString.size()); +} + +uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() { + // TODO(nobody): Implement virtual display + return 0; +} + +HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, + hwc2_callback_data_t data, + hwc2_function_pointer_t function) { + std::unique_lock<std::mutex> lock(callback_lock_); + + switch (static_cast<HWC2::Callback>(descriptor)) { + case HWC2::Callback::Hotplug: { + hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data); + lock.unlock(); + const auto &drm_devices = resource_manager_.GetDrmDevices(); + for (const auto &device : drm_devices) + HandleInitialHotplugState(device.get()); + break; + } + case HWC2::Callback::Refresh: { + refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data); + break; + } + case HWC2::Callback::Vsync: { + vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data); + break; + } +#if PLATFORM_SDK_VERSION > 29 + case HWC2::Callback::Vsync_2_4: { + vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data); + break; + } +#endif + default: + break; + } + return HWC2::Error::None; +} + +void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) { + const std::lock_guard<std::mutex> lock(callback_lock_); + + if (hotplug_callback_.first != nullptr && + hotplug_callback_.second != nullptr) { + hotplug_callback_.first(hotplug_callback_.second, displayid, + state == DRM_MODE_CONNECTED + ? HWC2_CONNECTION_CONNECTED + : HWC2_CONNECTION_DISCONNECTED); + } +} + +void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) { + for (const auto &conn : drmDevice->connectors()) { + if (conn->state() != DRM_MODE_CONNECTED) + continue; + HandleDisplayHotplug(conn->display(), conn->state()); + } +} + +void DrmHwcTwo::HandleHotplugUEvent() { + for (const auto &drm : resource_manager_.GetDrmDevices()) { + for (const auto &conn : drm->connectors()) { + drmModeConnection old_state = conn->state(); + drmModeConnection cur_state = conn->UpdateModes() + ? DRM_MODE_UNKNOWNCONNECTION + : conn->state(); + + if (cur_state == old_state) + continue; + + ALOGI("%s event for connector %u on display %d", + cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", conn->id(), + conn->display()); + + int display_id = conn->display(); + if (cur_state == DRM_MODE_CONNECTED) { + auto &display = displays_.at(display_id); + display.ChosePreferredConfig(); + } else { + auto &display = displays_.at(display_id); + display.ClearDisplay(); + } + + HandleDisplayHotplug(display_id, cur_state); + } + } +} + +} // namespace android diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h new file mode 100644 index 0000000..d096160 --- /dev/null +++ b/hwc2_device/DrmHwcTwo.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 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_DRM_HWC_TWO_H_ +#define ANDROID_DRM_HWC_TWO_H_ + +#include <hardware/hwcomposer2.h> + +#include "drm/ResourceManager.h" +#include "hwc2_device/HwcDisplay.h" + +namespace android { + +class DrmHwcTwo { + public: + DrmHwcTwo(); + + HWC2::Error Init(); + + 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 + std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{}; +#endif + std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{}; + + std::mutex callback_lock_; + + static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) { + auto it = hwc->displays_.find(display_handle); + if (it == hwc->displays_.end()) + return nullptr; + + return &it->second; + } + + // Device functions + HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height, + int32_t *format, hwc2_display_t *display); + HWC2::Error DestroyVirtualDisplay(hwc2_display_t display); + void Dump(uint32_t *outSize, char *outBuffer); + uint32_t GetMaxVirtualDisplayCount(); + HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data, + hwc2_function_pointer_t function); + HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type); + + private: + void HandleDisplayHotplug(hwc2_display_t displayid, int state); + void HandleInitialHotplugState(DrmDevice *drmDevice); + + void HandleHotplugUEvent(); + + ResourceManager resource_manager_; + std::map<hwc2_display_t, HwcDisplay> displays_; + + std::string mDumpString; +}; +} // namespace android + +#endif diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp new file mode 100644 index 0000000..9055a9a --- /dev/null +++ b/hwc2_device/HwcDisplay.cpp @@ -0,0 +1,827 @@ +/* + * 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. + */ + +#define LOG_TAG "hwc-display" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "HwcDisplay.h" + +#include "DrmHwcTwo.h" +#include "backend/BackendManager.h" +#include "bufferinfo/BufferInfoGetter.h" +#include "utils/log.h" +#include "utils/properties.h" + +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_); + + std::stringstream ss; + ss << " Total frames count: " << delta.total_frames_ << "\n" + << " Failed to test commit frames: " << delta.failed_kms_validate_ << "\n" + << " Failed to commit frames: " << delta.failed_kms_present_ << "\n" + << ((delta.failed_kms_present_ > 0) + ? " !!! Internal failure, FIX it please\n" + : "") + << " Flattened frames: " << delta.frames_flattened_ << "\n" + << " Pixel operations (free units)" + << " : [TOTAL: " << delta.total_pixops_ << " / GPU: " << delta.gpu_pixops_ + << "]\n" + << " Composition efficiency: " << ratio; + + return ss.str(); +} + +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::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" + << DumpDelta(total_stats_.minus(prev_stats_)) << "\n\n"; + + memcpy(&prev_stats_, &total_stats_, sizeof(Stats)); + return ss.str(); +} + +HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm, + hwc2_display_t handle, HWC2::DisplayType type, + DrmHwcTwo *hwc2) + : hwc2_(hwc2), + resource_manager_(resource_manager), + drm_(drm), + handle_(handle), + type_(type), + 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 +} + +void HwcDisplay::ClearDisplay() { + AtomicCommitArgs a_args = {.clear_active_composition = true}; + compositor_.ExecuteAtomicCommit(a_args); +} + +HWC2::Error HwcDisplay::Init(std::vector<DrmPlane *> *planes) { + int display = static_cast<int>(handle_); + int ret = compositor_.Init(resource_manager_, display); + if (ret) { + ALOGE("Failed display compositor init for display %d (%d)", display, ret); + return HWC2::Error::NoResources; + } + + // Split up the given display planes into primary and overlay to properly + // interface with the composition + char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; + property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop, + "1"); + bool use_overlay_planes = strtol(use_overlay_planes_prop, nullptr, 10); + for (auto &plane : *planes) { + if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) + primary_planes_.push_back(plane); + else if (use_overlay_planes && (plane)->GetType() == DRM_PLANE_TYPE_OVERLAY) + overlay_planes_.push_back(plane); + } + + crtc_ = drm_->GetCrtcForDisplay(display); + if (!crtc_) { + ALOGE("Failed to get crtc for display %d", display); + return HWC2::Error::BadDisplay; + } + + connector_ = drm_->GetConnectorForDisplay(display); + if (!connector_) { + ALOGE("Failed to get connector for display %d", display); + return HWC2::Error::BadDisplay; + } + + ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) { + const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_); + /* vsync callback */ +#if PLATFORM_SDK_VERSION > 29 + if (hwc2_->vsync_2_4_callback_.first != nullptr && + hwc2_->vsync_2_4_callback_.second != nullptr) { + hwc2_vsync_period_t period_ns{}; + GetDisplayVsyncPeriod(&period_ns); + hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second, + handle_, timestamp, period_ns); + } else +#endif + if (hwc2_->vsync_callback_.first != nullptr && + hwc2_->vsync_callback_.second != nullptr) { + hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_, + timestamp); + } + }); + if (ret) { + ALOGE("Failed to create event worker for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + ret = flattening_vsync_worker_ + .Init(drm_, display, [this](int64_t /*timestamp*/) { + const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_); + /* Frontend flattening */ + 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_); + flattening_vsync_worker_.VSyncControl(false); + } + }); + if (ret) { + ALOGE("Failed to create event worker for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + ret = BackendManager::GetInstance().SetBackendForDisplay(this); + if (ret) { + ALOGE("Failed to set backend for d=%d %d\n", display, ret); + return HWC2::Error::BadDisplay; + } + + client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED); + + return ChosePreferredConfig(); +} + +HWC2::Error HwcDisplay::ChosePreferredConfig() { + HWC2::Error err = configs_.Update(*connector_); + if (err != HWC2::Error::None) + return HWC2::Error::BadDisplay; + + return SetActiveConfig(configs_.preferred_config_id); +} + +HWC2::Error HwcDisplay::AcceptDisplayChanges() { + for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) + l.second.AcceptTypeChange(); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) { + layers_.emplace(static_cast<hwc2_layer_t>(layer_idx_), HwcLayer()); + *layer = static_cast<hwc2_layer_t>(layer_idx_); + ++layer_idx_; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) { + if (!get_layer(layer)) + return HWC2::Error::BadLayer; + + layers_.erase(layer); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const { + if (configs_.hwc_configs.count(configs_.active_config_id) == 0) + return HWC2::Error::BadConfig; + + *config = configs_.active_config_id; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *types) { + uint32_t num_changes = 0; + for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) { + if (l.second.IsTypeChanged()) { + if (layers && num_changes < *num_elements) + layers[num_changes] = l.first; + if (types && num_changes < *num_elements) + types[num_changes] = static_cast<int32_t>(l.second.GetValidatedType()); + ++num_changes; + } + } + if (!layers && !types) + *num_elements = num_changes; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t /*format*/, + int32_t dataspace) { + std::pair<uint32_t, uint32_t> min = drm_->min_resolution(); + std::pair<uint32_t, uint32_t> max = drm_->max_resolution(); + + if (width < min.first || height < min.second) + return HWC2::Error::Unsupported; + + if (width > max.first || height > max.second) + return HWC2::Error::Unsupported; + + if (dataspace != HAL_DATASPACE_UNKNOWN) + return HWC2::Error::Unsupported; + + // TODO(nobody): Validate format can be handled by either GL or planes + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) { + if (!modes) + *num_modes = 1; + + if (modes) + *modes = HAL_COLOR_MODE_NATIVE; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config, + int32_t attribute_in, + int32_t *value) { + int conf = static_cast<int>(config); + + if (configs_.hwc_configs.count(conf) == 0) { + ALOGE("Could not find active mode for %d", conf); + return HWC2::Error::BadConfig; + } + + auto &hwc_config = configs_.hwc_configs[conf]; + + static const int32_t kUmPerInch = 25400; + uint32_t mm_width = connector_->mm_width(); + uint32_t mm_height = connector_->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()); + break; + case HWC2::Attribute::Height: + *value = static_cast<int>(hwc_config.mode.v_display()); + break; + case HWC2::Attribute::VsyncPeriod: + // in nanoseconds + *value = static_cast<int>(1E9 / hwc_config.mode.v_refresh()); + break; + case HWC2::Attribute::DpiX: + // Dots per 1000 inches + *value = mm_width ? static_cast<int>(hwc_config.mode.h_display() * + 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) + : -1; + break; +#if PLATFORM_SDK_VERSION > 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 */ + *value = hwc_config.group_id; + break; +#endif + default: + *value = -1; + return HWC2::Error::BadConfig; + } + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs, + hwc2_config_t *configs) { + // Since this callback is normally invoked twice (once to get the count, and + // once to populate configs), we don't really want to read the edid + // redundantly. Instead, only update the modes on the first invocation. While + // it's possible this will result in stale modes, it'll all come out in the + // wash when we try to set the active config later. + if (!configs) { + configs_.Update(*connector_); + } + + uint32_t idx = 0; + for (auto &hwc_config : configs_.hwc_configs) { + if (hwc_config.second.disabled) { + continue; + } + + if (configs != nullptr) { + if (idx >= *num_configs) { + break; + } + configs[idx] = hwc_config.second.id; + } + + idx++; + } + *num_configs = idx; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) { + std::ostringstream stream; + stream << "display-" << connector_->id(); + std::string string = stream.str(); + size_t length = string.length(); + if (!name) { + *size = length; + return HWC2::Error::None; + } + + *size = std::min<uint32_t>(static_cast<uint32_t>(length - 1), *size); + strncpy(name, string.c_str(), *size); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayRequests(int32_t * /*display_requests*/, + uint32_t *num_elements, + hwc2_layer_t * /*layers*/, + int32_t * /*layer_requests*/) { + // TODO(nobody): I think virtual display should request + // HWC2_DISPLAY_REQUEST_WRITE_CLIENT_TARGET_TO_OUTPUT here + *num_elements = 0; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayType(int32_t *type) { + *type = static_cast<int32_t>(type_); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDozeSupport(int32_t *support) { + *support = 0; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types, + int32_t * /*types*/, + float * /*max_luminance*/, + float * /*max_average_luminance*/, + float * /*min_luminance*/) { + *num_types = 0; + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1767 + */ +HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements, + hwc2_layer_t *layers, + int32_t *fences) { + uint32_t num_layers = 0; + + for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) { + ++num_layers; + if (layers == nullptr || fences == nullptr) + continue; + + if (num_layers > *num_elements) { + ALOGW("Overflow num_elements %d/%d", num_layers, *num_elements); + return HWC2::Error::None; + } + + layers[num_layers - 1] = l.first; + fences[num_layers - 1] = l.second.GetReleaseFence().Release(); + } + *num_elements = num_layers; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { + // order the layers by z-order + bool use_client_layer = false; + uint32_t client_z_order = UINT32_MAX; + std::map<uint32_t, HwcLayer *> z_map; + 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)); + break; + case HWC2::Composition::Client: + // Place it at the z_order of the lowest client layer + use_client_layer = true; + client_z_order = std::min(client_z_order, l.second.GetZOrder()); + break; + default: + continue; + } + } + if (use_client_layer) + z_map.emplace(std::make_pair(client_z_order, &client_layer_)); + + if (z_map.empty()) + return HWC2::Error::BadLayer; + + std::vector<DrmHwcLayer> composition_layers; + + // now that they're ordered by z, add them to the composition + for (std::pair<const uint32_t, HwcLayer *> &l : z_map) { + DrmHwcLayer layer; + l.second->PopulateDrmLayer(&layer); + int ret = layer.ImportBuffer(drm_); + if (ret) { + ALOGE("Failed to import layer, ret=%d", ret); + return HWC2::Error::NoResources; + } + composition_layers.emplace_back(std::move(layer)); + } + + auto composition = std::make_shared<DrmDisplayComposition>(crtc_); + + // TODO(nobody): Don't always assume geometry changed + int ret = composition->SetLayers(composition_layers.data(), + composition_layers.size()); + if (ret) { + ALOGE("Failed to set layers in the composition ret=%d", ret); + return HWC2::Error::BadLayer; + } + + std::vector<DrmPlane *> primary_planes(primary_planes_); + std::vector<DrmPlane *> overlay_planes(overlay_planes_); + ret = composition->Plan(&primary_planes, &overlay_planes); + if (ret) { + ALOGV("Failed to plan the composition ret=%d", ret); + return HWC2::Error::BadConfig; + } + + a_args.composition = composition; + if (staged_mode) { + a_args.display_mode = *staged_mode; + } + ret = compositor_.ExecuteAtomicCommit(a_args); + + if (ret) { + if (!a_args.test_only) + ALOGE("Failed to apply the frame composition ret=%d", ret); + return HWC2::Error::BadParameter; + } + + if (!a_args.test_only) { + staged_mode.reset(); + } + + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805 + */ +HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) { + HWC2::Error ret; + + ++total_stats_.total_frames_; + + AtomicCommitArgs a_args{}; + ret = CreateComposition(a_args); + + if (ret != HWC2::Error::None) + ++total_stats_.failed_kms_present_; + + if (ret == HWC2::Error::BadLayer) { + // Can we really have no client or device layers? + *present_fence = -1; + return HWC2::Error::None; + } + if (ret != HWC2::Error::None) + return ret; + + *present_fence = a_args.out_fence.Release(); + + ++frame_no_; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) { + int conf = static_cast<int>(config); + + if (configs_.hwc_configs.count(conf) == 0) { + ALOGE("Could not find active mode for %d", conf); + return HWC2::Error::BadConfig; + } + + auto &mode = configs_.hwc_configs[conf].mode; + + staged_mode = mode; + + configs_.active_config_id = conf; + + // Setup the client layer's dimensions + hwc_rect_t display_frame = {.left = 0, + .top = 0, + .right = static_cast<int>(mode.h_display()), + .bottom = static_cast<int>(mode.v_display())}; + client_layer_.SetLayerDisplayFrame(display_frame); + + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861 + */ +HWC2::Error HwcDisplay::SetClientTarget(buffer_handle_t target, + int32_t acquire_fence, + int32_t dataspace, + hwc_region_t /*damage*/) { + client_layer_.SetLayerBuffer(target, acquire_fence); + client_layer_.SetLayerDataspace(dataspace); + + /* + * target can be nullptr, this does mean the Composer Service is calling + * cleanDisplayResources() on after receiving HOTPLUG event. See more at: + * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h;l=350;drc=944b68180b008456ed2eb4d4d329e33b19bd5166 + */ + if (target == nullptr) { + return HWC2::Error::None; + } + + /* TODO: Do not update source_crop every call. + * It makes sense to do it once after every hotplug event. */ + HwcDrmBo bo{}; + BufferInfoGetter::GetInstance()->ConvertBoInfo(target, &bo); + + hwc_frect_t source_crop = {.left = 0.0F, + .top = 0.0F, + .right = static_cast<float>(bo.width), + .bottom = static_cast<float>(bo.height)}; + client_layer_.SetLayerSourceCrop(source_crop); + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetColorMode(int32_t mode) { + if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) + return HWC2::Error::BadParameter; + + if (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::Unsupported; + + color_mode_ = mode; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetColorTransform(const float *matrix, int32_t hint) { + if (hint < HAL_COLOR_TRANSFORM_IDENTITY || + hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA) + return HWC2::Error::BadParameter; + + if (!matrix && hint == HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) + 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()); + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/, + int32_t /*release_fence*/) { + // TODO(nobody): Need virtual display support + return HWC2::Error::Unsupported; +} + +HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) { + auto mode = static_cast<HWC2::PowerMode>(mode_in); + AtomicCommitArgs a_args{}; + + switch (mode) { + case HWC2::PowerMode::Off: + a_args.active = false; + break; + case HWC2::PowerMode::On: + /* + * Setting the display to active before we have a composition + * can break some drivers, so skip setting a_args.active to + * true, as the next composition frame will implicitly activate + * the display + */ + return compositor_.ActivateDisplayUsingDPMS() == 0 + ? HWC2::Error::None + : HWC2::Error::BadParameter; + break; + case HWC2::PowerMode::Doze: + case HWC2::PowerMode::DozeSuspend: + return HWC2::Error::Unsupported; + default: + ALOGI("Power mode %d is unsupported\n", mode); + return HWC2::Error::BadParameter; + }; + + int err = compositor_.ExecuteAtomicCommit(a_args); + if (err) { + ALOGE("Failed to apply the dpms composition err=%d", err); + return HWC2::Error::BadParameter; + } + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) { + vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled); + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types, + uint32_t *num_requests) { + return backend_->ValidateDisplay(this, num_types, num_requests); +} + +std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() { + std::vector<HwcLayer *> ordered_layers; + ordered_layers.reserve(layers_.size()); + + for (auto &[handle, layer] : layers_) { + ordered_layers.emplace_back(&layer); + } + + std::sort(std::begin(ordered_layers), std::end(ordered_layers), + [](const HwcLayer *lhs, const HwcLayer *rhs) { + return lhs->GetZOrder() < rhs->GetZOrder(); + }); + + return ordered_layers; +} + +#if PLATFORM_SDK_VERSION > 29 +HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) { + if (connector_->internal()) + *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal); + else if (connector_->external()) + *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External); + else + return HWC2::Error::BadConfig; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayVsyncPeriod( + hwc2_vsync_period_t *outVsyncPeriod /* ns */) { + return GetDisplayAttribute(configs_.active_config_id, + HWC2_ATTRIBUTE_VSYNC_PERIOD, + (int32_t *)(outVsyncPeriod)); +} + +HWC2::Error HwcDisplay::SetActiveConfigWithConstraints( + hwc2_config_t /*config*/, + hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t *outTimeline) { + if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) { + return HWC2::Error::BadParameter; + } + + return HWC2::Error::BadConfig; +} + +HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) { + return HWC2::Error::Unsupported; +} + +HWC2::Error HwcDisplay::GetSupportedContentTypes( + uint32_t *outNumSupportedContentTypes, + const uint32_t *outSupportedContentTypes) { + if (outSupportedContentTypes == nullptr) + *outNumSupportedContentTypes = 0; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetContentType(int32_t contentType) { + if (contentType != HWC2_CONTENT_TYPE_NONE) + return HWC2::Error::Unsupported; + + /* TODO: Map to the DRM Connector property: + * https://elixir.bootlin.com/linux/v5.4-rc5/source/drivers/gpu/drm/drm_connector.c#L809 + */ + + return HWC2::Error::None; +} +#endif + +#if PLATFORM_SDK_VERSION > 28 +HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort, + uint32_t *outDataSize, + uint8_t *outData) { + auto blob = connector_->GetEdidBlob(); + + if (!blob) { + ALOGE("Failed to get edid property value."); + return HWC2::Error::Unsupported; + } + + if (outData) { + *outDataSize = std::min(*outDataSize, blob->length); + memcpy(outData, blob->data, *outDataSize); + } else { + *outDataSize = blob->length; + } + *outPort = connector_->id(); + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayCapabilities(uint32_t *outNumCapabilities, + uint32_t * /*outCapabilities*/) { + if (outNumCapabilities == nullptr) { + return HWC2::Error::BadParameter; + } + + *outNumCapabilities = 0; + + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::GetDisplayBrightnessSupport(bool *supported) { + *supported = false; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetDisplayBrightness(float /* brightness */) { + return HWC2::Error::Unsupported; +} + +#endif /* PLATFORM_SDK_VERSION > 28 */ + +#if PLATFORM_SDK_VERSION > 27 + +HWC2::Error HwcDisplay::GetRenderIntents( + int32_t mode, uint32_t *outNumIntents, + int32_t * /*android_render_intent_v1_1_t*/ outIntents) { + if (mode != HAL_COLOR_MODE_NATIVE) { + return HWC2::Error::BadParameter; + } + + if (outIntents == nullptr) { + *outNumIntents = 1; + return HWC2::Error::None; + } + *outNumIntents = 1; + outIntents[0] = HAL_RENDER_INTENT_COLORIMETRIC; + return HWC2::Error::None; +} + +HWC2::Error HwcDisplay::SetColorModeWithIntent(int32_t mode, int32_t intent) { + if (intent < HAL_RENDER_INTENT_COLORIMETRIC || + intent > HAL_RENDER_INTENT_TONE_MAP_ENHANCE) + return HWC2::Error::BadParameter; + + if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_BT2100_HLG) + return HWC2::Error::BadParameter; + + if (mode != HAL_COLOR_MODE_NATIVE) + return HWC2::Error::Unsupported; + + if (intent != HAL_RENDER_INTENT_COLORIMETRIC) + return HWC2::Error::Unsupported; + + color_mode_ = mode; + return HWC2::Error::None; +} + +#endif /* PLATFORM_SDK_VERSION > 27 */ + +const Backend *HwcDisplay::backend() const { + return backend_.get(); +} + +void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) { + backend_ = std::move(backend); +} + +} // namespace android diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h new file mode 100644 index 0000000..6f46f5d --- /dev/null +++ b/hwc2_device/HwcDisplay.h @@ -0,0 +1,252 @@ +/* + * 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. + */ + +#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_H +#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_H + +#include <hardware/hwcomposer2.h> + +#include <optional> + +#include "HwcDisplayConfigs.h" +#include "compositor/DrmDisplayCompositor.h" +#include "drm/ResourceManager.h" +#include "drm/VSyncWorker.h" +#include "drmhwcomposer.h" +#include "hwc2_device/HwcLayer.h" + +namespace android { + +class Backend; +class DrmHwcTwo; + +class HwcDisplay { + public: + HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm, + hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2); + HwcDisplay(const HwcDisplay &) = delete; + HWC2::Error Init(std::vector<DrmPlane *> *planes); + + HWC2::Error CreateComposition(AtomicCommitArgs &a_args); + std::vector<HwcLayer *> GetOrderLayersByZPos(); + + void ClearDisplay(); + + std::string Dump(); + + // HWC Hooks + HWC2::Error AcceptDisplayChanges(); + HWC2::Error CreateLayer(hwc2_layer_t *layer); + HWC2::Error DestroyLayer(hwc2_layer_t layer); + HWC2::Error GetActiveConfig(hwc2_config_t *config) const; + HWC2::Error GetChangedCompositionTypes(uint32_t *num_elements, + hwc2_layer_t *layers, int32_t *types); + HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, + int32_t format, int32_t dataspace); + HWC2::Error GetColorModes(uint32_t *num_modes, int32_t *modes); + HWC2::Error GetDisplayAttribute(hwc2_config_t config, int32_t attribute, + int32_t *value); + HWC2::Error GetDisplayConfigs(uint32_t *num_configs, hwc2_config_t *configs); + HWC2::Error GetDisplayName(uint32_t *size, char *name); + HWC2::Error GetDisplayRequests(int32_t *display_requests, + uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *layer_requests); + HWC2::Error GetDisplayType(int32_t *type); +#if PLATFORM_SDK_VERSION > 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 + HWC2::Error GetDisplayIdentificationData(uint8_t *outPort, + uint32_t *outDataSize, + uint8_t *outData); + HWC2::Error GetDisplayCapabilities(uint32_t *outNumCapabilities, + uint32_t *outCapabilities); + HWC2::Error GetDisplayBrightnessSupport(bool *supported); + HWC2::Error SetDisplayBrightness(float); +#endif +#if PLATFORM_SDK_VERSION > 29 + HWC2::Error GetDisplayConnectionType(uint32_t *outType); + HWC2::Error GetDisplayVsyncPeriod(hwc2_vsync_period_t *outVsyncPeriod); + + HWC2::Error SetActiveConfigWithConstraints( + hwc2_config_t config, + hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, + hwc_vsync_period_change_timeline_t *outTimeline); + HWC2::Error SetAutoLowLatencyMode(bool on); + HWC2::Error GetSupportedContentTypes( + uint32_t *outNumSupportedContentTypes, + const uint32_t *outSupportedContentTypes); + + HWC2::Error SetContentType(int32_t contentType); +#endif + + HWC2::Error GetDozeSupport(int32_t *support); + HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types, + float *max_luminance, + float *max_average_luminance, + float *min_luminance); + HWC2::Error GetReleaseFences(uint32_t *num_elements, hwc2_layer_t *layers, + int32_t *fences); + HWC2::Error PresentDisplay(int32_t *present_fence); + HWC2::Error SetActiveConfig(hwc2_config_t config); + HWC2::Error ChosePreferredConfig(); + HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence, + int32_t dataspace, hwc_region_t damage); + HWC2::Error SetColorMode(int32_t mode); + HWC2::Error SetColorTransform(const float *matrix, int32_t hint); + HWC2::Error SetOutputBuffer(buffer_handle_t buffer, int32_t release_fence); + HWC2::Error SetPowerMode(int32_t mode); + HWC2::Error SetVsyncEnabled(int32_t enabled); + HWC2::Error ValidateDisplay(uint32_t *num_types, uint32_t *num_requests); + HwcLayer *get_layer(hwc2_layer_t layer) { + auto it = layers_.find(layer); + if (it == layers_.end()) + return nullptr; + return &it->second; + } + + /* Statistics */ + struct Stats { + Stats minus(Stats b) const { + return {total_frames_ - b.total_frames_, + total_pixops_ - b.total_pixops_, + gpu_pixops_ - b.gpu_pixops_, + failed_kms_validate_ - b.failed_kms_validate_, + failed_kms_present_ - b.failed_kms_present_, + frames_flattened_ - b.frames_flattened_}; + } + + uint32_t total_frames_ = 0; + uint64_t total_pixops_ = 0; + uint64_t gpu_pixops_ = 0; + uint32_t failed_kms_validate_ = 0; + uint32_t failed_kms_present_ = 0; + uint32_t frames_flattened_ = 0; + }; + + const Backend *backend() const; + void set_backend(std::unique_ptr<Backend> backend); + + const std::vector<DrmPlane *> &primary_planes() const { + return primary_planes_; + } + + const std::vector<DrmPlane *> &overlay_planes() const { + return overlay_planes_; + } + + std::map<hwc2_layer_t, HwcLayer> &layers() { + return layers_; + } + + const DrmDisplayCompositor &compositor() const { + return compositor_; + } + + const DrmDevice *drm() const { + return drm_; + } + + const DrmConnector *connector() const { + return connector_; + } + + ResourceManager *resource_manager() const { + return resource_manager_; + } + + android_color_transform_t &color_transform_hint() { + return color_transform_hint_; + } + + Stats &total_stats() { + return total_stats_; + } + + /* returns true if composition should be sent to client */ + bool 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; + } + + flattening_vsync_worker_.VSyncControl(true); + flattenning_state_ = ClientFlattenningState::VsyncCountdownMax; + return false; + } + + 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}; + VSyncWorker flattening_vsync_worker_; + + constexpr static size_t MATRIX_SIZE = 16; + + HwcDisplayConfigs configs_; + + DrmHwcTwo *hwc2_; + + std::optional<DrmMode> staged_mode; + + ResourceManager *resource_manager_; + DrmDevice *drm_; + DrmDisplayCompositor compositor_; + + std::vector<DrmPlane *> primary_planes_; + std::vector<DrmPlane *> overlay_planes_; + + std::unique_ptr<Backend> backend_; + + VSyncWorker vsync_worker_; + DrmConnector *connector_ = nullptr; + DrmCrtc *crtc_ = nullptr; + hwc2_display_t handle_; + HWC2::DisplayType type_; + uint32_t layer_idx_ = 0; + 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_; + + uint32_t frame_no_ = 0; + Stats total_stats_; + Stats prev_stats_; + std::string DumpDelta(HwcDisplay::Stats delta); +}; + +} // namespace android + +#endif diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp new file mode 100644 index 0000000..d1a8d4c --- /dev/null +++ b/hwc2_device/HwcDisplayConfigs.cpp @@ -0,0 +1,165 @@ +/* + * 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. + */ + +#define LOG_TAG "hwc-display-configs" + +#include "HwcDisplayConfigs.h" + +#include <cmath> + +#include "drm/DrmConnector.h" +#include "utils/log.h" + +namespace android { + +// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme +HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) { + int ret = connector.UpdateModes(); + if (ret != 0) { + ALOGE("Failed to update display modes %d", ret); + return HWC2::Error::BadDisplay; + } + + hwc_configs.clear(); + preferred_config_id = 0; + int preferred_config_group_id = 0; + + if (connector.modes().empty()) { + ALOGE("No modes reported by KMS"); + return HWC2::Error::BadDisplay; + } + + int last_config_id = 1; + int last_group_id = 1; + + /* Group modes */ + for (const auto &mode : connector.modes()) { + /* Find group for the new mode or create new group */ + int 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()) { + group_found = hwc_config.second.group_id; + } + } + if (group_found == 0) { + group_found = last_group_id++; + } + + bool disabled = false; + if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) { + ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)", + mode.name().c_str()); + disabled = true; + } + + /* Add config */ + hwc_configs[last_config_id] = { + .id = last_config_id, + .group_id = group_found, + .mode = mode, + .disabled = disabled, + }; + + /* Chwck if the mode is preferred */ + if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 && + preferred_config_id == 0) { + preferred_config_id = last_config_id; + preferred_config_group_id = group_found; + } + + last_config_id++; + } + + /* We must have preferred mode. Set first mode as preferred + * in case KMS haven't reported anything. */ + if (preferred_config_id == 0) { + preferred_config_id = 1; + preferred_config_group_id = 1; + } + + for (int group = 1; group < last_group_id; group++) { + bool has_interlaced = false; + bool has_progressive = false; + for (auto &hwc_config : hwc_configs) { + if (hwc_config.second.group_id != group || hwc_config.second.disabled) { + continue; + } + + if (hwc_config.second.IsInterlaced()) { + has_interlaced = true; + } else { + has_progressive = true; + } + } + + bool has_both = has_interlaced && has_progressive; + if (!has_both) { + continue; + } + + bool group_contains_preferred_interlaced = false; + if (group == preferred_config_group_id && + hwc_configs[preferred_config_id].IsInterlaced()) { + group_contains_preferred_interlaced = true; + } + + for (auto &hwc_config : hwc_configs) { + if (hwc_config.second.group_id != group || hwc_config.second.disabled) { + continue; + } + + bool disable = group_contains_preferred_interlaced + ? !hwc_config.second.IsInterlaced() + : hwc_config.second.IsInterlaced(); + + if (disable) { + ALOGI( + "Group %i: Disabling display mode %s (This group should consist " + "of %s modes)", + group, hwc_config.second.mode.name().c_str(), + group_contains_preferred_interlaced ? "interlaced" : "progressive"); + + hwc_config.second.disabled = true; + } + } + } + + /* Group should not contain 2 modes with FPS delta less than ~1HZ + * otherwise android.graphics.cts.SetFrameRateTest CTS will fail + */ + constexpr float kMinFpsDelta = 1.0; // FPS + for (int m1 = 1; m1 < last_config_id; m1++) { + for (int m2 = 1; 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) { + 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].disabled = true; + } + } + } + + return HWC2::Error::None; +} + +} // namespace android diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h new file mode 100644 index 0000000..cb38625 --- /dev/null +++ b/hwc2_device/HwcDisplayConfigs.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H +#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H + +#include <hardware/hwcomposer2.h> + +#include <map> + +#include "drm/DrmMode.h" + +namespace android { + +class DrmConnector; + +struct HwcDisplayConfig { + int id{}; + int group_id{}; + DrmMode mode; + bool disabled{}; + + bool IsInterlaced() const { + return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0; + } +}; + +struct HwcDisplayConfigs { + HWC2::Error Update(DrmConnector &conn); + + std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs; + + int active_config_id = 0; + int preferred_config_id = 0; +}; + +} // namespace android + +#endif diff --git a/hwc2_device/HwcLayer.cpp b/hwc2_device/HwcLayer.cpp new file mode 100644 index 0000000..66babda --- /dev/null +++ b/hwc2_device/HwcLayer.cpp @@ -0,0 +1,180 @@ +/* + * 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. + */ + +#define LOG_TAG "hwc-layer" + +#include "HwcLayer.h" + +#include <fcntl.h> + +#include "utils/log.h" + +namespace android { + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +HWC2::Error HwcLayer::SetCursorPosition(int32_t /*x*/, int32_t /*y*/) { + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerBlendMode(int32_t mode) { + switch (static_cast<HWC2::BlendMode>(mode)) { + case HWC2::BlendMode::None: + blending_ = DrmHwcBlending::kNone; + break; + case HWC2::BlendMode::Premultiplied: + blending_ = DrmHwcBlending::kPreMult; + break; + case HWC2::BlendMode::Coverage: + blending_ = DrmHwcBlending::kCoverage; + break; + default: + ALOGE("Unknown blending mode b=%d", blending_); + blending_ = DrmHwcBlending::kNone; + break; + } + return HWC2::Error::None; +} + +/* Find API details at: + * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=2314 + */ +HWC2::Error HwcLayer::SetLayerBuffer(buffer_handle_t buffer, + int32_t acquire_fence) { + buffer_ = buffer; + acquire_fence_ = UniqueFd(acquire_fence); + return HWC2::Error::None; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +HWC2::Error HwcLayer::SetLayerColor(hwc_color_t /*color*/) { + // TODO(nobody): Put to client composition here? + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerCompositionType(int32_t type) { + sf_type_ = static_cast<HWC2::Composition>(type); + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerDataspace(int32_t dataspace) { + switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { + case HAL_DATASPACE_STANDARD_BT709: + color_space_ = DrmHwcColorSpace::kItuRec709; + break; + case HAL_DATASPACE_STANDARD_BT601_625: + case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED: + case HAL_DATASPACE_STANDARD_BT601_525: + case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED: + color_space_ = DrmHwcColorSpace::kItuRec601; + break; + case HAL_DATASPACE_STANDARD_BT2020: + case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE: + color_space_ = DrmHwcColorSpace::kItuRec2020; + break; + default: + color_space_ = DrmHwcColorSpace::kUndefined; + } + + switch (dataspace & HAL_DATASPACE_RANGE_MASK) { + case HAL_DATASPACE_RANGE_FULL: + sample_range_ = DrmHwcSampleRange::kFullRange; + break; + case HAL_DATASPACE_RANGE_LIMITED: + sample_range_ = DrmHwcSampleRange::kLimitedRange; + break; + default: + sample_range_ = DrmHwcSampleRange::kUndefined; + } + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerDisplayFrame(hwc_rect_t frame) { + display_frame_ = frame; + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerPlaneAlpha(float alpha) { + alpha_ = alpha; + return HWC2::Error::None; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +HWC2::Error HwcLayer::SetLayerSidebandStream( + const native_handle_t * /*stream*/) { + // TODO(nobody): We don't support sideband + return HWC2::Error::Unsupported; +} + +HWC2::Error HwcLayer::SetLayerSourceCrop(hwc_frect_t crop) { + source_crop_ = crop; + return HWC2::Error::None; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +HWC2::Error HwcLayer::SetLayerSurfaceDamage(hwc_region_t /*damage*/) { + // TODO(nobody): We don't use surface damage, marking as unsupported + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerTransform(int32_t transform) { + uint32_t l_transform = 0; + + // 270* and 180* cannot be combined with flips. More specifically, they + // already contain both horizontal and vertical flips, so those fields are + // redundant in this case. 90* rotation can be combined with either horizontal + // flip or vertical flip, so treat it differently + if (transform == HWC_TRANSFORM_ROT_270) { + l_transform = DrmHwcTransform::kRotate270; + } else if (transform == HWC_TRANSFORM_ROT_180) { + l_transform = DrmHwcTransform::kRotate180; + } else { + if ((transform & HWC_TRANSFORM_FLIP_H) != 0) + l_transform |= DrmHwcTransform::kFlipH; + if ((transform & HWC_TRANSFORM_FLIP_V) != 0) + l_transform |= DrmHwcTransform::kFlipV; + if ((transform & HWC_TRANSFORM_ROT_90) != 0) + l_transform |= DrmHwcTransform::kRotate90; + } + + transform_ = static_cast<DrmHwcTransform>(l_transform); + return HWC2::Error::None; +} + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +HWC2::Error HwcLayer::SetLayerVisibleRegion(hwc_region_t /*visible*/) { + // TODO(nobody): We don't use this information, marking as unsupported + return HWC2::Error::None; +} + +HWC2::Error HwcLayer::SetLayerZOrder(uint32_t order) { + z_order_ = order; + return HWC2::Error::None; +} + +void HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) { + layer->sf_handle = buffer_; + // TODO(rsglobal): Avoid extra fd duplication + layer->acquire_fence = UniqueFd(fcntl(acquire_fence_.Get(), F_DUPFD_CLOEXEC)); + layer->display_frame = display_frame_; + layer->alpha = std::lround(alpha_ * UINT16_MAX); + layer->blending = blending_; + layer->source_crop = source_crop_; + layer->transform = transform_; + layer->color_space = color_space_; + layer->sample_range = sample_range_; +} + +} // namespace android
\ No newline at end of file diff --git a/hwc2_device/HwcLayer.h b/hwc2_device/HwcLayer.h new file mode 100644 index 0000000..df4ce6d --- /dev/null +++ b/hwc2_device/HwcLayer.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef ANDROID_HWC2_DEVICE_HWC_LAYER_H +#define ANDROID_HWC2_DEVICE_HWC_LAYER_H + +#include <hardware/hwcomposer2.h> + +#include <cmath> + +#include "drmhwcomposer.h" + +namespace android { + +class HwcLayer { + public: + HWC2::Composition GetSfType() const { + return sf_type_; + } + HWC2::Composition GetValidatedType() const { + return validated_type_; + } + void AcceptTypeChange() { + sf_type_ = validated_type_; + } + void SetValidatedType(HWC2::Composition type) { + validated_type_ = type; + } + bool IsTypeChanged() const { + return sf_type_ != validated_type_; + } + + uint32_t GetZOrder() const { + return z_order_; + } + + buffer_handle_t GetBuffer() { + return buffer_; + } + + hwc_rect_t GetDisplayFrame() { + return display_frame_; + } + + UniqueFd GetReleaseFence() { + return std::move(release_fence_); + } + + void PopulateDrmLayer(DrmHwcLayer *layer); + + bool RequireScalingOrPhasing() const { + float src_width = source_crop_.right - source_crop_.left; + 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) || + (source_crop_.top - std::floor(source_crop_.top) != 0); + return scaling || phasing; + } + + // Layer hooks + HWC2::Error SetCursorPosition(int32_t /*x*/, int32_t /*y*/); + HWC2::Error SetLayerBlendMode(int32_t mode); + HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence); + HWC2::Error SetLayerColor(hwc_color_t /*color*/); + HWC2::Error SetLayerCompositionType(int32_t type); + HWC2::Error SetLayerDataspace(int32_t dataspace); + HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame); + HWC2::Error SetLayerPlaneAlpha(float alpha); + HWC2::Error SetLayerSidebandStream(const native_handle_t *stream); + HWC2::Error SetLayerSourceCrop(hwc_frect_t crop); + HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage); + HWC2::Error SetLayerTransform(int32_t transform); + HWC2::Error SetLayerVisibleRegion(hwc_region_t visible); + HWC2::Error SetLayerZOrder(uint32_t order); + + private: + // sf_type_ stores the initial type given to us by surfaceflinger, + // validated_type_ stores the type after running ValidateDisplay + HWC2::Composition sf_type_ = HWC2::Composition::Invalid; + HWC2::Composition validated_type_ = HWC2::Composition::Invalid; + + buffer_handle_t buffer_ = nullptr; + hwc_rect_t display_frame_; + static constexpr float kOpaqueFloat = 1.0F; + float alpha_ = kOpaqueFloat; + hwc_frect_t source_crop_; + DrmHwcTransform transform_ = DrmHwcTransform::kIdentity; + uint32_t z_order_ = 0; + DrmHwcBlending blending_ = DrmHwcBlending::kNone; + DrmHwcColorSpace color_space_ = DrmHwcColorSpace::kUndefined; + DrmHwcSampleRange sample_range_ = DrmHwcSampleRange::kUndefined; + + UniqueFd acquire_fence_; + + /* + * Release fence is not used. + * There is no release fence support available in the DRM/KMS. In case no + * release fence provided application will use this buffer for writing when + * the next frame present fence is signaled. + */ + UniqueFd release_fence_; +}; + +} // namespace android + +#endif diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp new file mode 100644 index 0000000..22e4589 --- /dev/null +++ b/hwc2_device/hwc2_device.cpp @@ -0,0 +1,390 @@ +/* + * 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. + */ + +#define LOG_TAG "hwc2-device" + +#include "DrmHwcTwo.h" +#include "backend/Backend.h" +#include "utils/log.h" + +namespace android { + +struct Drmhwc2Device : hwc2_device { + DrmHwcTwo drmhwctwo; +}; + +static DrmHwcTwo *ToDrmHwcTwo(hwc2_device_t *dev) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast): + return &static_cast<Drmhwc2Device *>(dev)->drmhwctwo; +} + +template <typename PFN, typename T> +static hwc2_function_pointer_t ToHook(T function) { + static_assert(std::is_same<PFN, T>::value, "Incompatible fn pointer"); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): + return reinterpret_cast<hwc2_function_pointer_t>(function); +} + +template <typename T, typename HookType, HookType func, typename... Args> +static T DeviceHook(hwc2_device_t *dev, Args... args) { + DrmHwcTwo *hwc = ToDrmHwcTwo(dev); + return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...)); +} + +template <typename HookType, HookType func, typename... Args> +static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle, + Args... args) { + HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle); + if (!display) + return static_cast<int32_t>(HWC2::Error::BadDisplay); + + return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...)); +} + +template <typename HookType, HookType func, typename... Args> +static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle, + hwc2_layer_t layer_handle, Args... args) { + HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle); + if (!display) + return static_cast<int32_t>(HWC2::Error::BadDisplay); + + HwcLayer *layer = display->get_layer(layer_handle); + if (!layer) + return static_cast<int32_t>(HWC2::Error::BadLayer); + + return static_cast<int32_t>((layer->*func)(std::forward<Args>(args)...)); +} + +static int HookDevClose(hw_device_t *dev) { + // NOLINTNEXTLINE (cppcoreguidelines-pro-type-reinterpret-cast): Safe + auto *hwc2_dev = reinterpret_cast<hwc2_device_t *>(dev); + std::unique_ptr<DrmHwcTwo> ctx(ToDrmHwcTwo(hwc2_dev)); + return 0; +} + +static void HookDevGetCapabilities(hwc2_device_t * /*dev*/, uint32_t *out_count, + int32_t * /*out_capabilities*/) { + *out_count = 0; +} + +static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/, + int32_t descriptor) { + auto func = static_cast<HWC2::FunctionDescriptor>(descriptor); + switch (func) { + // Device functions + case HWC2::FunctionDescriptor::CreateVirtualDisplay: + return ToHook<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>( + DeviceHook<int32_t, decltype(&DrmHwcTwo::CreateVirtualDisplay), + &DrmHwcTwo::CreateVirtualDisplay, uint32_t, uint32_t, + int32_t *, hwc2_display_t *>); + case HWC2::FunctionDescriptor::DestroyVirtualDisplay: + return ToHook<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>( + DeviceHook<int32_t, decltype(&DrmHwcTwo::DestroyVirtualDisplay), + &DrmHwcTwo::DestroyVirtualDisplay, hwc2_display_t>); + case HWC2::FunctionDescriptor::Dump: + return ToHook<HWC2_PFN_DUMP>( + DeviceHook<void, decltype(&DrmHwcTwo::Dump), &DrmHwcTwo::Dump, + uint32_t *, char *>); + case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: + return ToHook<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>( + DeviceHook<uint32_t, decltype(&DrmHwcTwo::GetMaxVirtualDisplayCount), + &DrmHwcTwo::GetMaxVirtualDisplayCount>); + case HWC2::FunctionDescriptor::RegisterCallback: + return ToHook<HWC2_PFN_REGISTER_CALLBACK>( + DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback), + &DrmHwcTwo::RegisterCallback, int32_t, + hwc2_callback_data_t, hwc2_function_pointer_t>); + + // Display functions + case HWC2::FunctionDescriptor::AcceptDisplayChanges: + return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>( + DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges), + &HwcDisplay::AcceptDisplayChanges>); + case HWC2::FunctionDescriptor::CreateLayer: + return ToHook<HWC2_PFN_CREATE_LAYER>( + DisplayHook<decltype(&HwcDisplay::CreateLayer), + &HwcDisplay::CreateLayer, hwc2_layer_t *>); + case HWC2::FunctionDescriptor::DestroyLayer: + return ToHook<HWC2_PFN_DESTROY_LAYER>( + DisplayHook<decltype(&HwcDisplay::DestroyLayer), + &HwcDisplay::DestroyLayer, hwc2_layer_t>); + case HWC2::FunctionDescriptor::GetActiveConfig: + return ToHook<HWC2_PFN_GET_ACTIVE_CONFIG>( + DisplayHook<decltype(&HwcDisplay::GetActiveConfig), + &HwcDisplay::GetActiveConfig, hwc2_config_t *>); + case HWC2::FunctionDescriptor::GetChangedCompositionTypes: + return ToHook<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>( + DisplayHook<decltype(&HwcDisplay::GetChangedCompositionTypes), + &HwcDisplay::GetChangedCompositionTypes, uint32_t *, + hwc2_layer_t *, int32_t *>); + case HWC2::FunctionDescriptor::GetClientTargetSupport: + return ToHook<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>( + DisplayHook<decltype(&HwcDisplay::GetClientTargetSupport), + &HwcDisplay::GetClientTargetSupport, uint32_t, uint32_t, + int32_t, int32_t>); + case HWC2::FunctionDescriptor::GetColorModes: + return ToHook<HWC2_PFN_GET_COLOR_MODES>( + DisplayHook<decltype(&HwcDisplay::GetColorModes), + &HwcDisplay::GetColorModes, uint32_t *, int32_t *>); + case HWC2::FunctionDescriptor::GetDisplayAttribute: + return ToHook<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>( + DisplayHook<decltype(&HwcDisplay::GetDisplayAttribute), + &HwcDisplay::GetDisplayAttribute, hwc2_config_t, int32_t, + int32_t *>); + case HWC2::FunctionDescriptor::GetDisplayConfigs: + return ToHook<HWC2_PFN_GET_DISPLAY_CONFIGS>( + DisplayHook<decltype(&HwcDisplay::GetDisplayConfigs), + &HwcDisplay::GetDisplayConfigs, uint32_t *, + hwc2_config_t *>); + case HWC2::FunctionDescriptor::GetDisplayName: + return ToHook<HWC2_PFN_GET_DISPLAY_NAME>( + DisplayHook<decltype(&HwcDisplay::GetDisplayName), + &HwcDisplay::GetDisplayName, uint32_t *, char *>); + case HWC2::FunctionDescriptor::GetDisplayRequests: + return ToHook<HWC2_PFN_GET_DISPLAY_REQUESTS>( + DisplayHook<decltype(&HwcDisplay::GetDisplayRequests), + &HwcDisplay::GetDisplayRequests, int32_t *, uint32_t *, + hwc2_layer_t *, int32_t *>); + case HWC2::FunctionDescriptor::GetDisplayType: + return ToHook<HWC2_PFN_GET_DISPLAY_TYPE>( + DisplayHook<decltype(&HwcDisplay::GetDisplayType), + &HwcDisplay::GetDisplayType, int32_t *>); + case HWC2::FunctionDescriptor::GetDozeSupport: + return ToHook<HWC2_PFN_GET_DOZE_SUPPORT>( + DisplayHook<decltype(&HwcDisplay::GetDozeSupport), + &HwcDisplay::GetDozeSupport, int32_t *>); + case HWC2::FunctionDescriptor::GetHdrCapabilities: + return ToHook<HWC2_PFN_GET_HDR_CAPABILITIES>( + DisplayHook<decltype(&HwcDisplay::GetHdrCapabilities), + &HwcDisplay::GetHdrCapabilities, uint32_t *, int32_t *, + float *, float *, float *>); + case HWC2::FunctionDescriptor::GetReleaseFences: + return ToHook<HWC2_PFN_GET_RELEASE_FENCES>( + DisplayHook<decltype(&HwcDisplay::GetReleaseFences), + &HwcDisplay::GetReleaseFences, uint32_t *, hwc2_layer_t *, + int32_t *>); + case HWC2::FunctionDescriptor::PresentDisplay: + return ToHook<HWC2_PFN_PRESENT_DISPLAY>( + DisplayHook<decltype(&HwcDisplay::PresentDisplay), + &HwcDisplay::PresentDisplay, int32_t *>); + case HWC2::FunctionDescriptor::SetActiveConfig: + return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG>( + DisplayHook<decltype(&HwcDisplay::SetActiveConfig), + &HwcDisplay::SetActiveConfig, hwc2_config_t>); + case HWC2::FunctionDescriptor::SetClientTarget: + return ToHook<HWC2_PFN_SET_CLIENT_TARGET>( + DisplayHook<decltype(&HwcDisplay::SetClientTarget), + &HwcDisplay::SetClientTarget, buffer_handle_t, int32_t, + int32_t, hwc_region_t>); + case HWC2::FunctionDescriptor::SetColorMode: + return ToHook<HWC2_PFN_SET_COLOR_MODE>( + DisplayHook<decltype(&HwcDisplay::SetColorMode), + &HwcDisplay::SetColorMode, int32_t>); + case HWC2::FunctionDescriptor::SetColorTransform: + return ToHook<HWC2_PFN_SET_COLOR_TRANSFORM>( + DisplayHook<decltype(&HwcDisplay::SetColorTransform), + &HwcDisplay::SetColorTransform, const float *, int32_t>); + case HWC2::FunctionDescriptor::SetOutputBuffer: + return ToHook<HWC2_PFN_SET_OUTPUT_BUFFER>( + DisplayHook<decltype(&HwcDisplay::SetOutputBuffer), + &HwcDisplay::SetOutputBuffer, buffer_handle_t, int32_t>); + case HWC2::FunctionDescriptor::SetPowerMode: + return ToHook<HWC2_PFN_SET_POWER_MODE>( + DisplayHook<decltype(&HwcDisplay::SetPowerMode), + &HwcDisplay::SetPowerMode, int32_t>); + case HWC2::FunctionDescriptor::SetVsyncEnabled: + return ToHook<HWC2_PFN_SET_VSYNC_ENABLED>( + DisplayHook<decltype(&HwcDisplay::SetVsyncEnabled), + &HwcDisplay::SetVsyncEnabled, int32_t>); + case HWC2::FunctionDescriptor::ValidateDisplay: + return ToHook<HWC2_PFN_VALIDATE_DISPLAY>( + DisplayHook<decltype(&HwcDisplay::ValidateDisplay), + &HwcDisplay::ValidateDisplay, uint32_t *, uint32_t *>); +#if PLATFORM_SDK_VERSION > 27 + case HWC2::FunctionDescriptor::GetRenderIntents: + return ToHook<HWC2_PFN_GET_RENDER_INTENTS>( + DisplayHook<decltype(&HwcDisplay::GetRenderIntents), + &HwcDisplay::GetRenderIntents, int32_t, uint32_t *, + int32_t *>); + case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent: + return ToHook<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>( + DisplayHook<decltype(&HwcDisplay::SetColorModeWithIntent), + &HwcDisplay::SetColorModeWithIntent, int32_t, int32_t>); +#endif +#if PLATFORM_SDK_VERSION > 28 + case HWC2::FunctionDescriptor::GetDisplayIdentificationData: + return ToHook<HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA>( + DisplayHook<decltype(&HwcDisplay::GetDisplayIdentificationData), + &HwcDisplay::GetDisplayIdentificationData, uint8_t *, + uint32_t *, uint8_t *>); + case HWC2::FunctionDescriptor::GetDisplayCapabilities: + return ToHook<HWC2_PFN_GET_DISPLAY_CAPABILITIES>( + DisplayHook<decltype(&HwcDisplay::GetDisplayCapabilities), + &HwcDisplay::GetDisplayCapabilities, uint32_t *, + uint32_t *>); + case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: + return ToHook<HWC2_PFN_GET_DISPLAY_BRIGHTNESS_SUPPORT>( + DisplayHook<decltype(&HwcDisplay::GetDisplayBrightnessSupport), + &HwcDisplay::GetDisplayBrightnessSupport, bool *>); + case HWC2::FunctionDescriptor::SetDisplayBrightness: + return ToHook<HWC2_PFN_SET_DISPLAY_BRIGHTNESS>( + DisplayHook<decltype(&HwcDisplay::SetDisplayBrightness), + &HwcDisplay::SetDisplayBrightness, float>); +#endif /* PLATFORM_SDK_VERSION > 28 */ +#if PLATFORM_SDK_VERSION > 29 + case HWC2::FunctionDescriptor::GetDisplayConnectionType: + return ToHook<HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE>( + DisplayHook<decltype(&HwcDisplay::GetDisplayConnectionType), + &HwcDisplay::GetDisplayConnectionType, uint32_t *>); + case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod: + return ToHook<HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD>( + DisplayHook<decltype(&HwcDisplay::GetDisplayVsyncPeriod), + &HwcDisplay::GetDisplayVsyncPeriod, + hwc2_vsync_period_t *>); + case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints: + return ToHook<HWC2_PFN_SET_ACTIVE_CONFIG_WITH_CONSTRAINTS>( + DisplayHook<decltype(&HwcDisplay::SetActiveConfigWithConstraints), + &HwcDisplay::SetActiveConfigWithConstraints, + hwc2_config_t, hwc_vsync_period_change_constraints_t *, + hwc_vsync_period_change_timeline_t *>); + case HWC2::FunctionDescriptor::SetAutoLowLatencyMode: + return ToHook<HWC2_PFN_SET_AUTO_LOW_LATENCY_MODE>( + DisplayHook<decltype(&HwcDisplay::SetAutoLowLatencyMode), + &HwcDisplay::SetAutoLowLatencyMode, bool>); + case HWC2::FunctionDescriptor::GetSupportedContentTypes: + return ToHook<HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES>( + DisplayHook<decltype(&HwcDisplay::GetSupportedContentTypes), + &HwcDisplay::GetSupportedContentTypes, uint32_t *, + uint32_t *>); + case HWC2::FunctionDescriptor::SetContentType: + return ToHook<HWC2_PFN_SET_CONTENT_TYPE>( + DisplayHook<decltype(&HwcDisplay::SetContentType), + &HwcDisplay::SetContentType, int32_t>); +#endif + // Layer functions + case HWC2::FunctionDescriptor::SetCursorPosition: + return ToHook<HWC2_PFN_SET_CURSOR_POSITION>( + LayerHook<decltype(&HwcLayer::SetCursorPosition), + &HwcLayer::SetCursorPosition, int32_t, int32_t>); + case HWC2::FunctionDescriptor::SetLayerBlendMode: + return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>( + LayerHook<decltype(&HwcLayer::SetLayerBlendMode), + &HwcLayer::SetLayerBlendMode, int32_t>); + case HWC2::FunctionDescriptor::SetLayerBuffer: + return ToHook<HWC2_PFN_SET_LAYER_BUFFER>( + LayerHook<decltype(&HwcLayer::SetLayerBuffer), + &HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>); + case HWC2::FunctionDescriptor::SetLayerColor: + return ToHook<HWC2_PFN_SET_LAYER_COLOR>( + LayerHook<decltype(&HwcLayer::SetLayerColor), + &HwcLayer::SetLayerColor, hwc_color_t>); + case HWC2::FunctionDescriptor::SetLayerCompositionType: + return ToHook<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>( + LayerHook<decltype(&HwcLayer::SetLayerCompositionType), + &HwcLayer::SetLayerCompositionType, int32_t>); + case HWC2::FunctionDescriptor::SetLayerDataspace: + return ToHook<HWC2_PFN_SET_LAYER_DATASPACE>( + LayerHook<decltype(&HwcLayer::SetLayerDataspace), + &HwcLayer::SetLayerDataspace, int32_t>); + case HWC2::FunctionDescriptor::SetLayerDisplayFrame: + return ToHook<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>( + LayerHook<decltype(&HwcLayer::SetLayerDisplayFrame), + &HwcLayer::SetLayerDisplayFrame, hwc_rect_t>); + case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: + return ToHook<HWC2_PFN_SET_LAYER_PLANE_ALPHA>( + LayerHook<decltype(&HwcLayer::SetLayerPlaneAlpha), + &HwcLayer::SetLayerPlaneAlpha, float>); + case HWC2::FunctionDescriptor::SetLayerSidebandStream: + return ToHook<HWC2_PFN_SET_LAYER_SIDEBAND_STREAM>( + LayerHook<decltype(&HwcLayer::SetLayerSidebandStream), + &HwcLayer::SetLayerSidebandStream, + const native_handle_t *>); + case HWC2::FunctionDescriptor::SetLayerSourceCrop: + return ToHook<HWC2_PFN_SET_LAYER_SOURCE_CROP>( + LayerHook<decltype(&HwcLayer::SetLayerSourceCrop), + &HwcLayer::SetLayerSourceCrop, hwc_frect_t>); + case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: + return ToHook<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>( + LayerHook<decltype(&HwcLayer::SetLayerSurfaceDamage), + &HwcLayer::SetLayerSurfaceDamage, hwc_region_t>); + case HWC2::FunctionDescriptor::SetLayerTransform: + return ToHook<HWC2_PFN_SET_LAYER_TRANSFORM>( + LayerHook<decltype(&HwcLayer::SetLayerTransform), + &HwcLayer::SetLayerTransform, int32_t>); + case HWC2::FunctionDescriptor::SetLayerVisibleRegion: + return ToHook<HWC2_PFN_SET_LAYER_VISIBLE_REGION>( + LayerHook<decltype(&HwcLayer::SetLayerVisibleRegion), + &HwcLayer::SetLayerVisibleRegion, hwc_region_t>); + case HWC2::FunctionDescriptor::SetLayerZOrder: + return ToHook<HWC2_PFN_SET_LAYER_Z_ORDER>( + LayerHook<decltype(&HwcLayer::SetLayerZOrder), + &HwcLayer::SetLayerZOrder, uint32_t>); + case HWC2::FunctionDescriptor::Invalid: + default: + return nullptr; + } +} + +static int HookDevOpen(const struct hw_module_t *module, const char *name, + struct hw_device_t **dev) { + if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) { + ALOGE("Invalid module name- %s", name); + return -EINVAL; + } + + auto ctx = std::make_unique<Drmhwc2Device>(); + if (!ctx) { + ALOGE("Failed to allocate DrmHwcTwo"); + return -ENOMEM; + } + + ctx->common.tag = HARDWARE_DEVICE_TAG; + ctx->common.version = HWC_DEVICE_API_VERSION_2_0; + ctx->common.close = HookDevClose; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + ctx->common.module = (hw_module_t *)module; + ctx->getCapabilities = HookDevGetCapabilities; + ctx->getFunction = HookDevGetFunction; + + HWC2::Error err = ctx->drmhwctwo.Init(); + if (err != HWC2::Error::None) { + ALOGE("Failed to initialize DrmHwcTwo err=%d\n", err); + return -EINVAL; + } + + *dev = &ctx.release()->common; + + return 0; +} + +} // namespace android + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +static struct hw_module_methods_t hwc2_module_methods = { + .open = android::HookDevOpen, +}; + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +hw_module_t HAL_MODULE_INFO_SYM = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0), + .id = HWC_HARDWARE_MODULE_ID, + .name = "DrmHwcTwo module", + .author = "The Android Open Source Project", + .methods = &hwc2_module_methods, + .dso = nullptr, + .reserved = {0}, +}; diff --git a/include/drmhwcgralloc.h b/include/drmhwcgralloc.h index 09c7499..949912d 100644 --- a/include/drmhwcgralloc.h +++ b/include/drmhwcgralloc.h @@ -17,22 +17,26 @@ #ifndef ANDROID_DRMHWCGRALLOC_H_ #define ANDROID_DRMHWCGRALLOC_H_ -#include <stdint.h> +#include <cstdint> -#define HWC_DRM_BO_MAX_PLANES 4 -typedef struct hwc_drm_bo { +constexpr int kHwcDrmBoMaxPlanes = 4; + +struct HwcDrmBo { uint32_t width; uint32_t height; uint32_t format; /* DRM_FORMAT_* from drm_fourcc.h */ uint32_t hal_format; /* HAL_PIXEL_FORMAT_* */ uint32_t usage; - uint32_t pitches[HWC_DRM_BO_MAX_PLANES]; - uint32_t offsets[HWC_DRM_BO_MAX_PLANES]; + uint32_t pitches[kHwcDrmBoMaxPlanes]; + uint32_t offsets[kHwcDrmBoMaxPlanes]; /* sizes[] is used only by mapper@4 metadata getter for internal purposes */ - uint32_t sizes[HWC_DRM_BO_MAX_PLANES]; - int prime_fds[HWC_DRM_BO_MAX_PLANES]; - uint64_t modifiers[HWC_DRM_BO_MAX_PLANES]; + uint32_t sizes[kHwcDrmBoMaxPlanes]; + int prime_fds[kHwcDrmBoMaxPlanes]; + uint64_t modifiers[kHwcDrmBoMaxPlanes]; int acquire_fence_fd; -} hwc_drm_bo_t; +}; + +// NOLINTNEXTLINE(readability-identifier-naming) +using hwc_drm_bo_t = HwcDrmBo; #endif // ANDROID_DRMHWCGRALLOC_H_ diff --git a/include/drmhwcomposer.h b/include/drmhwcomposer.h index d02445b..4fb0efd 100644 --- a/include/drmhwcomposer.h +++ b/include/drmhwcomposer.h @@ -19,9 +19,9 @@ #include <hardware/hardware.h> #include <hardware/hwcomposer.h> -#include <stdbool.h> -#include <stdint.h> +#include <cstdbool> +#include <cstdint> #include <vector> #include "drm/DrmFbImporter.h" @@ -61,14 +61,14 @@ enum class DrmHwcBlending : int32_t { }; struct DrmHwcLayer { - buffer_handle_t sf_handle = NULL; + buffer_handle_t sf_handle = nullptr; hwc_drm_bo_t buffer_info{}; - std::shared_ptr<DrmFbIdHandle> FbIdHandle; + std::shared_ptr<DrmFbIdHandle> fb_id_handle; int gralloc_buffer_usage = 0; DrmHwcTransform transform{}; DrmHwcBlending blending = DrmHwcBlending::kNone; - uint16_t alpha = 0xffff; + uint16_t alpha = UINT16_MAX; hwc_frect_t source_crop; hwc_rect_t display_frame; DrmHwcColorSpace color_space; @@ -76,9 +76,9 @@ struct DrmHwcLayer { UniqueFd acquire_fence; - int ImportBuffer(DrmDevice *drmDevice); + int ImportBuffer(DrmDevice *drm_device); - bool protected_usage() const { + bool IsProtected() const { return (gralloc_buffer_usage & GRALLOC_USAGE_PROTECTED) == GRALLOC_USAGE_PROTECTED; } diff --git a/presubmit.sh b/presubmit.sh index 249aaf5..a551398 100755 --- a/presubmit.sh +++ b/presubmit.sh @@ -4,18 +4,10 @@ set -e echo "Run native build:" -./.ci/.gitlab-ci-clang-build.sh +make -f .ci/Makefile -j12 echo "Run style check:" ./.ci/.gitlab-ci-checkcommit.sh -echo "Run coarse clang-tidy check:" - -./.ci/.gitlab-ci-clang-tidy-coarse.sh - -echo "Run fine clang-tidy check:" - -./.ci/.gitlab-ci-clang-tidy-fine.sh - echo -e "\n\e[32m --- SUCCESS ---" diff --git a/utils/Worker.h b/utils/Worker.h index 73a80da..ab01d5f 100644 --- a/utils/Worker.h +++ b/utils/Worker.h @@ -17,10 +17,9 @@ #ifndef ANDROID_WORKER_H_ #define ANDROID_WORKER_H_ -#include <stdint.h> -#include <stdlib.h> - #include <condition_variable> +#include <cstdint> +#include <cstdlib> #include <mutex> #include <string> #include <thread> diff --git a/utils/autolock.cpp b/utils/autolock.cpp index 3342e46..3afe488 100644 --- a/utils/autolock.cpp +++ b/utils/autolock.cpp @@ -33,7 +33,7 @@ int AutoLock::Lock() { return -EINVAL; } int ret = pthread_mutex_lock(mutex_); - if (ret) { + if (ret != 0) { ALOGE("Failed to acquire %s lock %d", name_, ret); return ret; } @@ -47,7 +47,7 @@ int AutoLock::Unlock() { return -EINVAL; } int ret = pthread_mutex_unlock(mutex_); - if (ret) { + if (ret != 0) { ALOGE("Failed to release %s lock %d", name_, ret); return ret; } diff --git a/utils/hwcutils.cpp b/utils/hwcutils.cpp index 5a46e9b..c537b99 100644 --- a/utils/hwcutils.cpp +++ b/utils/hwcutils.cpp @@ -17,30 +17,28 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #define LOG_TAG "hwc-drm-utils" -#include <log/log.h> -#include <ui/Gralloc.h> -#include <ui/GraphicBufferMapper.h> +#include <utils/log.h> + +#include <cerrno> #include "bufferinfo/BufferInfoGetter.h" #include "drm/DrmFbImporter.h" #include "drmhwcomposer.h" -#define UNUSED(x) (void)(x) - namespace android { -int DrmHwcLayer::ImportBuffer(DrmDevice *drmDevice) { +int DrmHwcLayer::ImportBuffer(DrmDevice *drm_device) { buffer_info = hwc_drm_bo_t{}; int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(sf_handle, &buffer_info); - if (ret) { + if (ret != 0) { ALOGE("Failed to convert buffer info %d", ret); return ret; } - FbIdHandle = drmDevice->GetDrmFbImporter().GetOrCreateFbId(&buffer_info); - if (!FbIdHandle) { + fb_id_handle = drm_device->GetDrmFbImporter().GetOrCreateFbId(&buffer_info); + if (!fb_id_handle) { ALOGE("Failed to import buffer"); return -EINVAL; } diff --git a/utils/properties.h b/utils/properties.h index c8ddbae..0b49c61 100644 --- a/utils/properties.h +++ b/utils/properties.h @@ -17,6 +17,7 @@ constexpr int PROPERTY_VALUE_MAX = 92; // NOLINTNEXTLINE(readability-identifier-naming) auto inline property_get(const char *name, char *value, const char *default_value) -> int { + // NOLINTNEXTLINE (concurrency-mt-unsafe) char *prop = std::getenv(name); snprintf(value, PROPERTY_VALUE_MAX, "%s", (prop == nullptr) ? default_value : prop); |