drm_hwcomposer: Handle writeback connectors
When writeback connectors are available assign them to displays, in
order to be able to use them for flattening of the current displayed
scene. The pipeline for each display will look like this:
CRTC ---- encoder ------------ display connector.
|------- writeback enc ------ writeback connector.
However, the writeback connector will be later used/enabled only if
one of the following conditions are met:
- Could be a clone of the display connector, as pointed by the
possible_clones property.
- The display_connector is disconnected, so we are safe to use it for
flattening the scene that's already presented on another display.
Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
diff --git a/drmdevice.cpp b/drmdevice.cpp
index 25273ac..b2f350c 100644
--- a/drmdevice.cpp
+++ b/drmdevice.cpp
@@ -62,6 +62,14 @@
return std::make_tuple(ret, 0);
}
+#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
+ ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+ if (ret) {
+ ALOGI("Failed to set writeback cap %d", ret);
+ ret = 0;
+ }
+#endif
+
drmModeResPtr res = drmModeGetResources(fd());
if (!res) {
ALOGE("Failed to get DrmDevice resources");
@@ -159,7 +167,10 @@
break;
}
- connectors_.emplace_back(std::move(conn));
+ if (conn->writeback())
+ writeback_connectors_.emplace_back(std::move(conn));
+ else
+ connectors_.emplace_back(std::move(conn));
}
// First look for primary amongst internal connectors
@@ -239,6 +250,9 @@
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());
}
@@ -255,6 +269,14 @@
return NULL;
}
+DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const {
+ for (auto &conn : writeback_connectors_) {
+ if (conn->display() == display)
+ return conn.get();
+ }
+ return NULL;
+}
+
DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
for (auto &crtc : crtcs_) {
if (crtc->display() == display)
@@ -333,6 +355,34 @@
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()) != NULL) {
+ 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;
+}
+
int DrmDevice::CreatePropertyBlob(void *data, size_t length,
uint32_t *blob_id) {
struct drm_mode_create_blob create_blob;
diff --git a/drmdevice.h b/drmdevice.h
index e086067..671cab6 100644
--- a/drmdevice.h
+++ b/drmdevice.h
@@ -57,6 +57,7 @@
}
DrmConnector *GetConnectorForDisplay(int display) const;
+ DrmConnector *GetWritebackConnectorForDisplay(int display) const;
DrmCrtc *GetCrtcForDisplay(int display) const;
DrmPlane *GetPlane(uint32_t id) const;
DrmEventListener *event_listener();
@@ -81,11 +82,13 @@
DrmProperty *property);
int CreateDisplayPipe(DrmConnector *connector);
+ int AttachWriteback(DrmConnector *display_conn);
UniqueFd fd_;
uint32_t mode_id_ = 0;
std::vector<std::unique_ptr<DrmConnector>> connectors_;
+ std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
std::vector<std::unique_ptr<DrmEncoder>> encoders_;
std::vector<std::unique_ptr<DrmCrtc>> crtcs_;
std::vector<std::unique_ptr<DrmPlane>> planes_;