aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Macnak <natsu@google.com>2022-01-25 10:20:06 -0800
committerJason Macnak <natsu@google.com>2022-01-25 10:25:50 -0800
commite6295d18ec2a30be5696001287b95b3603dc7d71 (patch)
treef76bfa060614336d3f355bec8d4321433403688e
parent6ca311696d3abc46c0548cc1467b6dc10eb1a41e (diff)
parentf377ff7bd6b971728ae764a3c7b78be21acfd26e (diff)
downloaddrm_hwcomposer-android-t-preview-1.tar.gz
... to pull in f0c507f16b99ff9ac30fb1a95fd1d1c1c9eaf55a to fix crashes when display does not yet have a active mode. Bug: b/216148216 Test: launch_cvd --gpu_mode=gfxstream --hwcomposer=drm Change-Id: Ic75a1c8b516017d93dc9fdb1ef691b457fb61742
-rwxr-xr-x.ci/.gitlab-ci-checkcommit.sh2
-rw-r--r--.ci/Makefile5
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--Android.bp1
-rw-r--r--README.md2
-rwxr-xr-xbuild_deploy.sh26
-rw-r--r--compositor/DrmDisplayCompositor.cpp13
-rw-r--r--compositor/DrmDisplayCompositor.h2
-rw-r--r--drm/DrmConnector.cpp6
-rw-r--r--drm/DrmDevice.cpp66
-rw-r--r--drm/DrmDevice.h3
-rw-r--r--drm/DrmFbImporter.cpp2
-rw-r--r--drm/DrmMode.cpp3
-rw-r--r--drm/ResourceManager.h6
-rw-r--r--drm/UEventListener.cpp4
-rw-r--r--drm/VSyncWorker.cpp2
-rw-r--r--hwc2_device/DrmHwcTwo.cpp56
-rw-r--r--hwc2_device/DrmHwcTwo.h6
-rw-r--r--hwc2_device/HwcDisplay.cpp57
-rw-r--r--hwc2_device/HwcDisplay.h10
-rw-r--r--hwc2_device/HwcDisplayConfigs.cpp49
-rw-r--r--hwc2_device/HwcDisplayConfigs.h5
-rw-r--r--hwc2_device/hwc2_device.cpp35
-rw-r--r--utils/autolock.cpp57
-rw-r--r--utils/autolock.h42
25 files changed, 223 insertions, 241 deletions
diff --git a/.ci/.gitlab-ci-checkcommit.sh b/.ci/.gitlab-ci-checkcommit.sh
index e59ad9f..c9c2e49 100755
--- a/.ci/.gitlab-ci-checkcommit.sh
+++ b/.ci/.gitlab-ci-checkcommit.sh
@@ -50,7 +50,7 @@ git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do
exit 1
fi
- git show "$h" -- | clang-format-diff-12 -p 1 -style=file > /tmp/format-fixup.patch
+ git show "$h" -- | clang-format-diff-13 -p 1 -style=file > /tmp/format-fixup.patch
if [ -s /tmp/format-fixup.patch ]; then
cat /tmp/format-fixup.patch >&2
exit 1
diff --git a/.ci/Makefile b/.ci/Makefile
index 4ca14d6..7f43a8a 100644
--- a/.ci/Makefile
+++ b/.ci/Makefile
@@ -2,8 +2,8 @@
INCLUDE_DIRS := . ../libdrm/include/drm include ./.ci/android_headers ./tests/test_include
SYSTEM_INCLUDE_DIRS := /usr/include/libdrm
-CLANG := clang++-12
-CLANG_TIDY := clang-tidy-12
+CLANG := clang++-13
+CLANG_TIDY := clang-tidy-13
OUT_DIR := /tmp/drm_hwcomposer/build
SRC_DIR := .
@@ -57,6 +57,7 @@ TIDY_CHECKS_FINE := * \
TIDY_CHECKS_NORMAL := \
$(TIDY_CHECKS_FINE) \
-hicpp* \
+ -bugprone-easily-swappable-parameters \
-cppcoreguidelines-special-member-functions \
-cppcoreguidelines-avoid-c-arrays \
-cppcoreguidelines-pro-bounds-array-to-pointer-decay \
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9a54b44..89ac1b8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,11 +1,11 @@
-image: ubuntu:21.04
+image: ubuntu:21.10
variables:
DEBIAN_FRONTEND: noninteractive
before_script:
- apt-get --quiet update --yes >/dev/null
- - apt-get --quiet install --yes clang-12 clang-tidy-12 clang-format-12 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
+ - apt-get --quiet install --yes clang-13 clang-tidy-13 clang-format-13 git libdrm-dev blueprint-tools libgtest-dev make >/dev/null
stages:
- build
diff --git a/Android.bp b/Android.bp
index a856594..1c3030c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -117,7 +117,6 @@ filegroup {
"drm/UEventListener.cpp",
"drm/VSyncWorker.cpp",
- "utils/autolock.cpp",
"utils/hwcutils.cpp",
"backend/Backend.cpp",
diff --git a/README.md b/README.md
index c142266..05ddc79 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ A short list of contribution guidelines:
you with formatting of your patches:
```
- git diff | clang-format-diff-12 -p 1 -style=file
+ git diff | clang-format-diff-13 -p 1 -style=file
```
* Hardware specific changes should be tested on relevant platforms before
diff --git a/build_deploy.sh b/build_deploy.sh
new file mode 100755
index 0000000..ba9732b
--- /dev/null
+++ b/build_deploy.sh
@@ -0,0 +1,26 @@
+#!/bin/bash -e
+
+# To see logs after deploy run: $ HWCLOG=1 TESTDEV=<DEV> ./build_deploy.sh
+
+[ -z "$TESTDEV" ] && echo "Run $ TESTDEV=<Your lunch target> ./build_deploy.sh" && false
+
+cd ../..
+. build/envsetup.sh
+lunch $TESTDEV
+cd -
+
+mm
+
+adb root && adb remount && adb sync vendor
+
+adb shell stop
+adb shell stop vendor.hwcomposer-2-1 || 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
+
+[ $HWCLOG -eq "1" ] && adb logcat -c
+
+adb shell start
+
+[ $HWCLOG -eq "1" ] && adb logcat | grep -i hwc
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
index 89e7f2d..c2e51ee 100644
--- a/compositor/DrmDisplayCompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -35,7 +35,6 @@
#include "drm/DrmDevice.h"
#include "drm/DrmPlane.h"
#include "drm/DrmUnique.h"
-#include "utils/autolock.h"
#include "utils/log.h"
namespace android {
@@ -54,18 +53,6 @@ auto DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display)
return 0;
}
-std::unique_ptr<DrmDisplayComposition>
-DrmDisplayCompositor::CreateInitializedComposition() const {
- DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
- DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
- if (!crtc) {
- ALOGE("Failed to find crtc for display = %d", display_);
- return std::unique_ptr<DrmDisplayComposition>();
- }
-
- return std::make_unique<DrmDisplayComposition>(crtc);
-}
-
// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
auto DrmDisplayCompositor::CommitFrame(AtomicCommitArgs &args) -> int {
ATRACE_CALL();
diff --git a/compositor/DrmDisplayCompositor.h b/compositor/DrmDisplayCompositor.h
index e7899ed..9679520 100644
--- a/compositor/DrmDisplayCompositor.h
+++ b/compositor/DrmDisplayCompositor.h
@@ -58,8 +58,6 @@ class DrmDisplayCompositor {
~DrmDisplayCompositor() = default;
auto Init(ResourceManager *resource_manager, int display) -> int;
- std::unique_ptr<DrmDisplayComposition> CreateInitializedComposition() const;
-
auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 32b6d24..7cbec95 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -102,12 +102,12 @@ auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
uint64_t blob_id = 0;
int ret = UpdateEdidProperty();
if (ret != 0) {
- return DrmModePropertyBlobUnique();
+ return {};
}
std::tie(ret, blob_id) = edid_property().value();
if (ret != 0) {
- return DrmModePropertyBlobUnique();
+ return {};
}
return MakeDrmModePropertyBlobUnique(drm_->fd(), blob_id);
@@ -175,6 +175,8 @@ int DrmConnector::UpdateModes() {
return -ENODEV;
}
+ state_ = c->connection;
+
modes_.clear();
for (int i = 0; i < c->count_modes; ++i) {
bool exists = false;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index a679bf5..8245b78 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -331,9 +331,6 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
return std::make_tuple(ret, 0);
}
- if (!AttachWriteback(conn.get())) {
- ALOGI("Display %d has writeback attach to it", conn->display());
- }
}
return std::make_tuple(ret, displays_.size());
}
@@ -350,39 +347,6 @@ DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
return nullptr;
}
-DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const {
- for (const auto &conn : writeback_connectors_) {
- if (conn->display() == display)
- return conn.get();
- }
- return nullptr;
-}
-
-// TODO(nobody): what happens when hotplugging
-DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const {
- DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display);
- DrmConnector *display_conn = GetConnectorForDisplay(display);
- // If we have a writeback already attached to the same CRTC just use that,
- // if possible.
- if (display_conn && writeback_conn &&
- writeback_conn->encoder()->CanClone(display_conn->encoder()))
- return writeback_conn;
-
- // Use another CRTC if available and doesn't have any connector
- for (const auto &crtc : crtcs_) {
- if (crtc->display() == display)
- continue;
- display_conn = GetConnectorForDisplay(crtc->display());
- // If we have a display connected don't use it for writeback
- if (display_conn && display_conn->state() == DRM_MODE_CONNECTED)
- continue;
- writeback_conn = GetWritebackConnectorForDisplay(crtc->display());
- if (writeback_conn)
- return writeback_conn;
- }
- return nullptr;
-}
-
DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
for (const auto &crtc : crtcs_) {
if (crtc->display() == display)
@@ -457,34 +421,6 @@ int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
return -ENODEV;
}
-// Attach writeback connector to the CRTC linked to the display_conn
-int DrmDevice::AttachWriteback(DrmConnector *display_conn) {
- DrmCrtc *display_crtc = display_conn->encoder()->crtc();
- if (GetWritebackConnectorForDisplay(display_crtc->display()) != nullptr) {
- ALOGE("Display already has writeback attach to it");
- return -EINVAL;
- }
- for (auto &writeback_conn : writeback_connectors_) {
- if (writeback_conn->display() >= 0)
- continue;
- for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) {
- for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) {
- if (possible_crtc != display_crtc)
- continue;
- // Use just encoders which had not been bound already
- if (writeback_enc->can_bind(display_crtc->display())) {
- writeback_enc->set_crtc(display_crtc);
- writeback_conn->set_encoder(writeback_enc);
- writeback_conn->set_display(display_crtc->display());
- writeback_conn->UpdateModes();
- return 0;
- }
- }
- }
- }
- return -EINVAL;
-}
-
auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
-> DrmModeUserPropertyBlobUnique {
struct drm_mode_create_blob create_blob {};
@@ -494,7 +430,7 @@ auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
if (ret) {
ALOGE("Failed to create mode property blob %d", ret);
- return DrmModeUserPropertyBlobUnique();
+ return {};
}
return DrmModeUserPropertyBlobUnique(
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index d3effc2..9983d61 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -60,8 +60,6 @@ class DrmDevice {
}
DrmConnector *GetConnectorForDisplay(int display) const;
- DrmConnector *GetWritebackConnectorForDisplay(int display) const;
- DrmConnector *AvailableWritebackConnector(int display) const;
DrmCrtc *GetCrtcForDisplay(int display) const;
int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
@@ -96,7 +94,6 @@ class DrmDevice {
int TryEncoderForDisplay(int display, DrmEncoder *enc);
int CreateDisplayPipe(DrmConnector *connector);
- int AttachWriteback(DrmConnector *display_conn);
UniqueFd fd_;
uint32_t mode_id_ = 0;
diff --git a/drm/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
index 25f32b7..6f2abe8 100644
--- a/drm/DrmFbImporter.cpp
+++ b/drm/DrmFbImporter.cpp
@@ -124,7 +124,7 @@ auto DrmFbImporter::GetOrCreateFbId(hwc_drm_bo_t *bo)
if (err != 0) {
ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
- return std::shared_ptr<DrmFbIdHandle>();
+ return {};
}
auto drm_fb_id_cached = drm_fb_id_handle_cache_.find(first_handle);
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index 1c8bd0f..010ea1b 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -94,6 +94,9 @@ uint16_t DrmMode::v_scan() const {
}
float DrmMode::v_refresh() const {
+ if (clock_ == 0) {
+ return v_refresh_;
+ }
// Always recalculate refresh to report correct float rate
return static_cast<float>(clock_) / (float)(v_total_ * h_total_) * 1000.0F;
}
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 773b350..f54d682 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -48,6 +48,10 @@ class ResourceManager {
return &uevent_listener_;
}
+ auto &GetMainLock() {
+ return main_lock_;
+ }
+
private:
int AddDrmDevice(std::string const &path);
@@ -57,6 +61,8 @@ class ResourceManager {
bool scale_with_gpu_{};
UEventListener uevent_listener_;
+
+ std::mutex main_lock_;
};
} // namespace android
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
index 470e89a..44c503d 100644
--- a/drm/UEventListener.cpp
+++ b/drm/UEventListener.cpp
@@ -90,6 +90,10 @@ void UEventListener::Routine() {
}
if (drm_event && hotplug_event && hotplug_handler_) {
+ constexpr useconds_t delay_after_uevent_us = 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);
hotplug_handler_();
}
}
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 6e92838..8d1cb99 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -77,7 +77,7 @@ int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) const {
last_timestamp_;
}
-static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
+static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
struct timespec vsync {};
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index 5bbb48a..a2a093f 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -66,8 +66,11 @@ HWC2::Error DrmHwcTwo::Init() {
}
}
- resource_manager_.GetUEventListener()->RegisterHotplugHandler(
- [this] { HandleHotplugUEvent(); });
+ resource_manager_.GetUEventListener()->RegisterHotplugHandler([this] {
+ const std::lock_guard<std::mutex> lock(GetResMan().GetMainLock());
+
+ HandleHotplugUEvent();
+ });
return ret;
}
@@ -111,12 +114,9 @@ uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
hwc2_callback_data_t data,
hwc2_function_pointer_t function) {
- std::unique_lock<std::mutex> lock(callback_lock_);
-
switch (static_cast<HWC2::Callback>(descriptor)) {
case HWC2::Callback::Hotplug: {
hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
- lock.unlock();
const auto &drm_devices = resource_manager_.GetDrmDevices();
for (const auto &device : drm_devices)
HandleInitialHotplugState(device.get());
@@ -143,22 +143,36 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
}
void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
- const std::lock_guard<std::mutex> lock(callback_lock_);
-
- if (hotplug_callback_.first != nullptr &&
- hotplug_callback_.second != nullptr) {
- hotplug_callback_.first(hotplug_callback_.second, displayid,
- state == DRM_MODE_CONNECTED
- ? HWC2_CONNECTION_CONNECTED
- : HWC2_CONNECTION_DISCONNECTED);
+ auto &mutex = GetResMan().GetMainLock();
+ if (mutex.try_lock()) {
+ ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
+ mutex.unlock();
+ return;
+ }
+
+ auto hc = hotplug_callback_;
+ if (hc.first != nullptr && hc.second != nullptr) {
+ /* For some reason CLIENT will call HWC2 API in hotplug callback handler,
+ * which will cause deadlock . Unlock main mutex to prevent this.
+ */
+ mutex.unlock();
+ hc.first(hc.second, displayid,
+ state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+ : HWC2_CONNECTION_DISCONNECTED);
+ mutex.lock();
}
}
void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
for (const auto &conn : drmDevice->connectors()) {
- if (conn->state() != DRM_MODE_CONNECTED)
+ int display_id = conn->display();
+ auto &display = displays_.at(display_id);
+
+ if (conn->state() != DRM_MODE_CONNECTED && !display.IsInHeadlessMode())
continue;
- HandleDisplayHotplug(conn->display(), conn->state());
+ HandleDisplayHotplug(conn->display(), display.IsInHeadlessMode()
+ ? DRM_MODE_CONNECTED
+ : conn->state());
}
}
@@ -178,15 +192,15 @@ void DrmHwcTwo::HandleHotplugUEvent() {
conn->display());
int display_id = conn->display();
- if (cur_state == DRM_MODE_CONNECTED) {
- auto &display = displays_.at(display_id);
- display.ChosePreferredConfig();
- } else {
- auto &display = displays_.at(display_id);
+ auto &display = displays_.at(display_id);
+ display.ChosePreferredConfig();
+ if (cur_state != DRM_MODE_CONNECTED) {
display.ClearDisplay();
}
- HandleDisplayHotplug(display_id, cur_state);
+ HandleDisplayHotplug(display_id, display.IsInHeadlessMode()
+ ? DRM_MODE_CONNECTED
+ : cur_state);
}
}
}
diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h
index d096160..f38ba05 100644
--- a/hwc2_device/DrmHwcTwo.h
+++ b/hwc2_device/DrmHwcTwo.h
@@ -37,8 +37,6 @@ class DrmHwcTwo {
#endif
std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
- std::mutex callback_lock_;
-
static HwcDisplay *GetDisplay(DrmHwcTwo *hwc, hwc2_display_t display_handle) {
auto it = hwc->displays_.find(display_handle);
if (it == hwc->displays_.end())
@@ -57,6 +55,10 @@ class DrmHwcTwo {
hwc2_function_pointer_t function);
HWC2::Error CreateDisplay(hwc2_display_t displ, HWC2::DisplayType type);
+ auto &GetResMan() {
+ return resource_manager_;
+ }
+
private:
void HandleDisplayHotplug(hwc2_display_t displayid, int state);
void HandleInitialHotplugState(DrmDevice *drmDevice);
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 9055a9a..8936136 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -98,6 +98,11 @@ HwcDisplay::HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
}
void HwcDisplay::ClearDisplay() {
+ if (IsInHeadlessMode()) {
+ ALOGE("%s: Headless mode, should never reach here: ", __func__);
+ return;
+ }
+
AtomicCommitArgs a_args = {.clear_active_composition = true};
compositor_.ExecuteAtomicCommit(a_args);
}
@@ -136,7 +141,7 @@ HWC2::Error HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
}
ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) {
- const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
+ 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 &&
@@ -160,7 +165,8 @@ HWC2::Error HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
ret = flattening_vsync_worker_
.Init(drm_, display, [this](int64_t /*timestamp*/) {
- const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
+ const std::lock_guard<std::mutex> lock(
+ hwc2_->GetResMan().GetMainLock());
/* Frontend flattening */
if (flattenning_state_ >
ClientFlattenningState::ClientRefreshRequested &&
@@ -191,7 +197,7 @@ HWC2::Error HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
HWC2::Error HwcDisplay::ChosePreferredConfig() {
HWC2::Error err = configs_.Update(*connector_);
- if (err != HWC2::Error::None)
+ if (!IsInHeadlessMode() && err != HWC2::Error::None)
return HWC2::Error::BadDisplay;
return SetActiveConfig(configs_.preferred_config_id);
@@ -229,6 +235,11 @@ HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
HWC2::Error HwcDisplay::GetChangedCompositionTypes(uint32_t *num_elements,
hwc2_layer_t *layers,
int32_t *types) {
+ if (IsInHeadlessMode()) {
+ *num_elements = 0;
+ return HWC2::Error::None;
+ }
+
uint32_t num_changes = 0;
for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
if (l.second.IsTypeChanged()) {
@@ -249,6 +260,9 @@ HWC2::Error HwcDisplay::GetClientTargetSupport(uint32_t width, uint32_t height,
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;
+ }
if (width < min.first || height < min.second)
return HWC2::Error::Unsupported;
@@ -286,8 +300,8 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
auto &hwc_config = configs_.hwc_configs[conf];
static const int32_t kUmPerInch = 25400;
- uint32_t mm_width = connector_->mm_width();
- uint32_t mm_height = connector_->mm_height();
+ uint32_t mm_width = configs_.mm_width;
+ uint32_t mm_height = configs_.mm_height;
auto attribute = static_cast<HWC2::Attribute>(attribute_in);
switch (attribute) {
case HWC2::Attribute::Width:
@@ -328,15 +342,6 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config,
HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
hwc2_config_t *configs) {
- // Since this callback is normally invoked twice (once to get the count, and
- // once to populate configs), we don't really want to read the edid
- // redundantly. Instead, only update the modes on the first invocation. While
- // it's possible this will result in stale modes, it'll all come out in the
- // wash when we try to set the active config later.
- if (!configs) {
- configs_.Update(*connector_);
- }
-
uint32_t idx = 0;
for (auto &hwc_config : configs_.hwc_configs) {
if (hwc_config.second.disabled) {
@@ -406,6 +411,11 @@ HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types,
HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
hwc2_layer_t *layers,
int32_t *fences) {
+ if (IsInHeadlessMode()) {
+ *num_elements = 0;
+ return HWC2::Error::None;
+ }
+
uint32_t num_layers = 0;
for (std::pair<const hwc2_layer_t, HwcLayer> &l : layers_) {
@@ -426,6 +436,11 @@ HWC2::Error HwcDisplay::GetReleaseFences(uint32_t *num_elements,
}
HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
+ if (IsInHeadlessMode()) {
+ ALOGE("%s: Display is in headless mode, should never reach here", __func__);
+ return HWC2::Error::None;
+ }
+
// order the layers by z-order
bool use_client_layer = false;
uint32_t client_z_order = UINT32_MAX;
@@ -505,7 +520,11 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
* https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1805
*/
HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) {
- HWC2::Error ret;
+ if (IsInHeadlessMode()) {
+ *present_fence = -1;
+ return HWC2::Error::None;
+ }
+ HWC2::Error ret{};
++total_stats_.total_frames_;
@@ -619,6 +638,10 @@ HWC2::Error HwcDisplay::SetOutputBuffer(buffer_handle_t /*buffer*/,
}
HWC2::Error HwcDisplay::SetPowerMode(int32_t mode_in) {
+ if (IsInHeadlessMode()) {
+ return HWC2::Error::None;
+ }
+
auto mode = static_cast<HWC2::PowerMode>(mode_in);
AtomicCommitArgs a_args{};
@@ -660,6 +683,10 @@ HWC2::Error HwcDisplay::SetVsyncEnabled(int32_t enabled) {
HWC2::Error HwcDisplay::ValidateDisplay(uint32_t *num_types,
uint32_t *num_requests) {
+ if (IsInHeadlessMode()) {
+ *num_types = *num_requests = 0;
+ return HWC2::Error::None;
+ }
return backend_->ValidateDisplay(this, num_types, num_requests);
}
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 6f46f5d..c3e0f6e 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -200,6 +200,16 @@ class HwcDisplay {
return false;
}
+ /* Headless mode required to keep SurfaceFlinger alive when all display are
+ * disconnected, Without headless mode Android will continuously crash.
+ * Only single internal (primary) display is required to be in HEADLESS mode
+ * to prevent the crash. See:
+ * https://source.android.com/devices/graphics/hotplug#handling-common-scenarios
+ */
+ bool IsInHeadlessMode() {
+ return handle_ == 0 && connector_->state() != DRM_MODE_CONNECTED;
+ }
+
private:
enum ClientFlattenningState : int32_t {
Disabled = -3,
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
index d1a8d4c..16f1ed0 100644
--- a/hwc2_device/HwcDisplayConfigs.cpp
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -23,26 +23,57 @@
#include "drm/DrmConnector.h"
#include "utils/log.h"
+constexpr uint32_t kHeadlessModeDisplayWidthMm = 163;
+constexpr uint32_t kHeadlessModeDisplayHeightMm = 122;
+constexpr uint32_t kHeadlessModeDisplayWidthPx = 1024;
+constexpr uint32_t kHeadlessModeDisplayHeightPx = 768;
+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*/
+ hwc_configs.clear();
+
+ last_config_id++;
+ preferred_config_id = active_config_id = last_config_id;
+ auto headless_drm_mode_info = (drmModeModeInfo){
+ .hdisplay = kHeadlessModeDisplayWidthPx,
+ .vdisplay = kHeadlessModeDisplayHeightPx,
+ .vrefresh = kHeadlessModeDisplayVRefresh,
+ .name = "HEADLESS-MODE",
+ };
+ hwc_configs[active_config_id] = (HwcDisplayConfig){
+ .id = active_config_id,
+ .group_id = 1,
+ .mode = DrmMode(&headless_drm_mode_info),
+ };
+
+ mm_width = kHeadlessModeDisplayWidthMm;
+ mm_height = kHeadlessModeDisplayHeightMm;
+
+ /* Read real configs */
int ret = connector.UpdateModes();
if (ret != 0) {
ALOGE("Failed to update display modes %d", ret);
return HWC2::Error::BadDisplay;
}
- hwc_configs.clear();
- preferred_config_id = 0;
- int preferred_config_group_id = 0;
-
if (connector.modes().empty()) {
ALOGE("No modes reported by KMS");
return HWC2::Error::BadDisplay;
}
- int last_config_id = 1;
+ hwc_configs.clear();
+ mm_width = connector.mm_width();
+ mm_height = connector.mm_height();
+
+ preferred_config_id = 0;
+ int preferred_config_group_id = 0;
+
+ int first_config_id = last_config_id;
int last_group_id = 1;
/* Group modes */
@@ -87,7 +118,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
/* We must have preferred mode. Set first mode as preferred
* in case KMS haven't reported anything. */
if (preferred_config_id == 0) {
- preferred_config_id = 1;
+ preferred_config_id = first_config_id;
preferred_config_group_id = 1;
}
@@ -142,8 +173,8 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
* otherwise android.graphics.cts.SetFrameRateTest CTS will fail
*/
constexpr float kMinFpsDelta = 1.0; // FPS
- for (int m1 = 1; m1 < last_config_id; m1++) {
- for (int m2 = 1; m2 < last_config_id; m2++) {
+ for (int m1 = first_config_id; m1 < last_config_id; m1++) {
+ for (int 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() -
@@ -159,6 +190,8 @@ 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 cb38625..5bcf696 100644
--- a/hwc2_device/HwcDisplayConfigs.h
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -45,6 +45,11 @@ struct HwcDisplayConfigs {
int active_config_id = 0;
int preferred_config_id = 0;
+
+ int last_config_id = 1;
+
+ uint32_t mm_width = 0;
+ uint32_t mm_height = 0;
};
} // namespace android
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index 22e4589..6d258e8 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -14,14 +14,35 @@
* limitations under the License.
*/
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+// #define LOG_NDEBUG 0 // Uncomment to see HWC2 API calls in logcat
+
#define LOG_TAG "hwc2-device"
+#include <cinttypes>
+
#include "DrmHwcTwo.h"
#include "backend/Backend.h"
#include "utils/log.h"
namespace android {
+/* Converts long __PRETTY_FUNCTION__ result, e.g.:
+ * "int32_t android::LayerHook(hwc2_device_t *, hwc2_display_t, hwc2_layer_t,"
+ * "Args...) [HookType = HWC2::Error (android::HwcLayer::*)(const native_handle"
+ * "*,int), func = &android::HwcLayer::SetLayerBuffer, Args = <const
+ * "native_handle, int>"
+ * to the short "android::HwcLayer::SetLayerBuffer" for better logs readability
+ */
+static std::string GetFuncName(const char *pretty_function) {
+ std::string str(pretty_function);
+ const char *start = "func = &";
+ size_t p1 = str.find(start);
+ p1 += strlen(start);
+ size_t p2 = str.find(',', p1);
+ return str.substr(p1, p2 - p1);
+}
+
struct Drmhwc2Device : hwc2_device {
DrmHwcTwo drmhwctwo;
};
@@ -40,14 +61,20 @@ static hwc2_function_pointer_t ToHook(T function) {
template <typename T, typename HookType, HookType func, typename... Args>
static T DeviceHook(hwc2_device_t *dev, Args... args) {
+ ALOGV("Device hook: %s", GetFuncName(__PRETTY_FUNCTION__).c_str());
DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+ const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
return static_cast<T>(((*hwc).*func)(std::forward<Args>(args)...));
}
template <typename HookType, HookType func, typename... Args>
static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
Args... args) {
- HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle);
+ ALOGV("Display #%" PRIu64 " hook: %s", display_handle,
+ GetFuncName(__PRETTY_FUNCTION__).c_str());
+ DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+ const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+ HwcDisplay *display = DrmHwcTwo::GetDisplay(hwc, display_handle);
if (!display)
return static_cast<int32_t>(HWC2::Error::BadDisplay);
@@ -57,7 +84,11 @@ static int32_t DisplayHook(hwc2_device_t *dev, hwc2_display_t display_handle,
template <typename HookType, HookType func, typename... Args>
static int32_t LayerHook(hwc2_device_t *dev, hwc2_display_t display_handle,
hwc2_layer_t layer_handle, Args... args) {
- HwcDisplay *display = DrmHwcTwo::GetDisplay(ToDrmHwcTwo(dev), display_handle);
+ ALOGV("Display #%" PRIu64 " Layer: #%" PRIu64 " hook: %s", display_handle,
+ layer_handle, GetFuncName(__PRETTY_FUNCTION__).c_str());
+ DrmHwcTwo *hwc = ToDrmHwcTwo(dev);
+ const std::lock_guard<std::mutex> lock(hwc->GetResMan().GetMainLock());
+ HwcDisplay *display = DrmHwcTwo::GetDisplay(hwc, display_handle);
if (!display)
return static_cast<int32_t>(HWC2::Error::BadDisplay);
diff --git a/utils/autolock.cpp b/utils/autolock.cpp
deleted file mode 100644
index 3afe488..0000000
--- a/utils/autolock.cpp
+++ /dev/null
@@ -1,57 +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-auto-lock"
-
-#include "autolock.h"
-
-#include <pthread.h>
-
-#include <cerrno>
-
-#include "utils/log.h"
-
-namespace android {
-
-int AutoLock::Lock() {
- if (locked_) {
- ALOGE("Invalid attempt to double lock AutoLock %s", name_);
- return -EINVAL;
- }
- int ret = pthread_mutex_lock(mutex_);
- if (ret != 0) {
- ALOGE("Failed to acquire %s lock %d", name_, ret);
- return ret;
- }
- locked_ = true;
- return 0;
-}
-
-int AutoLock::Unlock() {
- if (!locked_) {
- ALOGE("Invalid attempt to unlock unlocked AutoLock %s", name_);
- return -EINVAL;
- }
- int ret = pthread_mutex_unlock(mutex_);
- if (ret != 0) {
- ALOGE("Failed to release %s lock %d", name_, ret);
- return ret;
- }
- locked_ = false;
- return 0;
-}
-} // namespace android
diff --git a/utils/autolock.h b/utils/autolock.h
deleted file mode 100644
index 006406a..0000000
--- a/utils/autolock.h
+++ /dev/null
@@ -1,42 +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.
- */
-
-#include <pthread.h>
-
-namespace android {
-
-class AutoLock {
- public:
- AutoLock(pthread_mutex_t *mutex, const char *const name)
- : mutex_(mutex), name_(name) {
- }
- ~AutoLock() {
- if (locked_)
- Unlock();
- }
-
- AutoLock(const AutoLock &rhs) = delete;
- AutoLock &operator=(const AutoLock &rhs) = delete;
-
- int Lock();
- int Unlock();
-
- private:
- pthread_mutex_t *const mutex_;
- bool locked_ = false;
- const char *const name_;
-};
-} // namespace android