aboutsummaryrefslogtreecommitdiff
path: root/drmhwctwo.cpp
diff options
context:
space:
mode:
authorAndrii Chepurnyi <andrii_chepurnyi@epam.com>2018-08-01 17:42:56 +0300
committerAndrii Chepurnyi <andrii_chepurnyi@epam.com>2019-03-06 19:21:49 +0200
commit495e4cc3fd619bd8d8d10a9b595fbad831a46909 (patch)
treeabfd21f2e19d5a8afaeede2916dcee2bd9f6c998 /drmhwctwo.cpp
parent4bdd0fe281dbf7df203d4f01e059546813a623b1 (diff)
downloaddrm_hwcomposer-495e4cc3fd619bd8d8d10a9b595fbad831a46909.tar.gz
drm_hwcomposer: Added hotplug support of the external display
Unplug of the main display will not work because of Activity Manager code(ActivityStackSupervisor.java:handleDisplayRemoved). Only one display can be connected as an external display (see SurfaceFlinger::determineDisplayType). Tested-by: John Stultz <john.stultz@linaro.org> Signed-off-by: Andrii Chepurnyi <andrii_chepurnyi@epam.com>
Diffstat (limited to 'drmhwctwo.cpp')
-rw-r--r--drmhwctwo.cpp132
1 files changed, 103 insertions, 29 deletions
diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp
index 7bd8d64..f506bfc 100644
--- a/drmhwctwo.cpp
+++ b/drmhwctwo.cpp
@@ -57,43 +57,55 @@ DrmHwcTwo::DrmHwcTwo() {
getFunction = HookDevGetFunction;
}
-HWC2::Error DrmHwcTwo::Init() {
- int ret = resource_manager_.Init();
- if (ret) {
- ALOGE("Can't initialize the resource manager %d", ret);
- return HWC2::Error::NoResources;
- }
-
- DrmDevice *drm = resource_manager_.GetDrmDevice(HWC_DISPLAY_PRIMARY);
- std::shared_ptr<Importer> importer = resource_manager_.GetImporter(
- HWC_DISPLAY_PRIMARY);
+HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
+ HWC2::DisplayType type) {
+ DrmDevice *drm = resource_manager_.GetDrmDevice(displ);
+ std::shared_ptr<Importer> importer = resource_manager_.GetImporter(displ);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
-
- displays_.emplace(std::piecewise_construct,
- std::forward_as_tuple(HWC_DISPLAY_PRIMARY),
+ displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
std::forward_as_tuple(&resource_manager_, drm, importer,
- HWC_DISPLAY_PRIMARY,
- HWC2::DisplayType::Physical));
+ displ, type));
- DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
+ DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
if (!crtc) {
- ALOGE("Failed to get crtc for display %d",
- static_cast<int>(HWC_DISPLAY_PRIMARY));
+ ALOGE("Failed to get crtc for display %d", static_cast<int>(displ));
return HWC2::Error::BadDisplay;
}
-
std::vector<DrmPlane *> display_planes;
for (auto &plane : drm->planes()) {
if (plane->GetCrtcSupported(*crtc))
display_planes.push_back(plane.get());
}
- displays_.at(HWC_DISPLAY_PRIMARY).Init(&display_planes);
+ displays_.at(displ).Init(&display_planes);
return HWC2::Error::None;
}
+HWC2::Error DrmHwcTwo::Init() {
+ int rv = resource_manager_.Init();
+ if (rv) {
+ ALOGE("Can't initialize the resource manager %d", rv);
+ return HWC2::Error::NoResources;
+ }
+
+ HWC2::Error ret = HWC2::Error::None;
+ for (int i = 0; i < resource_manager_.getDisplayCount(); i++) {
+ ret = CreateDisplay(i, HWC2::DisplayType::Physical);
+ if (ret != HWC2::Error::None) {
+ ALOGE("Failed to create display %d with error %d", i, ret);
+ return ret;
+ }
+ }
+
+ auto &drmDevices = resource_manager_.getDrmDevices();
+ for (auto &device : drmDevices) {
+ device->RegisterHotplugHandler(new DrmHotplugHandler(this, device.get()));
+ }
+ return ret;
+}
+
template <typename... Args>
static inline HWC2::Error unsupported(char const *func, Args... /*args*/) {
ALOGV("Unsupported function: %s", func);
@@ -132,6 +144,12 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
hwc2_function_pointer_t function) {
supported(__func__);
auto callback = static_cast<HWC2::Callback>(descriptor);
+
+ if (!function) {
+ callbacks_.erase(callback);
+ return HWC2::Error::None;
+ }
+
callbacks_.emplace(callback, HwcCallback(data, function));
switch (callback) {
@@ -139,6 +157,9 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(function);
hotplug(data, HWC_DISPLAY_PRIMARY,
static_cast<int32_t>(HWC2::Connection::Connected));
+ auto &drmDevices = resource_manager_.getDrmDevices();
+ for (auto &device : drmDevices)
+ HandleInitialHotplugState(device.get());
break;
}
case HWC2::Callback::Vsync: {
@@ -165,6 +186,10 @@ DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
supported(__func__);
}
+void DrmHwcTwo::HwcDisplay::ClearDisplay() {
+ compositor_.ClearDisplay();
+}
+
HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
supported(__func__);
planner_ = Planner::CreateInstance(drm_);
@@ -204,6 +229,16 @@ HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
return HWC2::Error::BadDisplay;
}
+ ret = vsync_worker_.Init(drm_, display);
+ if (ret) {
+ ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
+ return HWC2::Error::BadDisplay;
+ }
+
+ return ChosePreferredConfig();
+}
+
+HWC2::Error DrmHwcTwo::HwcDisplay::ChosePreferredConfig() {
// Fetch the number of modes from the display
uint32_t num_configs;
HWC2::Error err = GetDisplayConfigs(&num_configs, NULL);
@@ -217,13 +252,6 @@ HWC2::Error DrmHwcTwo::HwcDisplay::Init(std::vector<DrmPlane *> *planes) {
err = GetDisplayConfigs(&num_configs, &default_config);
if (err != HWC2::Error::None)
return err;
-
- ret = vsync_worker_.Init(drm_, display);
- if (ret) {
- ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
- return HWC2::Error::BadDisplay;
- }
-
return SetActiveConfig(default_config);
}
@@ -617,8 +645,8 @@ HWC2::Error DrmHwcTwo::HwcDisplay::SetActiveConfig(hwc2_config_t config) {
ALOGE("Failed to queue dpms composition on %d", ret);
return HWC2::Error::BadConfig;
}
- if (connector_->active_mode().id() == 0)
- connector_->set_active_mode(*mode);
+
+ connector_->set_active_mode(*mode);
// Setup the client layer's dimensions
hwc_rect_t display_frame = {.left = 0,
@@ -880,6 +908,52 @@ void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) {
layer->SetTransform(static_cast<int32_t>(transform_));
}
+void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
+ auto cb = callbacks_.find(HWC2::Callback::Hotplug);
+ if (cb == callbacks_.end())
+ return;
+
+ auto hotplug = reinterpret_cast<HWC2_PFN_HOTPLUG>(cb->second.func);
+ hotplug(cb->second.data, displayid,
+ (state == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
+ : HWC2_CONNECTION_DISCONNECTED));
+}
+
+void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
+ for (auto &conn : drmDevice->connectors()) {
+ if (conn->state() != DRM_MODE_CONNECTED)
+ continue;
+ HandleDisplayHotplug(conn->display(), conn->state());
+ }
+}
+
+void DrmHwcTwo::DrmHotplugHandler::HandleEvent(uint64_t timestamp_us) {
+ for (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 @%" PRIu64 " for connector %u on display %d",
+ cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us,
+ conn->id(), conn->display());
+
+ int display_id = conn->display();
+ if (cur_state == DRM_MODE_CONNECTED) {
+ auto &display = hwc2_->displays_.at(display_id);
+ display.ChosePreferredConfig();
+ } else {
+ auto &display = hwc2_->displays_.at(display_id);
+ display.ClearDisplay();
+ }
+
+ hwc2_->HandleDisplayHotplug(display_id, cur_state);
+ }
+}
+
// static
int DrmHwcTwo::HookDevClose(hw_device_t * /*dev*/) {
unsupported(__func__);