merge in mnc-release history after reset to mnc-dev
diff --git a/Android.mk b/Android.mk
index e20615e..eadfe2b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -44,6 +44,8 @@
drmcompositorworker.cpp \
drmconnector.cpp \
drmcrtc.cpp \
+ drmdisplaycomposition.cpp \
+ drmdisplaycompositor.cpp \
drmencoder.cpp \
drmmode.cpp \
drmplane.cpp \
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 07e08da..7a50601 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -31,22 +31,8 @@
static const bool kUseOverlayPlanes = true;
-DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
- memset(&layer, 0, sizeof(layer));
- layer.acquireFenceFd = -1;
- memset(&bo, 0, sizeof(bo));
-}
-
-DrmCompositionLayer::~DrmCompositionLayer() {
-}
-
-DrmComposition::DrmComposition(DrmResources *drm, Importer *importer,
- uint64_t frame_no)
- : drm_(drm),
- importer_(importer),
- frame_no_(frame_no),
- timeline_fd_(-1),
- timeline_(0) {
+DrmComposition::DrmComposition(DrmResources *drm, Importer *importer)
+ : drm_(drm), importer_(importer) {
for (DrmResources::PlaneIter iter = drm_->begin_planes();
iter != drm_->end_planes(); ++iter) {
if ((*iter)->type() == DRM_PLANE_TYPE_PRIMARY)
@@ -57,25 +43,23 @@
}
DrmComposition::~DrmComposition() {
- for (DrmCompositionLayerMap_t::iterator iter = composition_map_.begin();
- iter != composition_map_.end(); ++iter) {
- importer_->ReleaseBuffer(&iter->second.bo);
-
- if (iter->second.layer.acquireFenceFd >= 0)
- close(iter->second.layer.acquireFenceFd);
- }
-
- if (timeline_fd_ >= 0)
- close(timeline_fd_);
}
int DrmComposition::Init() {
- int ret = sw_sync_timeline_create();
- if (ret < 0) {
- ALOGE("Failed to create sw sync timeline %d", ret);
- return ret;
+ for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+ iter != drm_->end_connectors(); ++iter) {
+ int display = (*iter)->display();
+ composition_map_[display].reset(new DrmDisplayComposition());
+ if (!composition_map_[display]) {
+ ALOGE("Failed to allocate new display composition\n");
+ return -ENOMEM;
+ }
+ int ret = composition_map_[(*iter)->display()]->Init(drm_, importer_);
+ if (ret) {
+ ALOGE("Failed to init display composition for %d", (*iter)->display());
+ return ret;
+ }
}
- timeline_fd_ = ret;
return 0;
}
@@ -83,7 +67,7 @@
unsigned num_needed) const {
DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
if (!crtc) {
- ALOGW("Failed to find crtc for display %d", display);
+ ALOGE("Failed to find crtc for display %d", display);
return 0;
}
@@ -103,65 +87,43 @@
int DrmComposition::AddLayer(int display, hwc_layer_1_t *layer,
hwc_drm_bo *bo) {
- if (layer->transform != 0)
- return -EINVAL;
-
DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
if (!crtc) {
- ALOGE("Could not find crtc for display %d", display);
+ ALOGE("Failed to find crtc for display %d", display);
return -ENODEV;
}
- ++timeline_;
- layer->releaseFenceFd =
- sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
- if (layer->releaseFenceFd < 0) {
- ALOGE("Could not create release fence %d", layer->releaseFenceFd);
- return layer->releaseFenceFd;
- }
-
- DrmCompositionLayer_t c_layer;
- c_layer.layer = *layer;
- c_layer.bo = *bo;
- c_layer.crtc = crtc;
-
- // First try to find a primary plane for the layer, then fallback on overlays
+ // Find a plane for the layer
+ DrmPlane *plane = NULL;
for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
iter != primary_planes_.end(); ++iter) {
if ((*iter)->GetCrtcSupported(*crtc)) {
- c_layer.plane = (*iter);
+ plane = *iter;
primary_planes_.erase(iter);
break;
}
}
for (std::deque<DrmPlane *>::iterator iter = overlay_planes_.begin();
- !c_layer.plane && iter != overlay_planes_.end(); ++iter) {
+ !plane && iter != overlay_planes_.end(); ++iter) {
if ((*iter)->GetCrtcSupported(*crtc)) {
- c_layer.plane = (*iter);
+ plane = *iter;
overlay_planes_.erase(iter);
break;
}
}
- if (!c_layer.plane) {
- close(layer->releaseFenceFd);
- layer->releaseFenceFd = -1;
+ if (!plane) {
+ ALOGE("Failed to find plane for display %d", display);
return -ENOENT;
}
-
- layer->acquireFenceFd = -1; // We own this now
- composition_map_.insert(DrmCompositionLayerPair_t(display, c_layer));
- return 0;
+ return composition_map_[display]->AddLayer(layer, bo, crtc, plane);
}
-int DrmComposition::FinishComposition() {
- int ret = sw_sync_timeline_inc(timeline_fd_, timeline_);
- if (ret)
- ALOGE("Failed to increment sync timeline %d", ret);
-
- return ret;
+int DrmComposition::AddDpmsMode(int display, uint32_t dpms_mode) {
+ return composition_map_[display]->AddDpmsMode(dpms_mode);
}
-DrmCompositionLayerMap_t *DrmComposition::GetCompositionMap() {
- return &composition_map_;
+std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition(
+ int display) {
+ return std::move(composition_map_[display]);
}
}
diff --git a/drmcomposition.h b/drmcomposition.h
index 5c47fbf..e490811 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -19,6 +19,7 @@
#include "compositor.h"
#include "drm_hwcomposer.h"
+#include "drmdisplaycomposition.h"
#include "drmplane.h"
#include "importer.h"
@@ -31,46 +32,35 @@
namespace android {
-typedef struct DrmCompositionLayer {
- DrmCompositionLayer();
- ~DrmCompositionLayer();
-
- hwc_layer_1_t layer;
- hwc_drm_bo_t bo;
- DrmCrtc *crtc;
- DrmPlane *plane;
-} DrmCompositionLayer_t;
-
-typedef std::multimap<int, DrmCompositionLayer> DrmCompositionLayerMap_t;
-typedef std::pair<int, DrmCompositionLayer> DrmCompositionLayerPair_t;
-
class DrmComposition : public Composition {
public:
- DrmComposition(DrmResources *drm, Importer *importer, uint64_t frame_no);
+ DrmComposition(DrmResources *drm, Importer *importer);
~DrmComposition();
virtual int Init();
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 FinishComposition();
-
- DrmCompositionLayerMap_t *GetCompositionMap();
+ std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
private:
+ DrmComposition(const DrmComposition &) = delete;
+
DrmResources *drm_;
Importer *importer_;
- uint64_t frame_no_;
-
- int timeline_fd_;
- int timeline_;
-
std::vector<DrmPlane *> primary_planes_;
std::deque<DrmPlane *> overlay_planes_;
- DrmCompositionLayerMap_t composition_map_;
+
+ /*
+ * This _must_ be read-only after it's passed to QueueComposition. Otherwise
+ * locking is required to maintain consistency across the compositor threads.
+ */
+ std::map<int, std::unique_ptr<DrmDisplayComposition>> composition_map_;
};
+
}
#endif // ANDROID_DRM_COMPOSITION_H_
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index 0c6d445..9ade368 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -14,63 +14,41 @@
* limitations under the License.
*/
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#define LOG_TAG "hwc-drm-compositor"
#include "drmcompositor.h"
-#include "drmcrtc.h"
-#include "drmplane.h"
+#include "drmdisplaycompositor.h"
#include "drmresources.h"
-#include <pthread.h>
#include <sstream>
#include <stdlib.h>
-#include <time.h>
-#include <utils/Trace.h>
#include <cutils/log.h>
-#include <sync/sync.h>
namespace android {
-DrmCompositor::DrmCompositor(DrmResources *drm)
- : drm_(drm),
- worker_(this),
- active_composition_(NULL),
- frame_no_(0),
- initialized_(false),
- dump_frames_composited_(0),
- dump_last_timestamp_ns_(0) {
- struct timespec ts;
- if (clock_gettime(CLOCK_MONOTONIC, &ts))
- return;
- dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+DrmCompositor::DrmCompositor(DrmResources *drm) : drm_(drm) {
}
DrmCompositor::~DrmCompositor() {
- if (initialized_)
- pthread_mutex_destroy(&lock_);
}
int DrmCompositor::Init() {
- int ret = pthread_mutex_init(&lock_, NULL);
- if (ret) {
- ALOGE("Failed to initialize drm compositor lock %d\n", ret);
- return ret;
- }
- ret = worker_.Init();
- if (ret) {
- pthread_mutex_destroy(&lock_);
- ALOGE("Failed to initialize compositor worker %d\n", ret);
- return ret;
+ for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+ iter != drm_->end_connectors(); ++iter) {
+ int display = (*iter)->display();
+ int ret = compositor_map_[display].Init(drm_, display);
+ if (ret) {
+ ALOGE("Failed to initialize display compositor for %d", display);
+ return ret;
+ }
}
- initialized_ = true;
return 0;
}
Composition *DrmCompositor::CreateComposition(Importer *importer) {
- DrmComposition *composition = new DrmComposition(drm_, importer, frame_no_++);
+ DrmComposition *composition = new DrmComposition(drm_, importer);
if (!composition) {
ALOGE("Failed to allocate drm composition");
return NULL;
@@ -85,187 +63,35 @@
}
int DrmCompositor::QueueComposition(Composition *composition) {
- int ret = pthread_mutex_lock(&lock_);
- if (ret) {
- ALOGE("Failed to acquire compositor lock %d", ret);
- return ret;
- }
-
- composite_queue_.push((DrmComposition *)composition);
-
- ret = pthread_mutex_unlock(&lock_);
- if (ret) {
- ALOGE("Failed to release compositor lock %d", ret);
- return ret;
- }
-
- worker_.Signal();
- return 0;
-}
-
-int DrmCompositor::CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
- DrmCompositionLayerMap_t::iterator end) {
- int ret = 0;
- // Wait for all acquire fences to signal
- for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
- hwc_layer_1_t *layer = &iter->second.layer;
-
- if (layer->acquireFenceFd < 0)
- continue;
-
- ret = sync_wait(layer->acquireFenceFd, -1);
- if (ret) {
- ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
- return ret;
- }
- close(layer->acquireFenceFd);
- layer->acquireFenceFd = -1;
- }
-
- drmModePropertySetPtr pset = drmModePropertySetAlloc();
- if (!pset) {
- ALOGE("Failed to allocate property set");
- return -ENOMEM;
- }
-
- for (DrmCompositionLayerMap_t::iterator iter = begin; iter != end; ++iter) {
- DrmCompositionLayer_t *comp = &iter->second;
- hwc_layer_1_t *layer = &comp->layer;
- DrmPlane *plane = comp->plane;
-
- ret =
- drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
- begin->second.crtc->id()) ||
- drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
- comp->bo.fb_id) ||
- drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
- layer->displayFrame.left) ||
- drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
- layer->displayFrame.top) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->crtc_w_property().id(),
- layer->displayFrame.right - layer->displayFrame.left) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->crtc_h_property().id(),
- layer->displayFrame.bottom - layer->displayFrame.top) ||
- drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
- layer->sourceCropf.left) ||
- drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
- layer->sourceCropf.top) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->src_w_property().id(),
- (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->src_h_property().id(),
- (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
- if (ret) {
- ALOGE("Failed to add plane %d to set", plane->id());
- break;
- }
- }
-
- if (!ret) {
- ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
- if (ret)
- ALOGE("Failed to commit pset ret=%d\n", ret);
- }
- if (pset)
- drmModePropertySetFree(pset);
-
- return ret;
-}
-
-int DrmCompositor::Composite() {
- ATRACE_CALL();
- int ret = pthread_mutex_lock(&lock_);
- if (ret) {
- ALOGE("Failed to acquire compositor lock %d", ret);
- return ret;
- }
- if (composite_queue_.empty()) {
- ret = pthread_mutex_unlock(&lock_);
- if (ret)
- ALOGE("Failed to release compositor lock %d", ret);
- return ret;
- }
-
- DrmComposition *composition = composite_queue_.front();
- composite_queue_.pop();
- ++dump_frames_composited_;
-
- ret = pthread_mutex_unlock(&lock_);
- if (ret) {
- ALOGE("Failed to release compositor lock %d", ret);
- return ret;
- }
-
- DrmCompositionLayerMap_t *map = composition->GetCompositionMap();
+ DrmComposition *drm_composition = (DrmComposition *)composition;
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
int display = (*iter)->display();
- std::pair<DrmCompositionLayerMap_t::iterator,
- DrmCompositionLayerMap_t::iterator> layer_iters =
- map->equal_range(display);
-
- if (layer_iters.first != layer_iters.second) {
- ret = CompositeDisplay(layer_iters.first, layer_iters.second);
- if (ret) {
- ALOGE("Composite failed for display %d:", display);
- break;
- }
+ int ret = compositor_map_[display].QueueComposition(
+ drm_composition->TakeDisplayComposition(display));
+ if (ret) {
+ ALOGE("Failed to queue composition for display %d", display);
+ delete composition;
+ return ret;
}
}
- if (active_composition_) {
- active_composition_->FinishComposition();
- delete active_composition_;
- }
- active_composition_ = composition;
- return ret;
+ return 0;
}
-bool DrmCompositor::HaveQueuedComposites() const {
- int ret = pthread_mutex_lock(&lock_);
- if (ret) {
- ALOGE("Failed to acquire compositor lock %d", ret);
- return false;
- }
-
- bool empty_ret = !composite_queue_.empty();
-
- ret = pthread_mutex_unlock(&lock_);
- if (ret) {
- ALOGE("Failed to release compositor lock %d", ret);
- return false;
- }
-
- return empty_ret;
+int DrmCompositor::Composite() {
+ /*
+ * This shouldn't be called, we should be calling Composite() on the display
+ * compositors directly.
+ */
+ ALOGE("Calling base drm compositor Composite() function");
+ return -EINVAL;
}
void DrmCompositor::Dump(std::ostringstream *out) const {
- uint64_t cur_ts;
-
- int ret = pthread_mutex_lock(&lock_);
- if (ret)
- return;
-
- uint64_t num_frames = dump_frames_composited_;
- dump_frames_composited_ = 0;
-
- struct timespec ts;
- ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-
- ret |= pthread_mutex_unlock(&lock_);
- if (ret)
- return;
-
- cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
- uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
- unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
-
- *out << "DrmCompositor: num_frames=" << num_frames << " num_ms=" << num_ms <<
- " fps=" << fps << "\n";
-
- dump_last_timestamp_ns_ = cur_ts;
+ *out << "DrmCompositor stats:\n";
+ for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+ iter != drm_->end_connectors(); ++iter)
+ compositor_map_[(*iter)->display()].Dump(out);
}
}
diff --git a/drmcompositor.h b/drmcompositor.h
index 2d4eb69..5f47034 100644
--- a/drmcompositor.h
+++ b/drmcompositor.h
@@ -18,23 +18,14 @@
#define ANDROID_DRM_COMPOSITOR_H_
#include "compositor.h"
-#include "drm_hwcomposer.h"
-#include "drmcomposition.h"
-#include "drmcompositorworker.h"
-#include "drmplane.h"
+#include "drmdisplaycompositor.h"
#include "importer.h"
-#include <pthread.h>
-#include <queue>
+#include <map>
#include <sstream>
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
namespace android {
-class Drm;
-
class DrmCompositor : public Compositor {
public:
DrmCompositor(DrmResources *drm);
@@ -52,32 +43,13 @@
virtual int Composite();
virtual void Dump(std::ostringstream *out) const;
- bool HaveQueuedComposites() const;
-
private:
- DrmCompositor(const DrmCompositor &);
-
- int CompositeDisplay(DrmCompositionLayerMap_t::iterator begin,
- DrmCompositionLayerMap_t::iterator end);
+ DrmCompositor(const DrmCompositor &) = delete;
DrmResources *drm_;
- DrmCompositorWorker worker_;
-
- std::queue<DrmComposition *> composite_queue_;
- DrmComposition *active_composition_;
-
- uint64_t frame_no_;
-
- bool initialized_;
-
- // mutable since we need to acquire in HaveQueuedComposites
- mutable pthread_mutex_t lock_;
-
- // State tracking progress since our last Dump(). These are mutable since
- // we need to reset them on every Dump() call.
- mutable uint64_t dump_frames_composited_;
- mutable uint64_t dump_last_timestamp_ns_;
+ // mutable for Dump() propagation
+ mutable std::map<int, DrmDisplayCompositor> compositor_map_;
};
}
diff --git a/drmcompositorworker.cpp b/drmcompositorworker.cpp
index 9406194..c8eae5f 100644
--- a/drmcompositorworker.cpp
+++ b/drmcompositorworker.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "hwc-drm-compositor-worker"
-#include "drmcompositor.h"
+#include "drmdisplaycompositor.h"
#include "drmcompositorworker.h"
#include "worker.h"
@@ -27,7 +27,7 @@
namespace android {
-DrmCompositorWorker::DrmCompositorWorker(DrmCompositor *compositor)
+DrmCompositorWorker::DrmCompositorWorker(DrmDisplayCompositor *compositor)
: Worker("drm-compositor", HAL_PRIORITY_URGENT_DISPLAY),
compositor_(compositor) {
}
diff --git a/drmcompositorworker.h b/drmcompositorworker.h
index 8b485bf..9f74fb6 100644
--- a/drmcompositorworker.h
+++ b/drmcompositorworker.h
@@ -21,11 +21,11 @@
namespace android {
-class DrmCompositor;
+class DrmDisplayCompositor;
class DrmCompositorWorker : public Worker {
public:
- DrmCompositorWorker(DrmCompositor *compositor);
+ DrmCompositorWorker(DrmDisplayCompositor *compositor);
~DrmCompositorWorker();
int Init();
@@ -33,7 +33,7 @@
protected:
virtual void Routine();
- DrmCompositor *compositor_;
+ DrmDisplayCompositor *compositor_;
};
}
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
new file mode 100644
index 0000000..2f8d651
--- /dev/null
+++ b/drmdisplaycomposition.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+
+#include <stdlib.h>
+
+#include <cutils/log.h>
+#include <sw_sync.h>
+#include <sync/sync.h>
+#include <xf86drmMode.h>
+
+namespace android {
+
+DrmCompositionLayer::DrmCompositionLayer() : crtc(NULL), plane(NULL) {
+ memset(&layer, 0, sizeof(layer));
+ layer.acquireFenceFd = -1;
+ memset(&bo, 0, sizeof(bo));
+}
+
+DrmCompositionLayer::~DrmCompositionLayer() {
+}
+
+DrmDisplayComposition::DrmDisplayComposition()
+ : 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_)
+ importer_->ReleaseBuffer(&iter->bo);
+
+ if (iter->layer.acquireFenceFd >= 0)
+ close(iter->layer.acquireFenceFd);
+ }
+
+ if (timeline_fd_ >= 0)
+ close(timeline_fd_);
+}
+
+int DrmDisplayComposition::Init(DrmResources *drm, Importer *importer) {
+ drm_ = drm;
+ importer_ = importer;
+
+ int ret = sw_sync_timeline_create();
+ if (ret < 0) {
+ ALOGE("Failed to create sw sync timeline %d", ret);
+ return ret;
+ }
+ timeline_fd_ = ret;
+ 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_);
+ if (layer->releaseFenceFd < 0) {
+ ALOGE("Could not create release fence %d", layer->releaseFenceFd);
+ return layer->releaseFenceFd;
+ }
+
+ DrmCompositionLayer_t c_layer;
+ c_layer.layer = *layer;
+ c_layer.bo = *bo;
+ c_layer.crtc = crtc;
+ c_layer.plane = plane;
+
+ 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::FinishComposition() {
+ int ret = sw_sync_timeline_inc(timeline_fd_, timeline_);
+ if (ret)
+ ALOGE("Failed to increment sync timeline %d", ret);
+
+ return ret;
+}
+
+DrmCompositionLayerVector_t *DrmDisplayComposition::GetCompositionLayers() {
+ return &layers_;
+}
+
+uint32_t DrmDisplayComposition::dpms_mode() const {
+ return dpms_mode_;
+}
+}
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
new file mode 100644
index 0000000..2ae696f
--- /dev/null
+++ b/drmdisplaycomposition.h
@@ -0,0 +1,84 @@
+/*
+ * 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 "drm_hwcomposer.h"
+#include "drmplane.h"
+#include "importer.h"
+
+#include <vector>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+enum DrmCompositionType {
+ DRM_COMPOSITION_TYPE_EMPTY,
+ DRM_COMPOSITION_TYPE_FRAME,
+ DRM_COMPOSITION_TYPE_DPMS,
+};
+
+typedef struct DrmCompositionLayer {
+ DrmCompositionLayer();
+ ~DrmCompositionLayer();
+
+ hwc_layer_1_t layer;
+ hwc_drm_bo_t bo;
+ DrmCrtc *crtc;
+ DrmPlane *plane;
+} DrmCompositionLayer_t;
+typedef std::vector<DrmCompositionLayer_t> DrmCompositionLayerVector_t;
+
+class DrmDisplayComposition {
+ public:
+ DrmDisplayComposition();
+ ~DrmDisplayComposition();
+
+ 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 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_;
+};
+}
+
+#endif // ANDROID_DRM_DISPLAY_COMPOSITION_H_
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
new file mode 100644
index 0000000..80b71f5
--- /dev/null
+++ b/drmdisplaycompositor.cpp
@@ -0,0 +1,314 @@
+/*
+ * 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 "drmcrtc.h"
+#include "drmplane.h"
+#include "drmresources.h"
+
+#include <pthread.h>
+#include <sstream>
+#include <stdlib.h>
+#include <time.h>
+#include <vector>
+
+#include <cutils/log.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+DrmDisplayCompositor::DrmDisplayCompositor()
+ : drm_(NULL),
+ display_(-1),
+ worker_(this),
+ frame_no_(0),
+ initialized_(false),
+ active_(false),
+ dump_frames_composited_(0),
+ dump_last_timestamp_ns_(0) {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ return;
+ dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+}
+
+DrmDisplayCompositor::~DrmDisplayCompositor() {
+ if (!initialized_)
+ return;
+
+ worker_.Exit();
+
+ int ret = pthread_mutex_lock(&lock_);
+ if (ret)
+ ALOGE("Failed to acquire compositor lock %d", ret);
+
+ while (!composite_queue_.empty()) {
+ composite_queue_.front().reset();
+ composite_queue_.pop();
+ }
+ active_composition_.reset();
+
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret)
+ ALOGE("Failed to acquire compositor lock %d", ret);
+
+ pthread_mutex_destroy(&lock_);
+}
+
+int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
+ drm_ = drm;
+ display_ = display;
+
+ int ret = pthread_mutex_init(&lock_, NULL);
+ if (ret) {
+ ALOGE("Failed to initialize drm compositor lock %d\n", ret);
+ return ret;
+ }
+ ret = worker_.Init();
+ if (ret) {
+ pthread_mutex_destroy(&lock_);
+ ALOGE("Failed to initialize compositor worker %d\n", ret);
+ return ret;
+ }
+
+ initialized_ = true;
+ return 0;
+}
+
+int DrmDisplayCompositor::QueueComposition(
+ std::unique_ptr<DrmDisplayComposition> composition) {
+ 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) {
+ ALOGE("Failed to acquire compositor lock %d", ret);
+ return ret;
+ }
+
+ composite_queue_.push(std::move(composition));
+
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret) {
+ ALOGE("Failed to release compositor lock %d", ret);
+ return ret;
+ }
+
+ worker_.Signal();
+ return 0;
+}
+
+int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
+ int ret = 0;
+
+ drmModePropertySetPtr pset = drmModePropertySetAlloc();
+ if (!pset) {
+ ALOGE("Failed to allocate property set");
+ return -ENOMEM;
+ }
+
+ DrmCompositionLayerVector_t *layers = display_comp->GetCompositionLayers();
+ for (DrmCompositionLayerVector_t::iterator iter = layers->begin();
+ iter != layers->end(); ++iter) {
+ hwc_layer_1_t *layer = &iter->layer;
+
+ if (layer->acquireFenceFd >= 0) {
+ ret = sync_wait(layer->acquireFenceFd, -1);
+ if (ret) {
+ ALOGE("Failed to wait for acquire %d/%d", layer->acquireFenceFd, ret);
+ drmModePropertySetFree(pset);
+ return ret;
+ }
+ close(layer->acquireFenceFd);
+ layer->acquireFenceFd = -1;
+ }
+
+ DrmPlane *plane = iter->plane;
+ ret =
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
+ iter->crtc->id()) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
+ iter->bo.fb_id) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
+ layer->displayFrame.left) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
+ layer->displayFrame.top) ||
+ drmModePropertySetAdd(
+ pset, plane->id(), plane->crtc_w_property().id(),
+ layer->displayFrame.right - layer->displayFrame.left) ||
+ drmModePropertySetAdd(
+ pset, plane->id(), plane->crtc_h_property().id(),
+ layer->displayFrame.bottom - layer->displayFrame.top) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
+ layer->sourceCropf.left) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
+ layer->sourceCropf.top) ||
+ drmModePropertySetAdd(
+ pset, plane->id(), plane->src_w_property().id(),
+ (int)(layer->sourceCropf.right - layer->sourceCropf.left) << 16) ||
+ drmModePropertySetAdd(
+ pset, plane->id(), plane->src_h_property().id(),
+ (int)(layer->sourceCropf.bottom - layer->sourceCropf.top) << 16);
+ if (ret) {
+ ALOGE("Failed to add plane %d to set", plane->id());
+ break;
+ }
+ }
+
+ if (!ret) {
+ ret = drmModePropertySetCommit(drm_->fd(), 0, drm_, pset);
+ if (ret)
+ ALOGE("Failed to commit pset ret=%d\n", ret);
+ }
+ if (pset)
+ drmModePropertySetFree(pset);
+
+ 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_);
+ if (ret) {
+ ALOGE("Failed to acquire compositor lock %d", ret);
+ return ret;
+ }
+ if (composite_queue_.empty()) {
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret)
+ ALOGE("Failed to release compositor lock %d", ret);
+ return ret;
+ }
+
+ std::unique_ptr<DrmDisplayComposition> composition(
+ std::move(composite_queue_.front()));
+ composite_queue_.pop();
+
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret) {
+ ALOGE("Failed to release compositor lock %d", ret);
+ return ret;
+ }
+
+ 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;
+ }
+
+ if (active_composition_)
+ active_composition_->FinishComposition();
+
+ active_composition_.swap(composition);
+ return ret;
+}
+
+bool DrmDisplayCompositor::HaveQueuedComposites() const {
+ int ret = pthread_mutex_lock(&lock_);
+ if (ret) {
+ ALOGE("Failed to acquire compositor lock %d", ret);
+ return false;
+ }
+
+ bool empty_ret = !composite_queue_.empty();
+
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret) {
+ ALOGE("Failed to release compositor lock %d", ret);
+ return false;
+ }
+
+ return empty_ret;
+}
+
+void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
+ uint64_t cur_ts;
+
+ int ret = pthread_mutex_lock(&lock_);
+ if (ret)
+ return;
+
+ uint64_t num_frames = dump_frames_composited_;
+ dump_frames_composited_ = 0;
+
+ struct timespec ts;
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ ret |= pthread_mutex_unlock(&lock_);
+ if (ret)
+ return;
+
+ cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+ uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
+ unsigned fps = num_ms ? (num_frames * 1000) / (num_ms) : 0;
+
+ *out << "--DrmDisplayCompositor[" << display_
+ << "]: num_frames=" << num_frames << " num_ms=" << num_ms
+ << " fps=" << fps << "\n";
+
+ dump_last_timestamp_ns_ = cur_ts;
+}
+}
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
new file mode 100644
index 0000000..9f50664
--- /dev/null
+++ b/drmdisplaycompositor.h
@@ -0,0 +1,75 @@
+/*
+ * 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_COMPOSITOR_H_
+#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
+
+#include "drm_hwcomposer.h"
+#include "drmcomposition.h"
+#include "drmcompositorworker.h"
+
+#include <pthread.h>
+#include <queue>
+#include <sstream>
+
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+
+namespace android {
+
+class DrmDisplayCompositor {
+ public:
+ DrmDisplayCompositor();
+ ~DrmDisplayCompositor();
+
+ int Init(DrmResources *drm, int display);
+
+ int QueueComposition(std::unique_ptr<DrmDisplayComposition> composition);
+ int Composite();
+ void Dump(std::ostringstream *out) const;
+
+ bool HaveQueuedComposites() const;
+
+ private:
+ DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
+
+ int ApplyFrame(DrmDisplayComposition *display_comp);
+ int ApplyDpms(DrmDisplayComposition *display_comp);
+
+ DrmResources *drm_;
+ int display_;
+
+ DrmCompositorWorker worker_;
+
+ std::queue<std::unique_ptr<DrmDisplayComposition>> composite_queue_;
+ std::unique_ptr<DrmDisplayComposition> active_composition_;
+
+ uint64_t frame_no_;
+
+ bool initialized_;
+ bool active_;
+
+ // mutable since we need to acquire in HaveQueuedComposites
+ mutable pthread_mutex_t lock_;
+
+ // State tracking progress since our last Dump(). These are mutable since
+ // we need to reset them on every Dump() call.
+ mutable uint64_t dump_frames_composited_;
+ mutable uint64_t dump_last_timestamp_ns_;
+};
+}
+
+#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
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);