aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2022-03-09 22:26:22 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-09 22:26:22 +0000
commit0ce361010578834528e6e987c2f75d942884e370 (patch)
tree8e2c640be06a05fdc28ced0de956702c43663f1d
parent01e9f85df3aede7333b35b5fc71ae1e64cb781e8 (diff)
parentb8f24097f289a4b95d1179e9f019f7250c546c3c (diff)
downloaddrm_hwcomposer-android13-d4-s2-release.tar.gz
Merge "drm_hwcomposer: Merge remote-tracking branch 'aosp/upstream-main' into HEAD" am: bc74646e90 am: b52fbe0ff4 am: b8f24097f2t_frc_odp_330442040t_frc_odp_330442000t_frc_ase_330444010android-13.0.0_r83android-13.0.0_r82android-13.0.0_r81android-13.0.0_r80android-13.0.0_r79android-13.0.0_r78android-13.0.0_r77android-13.0.0_r76android-13.0.0_r75android-13.0.0_r74android-13.0.0_r73android-13.0.0_r72android-13.0.0_r71android-13.0.0_r70android-13.0.0_r69android-13.0.0_r68android-13.0.0_r67android-13.0.0_r66android-13.0.0_r65android-13.0.0_r64android-13.0.0_r63android-13.0.0_r62android-13.0.0_r61android-13.0.0_r60android-13.0.0_r59android-13.0.0_r58android-13.0.0_r57android-13.0.0_r56android-13.0.0_r54android-13.0.0_r53android-13.0.0_r52android-13.0.0_r51android-13.0.0_r50android-13.0.0_r49android-13.0.0_r48android-13.0.0_r47android-13.0.0_r46android-13.0.0_r45android-13.0.0_r44android-13.0.0_r43android-13.0.0_r42android-13.0.0_r41android-13.0.0_r40android-13.0.0_r39android-13.0.0_r38android-13.0.0_r37android-13.0.0_r36android-13.0.0_r35android-13.0.0_r34android-13.0.0_r33android-13.0.0_r32aml_go_odp_330912000aml_go_ads_330915100aml_go_ads_330915000aml_go_ads_330913000android13-qpr3-s9-releaseandroid13-qpr3-s8-releaseandroid13-qpr3-s7-releaseandroid13-qpr3-s6-releaseandroid13-qpr3-s5-releaseandroid13-qpr3-s4-releaseandroid13-qpr3-s3-releaseandroid13-qpr3-s2-releaseandroid13-qpr3-s14-releaseandroid13-qpr3-s13-releaseandroid13-qpr3-s12-releaseandroid13-qpr3-s11-releaseandroid13-qpr3-s10-releaseandroid13-qpr3-s1-releaseandroid13-qpr3-releaseandroid13-qpr3-c-s8-releaseandroid13-qpr3-c-s7-releaseandroid13-qpr3-c-s6-releaseandroid13-qpr3-c-s5-releaseandroid13-qpr3-c-s4-releaseandroid13-qpr3-c-s3-releaseandroid13-qpr3-c-s2-releaseandroid13-qpr3-c-s12-releaseandroid13-qpr3-c-s11-releaseandroid13-qpr3-c-s10-releaseandroid13-qpr3-c-s1-releaseandroid13-qpr2-s9-releaseandroid13-qpr2-s8-releaseandroid13-qpr2-s7-releaseandroid13-qpr2-s6-releaseandroid13-qpr2-s5-releaseandroid13-qpr2-s3-releaseandroid13-qpr2-s2-releaseandroid13-qpr2-s12-releaseandroid13-qpr2-s11-releaseandroid13-qpr2-s10-releaseandroid13-qpr2-s1-releaseandroid13-qpr2-releaseandroid13-qpr2-b-s1-releaseandroid13-mainline-go-adservices-releaseandroid13-frc-odp-releaseandroid13-devandroid13-d4-s2-releaseandroid13-d4-s1-releaseandroid13-d4-releaseandroid13-d3-s1-release
Original change: https://android-review.googlesource.com/c/platform/external/drm_hwcomposer/+/2007868 Change-Id: Ie962b5ff821f166d79323474bc6fad66d930e8fa
-rw-r--r--.ci/Makefile16
-rw-r--r--Android.bp8
-rw-r--r--backend/Backend.cpp6
-rw-r--r--backend/BackendManager.cpp8
-rw-r--r--backend/BackendRCarDu.cpp47
-rw-r--r--bufferinfo/legacy/BufferInfoLibdrm.cpp5
-rwxr-xr-xbuild_deploy.sh8
-rw-r--r--compositor/DrmDisplayComposition.cpp92
-rw-r--r--compositor/DrmDisplayComposition.h90
-rw-r--r--compositor/DrmDisplayCompositor.cpp239
-rw-r--r--compositor/DrmKmsPlan.cpp59
-rw-r--r--compositor/DrmKmsPlan.h (renamed from backend/BackendRCarDu.h)30
-rw-r--r--compositor/Planner.cpp81
-rw-r--r--compositor/Planner.h95
-rw-r--r--drm/DrmAtomicStateManager.cpp191
-rw-r--r--drm/DrmAtomicStateManager.h (renamed from compositor/DrmDisplayCompositor.h)32
-rw-r--r--drm/DrmConnector.cpp214
-rw-r--r--drm/DrmConnector.h112
-rw-r--r--drm/DrmCrtc.cpp61
-rw-r--r--drm/DrmCrtc.h42
-rw-r--r--drm/DrmDevice.cpp423
-rw-r--r--drm/DrmDevice.h68
-rw-r--r--drm/DrmDisplayPipeline.cpp192
-rw-r--r--drm/DrmDisplayPipeline.h90
-rw-r--r--drm/DrmEncoder.cpp44
-rw-r--r--drm/DrmEncoder.h43
-rw-r--r--drm/DrmFbImporter.cpp19
-rw-r--r--drm/DrmFbImporter.h13
-rw-r--r--drm/DrmPlane.cpp54
-rw-r--r--drm/DrmPlane.h29
-rw-r--r--drm/ResourceManager.cpp131
-rw-r--r--drm/ResourceManager.h45
-rw-r--r--drm/UEventListener.cpp67
-rw-r--r--drm/UEventListener.h4
-rw-r--r--drm/VSyncWorker.cpp56
-rw-r--r--drm/VSyncWorker.h10
-rw-r--r--hwc2_device/DrmHwcTwo.cpp220
-rw-r--r--hwc2_device/DrmHwcTwo.h49
-rw-r--r--hwc2_device/HwcDisplay.cpp361
-rw-r--r--hwc2_device/HwcDisplay.h95
-rw-r--r--hwc2_device/HwcDisplayConfigs.cpp38
-rw-r--r--hwc2_device/HwcDisplayConfigs.h14
-rw-r--r--hwc2_device/hwc2_device.cpp14
-rw-r--r--tests/Android.bp14
-rw-r--r--tests/uevent_print.cpp25
-rw-r--r--utils/UEvent.h85
46 files changed, 1742 insertions, 1897 deletions
diff --git a/.ci/Makefile b/.ci/Makefile
index 7f43a8a..a0e4b73 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -21,21 +21,11 @@ TIDY_FILES_OVERRIDE := \
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 \
@@ -94,7 +84,7 @@ clean:
# Build
-BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/*' -path '*.cpp')
+BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' -path '*.cpp')
SKIP_FILES_path := $(foreach file,$(SKIP_FILES),$(SRC_DIR)/$(file))
BUILD_FILES := $(subst ./,,$(filter-out $(SKIP_FILES_path),$(BUILD_FILES_AUTO)))
@@ -117,7 +107,7 @@ $(OUT_DIR)/%.d: $(SRC_DIR)/%.cpp
$(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 := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' \( -path '*.cpp' -o -path '*.h' \))
TIDY_FILES_AUTO_filtered := $(filter-out $(SKIP_FILES_path),$(TIDY_FILES_AUTO))
@@ -154,7 +144,7 @@ $$(_TARG): _TARG := $$(_TARG)
$$(_TARG): TIDY_ARGS := $$(TIDY_ARGS)
$$(_TARG): $$(_DEP)
mkdir -p $$(dir $$(_TARG))
- $$(CLANG_TIDY) $$(_DEP) $$(TIDY_ARGS) -- -x c++ $$(CXXARGS)
+ $$(CLANG_TIDY) $$(_DEP) $$(TIDY_ARGS) -- -x c++ $$(CXXARGS) -Wno-pragma-once-outside-header
touch $$(_TARG)
endef
diff --git a/Android.bp b/Android.bp
index 1c3030c..c9c94af 100644
--- a/Android.bp
+++ b/Android.bp
@@ -83,6 +83,7 @@ cc_defaults {
cppflags: [
"-DHWC2_INCLUDE_STRINGIFICATION",
"-DHWC2_USE_CPP11",
+ "-std=c++17",
],
product_variables: {
@@ -101,13 +102,13 @@ filegroup {
"bufferinfo/BufferInfoGetter.cpp",
"bufferinfo/BufferInfoMapperMetadata.cpp",
- "compositor/DrmDisplayComposition.cpp",
- "compositor/DrmDisplayCompositor.cpp",
- "compositor/Planner.cpp",
+ "compositor/DrmKmsPlan.cpp",
+ "drm/DrmAtomicStateManager.cpp",
"drm/DrmConnector.cpp",
"drm/DrmCrtc.cpp",
"drm/DrmDevice.cpp",
+ "drm/DrmDisplayPipeline.cpp",
"drm/DrmEncoder.cpp",
"drm/DrmFbImporter.cpp",
"drm/DrmMode.cpp",
@@ -122,7 +123,6 @@ filegroup {
"backend/Backend.cpp",
"backend/BackendClient.cpp",
"backend/BackendManager.cpp",
- "backend/BackendRCarDu.cpp",
"hwc2_device/DrmHwcTwo.cpp",
"hwc2_device/HwcDisplay.cpp",
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index 98862ba..f6d9c18 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -86,7 +86,7 @@ bool Backend::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
!BufferInfoGetter::GetInstance()->IsHandleUsable(layer->GetBuffer()) ||
display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
(layer->RequireScalingOrPhasing() &&
- display->resource_manager()->ForcedScalingWithGpu());
+ display->GetHwc2()->GetResMan().ForcedScalingWithGpu());
}
bool Backend::HardwareSupportsLayerType(HWC2::Composition comp_type) {
@@ -119,8 +119,8 @@ void Backend::MarkValidated(std::vector<HwcLayer *> &layers,
std::tuple<int, int> Backend::GetExtraClientRange(
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();
+ auto planes = display->GetPipe().GetUsablePlanes();
+ size_t avail_planes = planes.size();
/*
* If more layers then planes, save one plane
diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp
index aadef36..9bf6324 100644
--- a/backend/BackendManager.cpp
+++ b/backend/BackendManager.cpp
@@ -42,7 +42,7 @@ int BackendManager::RegisterBackend(const std::string &name,
}
int BackendManager::SetBackendForDisplay(HwcDisplay *display) {
- std::string driver_name(display->drm()->GetName());
+ std::string driver_name(display->GetPipe().device->GetName());
char backend_override[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.backend_override", backend_override,
driver_name.c_str());
@@ -51,13 +51,15 @@ int BackendManager::SetBackendForDisplay(HwcDisplay *display) {
display->set_backend(GetBackendByName(backend_name));
if (display->backend() == nullptr) {
ALOGE("Failed to set backend '%s' for '%s' and driver '%s'",
- backend_name.c_str(), display->connector()->name().c_str(),
+ backend_name.c_str(),
+ display->GetPipe().connector->Get()->GetName().c_str(),
driver_name.c_str());
return -EINVAL;
}
ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set",
- backend_name.c_str(), display->connector()->name().c_str(),
+ backend_name.c_str(),
+ display->GetPipe().connector->Get()->GetName().c_str(),
driver_name.c_str());
return 0;
diff --git a/backend/BackendRCarDu.cpp b/backend/BackendRCarDu.cpp
deleted file mode 100644
index 0750ee4..0000000
--- a/backend/BackendRCarDu.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BackendRCarDu.h"
-
-#include "BackendManager.h"
-#include "bufferinfo/BufferInfoGetter.h"
-#include "drm_fourcc.h"
-
-namespace android {
-
-bool BackendRCarDu::IsClientLayer(HwcDisplay *display, HwcLayer *layer) {
- hwc_drm_bo_t bo;
-
- int ret = BufferInfoGetter::GetInstance()->ConvertBoInfo(layer->GetBuffer(),
- &bo);
- if (ret != 0)
- return true;
-
- if (bo.format == DRM_FORMAT_ABGR8888)
- return true;
-
- if (layer->RequireScalingOrPhasing())
- return true;
-
- return Backend::IsClientLayer(display, layer);
-}
-
-// clang-format off
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables, cert-err58-cpp)
-REGISTER_BACKEND("rcar-du", BackendRCarDu);
-// clang-format on
-
-} // namespace android \ No newline at end of file
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp
index 4f942fe..6baf6bb 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.cpp
+++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp
@@ -47,6 +47,11 @@ struct DroidYuvFormat {
int fourcc; /* DRM_FORMAT_ */
};
+#ifndef DRM_FORMAT_XYUV8888
+#define DRM_FORMAT_XYUV8888 \
+ fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */
+#endif
+
/* The following table is used to look up a DRI image FourCC based
* on native format and information contained in android_ycbcr struct. */
static const struct DroidYuvFormat kDroidYuvFormats[] = {
diff --git a/build_deploy.sh b/build_deploy.sh
index ba9732b..ef25e5c 100755
--- a/build_deploy.sh
+++ b/build_deploy.sh
@@ -14,10 +14,10 @@ mm
adb root && adb remount && adb sync vendor
adb shell stop
-adb shell stop vendor.hwcomposer-2-1 || true
-adb shell stop vendor.hwcomposer-2-2 || true
-adb shell stop vendor.hwcomposer-2-3 || true
-adb shell stop vendor.hwcomposer-2-4 || true
+adb shell stop vendor.hwcomposer-2-1 && adb shell start vendor.hwcomposer-2-1 || true
+adb shell stop vendor.hwcomposer-2-2 && adb shell start vendor.hwcomposer-2-2 || true
+adb shell stop vendor.hwcomposer-2-3 && adb shell start vendor.hwcomposer-2-3 || true
+adb shell stop vendor.hwcomposer-2-4 && adb shell start vendor.hwcomposer-2-4 || true
[ $HWCLOG -eq "1" ] && adb logcat -c
diff --git a/compositor/DrmDisplayComposition.cpp b/compositor/DrmDisplayComposition.cpp
deleted file mode 100644
index e571b26..0000000
--- a/compositor/DrmDisplayComposition.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2015 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-display-composition"
-
-#include "DrmDisplayComposition.h"
-
-#include <sync/sync.h>
-#include <xf86drmMode.h>
-
-#include <algorithm>
-#include <cstdlib>
-#include <unordered_set>
-
-#include "DrmDisplayCompositor.h"
-#include "Planner.h"
-#include "drm/DrmDevice.h"
-#include "utils/log.h"
-
-namespace android {
-
-DrmDisplayComposition::DrmDisplayComposition(DrmCrtc *crtc)
- : crtc_(crtc) // Can be NULL if we haven't modeset yet
-{
-}
-
-int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers) {
- for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
- layers_.emplace_back(std::move(layers[layer_index]));
- }
-
- return 0;
-}
-
-int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) {
- composition_planes_.emplace_back(std::move(plane));
- return 0;
-}
-
-int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes) {
- std::map<size_t, DrmHwcLayer *> to_composite;
-
- for (size_t i = 0; i < layers_.size(); ++i)
- 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);
- if (ret) {
- ALOGV("Planner failed provisioning planes ret=%d", ret);
- return ret;
- }
-
- // Remove the planes we used from the pool before returning. This ensures they
- // won't be reused by another display in the composition.
- for (auto &i : composition_planes_) {
- if (!i.plane())
- continue;
-
- std::vector<DrmPlane *> *container = nullptr;
- if (i.plane()->GetType() == DRM_PLANE_TYPE_PRIMARY)
- container = primary_planes;
- else
- container = overlay_planes;
- for (auto j = container->begin(); j != container->end(); ++j) {
- if (*j == i.plane()) {
- container->erase(j);
- break;
- }
- }
- }
-
- return 0;
-}
-
-} // namespace android
diff --git a/compositor/DrmDisplayComposition.h b/compositor/DrmDisplayComposition.h
deleted file mode 100644
index dcfd96e..0000000
--- a/compositor/DrmDisplayComposition.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 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_DISPLAY_COMPOSITION_H_
-#define ANDROID_DRM_DISPLAY_COMPOSITION_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <sstream>
-#include <vector>
-
-#include "drm/DrmCrtc.h"
-#include "drm/DrmPlane.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class Importer;
-
-constexpr size_t kUndefinedSourceLayer = UINT16_MAX;
-
-class DrmCompositionPlane {
- public:
- DrmCompositionPlane() = default;
- DrmCompositionPlane(DrmCompositionPlane &&rhs) = default;
- DrmCompositionPlane &operator=(DrmCompositionPlane &&other) = default;
- DrmCompositionPlane(DrmPlane *plane, size_t source_layer)
- : plane_(plane), source_layer_(source_layer) {
- }
-
- DrmPlane *plane() const {
- return plane_;
- }
-
- size_t source_layer() const {
- return source_layer_;
- }
-
- private:
- DrmPlane *plane_ = nullptr;
- size_t source_layer_ = kUndefinedSourceLayer;
-};
-
-class DrmDisplayComposition {
- public:
- DrmDisplayComposition(const DrmDisplayComposition &) = delete;
- explicit DrmDisplayComposition(DrmCrtc *crtc);
- ~DrmDisplayComposition() = default;
-
- int SetLayers(DrmHwcLayer *layers, size_t num_layers);
- int AddPlaneComposition(DrmCompositionPlane plane);
-
- int Plan(std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes);
-
- std::vector<DrmHwcLayer> &layers() {
- return layers_;
- }
-
- std::vector<DrmCompositionPlane> &composition_planes() {
- return composition_planes_;
- }
-
- DrmCrtc *crtc() const {
- return crtc_;
- }
-
- private:
- DrmCrtc *crtc_ = nullptr;
-
- std::vector<DrmHwcLayer> layers_;
- std::vector<DrmCompositionPlane> composition_planes_;
-};
-} // namespace android
-
-#endif // ANDROID_DRM_DISPLAY_COMPOSITION_H_
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
deleted file mode 100644
index c2e51ee..0000000
--- a/compositor/DrmDisplayCompositor.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2015 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-display-compositor"
-
-#include "DrmDisplayCompositor.h"
-
-#include <drm/drm_mode.h>
-#include <pthread.h>
-#include <sched.h>
-#include <sync/sync.h>
-#include <utils/Trace.h>
-
-#include <array>
-#include <cstdlib>
-#include <ctime>
-#include <sstream>
-#include <vector>
-
-#include "drm/DrmCrtc.h"
-#include "drm/DrmDevice.h"
-#include "drm/DrmPlane.h"
-#include "drm/DrmUnique.h"
-#include "utils/log.h"
-
-namespace android {
-
-auto DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display)
- -> int {
- resource_manager_ = resource_manager;
- display_ = display;
- DrmDevice *drm = resource_manager_->GetDrmDevice(display);
- if (!drm) {
- ALOGE("Could not find drmdevice for display");
- return -EINVAL;
- }
-
- initialized_ = true;
- return 0;
-}
-
-// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
-auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int {
- ATRACE_CALL();
-
- if (args.active && *args.active == active_frame_state_.crtc_active_state) {
- /* Don't set the same state twice */
- args.active.reset();
- }
-
- if (!args.HasInputs()) {
- /* nothing to do */
- return 0;
- }
-
- if (!active_frame_state_.crtc_active_state) {
- /* Force activate display */
- args.active = true;
- }
-
- if (args.clear_active_composition && args.composition) {
- ALOGE("%s: Invalid arguments", __func__);
- return -EINVAL;
- }
-
- auto new_frame_state = NewFrameState();
-
- DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-
- DrmConnector *connector = drm->GetConnectorForDisplay(display_);
- if (!connector) {
- ALOGE("Could not locate connector for display %d", display_);
- return -ENODEV;
- }
- DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
- if (!crtc) {
- ALOGE("Could not locate crtc for display %d", display_);
- return -ENODEV;
- }
-
- auto pset = MakeDrmModeAtomicReqUnique();
- if (!pset) {
- ALOGE("Failed to allocate property set");
- return -ENOMEM;
- }
-
- int64_t out_fence = -1;
- if (crtc->out_fence_ptr_property() &&
- !crtc->out_fence_ptr_property().AtomicSet(*pset, (uint64_t)&out_fence)) {
- return -EINVAL;
- }
-
- 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;
- }
- }
-
- if (args.display_mode) {
- new_frame_state.mode_blob = args.display_mode.value().CreateModeBlob(
- *resource_manager_->GetDrmDevice(display_));
-
- if (!new_frame_state.mode_blob) {
- ALOGE("Failed to create mode_blob");
- return -EINVAL;
- }
-
- 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();
- 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) {
- 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;
- }
- }
- }
-
- uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
- if (args.test_only)
- flags |= DRM_MODE_ATOMIC_TEST_ONLY;
-
- int err = drmModeAtomicCommit(drm->fd(), pset.get(), flags, drm);
- if (err) {
- if (!args.test_only)
- ALOGE("Failed to commit pset ret=%d\n", err);
- return err;
- }
-
- 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_frame_state_ = std::move(new_frame_state);
-
- if (crtc->out_fence_ptr_property()) {
- args.out_fence = UniqueFd((int)out_fence);
- }
- }
-
- return 0;
-}
-
-auto DrmDisplayCompositor::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
- int err = CommitFrame(args);
-
- if (!args.test_only) {
- if (err) {
- ALOGE("Composite failed for display %d", display_);
- // Disable the hw used by the last active composition. This allows us to
- // signal the release fences from that composition to avoid hanging.
- AtomicCommitArgs cl_args = {.clear_active_composition = true};
- if (CommitFrame(cl_args)) {
- ALOGE("Failed to clean-up active composition for display %d", display_);
- }
- return err;
- }
- }
-
- 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/DrmKmsPlan.cpp b/compositor/DrmKmsPlan.cpp
new file mode 100644
index 0000000..966bd4e
--- /dev/null
+++ b/compositor/DrmKmsPlan.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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-composition-drm-kms-plan"
+
+#include "DrmKmsPlan.h"
+
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "utils/log.h"
+
+namespace android {
+auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
+ std::vector<DrmHwcLayer> composition)
+ -> std::unique_ptr<DrmKmsPlan> {
+ auto plan = std::make_unique<DrmKmsPlan>();
+
+ auto avail_planes = pipe.GetUsablePlanes();
+
+ int z_pos = 0;
+ for (auto &dhl : composition) {
+ std::shared_ptr<BindingOwner<DrmPlane>> plane;
+
+ /* Skip unsupported planes */
+ do {
+ if (avail_planes.empty()) {
+ return {};
+ }
+
+ plane = *avail_planes.begin();
+ avail_planes.erase(avail_planes.begin());
+ } while (!plane->Get()->IsValidForLayer(&dhl));
+
+ LayerToPlaneJoining joining = {
+ .layer = std::move(dhl),
+ .plane = plane,
+ .z_pos = z_pos++,
+ };
+
+ plan->plan.emplace_back(std::move(joining));
+ }
+
+ return plan;
+}
+
+} // namespace android
diff --git a/backend/BackendRCarDu.h b/compositor/DrmKmsPlan.h
index 1259c9f..35e66e9 100644
--- a/backend/BackendRCarDu.h
+++ b/compositor/DrmKmsPlan.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,17 +14,31 @@
* limitations under the License.
*/
-#ifndef HWC_DISPLAY_BACKEND_RCAR_DU_H
-#define HWC_DISPLAY_BACKEND_RCAR_DU_H
+#ifndef ANDROID_DRM_KMS_PLAN_H_
+#define ANDROID_DRM_KMS_PLAN_H_
-#include "Backend.h"
+#include <memory>
+#include <vector>
+
+#include "drmhwcomposer.h"
namespace android {
-class BackendRCarDu : public Backend {
- public:
- bool IsClientLayer(HwcDisplay *display, HwcLayer *layer) override;
+class DrmDevice;
+
+struct DrmKmsPlan {
+ struct LayerToPlaneJoining {
+ DrmHwcLayer layer;
+ std::shared_ptr<BindingOwner<DrmPlane>> plane;
+ int z_pos;
+ };
+
+ std::vector<LayerToPlaneJoining> plan;
+
+ static auto CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
+ std::vector<DrmHwcLayer> composition)
+ -> std::unique_ptr<DrmKmsPlan>;
};
-} // namespace android
+} // namespace android
#endif
diff --git a/compositor/Planner.cpp b/compositor/Planner.cpp
deleted file mode 100644
index f43e314..0000000
--- a/compositor/Planner.cpp
+++ /dev/null
@@ -1,81 +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 LOG_TAG "hwc-platform"
-
-#include "Planner.h"
-
-#include <algorithm>
-
-#include "drm/DrmDevice.h"
-#include "utils/log.h"
-
-namespace android {
-
-std::vector<DrmPlane *> Planner::GetUsablePlanes(
- DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes) {
- std::vector<DrmPlane *> usable_planes;
- std::copy_if(primary_planes->begin(), primary_planes->end(),
- std::back_inserter(usable_planes),
- [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
- std::copy_if(overlay_planes->begin(), overlay_planes->end(),
- std::back_inserter(usable_planes),
- [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
- return usable_planes;
-}
-
-std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes(
- std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
- std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes) {
- std::vector<DrmCompositionPlane> composition;
- std::vector<DrmPlane *> planes = GetUsablePlanes(crtc, primary_planes,
- overlay_planes);
- if (planes.empty()) {
- ALOGE("Display %d has no usable planes", crtc->display());
- return std::make_tuple(-ENODEV, std::vector<DrmCompositionPlane>());
- }
-
- // Go through the provisioning stages and provision planes
- 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 Planner::ProvisionPlanesInternal(
- std::vector<DrmCompositionPlane> *composition,
- 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, std::make_pair(i->first, i->second));
- // We don't have any planes left
- if (ret == -ENOENT)
- break;
-
- if (ret != 0) {
- ALOGV("Failed to emplace layer %zu, dropping it", i->first);
- return ret;
- }
- }
-
- return 0;
-}
-} // namespace android
diff --git a/compositor/Planner.h b/compositor/Planner.h
deleted file mode 100644
index 7802d0c..0000000
--- a/compositor/Planner.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 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_PLATFORM_H_
-#define ANDROID_DRM_PLATFORM_H_
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "compositor/DrmDisplayComposition.h"
-#include "drmhwcomposer.h"
-
-namespace android {
-
-class DrmDevice;
-
-class Planner {
- 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;
- }
-
- // 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);
- }
-
- if (ret == 0) {
- composition->emplace_back(plane, layer.first);
- planes->insert(planes->begin(), unused_planes.begin(),
- unused_planes.end());
- }
-
- 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
- //
- // @layers: a map of index:layer of layers to composite
- // @primary_planes: a vector of primary planes available for this frame
- // @overlay_planes: a vector of overlay planes available for this frame
- //
- // Returns: A tuple with the status of the operation (0 for success) and
- // a vector of the resulting plan (ie: layer->plane mapping).
- 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);
-
- private:
- static std::vector<DrmPlane *> GetUsablePlanes(
- DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes);
-};
-} // namespace android
-#endif
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
new file mode 100644
index 0000000..65fb19e
--- /dev/null
+++ b/drm/DrmAtomicStateManager.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 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-atomic-state-manager"
+
+#include "DrmAtomicStateManager.h"
+
+#include <drm/drm_mode.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+#include <array>
+#include <cstdlib>
+#include <ctime>
+#include <sstream>
+#include <vector>
+
+#include "drm/DrmCrtc.h"
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "drm/DrmUnique.h"
+#include "utils/log.h"
+
+namespace android {
+
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
+ ATRACE_CALL();
+
+ if (args.active && *args.active == active_frame_state_.crtc_active_state) {
+ /* Don't set the same state twice */
+ args.active.reset();
+ }
+
+ if (!args.HasInputs()) {
+ /* nothing to do */
+ return 0;
+ }
+
+ if (!active_frame_state_.crtc_active_state) {
+ /* Force activate display */
+ args.active = true;
+ }
+
+ auto new_frame_state = NewFrameState();
+
+ auto *drm = pipe_->device;
+ auto *connector = pipe_->connector->Get();
+ auto *crtc = pipe_->crtc->Get();
+
+ auto pset = MakeDrmModeAtomicReqUnique();
+ if (!pset) {
+ ALOGE("Failed to allocate property set");
+ return -ENOMEM;
+ }
+
+ int64_t out_fence = -1;
+ if (crtc->GetOutFencePtrProperty() &&
+ !crtc->GetOutFencePtrProperty().AtomicSet(*pset, uint64_t(&out_fence))) {
+ return -EINVAL;
+ }
+
+ if (args.active) {
+ new_frame_state.crtc_active_state = *args.active;
+ if (!crtc->GetActiveProperty().AtomicSet(*pset, *args.active ? 1 : 0) ||
+ !connector->GetCrtcIdProperty().AtomicSet(*pset, crtc->GetId())) {
+ return -EINVAL;
+ }
+ }
+
+ if (args.display_mode) {
+ new_frame_state.mode_blob = args.display_mode.value().CreateModeBlob(*drm);
+
+ if (!new_frame_state.mode_blob) {
+ ALOGE("Failed to create mode_blob");
+ return -EINVAL;
+ }
+
+ if (!crtc->GetModeProperty().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();
+
+ for (auto &joining : args.composition->plan) {
+ DrmPlane *plane = joining.plane->Get();
+ DrmHwcLayer &layer = joining.layer;
+
+ new_frame_state.used_framebuffers.emplace_back(layer.fb_id_handle);
+ new_frame_state.used_planes.emplace_back(joining.plane);
+
+ /* Remove from 'unused' list, since plane is re-used */
+ auto &v = unused_planes;
+ v.erase(std::remove(v.begin(), v.end(), joining.plane), v.end());
+
+ if (plane->AtomicSetState(*pset, layer, joining.z_pos, crtc->GetId()) !=
+ 0) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (args.composition) {
+ for (auto &plane : unused_planes) {
+ if (plane->Get()->AtomicDisablePlane(*pset) != 0) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+ if (args.test_only)
+ flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+
+ int err = drmModeAtomicCommit(drm->GetFd(), pset.get(), flags, drm);
+ if (err != 0) {
+ if (!args.test_only)
+ ALOGE("Failed to commit pset ret=%d\n", err);
+ return err;
+ }
+
+ if (!args.test_only) {
+ if (args.display_mode) {
+ /* TODO(nobody): we still need this for synthetic vsync, remove after
+ * vsync reworked */
+ connector->SetActiveMode(*args.display_mode);
+ }
+
+ active_frame_state_ = std::move(new_frame_state);
+
+ if (crtc->GetOutFencePtrProperty()) {
+ args.out_fence = UniqueFd((int)out_fence);
+ }
+ }
+
+ return 0;
+}
+
+auto DrmAtomicStateManager::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
+ int err = CommitFrame(args);
+
+ if (!args.test_only) {
+ if (err != 0) {
+ ALOGE("Composite failed for pipeline %s",
+ pipe_->connector->Get()->GetName().c_str());
+ // Disable the hw used by the last active composition. This allows us to
+ // signal the release fences from that composition to avoid hanging.
+ AtomicCommitArgs cl_args{};
+ cl_args.composition = std::make_shared<DrmKmsPlan>();
+ if (CommitFrame(cl_args) != 0) {
+ ALOGE("Failed to clean-up active composition for pipeline %s",
+ pipe_->connector->Get()->GetName().c_str());
+ }
+ return err;
+ }
+ }
+
+ return err;
+} // namespace android
+
+auto DrmAtomicStateManager::ActivateDisplayUsingDPMS() -> int {
+ return drmModeConnectorSetProperty(pipe_->device->GetFd(),
+ pipe_->connector->Get()->GetId(),
+ pipe_->connector->Get()
+ ->GetDpmsProperty()
+ .id(),
+ DRM_MODE_DPMS_ON);
+}
+
+} // namespace android
diff --git a/compositor/DrmDisplayCompositor.h b/drm/DrmAtomicStateManager.h
index 9679520..08a1c13 100644
--- a/compositor/DrmDisplayCompositor.h
+++ b/drm/DrmAtomicStateManager.h
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
-#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
+#ifndef ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
+#define ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
#include <pthread.h>
#include <functional>
@@ -27,7 +25,8 @@
#include <sstream>
#include <tuple>
-#include "DrmDisplayComposition.h"
+#include "compositor/DrmKmsPlan.h"
+#include "drm/DrmPlane.h"
#include "drm/ResourceManager.h"
#include "drm/VSyncWorker.h"
#include "drmhwcomposer.h"
@@ -39,29 +38,24 @@ struct AtomicCommitArgs {
bool test_only = false;
std::optional<DrmMode> display_mode;
std::optional<bool> active;
- std::shared_ptr<DrmDisplayComposition> composition;
- /* 'clear' should never be used together with 'composition' */
- bool clear_active_composition = false;
+ std::shared_ptr<DrmKmsPlan> composition;
/* out */
UniqueFd out_fence;
/* helpers */
auto HasInputs() -> bool {
- return display_mode || active || composition || clear_active_composition;
+ return display_mode || active || composition;
}
};
-class DrmDisplayCompositor {
+class DrmAtomicStateManager {
public:
- DrmDisplayCompositor() = default;
- ~DrmDisplayCompositor() = default;
- auto Init(ResourceManager *resource_manager, int display) -> int;
+ explicit DrmAtomicStateManager(DrmDisplayPipeline *pipe) : pipe_(pipe){};
+ DrmAtomicStateManager(const DrmAtomicStateManager &) = delete;
+ ~DrmAtomicStateManager() = default;
auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
-
- DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
-
auto ActivateDisplayUsingDPMS() -> int;
private:
@@ -69,7 +63,7 @@ class DrmDisplayCompositor {
struct KmsState {
/* Required to cleanup unused planes */
- std::vector<DrmPlane *> used_planes;
+ std::vector<std::shared_ptr<BindingOwner<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;
@@ -88,9 +82,7 @@ class DrmDisplayCompositor {
};
}
- ResourceManager *resource_manager_ = nullptr;
- bool initialized_{};
- int display_ = -1;
+ DrmDisplayPipeline *const pipe_;
};
} // namespace android
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 7cbec95..4737316 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -29,10 +29,12 @@
#include "utils/log.h"
#ifndef DRM_MODE_CONNECTOR_SPI
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DRM_MODE_CONNECTOR_SPI 19
#endif
#ifndef DRM_MODE_CONNECTOR_USB
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DRM_MODE_CONNECTOR_USB 20
#endif
@@ -40,62 +42,60 @@ namespace android {
constexpr size_t kTypesCount = 21;
-DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
- DrmEncoder *current_encoder,
- std::vector<DrmEncoder *> &possible_encoders)
- : drm_(drm),
- id_(c->connector_id),
- encoder_(current_encoder),
- display_(-1),
- type_(c->connector_type),
- type_id_(c->connector_type_id),
- state_(c->connection),
- mm_width_(c->mmWidth),
- mm_height_(c->mmHeight),
- possible_encoders_(possible_encoders) {
+static bool GetOptionalConnectorProperty(const DrmDevice &dev,
+ const DrmConnector &connector,
+ const char *prop_name,
+ DrmProperty *property) {
+ return dev.GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR,
+ prop_name, property) == 0;
}
-int DrmConnector::Init() {
- int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_);
- if (ret) {
- ALOGE("Could not get DPMS property\n");
- return ret;
+static bool GetConnectorProperty(const DrmDevice &dev,
+ const DrmConnector &connector,
+ const char *prop_name, DrmProperty *property) {
+ if (!GetOptionalConnectorProperty(dev, connector, prop_name, property)) {
+ ALOGE("Could not get %s property\n", prop_name);
+ return false;
}
- ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_);
- if (ret) {
- ALOGE("Could not get CRTC_ID property\n");
- return ret;
+ return true;
+}
+
+auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
+ uint32_t index)
+ -> std::unique_ptr<DrmConnector> {
+ auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
+ if (!conn) {
+ ALOGE("Failed to get connector %d", connector_id);
+ return {};
}
- UpdateEdidProperty();
- if (writeback()) {
- ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
- &writeback_pixel_formats_);
- if (ret) {
- ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_);
- return ret;
- }
- ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID",
- &writeback_fb_id_);
- if (ret) {
- ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_);
- return ret;
- }
- ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR",
- &writeback_out_fence_);
- if (ret) {
- ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_);
- return ret;
- }
+
+ auto c = std::unique_ptr<DrmConnector>(
+ new DrmConnector(std::move(conn), &dev, index));
+
+ if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
+ !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
+ return {};
}
- return 0;
+
+ c->UpdateEdidProperty();
+
+ if (c->IsWriteback() &&
+ (!GetConnectorProperty(dev, *c, "WRITEBACK_PIXEL_FORMATS",
+ &c->writeback_pixel_formats_) ||
+ !GetConnectorProperty(dev, *c, "WRITEBACK_FB_ID",
+ &c->writeback_fb_id_) ||
+ !GetConnectorProperty(dev, *c, "WRITEBACK_OUT_FENCE_PTR",
+ &c->writeback_out_fence_))) {
+ return {};
+ }
+
+ return c;
}
int DrmConnector::UpdateEdidProperty() {
- int ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
- if (ret) {
- ALOGW("Could not get EDID property\n");
- }
- return ret;
+ return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
+ ? 0
+ : -EINVAL;
}
auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
@@ -105,145 +105,87 @@ auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
return {};
}
- std::tie(ret, blob_id) = edid_property().value();
+ std::tie(ret, blob_id) = GetEdidProperty().value();
if (ret != 0) {
return {};
}
- return MakeDrmModePropertyBlobUnique(drm_->fd(), blob_id);
-}
-
-uint32_t DrmConnector::id() const {
- return id_;
+ return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
}
-int DrmConnector::display() const {
- return display_;
+bool DrmConnector::IsInternal() const {
+ auto type = connector_->connector_type;
+ 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_SPI;
}
-void DrmConnector::set_display(int display) {
- display_ = display;
+bool DrmConnector::IsExternal() const {
+ auto type = connector_->connector_type;
+ 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_USB;
}
-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_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_USB;
-}
-
-bool DrmConnector::writeback() const {
+bool DrmConnector::IsWriteback() const {
#ifdef DRM_MODE_CONNECTOR_WRITEBACK
- return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
+ return connector_->connector_type == DRM_MODE_CONNECTOR_WRITEBACK;
#else
return false;
#endif
}
-bool DrmConnector::valid_type() const {
- return internal() || external() || writeback();
+bool DrmConnector::IsValid() const {
+ return IsInternal() || IsExternal() || IsWriteback();
}
-std::string DrmConnector::name() const {
+std::string DrmConnector::GetName() 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", "DPI",
"Writeback", "SPI", "USB"};
- if (type_ < kTypesCount) {
+ if (connector_->connector_type < kTypesCount) {
std::ostringstream name_buf;
- name_buf << kNames[type_] << "-" << type_id_;
+ name_buf << kNames[connector_->connector_type] << "-"
+ << connector_->connector_type_id;
return name_buf.str();
}
- ALOGE("Unknown type in connector %d, could not make his name", id_);
+ ALOGE("Unknown type in connector %d, could not make his name", GetId());
return "None";
}
int DrmConnector::UpdateModes() {
- drmModeConnectorPtr c = drmModeGetConnector(drm_->fd(), id_);
- if (!c) {
- ALOGE("Failed to get connector %d", id_);
+ auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
+ if (!conn) {
+ ALOGE("Failed to get connector %d", GetId());
return -ENODEV;
}
-
- state_ = c->connection;
+ connector_ = std::move(conn);
modes_.clear();
- for (int i = 0; i < c->count_modes; ++i) {
+ for (int i = 0; i < connector_->count_modes; ++i) {
bool exists = false;
for (const DrmMode &mode : modes_) {
- if (mode == c->modes[i]) {
+ if (mode == connector_->modes[i]) {
exists = true;
break;
}
}
if (!exists) {
- modes_.emplace_back(DrmMode(&c->modes[i]));
+ modes_.emplace_back(DrmMode(&connector_->modes[i]));
}
}
return 0;
}
-const DrmMode &DrmConnector::active_mode() const {
- return active_mode_;
-}
-
-void DrmConnector::set_active_mode(const DrmMode &mode) {
+void DrmConnector::SetActiveMode(DrmMode &mode) {
active_mode_ = mode;
}
-const DrmProperty &DrmConnector::dpms_property() const {
- return dpms_property_;
-}
-
-const DrmProperty &DrmConnector::crtc_id_property() const {
- return crtc_id_property_;
-}
-
-const DrmProperty &DrmConnector::edid_property() const {
- return edid_property_;
-}
-
-const DrmProperty &DrmConnector::writeback_pixel_formats() const {
- return writeback_pixel_formats_;
-}
-
-const DrmProperty &DrmConnector::writeback_fb_id() const {
- return writeback_fb_id_;
-}
-
-const DrmProperty &DrmConnector::writeback_out_fence() const {
- return writeback_out_fence_;
-}
-
-DrmEncoder *DrmConnector::encoder() const {
- return encoder_;
-}
-
-void DrmConnector::set_encoder(DrmEncoder *encoder) {
- encoder_ = encoder;
-}
-
-drmModeConnection DrmConnector::state() const {
- return state_;
-}
-
-uint32_t DrmConnector::mm_width() const {
- return mm_width_;
-}
-
-uint32_t DrmConnector::mm_height() const {
- return mm_height_;
-}
} // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 2bcb543..629b3cc 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -32,69 +32,97 @@ namespace android {
class DrmDevice;
-class DrmConnector {
+class DrmConnector : public PipelineBindable<DrmConnector> {
public:
- DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
- DrmEncoder *current_encoder,
- std::vector<DrmEncoder *> &possible_encoders);
+ static auto CreateInstance(DrmDevice &dev, uint32_t connector_id,
+ uint32_t index) -> std::unique_ptr<DrmConnector>;
+
DrmConnector(const DrmProperty &) = delete;
DrmConnector &operator=(const DrmProperty &) = delete;
- int Init();
int UpdateEdidProperty();
auto GetEdidBlob() -> DrmModePropertyBlobUnique;
- uint32_t id() const;
+ auto GetDev() const -> DrmDevice & {
+ return *drm_;
+ }
+
+ auto GetId() const {
+ return connector_->connector_id;
+ }
+
+ auto GetIndexInResArray() const {
+ return index_in_res_array_;
+ }
+
+ auto GetCurrentEncoderId() const {
+ return connector_->encoder_id;
+ }
+
+ auto SupportsEncoder(DrmEncoder &enc) const {
+ for (int i = 0; i < connector_->count_encoders; i++) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ if (connector_->encoders[i] == enc.GetId()) {
+ return true;
+ }
+ }
- int display() const;
- void set_display(int display);
+ return false;
+ }
- bool internal() const;
- bool external() const;
- bool writeback() const;
- bool valid_type() const;
+ bool IsInternal() const;
+ bool IsExternal() const;
+ bool IsWriteback() const;
+ bool IsValid() const;
- std::string name() const;
+ std::string GetName() const;
int UpdateModes();
- const std::vector<DrmMode> &modes() const {
+ auto &GetModes() const {
return modes_;
}
- const DrmMode &active_mode() const;
- void set_active_mode(const DrmMode &mode);
-
- const DrmProperty &dpms_property() const;
- const DrmProperty &crtc_id_property() const;
- const DrmProperty &edid_property() const;
- const DrmProperty &writeback_pixel_formats() const;
- const DrmProperty &writeback_fb_id() const;
- const DrmProperty &writeback_out_fence() const;
-
- const std::vector<DrmEncoder *> &possible_encoders() const {
- return possible_encoders_;
+
+ auto &GetActiveMode() const {
+ return active_mode_;
}
- DrmEncoder *encoder() const;
- void set_encoder(DrmEncoder *encoder);
- drmModeConnection state() const;
+ void SetActiveMode(DrmMode &mode);
- uint32_t mm_width() const;
- uint32_t mm_height() const;
+ auto &GetDpmsProperty() const {
+ return dpms_property_;
+ }
- private:
- DrmDevice *drm_;
+ auto &GetCrtcIdProperty() const {
+ return crtc_id_property_;
+ }
+
+ auto &GetEdidProperty() const {
+ return edid_property_;
+ }
- uint32_t id_;
- DrmEncoder *encoder_;
- int display_;
+ auto IsConnected() const {
+ return connector_->connection == DRM_MODE_CONNECTED;
+ }
- uint32_t type_;
- uint32_t type_id_;
- drmModeConnection state_;
+ auto GetMmWidth() const {
+ return connector_->mmWidth;
+ }
- uint32_t mm_width_;
- uint32_t mm_height_;
+ auto GetMmHeight() const {
+ return connector_->mmHeight;
+ };
+
+ private:
+ DrmConnector(DrmModeConnectorUnique connector, DrmDevice *drm, uint32_t index)
+ : connector_(std::move(connector)),
+ drm_(drm),
+ index_in_res_array_(index){};
+
+ DrmModeConnectorUnique connector_;
+ DrmDevice *const drm_;
+
+ const uint32_t index_in_res_array_;
DrmMode active_mode_;
std::vector<DrmMode> modes_;
@@ -105,8 +133,6 @@ class DrmConnector {
DrmProperty writeback_pixel_formats_;
DrmProperty writeback_fb_id_;
DrmProperty writeback_out_fence_;
-
- std::vector<DrmEncoder *> possible_encoders_;
};
} // namespace android
diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp
index 08a1922..b54f14b 100644
--- a/drm/DrmCrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -27,60 +27,41 @@
namespace android {
-DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe)
- : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) {
+static int GetCrtcProperty(const DrmDevice &dev, const DrmCrtc &crtc,
+ const char *prop_name, DrmProperty *property) {
+ return dev.GetProperty(crtc.GetId(), DRM_MODE_OBJECT_CRTC, prop_name,
+ property);
}
-int DrmCrtc::Init() {
- int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_);
+auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
+ -> std::unique_ptr<DrmCrtc> {
+ auto crtc = MakeDrmModeCrtcUnique(dev.GetFd(), crtc_id);
+ if (!crtc) {
+ ALOGE("Failed to get CRTC %d", crtc_id);
+ return {};
+ }
+
+ auto c = std::unique_ptr<DrmCrtc>(new DrmCrtc(std::move(crtc), index));
+
+ int ret = GetCrtcProperty(dev, *c, "ACTIVE", &c->active_property_);
if (ret != 0) {
ALOGE("Failed to get ACTIVE property");
- return ret;
+ return {};
}
- ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_);
+ ret = GetCrtcProperty(dev, *c, "MODE_ID", &c->mode_property_);
if (ret != 0) {
ALOGE("Failed to get MODE_ID property");
- return ret;
+ return {};
}
- ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_);
+ ret = GetCrtcProperty(dev, *c, "OUT_FENCE_PTR", &c->out_fence_ptr_property_);
if (ret != 0) {
ALOGE("Failed to get OUT_FENCE_PTR property");
- return ret;
+ return {};
}
- return 0;
-}
-uint32_t DrmCrtc::id() const {
- return id_;
+ return c;
}
-unsigned DrmCrtc::pipe() const {
- return pipe_;
-}
-
-int DrmCrtc::display() const {
- return display_;
-}
-
-void DrmCrtc::set_display(int display) {
- display_ = display;
-}
-
-bool DrmCrtc::can_bind(int display) const {
- return display_ == -1 || display_ == display;
-}
-
-const DrmProperty &DrmCrtc::active_property() const {
- return active_property_;
-}
-
-const DrmProperty &DrmCrtc::mode_property() const {
- return mode_property_;
-}
-
-const DrmProperty &DrmCrtc::out_fence_ptr_property() const {
- return out_fence_ptr_property_;
-}
} // namespace android
diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h
index 85e067a..ebf0a97 100644
--- a/drm/DrmCrtc.h
+++ b/drm/DrmCrtc.h
@@ -21,41 +21,51 @@
#include <cstdint>
+#include "DrmDisplayPipeline.h"
#include "DrmMode.h"
#include "DrmProperty.h"
+#include "DrmUnique.h"
namespace android {
class DrmDevice;
-class DrmCrtc {
+class DrmCrtc : public PipelineBindable<DrmCrtc> {
public:
- DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe);
+ static auto CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
+ -> std::unique_ptr<DrmCrtc>;
+
+ DrmCrtc() = delete;
DrmCrtc(const DrmCrtc &) = delete;
DrmCrtc &operator=(const DrmCrtc &) = delete;
- int Init();
+ auto GetId() const {
+ return crtc_->crtc_id;
+ }
- uint32_t id() const;
- unsigned pipe() const;
+ auto GetIndexInResArray() const {
+ return index_in_res_array_;
+ }
- int display() const;
- void set_display(int display);
+ auto &GetActiveProperty() const {
+ return active_property_;
+ }
- bool can_bind(int display) const;
+ auto &GetModeProperty() const {
+ return mode_property_;
+ }
- const DrmProperty &active_property() const;
- const DrmProperty &mode_property() const;
- const DrmProperty &out_fence_ptr_property() const;
+ auto &GetOutFencePtrProperty() const {
+ return out_fence_ptr_property_;
+ }
private:
- DrmDevice *drm_;
+ DrmCrtc(DrmModeCrtcUnique crtc, uint32_t index)
+ : crtc_(std::move(crtc)), index_in_res_array_(index){};
- uint32_t id_;
- unsigned pipe_;
- int display_;
+ DrmModeCrtcUnique crtc_;
- DrmMode mode_;
+ const uint32_t index_in_res_array_;
DrmProperty active_property_;
DrmProperty mode_property_;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 8245b78..fd4589e 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -22,148 +22,66 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <algorithm>
-#include <array>
-#include <cerrno>
#include <cinttypes>
#include <cstdint>
-#include <sstream>
#include <string>
+#include "drm/DrmAtomicStateManager.h"
#include "drm/DrmPlane.h"
#include "utils/log.h"
#include "utils/properties.h"
-static void trim_left(std::string *str) {
- str->erase(std::begin(*str),
- std::find_if(std::begin(*str), std::end(*str),
- [](int ch) { return std::isspace(ch) == 0; }));
-}
-
-static void trim_right(std::string *str) {
- str->erase(std::find_if(std::rbegin(*str), std::rend(*str),
- [](int ch) { return std::isspace(ch) == 0; })
- .base(),
- std::end(*str));
-}
-
-static void trim(std::string *str) {
- trim_left(str);
- trim_right(str);
-}
-
namespace android {
-static std::vector<std::string> read_primary_display_order_prop() {
- std::array<char, PROPERTY_VALUE_MAX> display_order_buf{};
- property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(),
- "...");
-
- std::vector<std::string> display_order;
- std::istringstream str(display_order_buf.data());
- for (std::string conn_name; std::getline(str, conn_name, ',');) {
- trim(&conn_name);
- display_order.push_back(std::move(conn_name));
- }
- return display_order;
-}
-
-static std::vector<DrmConnector *> make_primary_display_candidates(
- const std::vector<std::unique_ptr<DrmConnector>> &connectors) {
- std::vector<DrmConnector *> primary_candidates;
- std::transform(std::begin(connectors), std::end(connectors),
- std::back_inserter(primary_candidates),
- [](const std::unique_ptr<DrmConnector> &conn) {
- return conn.get();
- });
- primary_candidates.erase(std::remove_if(std::begin(primary_candidates),
- std::end(primary_candidates),
- [](const DrmConnector *conn) {
- return conn->state() !=
- DRM_MODE_CONNECTED;
- }),
- std::end(primary_candidates));
-
- std::vector<std::string> display_order = read_primary_display_order_prop();
- bool use_other = display_order.back() == "...";
-
- // putting connectors from primary_display_order first
- auto curr_connector = std::begin(primary_candidates);
- for (const std::string &display_name : display_order) {
- auto it = std::find_if(std::begin(primary_candidates),
- std::end(primary_candidates),
- [&display_name](const DrmConnector *conn) {
- return conn->name() == display_name;
- });
- if (it != std::end(primary_candidates)) {
- std::iter_swap(it, curr_connector);
- ++curr_connector;
- }
- }
-
- if (use_other) {
- // then putting internal connectors second, everything else afterwards
- std::partition(curr_connector, std::end(primary_candidates),
- [](const DrmConnector *conn) { return conn->internal(); });
- } else {
- primary_candidates.erase(curr_connector, std::end(primary_candidates));
- }
-
- return primary_candidates;
-}
-
DrmDevice::DrmDevice() {
- self.reset(this);
- mDrmFbImporter = std::make_unique<DrmFbImporter>(self);
+ drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
}
-// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
-std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
+auto DrmDevice::Init(const char *path) -> int {
/* TODO: Use drmOpenControl here instead */
fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
- if (fd() < 0) {
+ if (!fd_) {
// NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
ALOGE("Failed to open dri %s: %s", path, strerror(errno));
- return std::make_tuple(-ENODEV, 0);
+ return -ENODEV;
}
- int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- if (ret) {
+ int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ if (ret != 0) {
ALOGE("Failed to set universal plane cap %d", ret);
- return std::make_tuple(ret, 0);
+ return ret;
}
- ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
- if (ret) {
+ ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
+ if (ret != 0) {
ALOGE("Failed to set atomic cap %d", ret);
- return std::make_tuple(ret, 0);
+ return ret;
}
#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
- ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
- if (ret) {
+ ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+ if (ret != 0) {
ALOGI("Failed to set writeback cap %d", ret);
- ret = 0;
}
#endif
uint64_t cap_value = 0;
- if (drmGetCap(fd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value)) {
+ if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
ALOGW("drmGetCap failed. Fallback to no modifier support.");
cap_value = 0;
}
HasAddFb2ModifiersSupport_ = cap_value != 0;
- drmSetMaster(fd());
- if (!drmIsMaster(fd())) {
+ drmSetMaster(GetFd());
+ if (drmIsMaster(GetFd()) == 0) {
ALOGE("DRM/KMS master access required");
- return std::make_tuple(-EACCES, 0);
+ return -EACCES;
}
- auto res = MakeDrmModeResUnique(fd());
+ auto res = MakeDrmModeResUnique(GetFd());
if (!res) {
ALOGE("Failed to get DrmDevice resources");
- return std::make_tuple(-ENODEV, 0);
+ return -ENODEV;
}
min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
@@ -171,264 +89,64 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
res->max_height);
- // Assumes that the primary display will always be in the first
- // drm_device opened.
- bool found_primary = num_displays != 0;
-
- for (int i = 0; !ret && i < res->count_crtcs; ++i) {
- auto c = MakeDrmModeCrtcUnique(fd(), res->crtcs[i]);
- if (!c) {
- ALOGE("Failed to get crtc %d", res->crtcs[i]);
- ret = -ENODEV;
- break;
- }
-
- std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c.get(), i));
-
- ret = crtc->Init();
- if (ret) {
- ALOGE("Failed to initialize crtc %d", res->crtcs[i]);
- break;
+ for (int i = 0; i < res->count_crtcs; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
+ if (crtc) {
+ crtcs_.emplace_back(std::move(crtc));
}
- crtcs_.emplace_back(std::move(crtc));
}
- std::vector<uint32_t> possible_clones;
- for (int i = 0; !ret && i < res->count_encoders; ++i) {
- auto e = MakeDrmModeEncoderUnique(fd(), res->encoders[i]);
- if (!e) {
- ALOGE("Failed to get encoder %d", res->encoders[i]);
- ret = -ENODEV;
- break;
+ for (int i = 0; i < res->count_encoders; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
+ if (enc) {
+ encoders_.emplace_back(std::move(enc));
}
-
- std::vector<DrmCrtc *> possible_crtcs;
- DrmCrtc *current_crtc = nullptr;
- for (auto &crtc : crtcs_) {
- if ((1 << crtc->pipe()) & e->possible_crtcs)
- possible_crtcs.push_back(crtc.get());
-
- if (crtc->id() == e->crtc_id)
- current_crtc = crtc.get();
- }
-
- std::unique_ptr<DrmEncoder> enc(
- new DrmEncoder(e.get(), current_crtc, possible_crtcs));
- possible_clones.push_back(e->possible_clones);
-
- encoders_.emplace_back(std::move(enc));
}
- for (unsigned int i = 0; i < encoders_.size(); i++) {
- for (unsigned int j = 0; j < encoders_.size(); j++)
- if (possible_clones[i] & (1 << j))
- encoders_[i]->AddPossibleClone(encoders_[j].get());
- }
-
- for (int i = 0; !ret && i < res->count_connectors; ++i) {
- auto c = MakeDrmModeConnectorUnique(fd(), res->connectors[i]);
- if (!c) {
- ALOGE("Failed to get connector %d", res->connectors[i]);
- ret = -ENODEV;
- break;
- }
-
- std::vector<DrmEncoder *> possible_encoders;
- DrmEncoder *current_encoder = nullptr;
- for (int j = 0; j < c->count_encoders; ++j) {
- for (auto &encoder : encoders_) {
- if (encoder->id() == c->encoders[j])
- possible_encoders.push_back(encoder.get());
- if (encoder->id() == c->encoder_id)
- current_encoder = encoder.get();
- }
- }
-
- std::unique_ptr<DrmConnector> conn(
- new DrmConnector(this, c.get(), current_encoder, possible_encoders));
+ for (int i = 0; i < res->count_connectors; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
- ret = conn->Init();
- if (ret) {
- ALOGE("Init connector %d failed", res->connectors[i]);
- break;
+ if (!conn) {
+ continue;
}
- if (conn->writeback())
+ if (conn->IsWriteback()) {
writeback_connectors_.emplace_back(std::move(conn));
- else
+ } else {
connectors_.emplace_back(std::move(conn));
- }
-
- // Primary display priority:
- // 1) vendor.hwc.drm.primary_display_order property
- // 2) internal connectors
- // 3) anything else
- std::vector<DrmConnector *>
- primary_candidates = make_primary_display_candidates(connectors_);
- if (!primary_candidates.empty() && !found_primary) {
- DrmConnector &conn = **std::begin(primary_candidates);
- conn.set_display(num_displays);
- displays_[num_displays] = num_displays;
- ++num_displays;
- found_primary = true;
- } else {
- ALOGE(
- "Failed to find primary display from "
- "\"vendor.hwc.drm.primary_display_order\" property");
- }
-
- // If no priority display were found then pick first available as primary and
- // for the others assign consecutive display_numbers.
- for (auto &conn : connectors_) {
- if (conn->external() || conn->internal()) {
- if (!found_primary) {
- conn->set_display(num_displays);
- displays_[num_displays] = num_displays;
- found_primary = true;
- ++num_displays;
- } else if (conn->display() < 0) {
- conn->set_display(num_displays);
- displays_[num_displays] = num_displays;
- ++num_displays;
- }
}
}
- // Catch-all for the above loops
- if (ret)
- return std::make_tuple(ret, 0);
-
- auto plane_res = MakeDrmModePlaneResUnique(fd());
+ auto plane_res = MakeDrmModePlaneResUnique(GetFd());
if (!plane_res) {
ALOGE("Failed to get plane resources");
- return std::make_tuple(-ENOENT, 0);
+ return -ENOENT;
}
for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
- auto p = MakeDrmModePlaneUnique(fd(), plane_res->planes[i]);
- if (!p) {
- ALOGE("Failed to get plane %d", plane_res->planes[i]);
- ret = -ENODEV;
- break;
- }
-
- std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p.get()));
-
- ret = plane->Init();
- if (ret) {
- ALOGE("Init plane %d failed", plane_res->planes[i]);
- break;
- }
-
- planes_.emplace_back(std::move(plane));
- }
- if (ret)
- return std::make_tuple(ret, 0);
-
- for (auto &conn : connectors_) {
- ret = CreateDisplayPipe(conn.get());
- if (ret) {
- ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
- return std::make_tuple(ret, 0);
- }
- }
- return std::make_tuple(ret, displays_.size());
-}
-
-bool DrmDevice::HandlesDisplay(int display) const {
- return displays_.find(display) != displays_.end();
-}
-
-DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
- for (const auto &conn : connectors_) {
- if (conn->display() == display)
- return conn.get();
- }
- return nullptr;
-}
-
-DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
- for (const auto &crtc : crtcs_) {
- if (crtc->display() == display)
- return crtc.get();
- }
- return nullptr;
-}
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
-const std::vector<std::unique_ptr<DrmCrtc>> &DrmDevice::crtcs() const {
- return crtcs_;
-}
-
-uint32_t DrmDevice::next_mode_id() {
- return ++mode_id_;
-}
-
-int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) {
- /* First try to use the currently-bound crtc */
- DrmCrtc *crtc = enc->crtc();
- if (crtc && crtc->can_bind(display)) {
- crtc->set_display(display);
- enc->set_crtc(crtc);
- return 0;
- }
-
- /* Try to find a possible crtc which will work */
- for (DrmCrtc *crtc : enc->possible_crtcs()) {
- /* We've already tried this earlier */
- if (crtc == enc->crtc())
- continue;
-
- if (crtc->can_bind(display)) {
- crtc->set_display(display);
- enc->set_crtc(crtc);
- return 0;
+ if (plane) {
+ planes_.emplace_back(std::move(plane));
}
}
- /* We can't use the encoder, but nothing went wrong, try another one */
- return -EAGAIN;
-}
-
-int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
- int display = connector->display();
- /* Try to use current setup first */
- if (connector->encoder()) {
- int ret = TryEncoderForDisplay(display, connector->encoder());
- if (!ret) {
- return 0;
- }
-
- if (ret != -EAGAIN) {
- ALOGE("Could not set mode %d/%d", display, ret);
- return ret;
- }
- }
-
- for (DrmEncoder *enc : connector->possible_encoders()) {
- int ret = TryEncoderForDisplay(display, enc);
- if (!ret) {
- connector->set_encoder(enc);
- return 0;
- }
-
- if (ret != -EAGAIN) {
- ALOGE("Could not set mode %d/%d", display, ret);
- return ret;
- }
- }
- ALOGE("Could not find a suitable encoder/crtc for display %d",
- connector->display());
- return -ENODEV;
+ return 0;
}
auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
-> DrmModeUserPropertyBlobUnique {
struct drm_mode_create_blob create_blob {};
create_blob.length = length;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
create_blob.data = (__u64)data;
- int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
- if (ret) {
+ int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
+ if (ret != 0) {
ALOGE("Failed to create mode property blob %d", ret);
return {};
}
@@ -437,7 +155,8 @@ auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
struct drm_mode_destroy_blob destroy_blob {};
destroy_blob.blob_id = (__u32)*it;
- int err = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob);
+ int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
+ &destroy_blob);
if (err != 0) {
ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
err);
@@ -451,16 +170,18 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
const char *prop_name, DrmProperty *property) const {
drmModeObjectPropertiesPtr props = nullptr;
- props = drmModeObjectGetProperties(fd(), obj_id, obj_type);
- if (!props) {
+ props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
+ if (props == nullptr) {
ALOGE("Failed to get properties for %d/%x", obj_id, obj_type);
return -ENODEV;
}
bool found = false;
for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
- drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]);
- if (!strcmp(p->name, prop_name)) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
+ if (strcmp(p->name, prop_name) == 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
property->Init(obj_id, p, props->prop_values[i]);
found = true;
}
@@ -471,22 +192,10 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
return found ? 0 : -ENOENT;
}
-int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
- DrmProperty *property) const {
- return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
-}
-
-int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
- const char *prop_name,
- DrmProperty *property) const {
- return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
- property);
-}
-
std::string DrmDevice::GetName() const {
- auto *ver = drmGetVersion(fd());
- if (!ver) {
- ALOGW("Failed to get drm version for fd=%d", fd());
+ auto *ver = drmGetVersion(GetFd());
+ if (ver == nullptr) {
+ ALOGW("Failed to get drm version for fd=%d", GetFd());
return "generic";
}
@@ -512,4 +221,22 @@ auto DrmDevice::IsKMSDev(const char *path) -> bool {
return is_kms;
}
+auto DrmDevice::GetConnectors()
+ -> const std::vector<std::unique_ptr<DrmConnector>> & {
+ return connectors_;
+}
+
+auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
+ return planes_;
+}
+
+auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
+ return crtcs_;
+}
+
+auto DrmDevice::GetEncoders()
+ -> const std::vector<std::unique_ptr<DrmEncoder>> & {
+ return encoders_;
+}
+
} // namespace android
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index 9983d61..f2530ee 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -37,66 +37,65 @@ class DrmDevice {
DrmDevice();
~DrmDevice() = default;
- std::tuple<int, int> Init(const char *path, int num_displays);
+ auto Init(const char *path) -> int;
- int fd() const {
+ auto GetFd() const {
return fd_.Get();
}
- const std::vector<std::unique_ptr<DrmConnector>> &connectors() const {
- return connectors_;
- }
-
- const std::vector<std::unique_ptr<DrmPlane>> &planes() const {
- return planes_;
- }
+ auto GetConnectors() -> const std::vector<std::unique_ptr<DrmConnector>> &;
+ auto GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> &;
+ auto GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> &;
+ auto GetEncoders() -> const std::vector<std::unique_ptr<DrmEncoder>> &;
- std::pair<uint32_t, uint32_t> min_resolution() const {
+ auto GetMinResolution() const {
return min_resolution_;
}
- std::pair<uint32_t, uint32_t> max_resolution() const {
+ auto GetMaxResolution() const {
return max_resolution_;
}
- DrmConnector *GetConnectorForDisplay(int display) const;
- DrmCrtc *GetCrtcForDisplay(int display) const;
-
- int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
- DrmProperty *property) const;
- int GetConnectorProperty(const DrmConnector &connector, const char *prop_name,
- DrmProperty *property) const;
-
std::string GetName() const;
- const std::vector<std::unique_ptr<DrmCrtc>> &crtcs() const;
- uint32_t next_mode_id();
-
auto RegisterUserPropertyBlob(void *data, size_t length) const
-> DrmModeUserPropertyBlobUnique;
- bool HandlesDisplay(int display) const;
-
- bool HasAddFb2ModifiersSupport() const {
+ auto HasAddFb2ModifiersSupport() const {
return HasAddFb2ModifiersSupport_;
}
- DrmFbImporter &GetDrmFbImporter() {
- return *mDrmFbImporter;
+ auto &GetDrmFbImporter() {
+ return *drm_fb_importer_;
}
static auto IsKMSDev(const char *path) -> bool;
+ auto FindCrtcById(uint32_t id) const -> DrmCrtc * {
+ for (const auto &crtc : crtcs_) {
+ if (crtc->GetId() == id) {
+ return crtc.get();
+ }
+ };
+
+ return nullptr;
+ }
+
+ auto FindEncoderById(uint32_t id) const -> DrmEncoder * {
+ for (const auto &enc : encoders_) {
+ if (enc->GetId() == id) {
+ return enc.get();
+ }
+ };
+
+ return nullptr;
+ }
+
int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
DrmProperty *property) const;
private:
- int TryEncoderForDisplay(int display, DrmEncoder *enc);
-
- int CreateDisplayPipe(DrmConnector *connector);
-
UniqueFd fd_;
- uint32_t mode_id_ = 0;
std::vector<std::unique_ptr<DrmConnector>> connectors_;
std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
@@ -106,13 +105,10 @@ class DrmDevice {
std::pair<uint32_t, uint32_t> min_resolution_;
std::pair<uint32_t, uint32_t> max_resolution_;
- std::map<int, int> displays_;
bool HasAddFb2ModifiersSupport_{};
- std::shared_ptr<DrmDevice> self;
-
- std::unique_ptr<DrmFbImporter> mDrmFbImporter;
+ std::unique_ptr<DrmFbImporter> drm_fb_importer_;
};
} // namespace android
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
new file mode 100644
index 0000000..f993d28
--- /dev/null
+++ b/drm/DrmDisplayPipeline.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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-drm-display-pipeline"
+
+#include "DrmDisplayPipeline.h"
+
+#include "DrmAtomicStateManager.h"
+#include "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmDevice.h"
+#include "DrmEncoder.h"
+#include "DrmPlane.h"
+#include "utils/log.h"
+#include "utils/properties.h"
+
+namespace android {
+
+template <class O>
+auto PipelineBindable<O>::BindPipeline(DrmDisplayPipeline *pipeline,
+ bool return_object_if_bound)
+ -> std::shared_ptr<BindingOwner<O>> {
+ auto owner_object = owner_object_.lock();
+ if (owner_object) {
+ if (bound_pipeline_ == pipeline && return_object_if_bound) {
+ return owner_object;
+ }
+
+ return {};
+ }
+ owner_object = std::make_shared<BindingOwner<O>>(static_cast<O *>(this));
+
+ owner_object_ = owner_object;
+ bound_pipeline_ = pipeline;
+ return owner_object;
+}
+
+static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
+ DrmEncoder &enc, DrmCrtc &crtc)
+ -> std::unique_ptr<DrmDisplayPipeline> {
+ /* Check if resources are available */
+
+ auto pipe = std::make_unique<DrmDisplayPipeline>();
+ pipe->device = &dev;
+
+ pipe->connector = connector.BindPipeline(pipe.get());
+ pipe->encoder = enc.BindPipeline(pipe.get());
+ pipe->crtc = crtc.BindPipeline(pipe.get());
+
+ if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
+ return {};
+ }
+
+ std::vector<DrmPlane *> primary_planes;
+ std::vector<DrmPlane *> overlay_planes;
+
+ /* Attach necessary resources */
+ auto display_planes = std::vector<DrmPlane *>();
+ for (const auto &plane : dev.GetPlanes()) {
+ if (plane->IsCrtcSupported(crtc)) {
+ if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) {
+ primary_planes.emplace_back(plane.get());
+ } else if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
+ overlay_planes.emplace_back(plane.get());
+ } else {
+ ALOGI("Ignoring cursor plane %d", plane->GetId());
+ }
+ }
+ }
+
+ if (primary_planes.empty()) {
+ ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
+ return {};
+ }
+
+ if (primary_planes.size() > 1) {
+ ALOGE("Found more than 1 primary plane for CRTC %d", crtc.GetId());
+ return {};
+ }
+
+ pipe->primary_plane = primary_planes[0]->BindPipeline(pipe.get());
+ if (!pipe->primary_plane) {
+ ALOGE("Primary plane %d is already owned. Internal error.",
+ primary_planes[0]->GetId());
+ return {};
+ }
+
+ pipe->atomic_state_manager = std::make_unique<DrmAtomicStateManager>(
+ pipe.get());
+
+ return pipe;
+}
+
+static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
+ DrmEncoder &enc)
+ -> std::unique_ptr<DrmDisplayPipeline> {
+ /* First try to use the currently-bound crtc */
+ auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
+ if (crtc != nullptr) {
+ auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+
+ /* Try to find a possible crtc which will work */
+ for (const auto &crtc : dev.GetCrtcs()) {
+ if (enc.SupportsCrtc(*crtc)) {
+ auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+ }
+
+ /* We can't use this encoder, but nothing went wrong, try another one */
+ return {};
+}
+
+auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
+ -> std::unique_ptr<DrmDisplayPipeline> {
+ auto &dev = connector.GetDev();
+ /* Try to use current setup first */
+ auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
+
+ if (encoder != nullptr) {
+ auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+
+ for (const auto &enc : dev.GetEncoders()) {
+ if (connector.SupportsEncoder(*enc)) {
+ auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+ }
+
+ ALOGE("Could not find a suitable encoder/crtc for connector %s",
+ connector.GetName().c_str());
+
+ return {};
+}
+
+static bool ReadUseOverlayProperty() {
+ char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
+ property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
+ "1");
+ constexpr int kStrtolBase = 10;
+ return strtol(use_overlay_planes_prop, nullptr, kStrtolBase) != 0;
+}
+
+auto DrmDisplayPipeline::GetUsablePlanes()
+ -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> {
+ std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> planes;
+ planes.emplace_back(primary_plane);
+
+ static bool use_overlay_planes = ReadUseOverlayProperty();
+
+ if (use_overlay_planes) {
+ for (const auto &plane : device->GetPlanes()) {
+ if (plane->IsCrtcSupported(*crtc->Get())) {
+ if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
+ auto op = plane->BindPipeline(this, true);
+ if (op) {
+ planes.emplace_back(op);
+ }
+ }
+ }
+ }
+ }
+
+ return planes;
+}
+
+} // namespace android
diff --git a/drm/DrmDisplayPipeline.h b/drm/DrmDisplayPipeline.h
new file mode 100644
index 0000000..7ec619e
--- /dev/null
+++ b/drm/DrmDisplayPipeline.h
@@ -0,0 +1,90 @@
+/*
+ * 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_DRMDISPLAYPIPELINE_H_
+#define ANDROID_DRMDISPLAYPIPELINE_H_
+
+#include <memory>
+#include <vector>
+
+namespace android {
+
+class DrmConnector;
+class DrmDevice;
+class DrmPlane;
+class DrmCrtc;
+class DrmEncoder;
+class DrmAtomicStateManager;
+
+struct DrmDisplayPipeline;
+
+template <class O>
+class BindingOwner;
+
+template <class O>
+class PipelineBindable {
+ friend class BindingOwner<O>;
+
+ public:
+ auto *GetPipeline() {
+ return bound_pipeline_;
+ }
+
+ auto BindPipeline(DrmDisplayPipeline *pipeline,
+ bool return_object_if_bound = false)
+ -> std::shared_ptr<BindingOwner<O>>;
+
+ private:
+ DrmDisplayPipeline *bound_pipeline_;
+ std::weak_ptr<BindingOwner<O>> owner_object_;
+};
+
+template <class B>
+class BindingOwner {
+ public:
+ explicit BindingOwner(B *pb) : bindable_(pb){};
+ ~BindingOwner() {
+ bindable_->bound_pipeline_ = nullptr;
+ }
+
+ B *Get() {
+ return bindable_;
+ }
+
+ private:
+ B *const bindable_;
+};
+
+struct DrmDisplayPipeline {
+ static auto CreatePipeline(DrmConnector &connector)
+ -> std::unique_ptr<DrmDisplayPipeline>;
+
+ auto GetUsablePlanes()
+ -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>>;
+
+ DrmDevice *device;
+
+ std::shared_ptr<BindingOwner<DrmConnector>> connector;
+ std::shared_ptr<BindingOwner<DrmEncoder>> encoder;
+ std::shared_ptr<BindingOwner<DrmCrtc>> crtc;
+ std::shared_ptr<BindingOwner<DrmPlane>> primary_plane;
+
+ std::unique_ptr<DrmAtomicStateManager> atomic_state_manager;
+};
+
+} // namespace android
+
+#endif
diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp
index ad05f88..eed5b5f 100644
--- a/drm/DrmEncoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "hwc-drm-encoder"
+
#include "DrmEncoder.h"
#include <xf86drmMode.h>
@@ -21,43 +23,19 @@
#include <cstdint>
#include "DrmDevice.h"
+#include "utils/log.h"
namespace android {
-DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
- std::vector<DrmCrtc *> possible_crtcs)
- : id_(e->encoder_id),
- crtc_(current_crtc),
- display_(-1),
- possible_crtcs_(std::move(possible_crtcs)) {
-}
-
-uint32_t DrmEncoder::id() const {
- return id_;
-}
+auto DrmEncoder::CreateInstance(DrmDevice &dev, uint32_t encoder_id,
+ uint32_t index) -> std::unique_ptr<DrmEncoder> {
+ auto e = MakeDrmModeEncoderUnique(dev.GetFd(), encoder_id);
+ if (!e) {
+ ALOGE("Failed to get encoder %d", encoder_id);
+ return {};
+ }
-DrmCrtc *DrmEncoder::crtc() const {
- return crtc_;
+ return std::unique_ptr<DrmEncoder>(new DrmEncoder(std::move(e), index));
}
-bool DrmEncoder::CanClone(DrmEncoder *encoder) {
- return possible_clones_.find(encoder) != possible_clones_.end();
-}
-
-void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) {
- possible_clones_.insert(possible_clone);
-}
-
-void DrmEncoder::set_crtc(DrmCrtc *crtc) {
- crtc_ = crtc;
- display_ = crtc->display();
-}
-
-int DrmEncoder::display() const {
- return display_;
-}
-
-bool DrmEncoder::can_bind(int display) const {
- return display_ == -1 || display_ == display;
-}
} // namespace android
diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h
index b130b7d..39a695c 100644
--- a/drm/DrmEncoder.h
+++ b/drm/DrmEncoder.h
@@ -24,36 +24,45 @@
#include <vector>
#include "DrmCrtc.h"
+#include "DrmDisplayPipeline.h"
namespace android {
-class DrmEncoder {
+class DrmEncoder : public PipelineBindable<DrmEncoder> {
public:
- DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
- std::vector<DrmCrtc *> possible_crtcs);
+ static auto CreateInstance(DrmDevice &dev, uint32_t encoder_id,
+ uint32_t index) -> std::unique_ptr<DrmEncoder>;
+
DrmEncoder(const DrmEncoder &) = delete;
DrmEncoder &operator=(const DrmEncoder &) = delete;
- uint32_t id() const;
+ auto GetId() const {
+ return enc_->encoder_id;
+ };
+
+ auto GetIndexInResArray() const {
+ return index_in_res_array_;
+ }
- DrmCrtc *crtc() const;
- void set_crtc(DrmCrtc *crtc);
- bool can_bind(int display) const;
- int display() const;
+ auto CanClone(DrmEncoder &encoder) {
+ return (enc_->possible_clones & (1 << encoder.GetIndexInResArray())) != 0;
+ }
- const std::vector<DrmCrtc *> &possible_crtcs() const {
- return possible_crtcs_;
+ auto SupportsCrtc(DrmCrtc &crtc) {
+ return (enc_->possible_crtcs & (1 << crtc.GetIndexInResArray())) != 0;
+ }
+
+ auto GetCurrentCrtcId() {
+ return enc_->crtc_id;
}
- bool CanClone(DrmEncoder *encoder);
- void AddPossibleClone(DrmEncoder *possible_clone);
private:
- uint32_t id_;
- DrmCrtc *crtc_;
- int display_;
+ DrmEncoder(DrmModeEncoderUnique enc, uint32_t index)
+ : enc_(std::move(enc)), index_in_res_array_(index){};
+
+ DrmModeEncoderUnique enc_;
- std::vector<DrmCrtc *> possible_crtcs_;
- std::set<DrmEncoder *> possible_clones_;
+ const uint32_t index_in_res_array_;
};
} // namespace android
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index 6f2abe8..eeab076 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -32,7 +32,7 @@
namespace android {
auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
- const std::shared_ptr<DrmDevice> &drm)
+ DrmDevice &drm)
-> std::shared_ptr<DrmFbIdHandle> {
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm));
@@ -44,7 +44,7 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
for (size_t i = 1; i < local->gem_handles_.size(); i++) {
if (bo->prime_fds[i] > 0) {
if (bo->prime_fds[i] != bo->prime_fds[0]) {
- err = drmPrimeFDToHandle(drm->fd(), bo->prime_fds[i],
+ err = drmPrimeFDToHandle(drm.GetFd(), bo->prime_fds[i],
&local->gem_handles_.at(i));
if (err != 0) {
ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
@@ -59,7 +59,7 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
bool has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
- if (!drm->HasAddFb2ModifiersSupport() && has_modifiers) {
+ if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
bo->modifiers[0]);
local.reset();
@@ -68,11 +68,11 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
/* Create framebuffer object */
if (!has_modifiers) {
- err = drmModeAddFB2(drm->fd(), bo->width, bo->height, bo->format,
+ err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
&local->gem_handles_[0], &bo->pitches[0],
&bo->offsets[0], &local->fb_id_, 0);
} else {
- err = drmModeAddFB2WithModifiers(drm->fd(), bo->width, bo->height,
+ err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
bo->format, &local->gem_handles_[0],
&bo->pitches[0], &bo->offsets[0],
&bo->modifiers[0], &local->fb_id_,
@@ -88,7 +88,7 @@ auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
DrmFbIdHandle::~DrmFbIdHandle() {
/* Destroy framebuffer object */
- if (drmModeRmFB(drm_->fd(), fb_id_) != 0) {
+ if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
ALOGE("Failed to rm fb");
}
@@ -109,7 +109,7 @@ DrmFbIdHandle::~DrmFbIdHandle() {
continue;
}
gem_close.handle = gem_handles_[i];
- int32_t err = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+ int32_t err = drmIoctl(drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
if (err != 0) {
ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
}
@@ -120,7 +120,8 @@ auto DrmFbImporter::GetOrCreateFbId(hwc_drm_bo_t *bo)
-> std::shared_ptr<DrmFbIdHandle> {
/* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
GemHandle first_handle = 0;
- int32_t err = drmPrimeFDToHandle(drm_->fd(), bo->prime_fds[0], &first_handle);
+ int32_t err = drmPrimeFDToHandle(drm_->GetFd(), bo->prime_fds[0],
+ &first_handle);
if (err != 0) {
ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
@@ -143,7 +144,7 @@ auto DrmFbImporter::GetOrCreateFbId(hwc_drm_bo_t *bo)
}
/* No DrmFbIdHandle found in cache, create framebuffer object */
- auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, drm_);
+ auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, *drm_);
if (fb_id_handle) {
drm_fb_id_handle_cache_[first_handle] = fb_id_handle;
}
diff --git a/drm/DrmFbImporter.h b/drm/DrmFbImporter.h
index efeb457..7f17bbe 100644
--- a/drm/DrmFbImporter.h
+++ b/drm/DrmFbImporter.h
@@ -37,8 +37,7 @@ namespace android {
class DrmFbIdHandle {
public:
static auto CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
- const std::shared_ptr<DrmDevice> &drm)
- -> std::shared_ptr<DrmFbIdHandle>;
+ DrmDevice &drm) -> std::shared_ptr<DrmFbIdHandle>;
~DrmFbIdHandle();
DrmFbIdHandle(DrmFbIdHandle &&) = delete;
@@ -51,10 +50,9 @@ class DrmFbIdHandle {
}
private:
- explicit DrmFbIdHandle(std::shared_ptr<DrmDevice> drm)
- : drm_(std::move(drm)){};
+ explicit DrmFbIdHandle(DrmDevice &drm) : drm_(&drm){};
- const std::shared_ptr<DrmDevice> drm_;
+ DrmDevice *const drm_;
uint32_t fb_id_{};
std::array<GemHandle, kHwcDrmBoMaxPlanes> gem_handles_{};
@@ -62,8 +60,7 @@ class DrmFbIdHandle {
class DrmFbImporter {
public:
- explicit DrmFbImporter(std::shared_ptr<DrmDevice> drm)
- : drm_(std::move(drm)){};
+ explicit DrmFbImporter(DrmDevice &drm) : drm_(&drm){};
~DrmFbImporter() = default;
DrmFbImporter(const DrmFbImporter &) = delete;
DrmFbImporter(DrmFbImporter &&) = delete;
@@ -84,7 +81,7 @@ class DrmFbImporter {
}
}
- const std::shared_ptr<DrmDevice> drm_;
+ DrmDevice *const drm_;
std::map<GemHandle, std::weak_ptr<DrmFbIdHandle>> drm_fb_id_handle_cache_;
};
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 25a4902..28f48f3 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -29,15 +29,28 @@
namespace android {
-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) {
+auto DrmPlane::CreateInstance(DrmDevice &dev, uint32_t plane_id)
+ -> std::unique_ptr<DrmPlane> {
+ auto p = MakeDrmModePlaneUnique(dev.GetFd(), plane_id);
+ if (!p) {
+ ALOGE("Failed to get plane %d", plane_id);
+ return {};
+ }
+
+ auto plane = std::unique_ptr<DrmPlane>(new DrmPlane(dev, std::move(p)));
+
+ if (plane->Init() != 0) {
+ ALOGE("Failed to init plane %d", plane_id);
+ return {};
+ }
+
+ return plane;
}
int DrmPlane::Init() {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ formats_ = {plane_->formats, plane_->formats + plane_->count_formats};
+
DrmProperty p;
if (!GetPlaneProperty("type", p)) {
@@ -134,38 +147,38 @@ int DrmPlane::Init() {
return 0;
}
-bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const {
- return ((1 << crtc.pipe()) & possible_crtc_mask_) != 0;
+bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
+ return ((1 << crtc.GetIndexInResArray()) & plane_->possible_crtcs) != 0;
}
bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
if (!rotation_property_) {
if (layer->transform != DrmHwcTransform::kIdentity) {
- ALOGV("No rotation property on plane %d", id_);
+ ALOGV("No rotation property on plane %d", GetId());
return false;
}
} else {
if (transform_enum_map_.count(layer->transform) == 0) {
- ALOGV("Transform is not supported on plane %d", id_);
+ ALOGV("Transform is not supported on plane %d", GetId());
return false;
}
}
if (alpha_property_.id() == 0 && layer->alpha != UINT16_MAX) {
- ALOGV("Alpha is not supported on plane %d", id_);
+ ALOGV("Alpha is not supported on plane %d", GetId());
return false;
}
if (blending_enum_map_.count(layer->blending) == 0 &&
layer->blending != DrmHwcBlending::kNone &&
layer->blending != DrmHwcBlending::kPreMult) {
- ALOGV("Blending is not supported on plane %d", id_);
+ ALOGV("Blending is not supported on plane %d", GetId());
return false;
}
uint32_t format = layer->buffer_info.format;
if (!IsFormatSupported(format)) {
- ALOGV("Plane %d does not supports %c%c%c%c format", id_, format,
+ ALOGV("Plane %d does not supports %c%c%c%c format", GetId(), format,
format >> 8, format >> 16, format >> 24);
return false;
}
@@ -173,10 +186,6 @@ bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
return true;
}
-uint32_t DrmPlane::GetType() const {
- return type_;
-}
-
bool DrmPlane::IsFormatSupported(uint32_t format) const {
return std::find(std::begin(formats_), std::end(formats_), format) !=
std::end(formats_);
@@ -290,20 +299,17 @@ auto DrmPlane::AtomicDisablePlane(drmModeAtomicReq &pset) -> int {
return 0;
}
-const DrmProperty &DrmPlane::GetZPosProperty() const {
- return zpos_property_;
-}
-
auto DrmPlane::GetPlaneProperty(const char *prop_name, DrmProperty &property,
Presence presence) -> bool {
- int err = drm_->GetProperty(id_, DRM_MODE_OBJECT_PLANE, prop_name, &property);
+ int err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_PLANE, prop_name,
+ &property);
if (err != 0) {
if (presence == Presence::kMandatory) {
ALOGE("Could not get mandatory property \"%s\" from plane %d", prop_name,
- id_);
+ GetId());
} else {
ALOGV("Could not get optional property \"%s\" from plane %d", prop_name,
- id_);
+ GetId());
}
return false;
}
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index e1ee920..65f458f 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -31,18 +31,20 @@ namespace android {
class DrmDevice;
struct DrmHwcLayer;
-class DrmPlane {
+class DrmPlane : public PipelineBindable<DrmPlane> {
public:
- DrmPlane(DrmDevice *drm, drmModePlanePtr p);
DrmPlane(const DrmPlane &) = delete;
DrmPlane &operator=(const DrmPlane &) = delete;
- int Init();
+ static auto CreateInstance(DrmDevice &dev, uint32_t plane_id)
+ -> std::unique_ptr<DrmPlane>;
- bool GetCrtcSupported(const DrmCrtc &crtc) const;
+ bool IsCrtcSupported(const DrmCrtc &crtc) const;
bool IsValidForLayer(DrmHwcLayer *layer);
- uint32_t GetType() const;
+ auto GetType() const {
+ return type_;
+ }
bool IsFormatSupported(uint32_t format) const;
bool HasNonRgbFormat() const;
@@ -50,19 +52,26 @@ class DrmPlane {
auto AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos,
uint32_t crtc_id) -> int;
auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
- const DrmProperty &GetZPosProperty() const;
+ auto &GetZPosProperty() const {
+ return zpos_property_;
+ }
+
+ auto GetId() const {
+ return plane_->plane_id;
+ }
private:
- DrmDevice *drm_;
- uint32_t id_;
+ DrmPlane(DrmDevice &dev, DrmModePlaneUnique plane)
+ : drm_(&dev), plane_(std::move(plane)){};
+ DrmDevice *const drm_;
+ DrmModePlaneUnique plane_;
enum class Presence { kOptional, kMandatory };
+ auto Init() -> int;
auto GetPlaneProperty(const char *prop_name, DrmProperty &property,
Presence presence = Presence::kMandatory) -> bool;
- uint32_t possible_crtc_mask_;
-
uint32_t type_{};
std::vector<uint32_t> formats_;
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index 46f77e4..c8235e9 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -21,35 +21,47 @@
#include <fcntl.h>
#include <sys/stat.h>
+#include <ctime>
#include <sstream>
#include "bufferinfo/BufferInfoGetter.h"
+#include "drm/DrmAtomicStateManager.h"
#include "drm/DrmDevice.h"
+#include "drm/DrmDisplayPipeline.h"
#include "drm/DrmPlane.h"
#include "utils/log.h"
#include "utils/properties.h"
namespace android {
-ResourceManager::ResourceManager() : num_displays_(0) {
+ResourceManager::ResourceManager(
+ PipelineToFrontendBindingInterface *p2f_bind_interface)
+ : frontend_interface_(p2f_bind_interface) {
+ if (uevent_listener_.Init() != 0) {
+ ALOGE("Can't initialize event listener");
+ }
}
ResourceManager::~ResourceManager() {
uevent_listener_.Exit();
}
-int ResourceManager::Init() {
+void ResourceManager::Init() {
+ if (initialized_) {
+ ALOGE("Already initialized");
+ return;
+ }
+
char path_pattern[PROPERTY_VALUE_MAX];
// Could be a valid path or it can have at the end of it the wildcard %
// which means that it will try open all devices until an error is met.
int path_len = property_get("vendor.hwc.drm.device", path_pattern,
"/dev/dri/card%");
- int ret = 0;
if (path_pattern[path_len - 1] != '%') {
- ret = AddDrmDevice(std::string(path_pattern));
+ AddDrmDevice(std::string(path_pattern));
} else {
path_pattern[path_len - 1] = '\0';
- for (int idx = 0; ret == 0; ++idx) {
+ for (int idx = 0;; ++idx) {
std::ostringstream path;
path << path_pattern << idx;
@@ -57,49 +69,116 @@ int ResourceManager::Init() {
if (stat(path.str().c_str(), &buf) != 0)
break;
- if (DrmDevice::IsKMSDev(path.str().c_str()))
- ret = AddDrmDevice(path.str());
+ if (DrmDevice::IsKMSDev(path.str().c_str())) {
+ AddDrmDevice(path.str());
+ }
}
}
- if (num_displays_ == 0) {
- ALOGE("Failed to initialize any displays");
- 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() == nullptr) {
ALOGE("Failed to initialize BufferInfoGetter");
- return -EINVAL;
+ return;
}
- ret = uevent_listener_.Init();
- if (ret != 0) {
- ALOGE("Can't initialize event listener %d", ret);
- return ret;
+ uevent_listener_.RegisterHotplugHandler([this] {
+ const std::lock_guard<std::mutex> lock(GetMainLock());
+ UpdateFrontendDisplays();
+ });
+
+ UpdateFrontendDisplays();
+
+ initialized_ = true;
+}
+
+void ResourceManager::DeInit() {
+ if (!initialized_) {
+ ALOGE("Not initialized");
+ return;
}
- return 0;
+ uevent_listener_.RegisterHotplugHandler([] {});
+
+ DetachAllFrontendDisplays();
+ drms_.clear();
+
+ initialized_ = false;
}
int ResourceManager::AddDrmDevice(const std::string &path) {
auto drm = std::make_unique<DrmDevice>();
- int displays_added = 0;
- int ret = 0;
- std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_);
+ int ret = drm->Init(path.c_str());
drms_.push_back(std::move(drm));
- num_displays_ += displays_added;
return ret;
}
-DrmDevice *ResourceManager::GetDrmDevice(int display) {
+auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
+ struct timespec ts {};
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ constexpr int64_t kNsInSec = 1000000000LL;
+ return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
+}
+
+void ResourceManager::UpdateFrontendDisplays() {
+ auto ordered_connectors = GetOrderedConnectors();
+
+ for (auto *conn : ordered_connectors) {
+ conn->UpdateModes();
+ bool connected = conn->IsConnected();
+ bool attached = attached_pipelines_.count(conn) != 0;
+
+ if (connected != attached) {
+ ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
+ conn->GetName().c_str());
+
+ if (connected) {
+ auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
+ frontend_interface_->BindDisplay(pipeline.get());
+ attached_pipelines_[conn] = std::move(pipeline);
+ } else {
+ auto &pipeline = attached_pipelines_[conn];
+ frontend_interface_->UnbindDisplay(pipeline.get());
+ attached_pipelines_.erase(conn);
+ }
+ }
+ }
+ frontend_interface_->FinalizeDisplayBinding();
+}
+
+void ResourceManager::DetachAllFrontendDisplays() {
+ for (auto &p : attached_pipelines_) {
+ frontend_interface_->UnbindDisplay(p.second.get());
+ }
+ attached_pipelines_.clear();
+ frontend_interface_->FinalizeDisplayBinding();
+}
+
+auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
+ /* Put internal displays first then external to
+ * ensure Internal will take Primary slot
+ */
+
+ std::vector<DrmConnector *> ordered_connectors;
+
for (auto &drm : drms_) {
- if (drm->HandlesDisplay(display))
- return drm.get();
+ for (const auto &conn : drm->GetConnectors()) {
+ if (conn->IsInternal()) {
+ ordered_connectors.emplace_back(conn.get());
+ }
+ }
}
- return nullptr;
+
+ for (auto &drm : drms_) {
+ for (const auto &conn : drm->GetConnectors()) {
+ if (conn->IsExternal()) {
+ ordered_connectors.emplace_back(conn.get());
+ }
+ }
+ }
+
+ return ordered_connectors;
}
} // namespace android
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index f54d682..88ba878 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -20,42 +20,50 @@
#include <cstring>
#include "DrmDevice.h"
+#include "DrmDisplayPipeline.h"
#include "DrmFbImporter.h"
#include "UEventListener.h"
namespace android {
+class PipelineToFrontendBindingInterface {
+ public:
+ virtual ~PipelineToFrontendBindingInterface() = default;
+ virtual bool BindDisplay(DrmDisplayPipeline *);
+ virtual bool UnbindDisplay(DrmDisplayPipeline *);
+ virtual void FinalizeDisplayBinding();
+};
+
class ResourceManager {
public:
- ResourceManager();
+ explicit ResourceManager(
+ PipelineToFrontendBindingInterface *p2f_bind_interface);
ResourceManager(const ResourceManager &) = delete;
ResourceManager &operator=(const ResourceManager &) = delete;
+ ResourceManager(const ResourceManager &&) = delete;
+ ResourceManager &&operator=(const ResourceManager &&) = delete;
~ResourceManager();
- int Init();
- DrmDevice *GetDrmDevice(int display);
- const std::vector<std::unique_ptr<DrmDevice>> &GetDrmDevices() const {
- return drms_;
- }
- int GetDisplayCount() const {
- return num_displays_;
- }
+ void Init();
+
+ void DeInit();
+
bool ForcedScalingWithGpu() const {
return scale_with_gpu_;
}
- UEventListener *GetUEventListener() {
- return &uevent_listener_;
- }
-
auto &GetMainLock() {
return main_lock_;
}
+ static auto GetTimeMonotonicNs() -> int64_t;
+
private:
- int AddDrmDevice(std::string const &path);
+ auto AddDrmDevice(std::string const &path) -> int;
+ auto GetOrderedConnectors() -> std::vector<DrmConnector *>;
+ void UpdateFrontendDisplays();
+ void DetachAllFrontendDisplays();
- int num_displays_;
std::vector<std::unique_ptr<DrmDevice>> drms_;
bool scale_with_gpu_{};
@@ -63,6 +71,13 @@ class ResourceManager {
UEventListener uevent_listener_;
std::mutex main_lock_;
+
+ std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>
+ attached_pipelines_;
+
+ PipelineToFrontendBindingInterface *const frontend_interface_;
+
+ bool initialized_{};
};
} // namespace android
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
index 44c503d..b56b8e1 100644
--- a/drm/UEventListener.cpp
+++ b/drm/UEventListener.cpp
@@ -18,82 +18,43 @@
#include "UEventListener.h"
-#include <linux/netlink.h>
-#include <sys/socket.h>
-#include <xf86drm.h>
-
-#include <cassert>
#include <cerrno>
-#include <cstring>
#include "utils/log.h"
-/* Originally defined in system/core/libsystem/include/system/graphics.h */
-#define HAL_PRIORITY_URGENT_DISPLAY (-8)
+/* Originally defined in system/core/libsystem/include/system/graphics.h as
+ * #define HAL_PRIORITY_URGENT_DISPLAY (-8)*/
+constexpr int kHalPriorityUrgentDisplay = -8;
namespace android {
UEventListener::UEventListener()
- : Worker("uevent-listener", HAL_PRIORITY_URGENT_DISPLAY){};
+ : Worker("uevent-listener", kHalPriorityUrgentDisplay){};
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;
- }
-
- struct sockaddr_nl addr {};
- addr.nl_family = AF_NETLINK;
- addr.nl_pid = 0;
- addr.nl_groups = 0xFFFFFFFF;
-
- 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;
+ uevent_ = UEvent::CreateInstance();
+ if (!uevent_) {
+ return -ENODEV;
}
return InitWorker();
}
void UEventListener::Routine() {
- char buffer[1024];
- ssize_t ret = 0;
-
while (true) {
- ret = read(uevent_fd_.Get(), &buffer, sizeof(buffer));
- if (ret == 0)
- return;
+ auto uevent_str = uevent_->ReadNext();
- if (ret < 0) {
- ALOGE("Got error reading uevent %zd", ret);
- return;
- }
-
- if (!hotplug_handler_)
+ if (!hotplug_handler_ || !uevent_str)
continue;
- bool drm_event = false;
- bool hotplug_event = false;
- for (uint32_t i = 0; i < ret;) {
- char *event = buffer + i;
- if (strcmp(event, "DEVTYPE=drm_minor") != 0)
- drm_event = true;
- else if (strcmp(event, "HOTPLUG=1") != 0)
- hotplug_event = true;
-
- i += strlen(event) + 1;
- }
+ bool drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
+ bool hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
- if (drm_event && hotplug_event && hotplug_handler_) {
- constexpr useconds_t delay_after_uevent_us = 200000;
+ if (drm_event && hotplug_event) {
+ constexpr useconds_t kDelayAfterUeventUs = 200000;
/* We need some delay to ensure DrmConnector::UpdateModes() will query
* correct modes list, otherwise at least RPI4 board may report 0 modes */
- usleep(delay_after_uevent_us);
+ usleep(kDelayAfterUeventUs);
hotplug_handler_();
}
}
diff --git a/drm/UEventListener.h b/drm/UEventListener.h
index 0724443..c8b8582 100644
--- a/drm/UEventListener.h
+++ b/drm/UEventListener.h
@@ -19,7 +19,7 @@
#include <functional>
-#include "utils/UniqueFd.h"
+#include "utils/UEvent.h"
#include "utils/Worker.h"
namespace android {
@@ -39,7 +39,7 @@ class UEventListener : public Worker {
void Routine() override;
private:
- UniqueFd uevent_fd_;
+ std::unique_ptr<UEvent> uevent_;
std::function<void()> hotplug_handler_;
};
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index dc52450..ed41189 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -29,19 +29,12 @@
namespace android {
-VSyncWorker::VSyncWorker()
- : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY),
- drm_(nullptr),
- display_(-1),
- enabled_(false),
- last_timestamp_(-1) {
-}
+VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY){};
-auto VSyncWorker::Init(DrmDevice *drm, int display,
+auto VSyncWorker::Init(DrmDisplayPipeline *pipe,
std::function<void(uint64_t /*timestamp*/)> callback)
-> int {
- drm_ = drm;
- display_ = display;
+ pipe_ = pipe;
callback_ = std::move(callback);
return InitWorker();
@@ -86,12 +79,10 @@ int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
return ret;
float refresh = 60.0F; // Default to 60Hz refresh rate
- DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
- if (conn && conn->active_mode().v_refresh() != 0.0F)
- refresh = conn->active_mode().v_refresh();
- else
- ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn,
- conn ? conn->active_mode().v_refresh() : 0.0F);
+ if (pipe_ != nullptr &&
+ pipe_->connector->Get()->GetActiveMode().v_refresh() != 0.0F) {
+ refresh = pipe_->connector->Get()->GetActiveMode().v_refresh();
+ }
int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs /
static_cast<int>(refresh),
@@ -121,27 +112,26 @@ void VSyncWorker::Routine() {
}
}
- int display = display_;
+ auto *pipe = pipe_;
Unlock();
- DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
- if (!crtc) {
- ALOGE("Failed to get crtc for display");
- return;
- }
- uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT);
+ ret = -EAGAIN;
+ int64_t timestamp = 0;
+ drmVBlank vblank{};
- drmVBlank vblank;
- memset(&vblank, 0, sizeof(vblank));
- vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
- (high_crtc &
- DRM_VBLANK_HIGH_CRTC_MASK));
- vblank.request.sequence = 1;
+ if (pipe != nullptr) {
+ uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
+ << DRM_VBLANK_HIGH_CRTC_SHIFT);
- int64_t timestamp = 0;
- ret = drmWaitVBlank(drm_->fd(), &vblank);
- if (ret == -EINTR)
- return;
+ vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
+ (high_crtc &
+ DRM_VBLANK_HIGH_CRTC_MASK));
+ vblank.request.sequence = 1;
+
+ ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
+ if (ret == -EINTR)
+ return;
+ }
if (ret) {
ret = SyntheticWaitVBlank(&timestamp);
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 67aaa16..1e6d39f 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -36,7 +36,7 @@ class VSyncWorker : public Worker {
VSyncWorker();
~VSyncWorker() override = default;
- auto Init(DrmDevice *drm, int display,
+ auto Init(DrmDisplayPipeline *pipe,
std::function<void(uint64_t /*timestamp*/)> callback) -> int;
void VSyncControl(bool enabled);
@@ -48,13 +48,11 @@ class VSyncWorker : public Worker {
int64_t GetPhasedVSync(int64_t frame_ns, int64_t current) const;
int SyntheticWaitVBlank(int64_t *timestamp);
- DrmDevice *drm_;
-
std::function<void(uint64_t /*timestamp*/)> callback_;
- int display_;
- std::atomic_bool enabled_;
- int64_t last_timestamp_;
+ DrmDisplayPipeline *pipe_ = nullptr;
+ std::atomic_bool enabled_ = false;
+ int64_t last_timestamp_ = -1;
};
} // namespace android
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index a2a093f..e689419 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -18,61 +18,117 @@
#include "DrmHwcTwo.h"
+#include <cinttypes>
+
#include "backend/Backend.h"
#include "utils/log.h"
namespace android {
-DrmHwcTwo::DrmHwcTwo() = default;
+DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){};
-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;
+/* Must be called after every display attach/detach cycle */
+void DrmHwcTwo::FinalizeDisplayBinding() {
+ if (displays_.count(kPrimaryDisplay) == 0) {
+ /* Primary display MUST always exist */
+ ALOGI("No pipelines available. Creating null-display for headless mode");
+ displays_[kPrimaryDisplay] = std::make_unique<
+ HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
+ /* Initializes null-display */
+ displays_[kPrimaryDisplay]->SetPipeline(nullptr);
}
- 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;
+ if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
+ !display_handles_.empty()) {
+ /* Reattach first secondary display to take place of the primary */
+ auto *pipe = display_handles_.begin()->first;
+ ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
+ pipe->connector->Get()->GetName().c_str());
+ UnbindDisplay(pipe);
+ BindDisplay(pipe);
}
- auto display_planes = std::vector<DrmPlane *>();
- for (const auto &plane : drm->planes()) {
- if (plane->GetCrtcSupported(*crtc))
- display_planes.push_back(plane.get());
+
+ // Finally, send hotplug events to the client
+ for (auto &dhe : deferred_hotplug_events_) {
+ SendHotplugEventToClient(dhe.first, dhe.second);
}
- displays_.at(displ).Init(&display_planes);
- return HWC2::Error::None;
+ deferred_hotplug_events_.clear();
+
+ /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
+ */
+ auto &mutex = GetResMan().GetMainLock();
+ mutex.unlock();
+ const int kTimeForSFToDisposeDisplayUs = 200000;
+ usleep(kTimeForSFToDisposeDisplayUs);
+ mutex.lock();
+ std::vector<std::unique_ptr<HwcDisplay>> for_disposal;
+ for (auto handle : displays_for_removal_list_) {
+ for_disposal.emplace_back(
+ std::unique_ptr<HwcDisplay>(displays_[handle].release()));
+ displays_.erase(handle);
+ }
+ /* Destroy HwcDisplays while unlocked to avoid vsyncworker deadlocks */
+ mutex.unlock();
+ for_disposal.clear();
+ mutex.lock();
}
-HWC2::Error DrmHwcTwo::Init() {
- int rv = resource_manager_.Init();
- if (rv) {
- ALOGE("Can't initialize the resource manager %d", rv);
- return HWC2::Error::NoResources;
+bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
+ if (display_handles_.count(pipeline) != 0) {
+ ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
+ __func__, pipeline);
+ return false;
}
- 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;
- }
+ uint32_t disp_handle = kPrimaryDisplay;
+
+ if (displays_.count(kPrimaryDisplay) != 0 &&
+ !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
+ disp_handle = ++last_display_handle_;
}
- resource_manager_.GetUEventListener()->RegisterHotplugHandler([this] {
- const std::lock_guard<std::mutex> lock(GetResMan().GetMainLock());
+ if (displays_.count(disp_handle) == 0) {
+ auto disp = std::make_unique<HwcDisplay>(disp_handle,
+ HWC2::DisplayType::Physical, this);
+ displays_[disp_handle] = std::move(disp);
+ }
+
+ ALOGI("Attaching pipeline '%s' to the display #%d%s",
+ pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
+ disp_handle == kPrimaryDisplay ? " (Primary)" : "");
- HandleHotplugUEvent();
- });
+ displays_[disp_handle]->SetPipeline(pipeline);
+ display_handles_[pipeline] = disp_handle;
- return ret;
+ return true;
+}
+
+bool DrmHwcTwo::UnbindDisplay(DrmDisplayPipeline *pipeline) {
+ if (display_handles_.count(pipeline) == 0) {
+ ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline);
+ return false;
+ }
+ auto handle = display_handles_[pipeline];
+ display_handles_.erase(pipeline);
+
+ ALOGI("Detaching the pipeline '%s' from the display #%i%s",
+ pipeline->connector->Get()->GetName().c_str(), (int)handle,
+ handle == kPrimaryDisplay ? " (Primary)" : "");
+
+ if (displays_.count(handle) == 0) {
+ ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
+ return false;
+ }
+ displays_[handle]->SetPipeline(nullptr);
+
+ /* We must defer display disposal and removal, since it may still have pending
+ * HWC_API calls scheduled and waiting until ueventlistener thread releases
+ * main lock, otherwise transaction may fail and SF may crash
+ */
+ if (handle != kPrimaryDisplay) {
+ displays_for_removal_list_.emplace_back(handle);
+ }
+ return true;
}
HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t /*width*/,
@@ -99,8 +155,8 @@ void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
output << "-- drm_hwcomposer --\n\n";
- for (std::pair<const hwc2_display_t, HwcDisplay> &dp : displays_)
- output << dp.second.Dump();
+ for (auto &disp : displays_)
+ output << disp.second->Dump();
mDumpString = output.str();
*outSize = static_cast<uint32_t>(mDumpString.size());
@@ -117,9 +173,13 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
switch (static_cast<HWC2::Callback>(descriptor)) {
case HWC2::Callback::Hotplug: {
hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
- const auto &drm_devices = resource_manager_.GetDrmDevices();
- for (const auto &device : drm_devices)
- HandleInitialHotplugState(device.get());
+ if (function != nullptr) {
+ resource_manager_.Init();
+ } else {
+ resource_manager_.DeInit();
+ /* Headless display may still be here, remove it */
+ displays_.erase(kPrimaryDisplay);
+ }
break;
}
case HWC2::Callback::Refresh: {
@@ -135,6 +195,11 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
break;
}
+ case HWC2::Callback::VsyncPeriodTimingChanged: {
+ period_timing_changed_callback_ = std::
+ make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
+ break;
+ }
#endif
default:
break;
@@ -142,7 +207,8 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
return HWC2::Error::None;
}
-void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
+void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
+ bool connected) {
auto &mutex = GetResMan().GetMainLock();
if (mutex.try_lock()) {
ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
@@ -157,52 +223,44 @@ void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
*/
mutex.unlock();
hc.first(hc.second, displayid,
- state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
- : HWC2_CONNECTION_DISCONNECTED);
+ connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+ : HWC2_CONNECTION_DISCONNECTED);
mutex.lock();
}
}
-void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
- for (const auto &conn : drmDevice->connectors()) {
- int display_id = conn->display();
- auto &display = displays_.at(display_id);
-
- if (conn->state() != DRM_MODE_CONNECTED && !display.IsInHeadlessMode())
- continue;
- HandleDisplayHotplug(conn->display(), display.IsInHeadlessMode()
- ? DRM_MODE_CONNECTED
- : conn->state());
+void DrmHwcTwo::SendVsyncEventToClient(
+ hwc2_display_t displayid, int64_t timestamp,
+ [[maybe_unused]] uint32_t vsync_period) const {
+ /* vsync callback */
+#if PLATFORM_SDK_VERSION > 29
+ if (vsync_2_4_callback_.first != nullptr &&
+ vsync_2_4_callback_.second != nullptr) {
+ vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
+ vsync_period);
+ } else
+#endif
+ if (vsync_callback_.first != nullptr &&
+ vsync_callback_.second != nullptr) {
+ vsync_callback_.first(vsync_callback_.second, displayid, timestamp);
}
}
-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();
- auto &display = displays_.at(display_id);
- display.ChosePreferredConfig();
- if (cur_state != DRM_MODE_CONNECTED) {
- display.ClearDisplay();
- }
-
- HandleDisplayHotplug(display_id, display.IsInHeadlessMode()
- ? DRM_MODE_CONNECTED
- : cur_state);
- }
+void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
+ [[maybe_unused]] hwc2_display_t displayid,
+ [[maybe_unused]] int64_t timestamp) const {
+#if PLATFORM_SDK_VERSION > 29
+ hwc_vsync_period_change_timeline_t timeline = {
+ .newVsyncAppliedTimeNanos = timestamp,
+ .refreshRequired = false,
+ .refreshTimeNanos = 0,
+ };
+ if (period_timing_changed_callback_.first != nullptr &&
+ period_timing_changed_callback_.second != nullptr) {
+ period_timing_changed_callback_
+ .first(period_timing_changed_callback_.second, displayid, &timeline);
}
+#endif
}
} // namespace android
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index f38ba05..2b8a74f 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -24,27 +24,20 @@
namespace android {
-class DrmHwcTwo {
+class DrmHwcTwo : public PipelineToFrontendBindingInterface {
public:
DrmHwcTwo();
-
- HWC2::Error Init();
+ ~DrmHwcTwo() override = default;
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_{};
+ std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t>
+ period_timing_changed_callback_{};
#endif
std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
- 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);
@@ -53,22 +46,44 @@ class DrmHwcTwo {
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);
+
+ auto GetDisplay(hwc2_display_t display_handle) {
+ return displays_.count(display_handle) != 0
+ ? displays_[display_handle].get()
+ : nullptr;
+ }
auto &GetResMan() {
return resource_manager_;
}
- private:
- void HandleDisplayHotplug(hwc2_display_t displayid, int state);
- void HandleInitialHotplugState(DrmDevice *drmDevice);
+ void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
+ deferred_hotplug_events_[displayid] = connected;
+ }
+
+ // PipelineToFrontendBindingInterface
+ bool BindDisplay(DrmDisplayPipeline *pipeline) override;
+ bool UnbindDisplay(DrmDisplayPipeline *pipeline) override;
+ void FinalizeDisplayBinding() override;
+
+ void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
+ uint32_t vsync_period) const;
+ void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,
+ int64_t timestamp) const;
- void HandleHotplugUEvent();
+ private:
+ void SendHotplugEventToClient(hwc2_display_t displayid, bool connected);
ResourceManager resource_manager_;
- std::map<hwc2_display_t, HwcDisplay> displays_;
+ std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
+ std::map<DrmDisplayPipeline *, hwc2_display_t> display_handles_;
std::string mDumpString;
+
+ std::map<hwc2_display_t, bool> deferred_hotplug_events_;
+ std::vector<hwc2_display_t> displays_for_removal_list_;
+
+ uint32_t last_display_handle_ = kPrimaryDisplay;
};
} // namespace android
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 8936136..cedac19 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -20,6 +20,7 @@
#include "HwcDisplay.h"
#include "DrmHwcTwo.h"
+#include "backend/Backend.h"
#include "backend/BackendManager.h"
#include "bufferinfo/BufferInfoGetter.h"
#include "utils/log.h"
@@ -68,8 +69,12 @@ std::string HwcDisplay::Dump() {
" VSync remains";
}
+ std::string connector_name = IsInHeadlessMode()
+ ? "NULL-DISPLAY"
+ : GetPipe().connector->Get()->GetName();
+
std::stringstream ss;
- ss << "- Display on: " << connector_->name() << "\n"
+ ss << "- Display on: " << connector_name << "\n"
<< " Flattening state: " << flattening_state_str << "\n"
<< "Statistics since system boot:\n"
<< DumpDelta(total_stats_) << "\n\n"
@@ -80,12 +85,9 @@ std::string HwcDisplay::Dump() {
return ss.str();
}
-HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
- hwc2_display_t handle, HWC2::DisplayType type,
+HwcDisplay::HwcDisplay(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) {
@@ -97,108 +99,72 @@ HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
// clang-format on
}
-void HwcDisplay::ClearDisplay() {
- if (IsInHeadlessMode()) {
- ALOGE("%s: Headless mode, should never reach here: ", __func__);
- return;
- }
+HwcDisplay::~HwcDisplay() = default;
- AtomicCommitArgs a_args = {.clear_active_composition = true};
- compositor_.ExecuteAtomicCommit(a_args);
-}
+void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
+ pipeline_ = pipeline;
-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;
- }
+ if (pipeline != nullptr) {
+ ChosePreferredConfig();
+ Init();
- connector_ = drm_->GetConnectorForDisplay(display);
- if (!connector_) {
- ALOGE("Failed to get connector for display %d", display);
- return HWC2::Error::BadDisplay;
+ hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
+ } else {
+ backend_.reset();
+ vsync_worker_.Init(nullptr, [](int64_t) {});
+ SetClientTarget(nullptr, -1, 0, {});
+ if (handle_ != kPrimaryDisplay) {
+ hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
+ }
}
+}
- ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) {
+HWC2::Error HwcDisplay::Init() {
+ int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
- /* 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{};
+ if (vsync_event_en_) {
+ uint32_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);
+ hwc2_->SendVsyncEventToClient(handle_, timestamp, period_ns);
+ }
+ if (vsync_flattening_en_) {
+ ProcessFlatenningVsyncInternal();
+ }
+ if (vsync_tracking_en_) {
+ last_vsync_ts_ = timestamp;
+ }
+ if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) {
+ vsync_worker_.VSyncControl(false);
}
});
- if (ret) {
- ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
+ if (ret && ret != -EALREADY) {
+ ALOGE("Failed to create event worker for d=%d %d\n", int(handle_), ret);
return HWC2::Error::BadDisplay;
}
- ret = flattening_vsync_worker_
- .Init(drm_, display, [this](int64_t /*timestamp*/) {
- const std::lock_guard<std::mutex> lock(
- hwc2_->GetResMan().GetMainLock());
- /* 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;
+ if (!IsInHeadlessMode()) {
+ ret = BackendManager::GetInstance().SetBackendForDisplay(this);
+ if (ret) {
+ ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
+ return HWC2::Error::BadDisplay;
+ }
}
client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
- return ChosePreferredConfig();
+ return HWC2::Error::None;
}
HWC2::Error HwcDisplay::ChosePreferredConfig() {
- HWC2::Error err = configs_.Update(*connector_);
- if (!IsInHeadlessMode() && err != HWC2::Error::None)
+ HWC2::Error err{};
+ if (!IsInHeadlessMode()) {
+ err = configs_.Update(*pipeline_->connector->Get());
+ } else {
+ configs_.FillHeadless();
+ }
+ if (!IsInHeadlessMode() && err != HWC2::Error::None) {
return HWC2::Error::BadDisplay;
+ }
return SetActiveConfig(configs_.preferred_config_id);
}
@@ -217,18 +183,19 @@ HWC2::Error HwcDisplay::CreateLayer(hwc2_layer_t *layer) {
}
HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) {
- if (!get_layer(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)
+ if (configs_.hwc_configs.count(staged_mode_config_id_) == 0)
return HWC2::Error::BadConfig;
- *config = configs_.active_config_id;
+ *config = staged_mode_config_id_;
return HWC2::Error::None;
}
@@ -258,12 +225,13 @@ HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
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 (IsInHeadlessMode()) {
return HWC2::Error::None;
}
+ std::pair<uint32_t, uint32_t> min = pipeline_->device->GetMinResolution();
+ std::pair<uint32_t, uint32_t> max = pipeline_->device->GetMaxResolution();
+
if (width < min.first || height < min.second)
return HWC2::Error::Unsupported;
@@ -293,7 +261,7 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(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);
+ ALOGE("Could not find mode #%d", conf);
return HWC2::Error::BadConfig;
}
@@ -330,7 +298,7 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
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;
+ *value = int(hwc_config.group_id);
break;
#endif
default:
@@ -363,7 +331,11 @@ HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
HWC2::Error HwcDisplay::GetDisplayName(uint32_t *size, char *name) {
std::ostringstream stream;
- stream << "display-" << connector_->id();
+ if (IsInHeadlessMode()) {
+ stream << "null-display";
+ } else {
+ stream << "display-" << GetPipe().connector->Get()->GetId();
+ }
std::string string = stream.str();
size_t length = string.length();
if (!name) {
@@ -441,6 +413,26 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::None;
}
+ int PrevModeVsyncPeriodNs = static_cast<int>(
+ 1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh());
+
+ auto mode_update_commited_ = false;
+ if (staged_mode_ &&
+ staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) {
+ client_layer_.SetLayerDisplayFrame(
+ (hwc_rect_t){.left = 0,
+ .top = 0,
+ .right = static_cast<int>(staged_mode_->h_display()),
+ .bottom = static_cast<int>(staged_mode_->v_display())});
+
+ configs_.active_config_id = staged_mode_config_id_;
+
+ a_args.display_mode = *staged_mode_;
+ if (!a_args.test_only) {
+ mode_update_commited_ = true;
+ }
+ }
+
// order the layers by z-order
bool use_client_layer = false;
uint32_t client_z_order = UINT32_MAX;
@@ -471,7 +463,7 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
for (std::pair<const uint32_t, HwcLayer *> &l : z_map) {
DrmHwcLayer layer;
l.second->PopulateDrmLayer(&layer);
- int ret = layer.ImportBuffer(drm_);
+ int ret = layer.ImportBuffer(GetPipe().device);
if (ret) {
ALOGE("Failed to import layer, ret=%d", ret);
return HWC2::Error::NoResources;
@@ -479,29 +471,21 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
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);
+ /* Store plan to ensure shared planes won't be stolen by other display
+ * in between of ValidateDisplay() and PresentDisplay() calls
+ */
+ current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
+ std::move(composition_layers));
+ if (!current_plan_) {
+ if (!a_args.test_only) {
+ ALOGE("Failed to create DrmKmsPlan");
+ }
return HWC2::Error::BadConfig;
}
- a_args.composition = composition;
- if (staged_mode) {
- a_args.display_mode = *staged_mode;
- }
- ret = compositor_.ExecuteAtomicCommit(a_args);
+ a_args.composition = current_plan_;
+
+ int ret = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
if (ret) {
if (!a_args.test_only)
@@ -509,8 +493,13 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
return HWC2::Error::BadParameter;
}
- if (!a_args.test_only) {
- staged_mode.reset();
+ if (mode_update_commited_) {
+ staged_mode_.reset();
+ vsync_tracking_en_ = false;
+ if (last_vsync_ts_ != 0) {
+ hwc2_->SendVsyncPeriodTimingChangedEventToClient(
+ handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs);
+ }
}
return HWC2::Error::None;
@@ -548,30 +537,24 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
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);
+HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config,
+ int64_t change_time) {
+ if (configs_.hwc_configs.count(config) == 0) {
+ ALOGE("Could not find active mode for %u", config);
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);
+ staged_mode_ = configs_.hwc_configs[config].mode;
+ staged_mode_change_time_ = change_time;
+ staged_mode_config_id_ = config;
return HWC2::Error::None;
}
+HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
+ return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs());
+}
+
/* Find API details at:
* https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861
*/
@@ -656,7 +639,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
* true, as the next composition frame will implicitly activate
* the display
*/
- return compositor_.ActivateDisplayUsingDPMS() == 0
+ return GetPipe().atomic_state_manager->ActivateDisplayUsingDPMS() == 0
? HWC2::Error::None
: HWC2::Error::BadParameter;
break;
@@ -668,7 +651,7 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
return HWC2::Error::BadParameter;
};
- int err = compositor_.ExecuteAtomicCommit(a_args);
+ int err = GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
if (err) {
ALOGE("Failed to apply the dpms composition err=%d", err);
return HWC2::Error::BadParameter;
@@ -677,7 +660,10 @@ HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
}
HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
- vsync_worker_.VSyncControl(HWC2_VSYNC_ENABLE == enabled);
+ vsync_event_en_ = HWC2_VSYNC_ENABLE == enabled;
+ if (vsync_event_en_) {
+ vsync_worker_.VSyncControl(true);
+ }
return HWC2::Error::None;
}
@@ -706,11 +692,25 @@ std::vector<HwcLayer *> HwcDisplay::GetOrderLayersByZPos() {
return ordered_layers;
}
+HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
+ uint32_t *outVsyncPeriod /* ns */) {
+ return GetDisplayAttribute(configs_.active_config_id,
+ HWC2_ATTRIBUTE_VSYNC_PERIOD,
+ (int32_t *)(outVsyncPeriod));
+}
+
#if PLATFORM_SDK_VERSION > 29
HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
- if (connector_->internal())
+ if (IsInHeadlessMode()) {
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
- else if (connector_->external())
+ return HWC2::Error::None;
+ }
+ /* Primary display should be always internal,
+ * otherwise SF will be unhappy and will crash
+ */
+ if (GetPipe().connector->Get()->IsInternal() || handle_ == kPrimaryDisplay)
+ *outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::Internal);
+ else if (GetPipe().connector->Get()->IsExternal())
*outType = static_cast<uint32_t>(HWC2::DisplayConnectionType::External);
else
return HWC2::Error::BadConfig;
@@ -718,22 +718,38 @@ HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
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*/,
+ 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;
+ uint32_t current_vsync_period{};
+ GetDisplayVsyncPeriod(&current_vsync_period);
+
+ if (vsyncPeriodChangeConstraints->seamlessRequired) {
+ return HWC2::Error::SeamlessNotAllowed;
+ }
+
+ outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints
+ ->desiredTimeNanos -
+ current_vsync_period;
+ auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos);
+ if (ret != HWC2::Error::None) {
+ return ret;
+ }
+
+ outTimeline->refreshRequired = true;
+ outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints
+ ->desiredTimeNanos;
+
+ last_vsync_ts_ = 0;
+ vsync_tracking_en_ = true;
+ vsync_worker_.VSyncControl(true);
+
+ return HWC2::Error::None;
}
HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) {
@@ -765,11 +781,18 @@ HWC2::Error HwcDisplay::SetContentType(int32_t contentType) {
HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
uint32_t *outDataSize,
uint8_t *outData) {
- auto blob = connector_->GetEdidBlob();
+ if (IsInHeadlessMode()) {
+ return HWC2::Error::None;
+ }
+ auto blob = GetPipe().connector->Get()->GetEdidBlob();
+
+ *outPort = handle_ - 1;
if (!blob) {
- ALOGE("Failed to get edid property value.");
- return HWC2::Error::Unsupported;
+ if (outData == nullptr) {
+ *outDataSize = 0;
+ }
+ return HWC2::Error::None;
}
if (outData) {
@@ -778,7 +801,6 @@ HWC2::Error HwcDisplay::GetDisplayIdentificationData(uint8_t *outPort,
} else {
*outDataSize = blob->length;
}
- *outPort = connector_->id();
return HWC2::Error::None;
}
@@ -851,4 +873,37 @@ void HwcDisplay::set_backend(std::unique_ptr<Backend> backend) {
backend_ = std::move(backend);
}
+/* returns true if composition should be sent to client */
+bool HwcDisplay::ProcessClientFlatteningState(bool skip) {
+ int flattenning_state = flattenning_state_;
+ if (flattenning_state == ClientFlattenningState::Disabled) {
+ return false;
+ }
+
+ if (skip) {
+ flattenning_state_ = ClientFlattenningState::NotRequired;
+ return false;
+ }
+
+ if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) {
+ flattenning_state_ = ClientFlattenningState::Flattened;
+ return true;
+ }
+
+ vsync_flattening_en_ = true;
+ vsync_worker_.VSyncControl(true);
+ flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
+ return false;
+}
+
+void HwcDisplay::ProcessFlatenningVsyncInternal() {
+ if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
+ --flattenning_state_ == ClientFlattenningState::ClientRefreshRequested &&
+ hwc2_->refresh_callback_.first != nullptr &&
+ hwc2_->refresh_callback_.second != nullptr) {
+ hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
+ vsync_flattening_en_ = false;
+ }
+}
+
} // namespace android
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index c3e0f6e..98d8e9b 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -22,7 +22,7 @@
#include <optional>
#include "HwcDisplayConfigs.h"
-#include "compositor/DrmDisplayCompositor.h"
+#include "drm/DrmAtomicStateManager.h"
#include "drm/ResourceManager.h"
#include "drm/VSyncWorker.h"
#include "drmhwcomposer.h"
@@ -33,12 +33,16 @@ namespace android {
class Backend;
class DrmHwcTwo;
+inline constexpr uint32_t kPrimaryDisplay = 0;
+
class HwcDisplay {
public:
- HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
- hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
+ HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
HwcDisplay(const HwcDisplay &) = delete;
- HWC2::Error Init(std::vector<DrmPlane *> *planes);
+ ~HwcDisplay();
+
+ /* SetPipeline should be carefully used only by DrmHwcTwo hotplug handlers */
+ void SetPipeline(DrmDisplayPipeline *pipeline);
HWC2::Error CreateComposition(AtomicCommitArgs &a_args);
std::vector<HwcLayer *> GetOrderLayersByZPos();
@@ -81,7 +85,6 @@ class HwcDisplay {
#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,
@@ -94,6 +97,7 @@ class HwcDisplay {
HWC2::Error SetContentType(int32_t contentType);
#endif
+ HWC2::Error GetDisplayVsyncPeriod(uint32_t *outVsyncPeriod);
HWC2::Error GetDozeSupport(int32_t *support);
HWC2::Error GetHdrCapabilities(uint32_t *num_types, int32_t *types,
@@ -142,32 +146,16 @@ class HwcDisplay {
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_;
+ auto GetHwc2() {
+ return hwc2_;
}
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_;
+ auto &GetPipe() {
+ return *pipeline_;
}
android_color_transform_t &color_transform_hint() {
@@ -179,26 +167,8 @@ class HwcDisplay {
}
/* 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;
- }
+ bool ProcessClientFlatteningState(bool skip);
+ void ProcessFlatenningVsyncInternal();
/* Headless mode required to keep SurfaceFlinger alive when all display are
* disconnected, Without headless mode Android will continuously crash.
@@ -207,7 +177,7 @@ class HwcDisplay {
* https://source.android.com/devices/graphics/hotplug#handling-common-scenarios
*/
bool IsInHeadlessMode() {
- return handle_ == 0 && connector_->state() != DRM_MODE_CONNECTED;
+ return !pipeline_;
}
private:
@@ -220,41 +190,48 @@ class HwcDisplay {
};
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;
+ DrmHwcTwo *const hwc2_;
- ResourceManager *resource_manager_;
- DrmDevice *drm_;
- DrmDisplayCompositor compositor_;
+ std::optional<DrmMode> staged_mode_;
+ int64_t staged_mode_change_time_{};
+ uint32_t staged_mode_config_id_{};
- std::vector<DrmPlane *> primary_planes_;
- std::vector<DrmPlane *> overlay_planes_;
+ DrmDisplayPipeline *pipeline_{};
std::unique_ptr<Backend> backend_;
VSyncWorker vsync_worker_;
- DrmConnector *connector_ = nullptr;
- DrmCrtc *crtc_ = nullptr;
- hwc2_display_t handle_;
+ bool vsync_event_en_{};
+ bool vsync_flattening_en_{};
+ bool vsync_tracking_en_{};
+ int64_t last_vsync_ts_{};
+
+ const hwc2_display_t handle_;
HWC2::DisplayType type_;
- uint32_t layer_idx_ = 0;
+
+ uint32_t layer_idx_{};
+
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_;
+ std::shared_ptr<DrmKmsPlan> current_plan_;
+
uint32_t frame_no_ = 0;
Stats total_stats_;
Stats prev_stats_;
std::string DumpDelta(HwcDisplay::Stats delta);
+
+ HWC2::Error Init();
+
+ HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time);
};
} // namespace android
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index 16f1ed0..6a3ed5a 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -31,10 +31,10 @@ constexpr uint32_t kHeadlessModeDisplayVRefresh = 60;
namespace android {
-// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
-HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
- /* In case UpdateModes will fail we will still have one mode for headless
- * mode*/
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+uint32_t HwcDisplayConfigs::last_config_id = 1;
+
+void HwcDisplayConfigs::FillHeadless() {
hwc_configs.clear();
last_config_id++;
@@ -53,7 +53,13 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
mm_width = kHeadlessModeDisplayWidthMm;
mm_height = kHeadlessModeDisplayHeightMm;
+}
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
+ /* In case UpdateModes will fail we will still have one mode for headless
+ * mode*/
+ FillHeadless();
/* Read real configs */
int ret = connector.UpdateModes();
if (ret != 0) {
@@ -61,25 +67,25 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
return HWC2::Error::BadDisplay;
}
- if (connector.modes().empty()) {
+ if (connector.GetModes().empty()) {
ALOGE("No modes reported by KMS");
return HWC2::Error::BadDisplay;
}
hwc_configs.clear();
- mm_width = connector.mm_width();
- mm_height = connector.mm_height();
+ mm_width = connector.GetMmWidth();
+ mm_height = connector.GetMmHeight();
preferred_config_id = 0;
- int preferred_config_group_id = 0;
+ uint32_t preferred_config_group_id = 0;
- int first_config_id = last_config_id;
- int last_group_id = 1;
+ uint32_t first_config_id = last_config_id;
+ uint32_t last_group_id = 1;
/* Group modes */
- for (const auto &mode : connector.modes()) {
+ for (const auto &mode : connector.GetModes()) {
/* Find group for the new mode or create new group */
- int group_found = 0;
+ uint32_t group_found = 0;
for (auto &hwc_config : hwc_configs) {
if (mode.h_display() == hwc_config.second.mode.h_display() &&
mode.v_display() == hwc_config.second.mode.v_display()) {
@@ -122,7 +128,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
preferred_config_group_id = 1;
}
- for (int group = 1; group < last_group_id; group++) {
+ for (uint32_t group = 1; group < last_group_id; group++) {
bool has_interlaced = false;
bool has_progressive = false;
for (auto &hwc_config : hwc_configs) {
@@ -173,8 +179,8 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
* otherwise android.graphics.cts.SetFrameRateTest CTS will fail
*/
constexpr float kMinFpsDelta = 1.0; // FPS
- for (int m1 = first_config_id; m1 < last_config_id; m1++) {
- for (int m2 = first_config_id; m2 < last_config_id; m2++) {
+ for (uint32_t m1 = first_config_id; m1 < last_config_id; m1++) {
+ for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) {
if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
!hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
fabsf(hwc_configs[m1].mode.v_refresh() -
@@ -190,8 +196,6 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
}
}
- /* Set active mode to be valid mode */
- active_config_id = preferred_config_id;
return HWC2::Error::None;
}
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
index 5bcf696..7c173d6 100644
--- a/hwc2_device/HwcDisplayConfigs.h
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -28,8 +28,8 @@ namespace android {
class DrmConnector;
struct HwcDisplayConfig {
- int id{};
- int group_id{};
+ uint32_t id{};
+ uint32_t group_id{};
DrmMode mode;
bool disabled{};
@@ -40,13 +40,15 @@ struct HwcDisplayConfig {
struct HwcDisplayConfigs {
HWC2::Error Update(DrmConnector &conn);
+ void FillHeadless();
- std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs;
+ std::map<uint32_t /*config_id*/, struct HwcDisplayConfig> hwc_configs;
- int active_config_id = 0;
- int preferred_config_id = 0;
+ uint32_t active_config_id = 0;
+ uint32_t preferred_config_id = 0;
- int last_config_id = 1;
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ static uint32_t last_config_id;
uint32_t mm_width = 0;
uint32_t mm_height = 0;
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index 6d258e8..a6dedb4 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -74,8 +74,8 @@ static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
GetFuncName(__PRETTY_FUNCTION__).c_str());
DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
- HwcDisplay *display = DrmHwcTwo::GetDisplay(hwc, display_handle);
- if (!display)
+ auto *display = hwc->GetDisplay(display_handle);
+ if (display == nullptr)
return static_cast<int32_t>(HWC2::Error::BadDisplay);
return static_cast<int32_t>((display->*func)(std::forward<Args>(args)...));
@@ -88,8 +88,8 @@ static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str());
DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
- HwcDisplay *display = DrmHwcTwo::GetDisplay(hwc, display_handle);
- if (!display)
+ auto *display = hwc->GetDisplay(display_handle);
+ if (display == nullptr)
return static_cast<int32_t>(HWC2::Error::BadDisplay);
HwcLayer *layer = display->get_layer(layer_handle);
@@ -390,12 +390,6 @@ static int HookDevOpen(const struct hw_module_t *module, const char *name,
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;
diff --git a/tests/Android.bp b/tests/Android.bp
index 20b87a8..b25342e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -42,3 +42,17 @@ cc_test {
"external/drm_hwcomposer/include",
],
}
+
+// Tool for listening and dumping uevents
+cc_test {
+ name: "hwc-drm-uevent-print",
+
+ srcs: ["uevent_print.cpp"],
+
+ vendor: true,
+ header_libs: ["libhardware_headers"],
+ shared_libs: ["liblog"],
+ include_dirs: [
+ "external/drm_hwcomposer",
+ ],
+}
diff --git a/tests/uevent_print.cpp b/tests/uevent_print.cpp
new file mode 100644
index 0000000..6ffbbfb
--- /dev/null
+++ b/tests/uevent_print.cpp
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#include <iostream>
+
+#include "utils/UEvent.h"
+
+int main() {
+ auto uevent = android::UEvent::CreateInstance();
+ if (!uevent) {
+ std::cout << "Can't initialize UEvent class" << std::endl;
+ return -ENODEV;
+ }
+
+ int number = 0;
+ for (;;) {
+ auto msg = uevent->ReadNext();
+ if (!msg) {
+ continue;
+ }
+
+ std::cout << "New event #" << number++ << std::endl
+ << *msg << std::endl
+ << std::endl;
+ }
+}
diff --git a/utils/UEvent.h b/utils/UEvent.h
new file mode 100644
index 0000000..17b3cab
--- /dev/null
+++ b/utils/UEvent.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+#include <cerrno>
+#include <memory>
+#include <optional>
+#include <string>
+
+#include "UniqueFd.h"
+#include "log.h"
+
+namespace android {
+
+class UEvent {
+ public:
+ static auto CreateInstance() -> std::unique_ptr<UEvent> {
+ auto fd = UniqueFd(
+ socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT));
+
+ if (!fd) {
+ ALOGE("Failed to open uevent socket: errno=%i", errno);
+ return {};
+ }
+
+ struct sockaddr_nl addr {};
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pid = 0;
+ addr.nl_groups = UINT32_MAX;
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
+ int ret = bind(fd.Get(), (struct sockaddr *)&addr, sizeof(addr));
+ if (ret != 0) {
+ ALOGE("Failed to bind uevent socket: errno=%i", errno);
+ return {};
+ }
+
+ return std::unique_ptr<UEvent>(new UEvent(fd));
+ }
+
+ auto ReadNext() -> std::optional<std::string> {
+ constexpr int kUEventBufferSize = 1024;
+ char buffer[kUEventBufferSize];
+ ssize_t ret = 0;
+ ret = read(fd_.Get(), &buffer, sizeof(buffer));
+ if (ret == 0)
+ return {};
+
+ if (ret < 0) {
+ ALOGE("Got error reading uevent %zd", ret);
+ return {};
+ }
+
+ for (int i = 0; i < ret - 1; i++) {
+ if (buffer[i] == '\0') {
+ buffer[i] = '\n';
+ }
+ }
+
+ return std::string(buffer);
+ }
+
+ private:
+ explicit UEvent(UniqueFd &fd) : fd_(std::move(fd)){};
+ UniqueFd fd_;
+};
+
+} // namespace android