am e86fcfbb: (-s ours) drm_hwcomposer: Split the drm compositor into per-display threads
* commit 'e86fcfbb5c3f857efbcccb335c9a1a72a7a101cb':
drm_hwcomposer: Split the drm compositor into per-display threads
diff --git a/compositor.h b/compositor.h
index e148416..b424b37 100644
--- a/compositor.h
+++ b/compositor.h
@@ -90,6 +90,8 @@
// Starts a fresh composition.
virtual Composition *CreateComposition(Importer *importer) = 0;
+ // Transfers ownership of composition to the Compositor (whether or not this
+ // call returns success) for compositing.
// On success returns a syncpoint fd that will be signaled when composition is
// complete or -1 if compositing was completed by this method's return. On
// error returns an integer less than -1. The composition is invalid after
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 37e3bad..805fd26 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -77,7 +77,7 @@
if ((*iter)->GetCrtcSupported(*crtc))
++num_planes;
}
- for (std::deque<DrmPlane *>::const_iterator iter = overlay_planes_.begin();
+ for (std::vector<DrmPlane *>::const_iterator iter = overlay_planes_.begin();
iter != overlay_planes_.end(); ++iter) {
if ((*iter)->GetCrtcSupported(*crtc))
++num_planes;
@@ -103,7 +103,7 @@
break;
}
}
- for (std::deque<DrmPlane *>::iterator iter = overlay_planes_.begin();
+ for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin();
!plane && iter != overlay_planes_.end(); ++iter) {
if ((*iter)->GetCrtcSupported(*crtc)) {
plane = *iter;
@@ -118,8 +118,57 @@
return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
}
+int DrmComposition::AddDpmsMode(int display, uint32_t dpms_mode) {
+ return composition_map_[display]->AddDpmsMode(dpms_mode);
+}
+
std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition(
int display) {
return std::move(composition_map_[display]);
}
+
+int DrmComposition::DisableUnusedPlanes() {
+ for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+ iter != drm_->end_connectors(); ++iter) {
+ int display = (*iter)->display();
+ DrmDisplayComposition *comp = GetDisplayComposition(display);
+
+ /*
+ * Leave empty compositions alone
+ * TODO: re-visit this and potentially disable leftover planes after the
+ * active compositions have gobbled up all they can
+ */
+ if (comp->type() == DRM_COMPOSITION_TYPE_EMPTY)
+ continue;
+
+ DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
+ if (!crtc) {
+ ALOGE("Failed to find crtc for display %d", display);
+ continue;
+ }
+
+ for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
+ iter != primary_planes_.end(); ++iter) {
+ if ((*iter)->GetCrtcSupported(*crtc)) {
+ comp->AddPlaneDisable(*iter);
+ primary_planes_.erase(iter);
+ break;
+ }
+ }
+ for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin();
+ iter != overlay_planes_.end();) {
+ if ((*iter)->GetCrtcSupported(*crtc)) {
+ comp->AddPlaneDisable(*iter);
+ iter = overlay_planes_.erase(iter);
+ } else {
+ iter++;
+ }
+ }
+ }
+ return 0;
+}
+
+DrmDisplayComposition *DrmComposition::GetDisplayComposition(int display) {
+ return composition_map_[display].get();
+}
}
diff --git a/drmcomposition.h b/drmcomposition.h
index a8f9836..06af71d 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -41,8 +41,12 @@
virtual unsigned GetRemainingLayers(int display, unsigned num_needed) const;
virtual int AddLayer(int display, hwc_layer_1_t *layer, hwc_drm_bo_t *bo);
+ int AddDpmsMode(int display, uint32_t dpms_mode);
+
+ int DisableUnusedPlanes();
std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
+ DrmDisplayComposition *GetDisplayComposition(int display);
private:
DrmComposition(const DrmComposition &) = delete;
@@ -51,7 +55,7 @@
Importer *importer_;
std::vector<DrmPlane *> primary_planes_;
- std::deque<DrmPlane *> overlay_planes_;
+ std::vector<DrmPlane *> overlay_planes_;
/*
* This _must_ be read-only after it's passed to QueueComposition. Otherwise
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index 4268ab5..3bab93f 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -64,6 +64,13 @@
int DrmCompositor::QueueComposition(Composition *composition) {
DrmComposition *drm_composition = (DrmComposition *)composition;
+
+ int ret = drm_composition->DisableUnusedPlanes();
+ if (ret) {
+ ALOGE("Failed to disable unused planes %d", ret);
+ return ret;
+ }
+
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
int display = (*iter)->display();
@@ -71,6 +78,7 @@
drm_composition->TakeDisplayComposition(display));
if (ret) {
ALOGE("Failed to queue composition for display %d", display);
+ delete composition;
return ret;
}
}
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 75046fb..364a64e 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -26,6 +26,7 @@
#include <cutils/log.h>
#include <sw_sync.h>
#include <sync/sync.h>
+#include <xf86drmMode.h>
namespace android {
@@ -39,13 +40,18 @@
}
DrmDisplayComposition::DrmDisplayComposition()
- : drm_(NULL), importer_(NULL), timeline_fd_(-1), timeline_(0) {
+ : drm_(NULL),
+ importer_(NULL),
+ type_(DRM_COMPOSITION_TYPE_EMPTY),
+ timeline_fd_(-1),
+ timeline_(0),
+ dpms_mode_(DRM_MODE_DPMS_ON) {
}
DrmDisplayComposition::~DrmDisplayComposition() {
for (DrmCompositionLayerVector_t::iterator iter = layers_.begin();
iter != layers_.end(); ++iter) {
- if (importer_)
+ if (importer_ && iter->bo.fb_id)
importer_->ReleaseBuffer(&iter->bo);
if (iter->layer.acquireFenceFd >= 0)
@@ -69,11 +75,22 @@
return 0;
}
+DrmCompositionType DrmDisplayComposition::type() const {
+ return type_;
+}
+
+bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) {
+ return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des;
+}
+
int DrmDisplayComposition::AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo,
DrmCrtc *crtc, DrmPlane *plane) {
if (layer->transform != 0)
return -EINVAL;
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+ return -EINVAL;
+
++timeline_;
layer->releaseFenceFd =
sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
@@ -90,6 +107,23 @@
layer->acquireFenceFd = -1; // We own this now
layers_.push_back(c_layer);
+ type_ = DRM_COMPOSITION_TYPE_FRAME;
+ return 0;
+}
+
+int DrmDisplayComposition::AddDpmsMode(uint32_t dpms_mode) {
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_DPMS))
+ return -EINVAL;
+ dpms_mode_ = dpms_mode;
+ type_ = DRM_COMPOSITION_TYPE_DPMS;
+ return 0;
+}
+
+int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
+ DrmCompositionLayer_t c_layer;
+ c_layer.crtc = NULL;
+ c_layer.plane = plane;
+ layers_.push_back(c_layer);
return 0;
}
@@ -104,4 +138,8 @@
DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() {
return &layers_;
}
+
+uint32_t DrmDisplayComposition::dpms_mode() const {
+ return dpms_mode_;
+}
}
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index cf03360..09ad3ff 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -28,6 +28,12 @@
namespace android {
+enum DrmCompositionType {
+ DRM_COMPOSITION_TYPE_EMPTY,
+ DRM_COMPOSITION_TYPE_FRAME,
+ DRM_COMPOSITION_TYPE_DPMS,
+};
+
typedef struct DrmCompositionLayer {
DrmCompositionLayer();
~DrmCompositionLayer();
@@ -46,23 +52,33 @@
int Init(DrmResources *drm, Importer *importer);
+ DrmCompositionType type() const;
+
int AddLayer(hwc_layer_1_t *layer, hwc_drm_bo_t *bo, DrmCrtc *crtc,
DrmPlane *plane);
+ int AddPlaneDisable(DrmPlane *plane);
+ int AddDpmsMode(uint32_t dpms_mode);
int FinishComposition();
DrmCompositionLayerVector_t *GetCompositionLayers();
+ uint32_t dpms_mode() const;
private:
DrmDisplayComposition(const DrmDisplayComposition &) = delete;
+ bool validate_composition_type(DrmCompositionType desired);
+
DrmResources *drm_;
Importer *importer_;
+ DrmCompositionType type_;
+
int timeline_fd_;
int timeline_;
DrmCompositionLayerVector_t layers_;
+ uint32_t dpms_mode_;
};
}
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index 2b4b4df..8168e1a 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -40,6 +40,7 @@
worker_(this),
frame_no_(0),
initialized_(false),
+ active_(false),
dump_frames_composited_(0),
dump_last_timestamp_ns_(0) {
struct timespec ts;
@@ -93,8 +94,24 @@
int DrmDisplayCompositor::QueueComposition(
std::unique_ptr<DrmDisplayComposition> composition) {
- if (composition->GetCompositionLayers()->empty())
+ switch (composition->type()) {
+ case DRM_COMPOSITION_TYPE_FRAME:
+ if (!active_)
+ return -ENODEV;
+ break;
+ case DRM_COMPOSITION_TYPE_DPMS:
+ /*
+ * Update the state as soon as we get it so we can start/stop queuing
+ * frames asap.
+ */
+ active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
+ break;
+ case DRM_COMPOSITION_TYPE_EMPTY:
return 0;
+ default:
+ ALOGE("Unknown composition type %d/%d", composition->type(), display_);
+ return -ENOENT;
+ }
int ret = pthread_mutex_lock(&lock_);
if (ret) {
@@ -140,9 +157,25 @@
}
DrmPlane *plane = iter->plane;
+ DrmCrtc *crtc = iter->crtc;
+
+ // Disable the plane if there's no crtc
+ if (!crtc) {
+ ret =
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
+ 0) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
+ 0);
+ if (ret) {
+ ALOGE("Failed to add plane %d disable to pset", plane->id());
+ break;
+ }
+ continue;
+ }
+
ret =
drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
- iter->crtc->id()) ||
+ crtc->id()) ||
drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
iter->bo.fb_id) ||
drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
@@ -182,6 +215,23 @@
return ret;
}
+int DrmDisplayCompositor::ApplyDpms(DrmDisplayComposition *display_comp) {
+ DrmConnector *conn = drm_->GetConnectorForDisplay(display_);
+ if (!conn) {
+ ALOGE("Failed to get DrmConnector for display %d", display_);
+ return -ENODEV;
+ }
+
+ const DrmProperty &prop = conn->dpms_property();
+ int ret = drmModeConnectorSetProperty(drm_->fd(), conn->id(), prop.id(),
+ display_comp->dpms_mode());
+ if (ret) {
+ ALOGE("Failed to set DPMS property for connector %d", conn->id());
+ return ret;
+ }
+ return 0;
+}
+
int DrmDisplayCompositor::Composite() {
ATRACE_CALL();
int ret = pthread_mutex_lock(&lock_);
@@ -206,12 +256,24 @@
return ret;
}
- ret = ApplyFrame(composition.get());
- if (ret) {
- ALOGE("Composite failed for display %d", display_);
+ switch (composition->type()) {
+ case DRM_COMPOSITION_TYPE_FRAME:
+ ret = ApplyFrame(composition.get());
+ if (ret) {
+ ALOGE("Composite failed for display %d", display_);
+ return ret;
+ }
+ ++dump_frames_composited_;
+ break;
+ case DRM_COMPOSITION_TYPE_DPMS:
+ ret = ApplyDpms(composition.get());
+ if (ret)
+ ALOGE("Failed to apply dpms for display %d", display_);
return ret;
+ default:
+ ALOGE("Unknown composition type %d", composition->type());
+ return -EINVAL;
}
- ++dump_frames_composited_;
if (active_composition_)
active_composition_->FinishComposition();
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 928ce46..9f50664 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -47,6 +47,7 @@
DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
int ApplyFrame(DrmDisplayComposition *display_comp);
+ int ApplyDpms(DrmDisplayComposition *display_comp);
DrmResources *drm_;
int display_;
@@ -59,6 +60,7 @@
uint64_t frame_no_;
bool initialized_;
+ bool active_;
// mutable since we need to acquire in HaveQueuedComposites
mutable pthread_mutex_t lock_;
diff --git a/drmresources.cpp b/drmresources.cpp
index 2cda217..9be990f 100644
--- a/drmresources.cpp
+++ b/drmresources.cpp
@@ -467,19 +467,22 @@
return -EINVAL;
}
- DrmConnector *c = GetConnectorForDisplay(display);
- if (!c) {
- ALOGE("Failed to get DrmConnector for display %d", display);
- return -ENODEV;
+ DrmComposition *comp = (DrmComposition *)compositor_.CreateComposition(NULL);
+ if (!comp) {
+ ALOGE("Failed to create composition for dpms on %d", display);
+ return -ENOMEM;
}
-
- const DrmProperty &prop = c->dpms_property();
- int ret = drmModeConnectorSetProperty(fd_, c->id(), prop.id(), mode);
+ int ret = comp->AddDpmsMode(display, mode);
if (ret) {
- ALOGE("Failed to set DPMS property for connector %d", c->id());
+ ALOGE("Failed to add dpms %ld to composition on %d %d", mode, display, ret);
+ delete comp;
return ret;
}
-
+ ret = compositor_.QueueComposition((Composition *)comp);
+ if (ret) {
+ ALOGE("Failed to queue dpms composition on %d %d", display, ret);
+ return ret;
+ }
return 0;
}
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index 02c13af..b4fb340 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -407,9 +407,10 @@
}
ret = ctx->drm.compositor()->QueueComposition(composition);
+ composition = NULL;
if (ret) {
ALOGE("Failed to queue the composition");
- hwc_set_cleanup(num_displays, display_contents, composition);
+ hwc_set_cleanup(num_displays, display_contents, NULL);
return ret;
}
hwc_set_cleanup(num_displays, display_contents, NULL);