Merge "drm_hwcomposer: ground work for squashing" into mnc-dr-dev
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 4b293ee..dadb053 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -75,14 +75,13 @@
DrmCompositionDisplayLayersMap &map = maps[display_index];
int display = map.display;
- ret = composition_map_[display]->SetLayers(
- map.layers.data(), map.layers.size(), &primary_planes_,
- &overlay_planes_);
+ ret = composition_map_[display]->SetLayers(map.layers.data(),
+ map.layers.size());
if (ret)
return ret;
}
- return DisableUnusedPlanes();
+ return 0;
}
int DrmComposition::SetDpmsMode(int display, uint32_t dpms_mode) {
@@ -98,6 +97,23 @@
return std::move(composition_map_[display]);
}
+int DrmComposition::Plan(std::map<int, DrmDisplayCompositor> &compositor_map) {
+ int ret = 0;
+ for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
+ iter != drm_->end_connectors(); ++iter) {
+ int display = (*iter)->display();
+ DrmDisplayComposition *comp = GetDisplayComposition(display);
+ ret = comp->Plan(compositor_map[display].squash_state(), &primary_planes_,
+ &overlay_planes_);
+ if (ret) {
+ ALOGE("Failed to plan composition for dislay %d", display);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int DrmComposition::DisableUnusedPlanes() {
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
diff --git a/drmcomposition.h b/drmcomposition.h
index ad7a5df..ed176f1 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -30,6 +30,8 @@
namespace android {
+class DrmDisplayCompositor;
+
struct DrmCompositionDisplayLayersMap {
int display;
std::vector<DrmHwcLayer> layers;
@@ -51,6 +53,8 @@
std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
DrmDisplayComposition *GetDisplayComposition(int display);
+
+ int Plan(std::map<int, DrmDisplayCompositor> &compositor_map);
int DisableUnusedPlanes();
private:
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
index b486d7b..6b3c294 100644
--- a/drmcompositor.cpp
+++ b/drmcompositor.cpp
@@ -64,11 +64,15 @@
int DrmCompositor::QueueComposition(
std::unique_ptr<DrmComposition> composition) {
- int ret = composition->DisableUnusedPlanes();
- if (ret) {
- ALOGE("Failed to disable unused planes %d", ret);
+ int ret;
+
+ ret = composition->Plan(compositor_map_);
+ if (ret)
return ret;
- }
+
+ ret = composition->DisableUnusedPlanes();
+ if (ret)
+ return ret;
for (DrmResources::ConnectorIter iter = drm_->begin_connectors();
iter != drm_->end_connectors(); ++iter) {
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index d47b5dc..b374634 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -23,6 +23,9 @@
#include <stdlib.h>
+#include <algorithm>
+#include <unordered_set>
+
#include <cutils/log.h>
#include <sw_sync.h>
#include <sync/sync.h>
@@ -30,38 +33,15 @@
namespace android {
-DrmCompositionLayer::DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l)
- : crtc(crtc),
- sf_handle(l.sf_handle),
- buffer(std::move(l.buffer)),
- handle(std::move(l.handle)),
- transform(l.transform),
- blending(l.blending),
- alpha(l.alpha),
- source_crop(l.source_crop),
- display_frame(l.display_frame),
- source_damage(l.source_damage),
- acquire_fence(std::move(l.acquire_fence)) {
-}
-
-DrmDisplayComposition::DrmDisplayComposition()
- : drm_(NULL),
- importer_(NULL),
- type_(DRM_COMPOSITION_TYPE_EMPTY),
- timeline_fd_(-1),
- timeline_(0),
- timeline_current_(0),
- timeline_pre_comp_done_(0),
- pre_composition_layer_index_(-1),
- dpms_mode_(DRM_MODE_DPMS_ON),
- frame_no_(0) {
-}
+const size_t DrmCompositionPlane::kSourceNone;
+const size_t DrmCompositionPlane::kSourcePreComp;
+const size_t DrmCompositionPlane::kSourceSquash;
+const size_t DrmCompositionPlane::kSourceLayerMax;
DrmDisplayComposition::~DrmDisplayComposition() {
if (timeline_fd_ >= 0) {
- FinishComposition();
+ SignalCompositionDone();
close(timeline_fd_);
- timeline_fd_ = -1;
}
}
@@ -81,14 +61,77 @@
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::CreateNextTimelineFence() {
+ ++timeline_;
+ return sw_sync_fence_create(timeline_fd_, "hwc drm display composition fence",
+ timeline_);
+}
+
+int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
+ int timeline_increase = point - timeline_current_;
+ if (timeline_increase <= 0)
+ return 0;
+
+ int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
+ if (ret)
+ ALOGE("Failed to increment sync timeline %d", ret);
+ else
+ timeline_current_ = point;
+
+ return ret;
+}
+
+int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers) {
+ int ret = 0;
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
+ return -EINVAL;
+
+ for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
+ layers_.emplace_back(std::move(layers[layer_index]));
+ }
+
+ type_ = DRM_COMPOSITION_TYPE_FRAME;
+ return 0;
+}
+
+int DrmDisplayComposition::SetDpmsMode(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::SetDisplayMode(const DrmMode &display_mode) {
+ if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET))
+ return -EINVAL;
+ display_mode_ = display_mode;
+ dpms_mode_ = DRM_MODE_DPMS_ON;
+ type_ = DRM_COMPOSITION_TYPE_MODESET;
+ return 0;
+}
+
+int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{plane, crtc_, DrmCompositionPlane::kSourceNone});
+ return 0;
+}
+
+static size_t CountUsablePlanes(DrmCrtc *crtc,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ return std::count_if(
+ primary_planes->begin(), primary_planes->end(),
+ [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); }) +
+ std::count_if(
+ overlay_planes->begin(), overlay_planes->end(),
+ [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); });
+}
+
static DrmPlane *TakePlane(DrmCrtc *crtc, std::vector<DrmPlane *> *planes) {
for (auto iter = planes->begin(); iter != planes->end(); ++iter) {
if ((*iter)->GetCrtcSupported(*crtc)) {
@@ -109,182 +152,180 @@
return TakePlane(crtc, overlay_planes);
}
-int DrmDisplayComposition::CreateNextTimelineFence() {
- ++timeline_;
- return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_);
+static std::vector<size_t> SetBitsToVector(uint64_t in, size_t *index_map) {
+ std::vector<size_t> out;
+ size_t msb = sizeof(in) * 8 - 1;
+ uint64_t mask = (uint64_t)1 << msb;
+ for (size_t i = msb; mask != (uint64_t)0; i--, mask >>= 1)
+ if (in & mask)
+ out.push_back(index_map[i]);
+ return out;
}
-int DrmDisplayComposition::IncreaseTimelineToPoint(int point) {
- int timeline_increase = point - timeline_current_;
- if (timeline_increase <= 0)
- return 0;
+static void SeperateLayers(DrmHwcLayer *layers, size_t *used_layers,
+ size_t num_used_layers,
+ DrmHwcRect<int> *exclude_rects,
+ size_t num_exclude_rects,
+ std::vector<DrmCompositionRegion> ®ions) {
+ if (num_used_layers > 64) {
+ ALOGE("Failed to separate layers because there are more than 64");
+ return;
+ }
- int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase);
- if (ret)
- ALOGE("Failed to increment sync timeline %d", ret);
- else
- timeline_current_ = point;
+ if (num_used_layers + num_exclude_rects > 64) {
+ ALOGW(
+ "Exclusion rectangles are being truncated to make the rectangle count "
+ "fit into 64");
+ num_exclude_rects = 64 - num_used_layers;
+ }
- return ret;
+ // We inject all the exclude rects into the rects list. Any resulting rect
+ // that includes ANY of the first num_exclude_rects is rejected.
+ std::vector<DrmHwcRect<int>> layer_rects(num_used_layers + num_exclude_rects);
+ std::copy(exclude_rects, exclude_rects + num_exclude_rects,
+ layer_rects.begin());
+ std::transform(
+ used_layers, used_layers + num_used_layers,
+ layer_rects.begin() + num_exclude_rects,
+ [=](size_t layer_index) { return layers[layer_index].display_frame; });
+
+ std::vector<seperate_rects::RectSet<uint64_t, int>> seperate_regions;
+ seperate_rects::seperate_rects_64(layer_rects, &seperate_regions);
+ uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1;
+
+ for (seperate_rects::RectSet<uint64_t, int> ®ion : seperate_regions) {
+ if (region.id_set.getBits() & exclude_mask)
+ continue;
+ regions.emplace_back(DrmCompositionRegion{
+ region.rect,
+ SetBitsToVector(region.id_set.getBits() >> num_exclude_rects,
+ used_layers)});
+ }
}
-int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
- std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes) {
- int ret = 0;
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
- return -EINVAL;
+int DrmDisplayComposition::Plan(SquashState *squash,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ size_t planes_can_use =
+ CountUsablePlanes(crtc_, primary_planes, overlay_planes);
+ if (planes_can_use == 0) {
+ ALOGE("Display %d has no usable planes", crtc_->display());
+ return -ENODEV;
+ }
- for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
- DrmHwcLayer *layer = &layers[layer_index];
+ std::vector<int> layer_squash_area(layers_.size());
+ if (squash != NULL && planes_can_use >= 3) {
+ std::vector<bool> changed_regions;
+ squash->GenerateHistory(layers_.data(), changed_regions);
- layers_.emplace_back(crtc_, std::move(*layer));
- DrmCompositionLayer *c_layer = &layers_.back();
+ std::vector<bool> stable_regions;
+ squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions);
- if (pre_composition_layer_index_ == -1) {
- c_layer->plane = TakePlane(crtc_, primary_planes, overlay_planes);
- if (c_layer->plane == NULL) {
- if (layers_.size() <= 1) {
- ALOGE("Failed to match any planes to the crtc of this display");
- ret = -ENODEV;
- goto fail;
+ squash->RecordHistory(layers_.data(), changed_regions);
+
+ squash->RecordSquashed(stable_regions);
+
+ for (size_t region_index = 0; region_index < stable_regions.size();
+ region_index++) {
+ const SquashState::Region ®ion = squash->regions()[region_index];
+ if (stable_regions[region_index]) {
+ squash_regions_.emplace_back();
+ DrmCompositionRegion &squash_region = squash_regions_.back();
+ squash_region.frame = region.rect;
+ for (size_t layer_index = 0; layer_index < SquashState::kMaxLayers;
+ layer_index++) {
+ if (region.layer_refs[layer_index]) {
+ squash_region.source_layers.push_back(layer_index);
+ layer_squash_area[layer_index] += squash_region.frame.area();
+ }
}
-
- layers_.emplace_back();
- // c_layer's address might have changed when we resized the vector
- c_layer = &layers_[layers_.size() - 2];
- DrmCompositionLayer &pre_comp_layer = layers_.back();
- pre_comp_layer.crtc = crtc_;
-
- pre_composition_layer_index_ = layers_.size() - 1;
-
- // This is all to fix up the previous layer, which has now become part
- // of the set of pre-composition layers because we are stealing its
- // plane.
- DrmCompositionLayer &last_c_layer = layers_[layers_.size() - 3];
- std::swap(pre_comp_layer.plane, last_c_layer.plane);
- OutputFd &last_release_fence = layers[layer_index - 1].release_fence;
- last_release_fence.Set(CreateNextTimelineFence());
- ret = last_release_fence.get();
- if (ret < 0) {
- ALOGE("Could not create release fence %d", ret);
- goto fail;
- }
- }
- }
-
- if (c_layer->plane == NULL) {
- // Layers to be pre composited all get the earliest release fences as they
- // will get released soonest.
- layer->release_fence.Set(CreateNextTimelineFence());
- ret = layer->release_fence.get();
- if (ret < 0) {
- ALOGE("Could not create release fence %d", ret);
- goto fail;
}
}
}
+ std::vector<size_t> layers_remaining;
+ for (size_t layer_index = 0; layer_index < layers_.size(); layer_index++) {
+ // Skip layers that were completely squashed
+ if (layer_squash_area[layer_index] >=
+ layers_[layer_index].display_frame.area()) {
+ continue;
+ }
+
+ layers_remaining.push_back(layer_index);
+ }
+
+ size_t layer_to_composite = layers_remaining.size();
+ size_t num_layers_to_pre_composite = 0;
+ if (squash_regions_.size() > 0) {
+ layers_remaining.push_back(DrmCompositionPlane::kSourceSquash);
+ }
+
+ if (layers_remaining.size() > planes_can_use) {
+ layers_remaining.insert(layers_remaining.begin() + layer_to_composite,
+ DrmCompositionPlane::kSourcePreComp);
+ size_t num_layers_to_pre_composite =
+ layer_to_composite - planes_can_use + 1;
+ size_t first_layer_to_pre_composite = planes_can_use - 1;
+ SeperateLayers(layers_.data(),
+ &layers_remaining[first_layer_to_pre_composite],
+ num_layers_to_pre_composite, NULL, 0, pre_comp_regions_);
+ layers_remaining.erase(
+ layers_remaining.begin() + first_layer_to_pre_composite,
+ layers_remaining.begin() + layer_to_composite);
+ }
+
+ for (size_t i : layers_remaining) {
+ composition_planes_.emplace_back(DrmCompositionPlane{
+ TakePlane(crtc_, primary_planes, overlay_planes), crtc_, i});
+ }
+
+ std::unordered_set<DrmHwcLayer *> squash_layers;
+ std::unordered_set<DrmHwcLayer *> pre_comp_layers;
+ std::unordered_set<DrmHwcLayer *> comp_layers;
+
+ for (const DrmCompositionRegion ®ion : squash_regions_) {
+ for (size_t source_layer_index : region.source_layers) {
+ DrmHwcLayer *source_layer = &layers_[source_layer_index];
+ squash_layers.emplace(source_layer);
+ }
+ }
+
+ for (const DrmCompositionRegion ®ion : pre_comp_regions_) {
+ for (size_t source_layer_index : region.source_layers) {
+ DrmHwcLayer *source_layer = &layers_[source_layer_index];
+ pre_comp_layers.emplace(source_layer);
+ squash_layers.erase(source_layer);
+ }
+ }
+
+ for (const DrmCompositionPlane &plane : composition_planes_) {
+ if (plane.source_layer <= DrmCompositionPlane::kSourceLayerMax) {
+ DrmHwcLayer *source_layer = &layers_[plane.source_layer];
+ comp_layers.emplace(source_layer);
+ pre_comp_layers.erase(source_layer);
+ }
+ }
+
+ for (DrmHwcLayer *layer : squash_layers) {
+ int ret = layer->release_fence.Set(CreateNextTimelineFence());
+ if (ret < 0)
+ return ret;
+ }
+ timeline_squash_done_ = timeline_;
+
+ for (DrmHwcLayer *layer : pre_comp_layers) {
+ int ret = layer->release_fence.Set(CreateNextTimelineFence());
+ if (ret < 0)
+ return ret;
+ }
timeline_pre_comp_done_ = timeline_;
- for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
- DrmHwcLayer *layer = &layers[layer_index];
- if (layer->release_fence.get() >= 0)
- continue;
-
- ret = layer->release_fence.Set(CreateNextTimelineFence());
- if (ret < 0) {
- ALOGE("Could not create release fence %d", ret);
- goto fail;
- }
+ for (DrmHwcLayer *layer : comp_layers) {
+ int ret = layer->release_fence.Set(CreateNextTimelineFence());
+ if (ret < 0)
+ return ret;
}
- type_ = DRM_COMPOSITION_TYPE_FRAME;
return 0;
-
-fail:
-
- for (size_t c_layer_index = 0; c_layer_index < layers_.size();
- c_layer_index++) {
- DrmCompositionLayer &c_layer = layers_[c_layer_index];
- if (c_layer.plane != NULL) {
- std::vector<DrmPlane *> *return_to =
- (c_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY) ? primary_planes
- : overlay_planes;
- return_to->insert(return_to->begin() + c_layer_index, c_layer.plane);
- }
- }
-
- layers_.clear();
-
- sw_sync_timeline_inc(timeline_fd_, timeline_ - timeline_current_);
-
- timeline_ = timeline_current_;
- return ret;
-}
-
-int DrmDisplayComposition::SetDpmsMode(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::SetDisplayMode(const DrmMode &display_mode) {
- if (!validate_composition_type(DRM_COMPOSITION_TYPE_MODESET))
- return -EINVAL;
- display_mode_ = display_mode;
- dpms_mode_ = DRM_MODE_DPMS_ON;
- type_ = DRM_COMPOSITION_TYPE_MODESET;
- return 0;
-}
-
-int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) {
- layers_.emplace_back();
- DrmCompositionLayer &c_layer = layers_.back();
- c_layer.crtc = NULL;
- c_layer.plane = plane;
- return 0;
-}
-
-void DrmDisplayComposition::RemoveNoPlaneLayers() {
- layers_.erase(
- std::remove_if(layers_.begin(), layers_.end(),
- [](DrmCompositionLayer &l) { return l.plane == NULL; }),
- layers_.end());
-}
-
-int DrmDisplayComposition::SignalPreCompositionDone() {
- return IncreaseTimelineToPoint(timeline_pre_comp_done_);
-}
-
-int DrmDisplayComposition::FinishComposition() {
- return IncreaseTimelineToPoint(timeline_);
-}
-
-std::vector<DrmCompositionLayer>
- *DrmDisplayComposition::GetCompositionLayers() {
- return &layers_;
-}
-
-int DrmDisplayComposition::pre_composition_layer_index() const {
- return pre_composition_layer_index_;
-}
-
-uint32_t DrmDisplayComposition::dpms_mode() const {
- return dpms_mode_;
-}
-
-uint64_t DrmDisplayComposition::frame_no() const {
- return frame_no_;
-}
-
-const DrmMode &DrmDisplayComposition::display_mode() const {
- return display_mode_;
-}
-
-Importer *DrmDisplayComposition::importer() const {
- return importer_;
}
}
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 57e8521..814ca24 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -31,6 +31,8 @@
namespace android {
+struct SquashState;
+
enum DrmCompositionType {
DRM_COMPOSITION_TYPE_EMPTY,
DRM_COMPOSITION_TYPE_FRAME,
@@ -38,90 +40,114 @@
DRM_COMPOSITION_TYPE_MODESET,
};
-struct DrmCompositionLayer {
- DrmCrtc *crtc = NULL;
- DrmPlane *plane = NULL;
+struct DrmCompositionRegion {
+ DrmHwcRect<int> frame;
+ std::vector<size_t> source_layers;
+};
- buffer_handle_t sf_handle = NULL;
- DrmHwcBuffer buffer;
- DrmHwcNativeHandle handle;
- DrmHwcTransform transform = DrmHwcTransform::kIdentity;
- DrmHwcBlending blending = DrmHwcBlending::kNone;
- uint8_t alpha = 0xff;
- DrmHwcRect<float> source_crop;
- DrmHwcRect<int> display_frame;
- std::vector<DrmHwcRect<int>> source_damage;
-
- UniqueFd acquire_fence;
-
- DrmCompositionLayer() = default;
- DrmCompositionLayer(DrmCrtc *crtc, DrmHwcLayer &&l);
- DrmCompositionLayer(DrmCompositionLayer &&l) = default;
-
- DrmCompositionLayer &operator=(DrmCompositionLayer &&l) = default;
-
- buffer_handle_t get_usable_handle() const {
- return handle.get() != NULL ? handle.get() : sf_handle;
- }
+struct DrmCompositionPlane {
+ const static size_t kSourceNone = SIZE_MAX;
+ const static size_t kSourcePreComp = kSourceNone - 1;
+ const static size_t kSourceSquash = kSourcePreComp - 1;
+ const static size_t kSourceLayerMax = kSourceSquash - 1;
+ DrmPlane *plane;
+ DrmCrtc *crtc;
+ size_t source_layer;
};
class DrmDisplayComposition {
public:
- DrmDisplayComposition();
+ DrmDisplayComposition() = default;
+ DrmDisplayComposition(const DrmDisplayComposition &) = delete;
~DrmDisplayComposition();
int Init(DrmResources *drm, DrmCrtc *crtc, Importer *importer,
uint64_t frame_no);
- DrmCompositionType type() const;
-
- int SetLayers(DrmHwcLayer *layers, size_t num_layers,
- std::vector<DrmPlane *> *primary_planes,
- std::vector<DrmPlane *> *overlay_planes);
+ int SetLayers(DrmHwcLayer *layers, size_t num_layers);
int AddPlaneDisable(DrmPlane *plane);
int SetDpmsMode(uint32_t dpms_mode);
int SetDisplayMode(const DrmMode &display_mode);
- void RemoveNoPlaneLayers();
- int SignalPreCompositionDone();
- int FinishComposition();
-
- std::vector<DrmCompositionLayer> *GetCompositionLayers();
- int pre_composition_layer_index() const;
- uint32_t dpms_mode() const;
- const DrmMode &display_mode() const;
-
- uint64_t frame_no() const;
-
- Importer *importer() const;
-
- private:
- DrmDisplayComposition(const DrmDisplayComposition &) = delete;
-
- bool validate_composition_type(DrmCompositionType desired);
+ int Plan(SquashState *squash, std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes);
int CreateNextTimelineFence();
+ int SignalSquashDone() {
+ return IncreaseTimelineToPoint(timeline_squash_done_);
+ }
+ int SignalPreCompDone() {
+ return IncreaseTimelineToPoint(timeline_pre_comp_done_);
+ }
+ int SignalCompositionDone() {
+ return IncreaseTimelineToPoint(timeline_);
+ }
+
+ std::vector<DrmHwcLayer> &layers() {
+ return layers_;
+ }
+
+ std::vector<DrmCompositionRegion> &squash_regions() {
+ return squash_regions_;
+ }
+
+ std::vector<DrmCompositionRegion> &pre_comp_regions() {
+ return pre_comp_regions_;
+ }
+
+ std::vector<DrmCompositionPlane> &composition_planes() {
+ return composition_planes_;
+ }
+
+ uint64_t frame_no() const {
+ return frame_no_;
+ }
+
+ DrmCompositionType type() const {
+ return type_;
+ }
+
+ uint32_t dpms_mode() const {
+ return dpms_mode_;
+ }
+
+ const DrmMode &display_mode() const {
+ return display_mode_;
+ }
+
+ DrmCrtc *crtc() const {
+ return crtc_;
+ }
+
+ Importer *importer() const {
+ return importer_;
+ }
+
+ private:
+ bool validate_composition_type(DrmCompositionType desired);
+
int IncreaseTimelineToPoint(int point);
- DrmResources *drm_;
- DrmCrtc *crtc_;
- Importer *importer_;
- const gralloc_module_t *gralloc_;
- EGLDisplay egl_display_;
+ DrmResources *drm_ = NULL;
+ DrmCrtc *crtc_ = NULL;
+ Importer *importer_ = NULL;
- DrmCompositionType type_;
-
- int timeline_fd_;
- int timeline_;
- int timeline_current_;
- int timeline_pre_comp_done_;
-
- std::vector<DrmCompositionLayer> layers_;
- int pre_composition_layer_index_;
- uint32_t dpms_mode_;
+ DrmCompositionType type_ = DRM_COMPOSITION_TYPE_EMPTY;
+ uint32_t dpms_mode_ = DRM_MODE_DPMS_ON;
DrmMode display_mode_;
- uint64_t frame_no_;
+ int timeline_fd_ = -1;
+ int timeline_ = 0;
+ int timeline_current_ = 0;
+ int timeline_squash_done_ = 0;
+ int timeline_pre_comp_done_ = 0;
+
+ std::vector<DrmHwcLayer> layers_;
+ std::vector<DrmCompositionRegion> squash_regions_;
+ std::vector<DrmCompositionRegion> pre_comp_regions_;
+ std::vector<DrmCompositionPlane> composition_planes_;
+
+ uint64_t frame_no_ = 0;
};
}
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index 20779dd..9f349c0 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -23,7 +23,6 @@
#include "drmresources.h"
#include "glworker.h"
-#include <algorithm>
#include <pthread.h>
#include <sched.h>
#include <sstream>
@@ -40,6 +39,76 @@
namespace android {
+void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) {
+ generation_number_++;
+ valid_history_ = 0;
+ regions_.clear();
+ last_handles_.clear();
+
+ std::vector<DrmHwcRect<int>> in_rects;
+ for (size_t i = 0; i < num_layers; i++) {
+ DrmHwcLayer *layer = &layers[i];
+ in_rects.emplace_back(layer->display_frame);
+ last_handles_.push_back(layer->sf_handle);
+ }
+
+ std::vector<seperate_rects::RectSet<uint64_t, int>> out_regions;
+ seperate_rects::seperate_rects_64(in_rects, &out_regions);
+
+ for (const seperate_rects::RectSet<uint64_t, int> &out_region : out_regions) {
+ regions_.emplace_back();
+ Region ®ion = regions_.back();
+ region.rect = out_region.rect;
+ region.layer_refs = out_region.id_set.getBits();
+ }
+}
+
+void SquashState::GenerateHistory(DrmHwcLayer *layers,
+ std::vector<bool> &changed_regions) const {
+ std::bitset<kMaxLayers> changed_layers;
+ for (size_t i = 0; i < last_handles_.size(); i++) {
+ DrmHwcLayer *layer = &layers[i];
+ if (last_handles_[i] != layer->sf_handle) {
+ changed_layers.set(i);
+ }
+ }
+
+ changed_regions.resize(regions_.size());
+ for (size_t i = 0; i < regions_.size(); i++) {
+ changed_regions[i] = (regions_[i].layer_refs & changed_layers).any();
+ }
+}
+
+void SquashState::StableRegionsWithMarginalHistory(
+ const std::vector<bool> &changed_regions,
+ std::vector<bool> &stable_regions) const {
+ stable_regions.resize(regions_.size());
+ for (size_t i = 0; i < regions_.size(); i++) {
+ stable_regions[i] = !changed_regions[i] && is_stable(i);
+ }
+}
+
+void SquashState::RecordHistory(DrmHwcLayer *layers,
+ const std::vector<bool> &changed_regions) {
+ for (size_t i = 0; i < last_handles_.size(); i++) {
+ DrmHwcLayer *layer = &layers[i];
+ last_handles_[i] = layer->sf_handle;
+ }
+
+ for (size_t i = 0; i < regions_.size(); i++) {
+ regions_[i].change_history <<= 1;
+ regions_[i].change_history.set(/* LSB */ 0, changed_regions[i]);
+ }
+
+ valid_history_++;
+}
+
+void SquashState::RecordSquashed(const std::vector<bool> &squashed_regions) {
+ for (size_t i = 0; i < regions_.size(); i++) {
+ regions_[i].squashed = squashed_regions[i];
+ }
+}
+
DrmDisplayCompositor::DrmDisplayCompositor()
: drm_(NULL),
display_(-1),
@@ -99,6 +168,11 @@
return 0;
}
+std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
+ const {
+ return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
+}
+
int DrmDisplayCompositor::QueueComposition(
std::unique_ptr<DrmDisplayComposition> composition) {
switch (composition->type()) {
@@ -148,56 +222,71 @@
return 0;
}
-static bool drm_composition_layer_has_plane(
- const DrmCompositionLayer &comp_layer) {
- if (comp_layer.plane != NULL)
- if (comp_layer.plane->type() == DRM_PLANE_TYPE_OVERLAY ||
- comp_layer.plane->type() == DRM_PLANE_TYPE_PRIMARY)
- return true;
- return false;
+std::tuple<uint32_t, uint32_t, int>
+DrmDisplayCompositor::GetActiveModeResolution() {
+ DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
+ if (connector == NULL) {
+ ALOGE("Failed to determine display mode: no connector for display %d",
+ display_);
+ return std::make_tuple(0, 0, -ENODEV);
+ }
+
+ const DrmMode &mode = connector->active_mode();
+ return std::make_tuple(mode.h_display(), mode.v_display(), 0);
}
-static bool drm_composition_layer_has_no_plane(
- const DrmCompositionLayer &comp_layer) {
- return comp_layer.plane == NULL;
+int DrmDisplayCompositor::PrepareFramebuffer(
+ DrmFramebuffer &fb, DrmDisplayComposition *display_comp) {
+ int ret = fb.WaitReleased(-1);
+ if (ret) {
+ ALOGE("Failed to wait for framebuffer release %d", ret);
+ return ret;
+ }
+ uint32_t width, height;
+ std::tie(width, height, ret) = GetActiveModeResolution();
+ if (ret) {
+ ALOGE(
+ "Failed to allocate framebuffer because the display resolution could "
+ "not be determined %d",
+ ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(-1);
+ if (!fb.Allocate(width, height)) {
+ ALOGE("Failed to allocate framebuffer with size %dx%d", width, height);
+ return -ENOMEM;
+ }
+
+ display_comp->layers().emplace_back();
+ DrmHwcLayer &pre_comp_layer = display_comp->layers().back();
+ pre_comp_layer.sf_handle = fb.buffer()->handle;
+ pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, width, height);
+ pre_comp_layer.display_frame = DrmHwcRect<int>(0, 0, width, height);
+ ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
+ display_comp->importer());
+ if (ret) {
+ ALOGE("Failed to import framebuffer for display %d", ret);
+ return ret;
+ }
+
+ return ret;
}
int DrmDisplayCompositor::ApplyPreComposite(
DrmDisplayComposition *display_comp) {
int ret = 0;
- std::vector<DrmCompositionLayer> *layers =
- display_comp->GetCompositionLayers();
- DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
- if (connector == NULL) {
- ALOGE("Failed to determine display mode: no connector for display %d",
- display_);
- return -ENODEV;
- }
-
- const DrmMode &mode = connector->active_mode();
DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
- ret = fb.WaitReleased(fb.kReleaseWaitTimeoutMs);
+ ret = PrepareFramebuffer(fb, display_comp);
if (ret) {
- ALOGE("Failed to wait for framebuffer release %d", ret);
+ ALOGE("Failed to prepare framebuffer for precomposite %d", ret);
return ret;
}
- fb.set_release_fence_fd(-1);
- if (!fb.Allocate(mode.h_display(), mode.v_display())) {
- ALOGE("Failed to allocate framebuffer with size %dx%d", mode.h_display(),
- mode.v_display());
- return -ENOMEM;
- }
- std::vector<DrmCompositionLayer> pre_comp_layers;
- for (auto &comp_layer : *layers) {
- if (comp_layer.plane == NULL) {
- pre_comp_layers.emplace_back(std::move(comp_layer));
- }
- }
-
- ret = pre_compositor_->Composite(pre_comp_layers.data(),
- pre_comp_layers.size(), fb.buffer());
+ std::vector<DrmCompositionRegion> ®ions = display_comp->pre_comp_regions();
+ ret = pre_compositor_->Composite(display_comp->layers().data(),
+ regions.data(), regions.size(), fb.buffer());
pre_compositor_->Finish();
if (ret) {
@@ -205,26 +294,16 @@
return ret;
}
- DrmCompositionLayer &pre_comp_layer =
- layers->at(display_comp->pre_composition_layer_index());
- ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle,
- display_comp->importer());
- if (ret) {
- ALOGE("Failed to import handle of layer %d", ret);
+ ret = display_comp->CreateNextTimelineFence();
+ if (ret <= 0) {
+ ALOGE("Failed to create pre comp framebuffer release fence %d", ret);
return ret;
}
- pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, fb.buffer()->getWidth(),
- fb.buffer()->getHeight());
- pre_comp_layer.display_frame =
- DrmHwcRect<int>(0, 0, fb.buffer()->getWidth(), fb.buffer()->getHeight());
- // TODO(zachr) get a release fence
- // fb.set_release_fence_fd(pre_comp_layer.release_fence.Release());
- framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+ fb.set_release_fence_fd(ret);
+ display_comp->SignalPreCompDone();
- display_comp->RemoveNoPlaneLayers();
- display_comp->SignalPreCompositionDone();
- return ret;
+ return 0;
}
int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
@@ -235,14 +314,14 @@
}
int ret;
- std::vector<DrmCompositionLayer> *layers =
- display_comp->GetCompositionLayers();
- for (DrmCompositionLayer &layer : *layers) {
- DrmPlane *plane = layer.plane;
- ret = drmModePropertySetAdd(pset, plane->id(),
- plane->crtc_property().id(), 0) ||
- drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
- 0);
+ std::vector<DrmCompositionPlane> &comp_planes =
+ display_comp->composition_planes();
+ for (DrmCompositionPlane &comp_plane : comp_planes) {
+ DrmPlane *plane = comp_plane.plane;
+ 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());
drmModePropertySetFree(pset);
@@ -264,10 +343,23 @@
int DrmDisplayCompositor::ApplyFrame(DrmDisplayComposition *display_comp) {
int ret = 0;
- if (display_comp->pre_composition_layer_index() >= 0) {
+ std::vector<DrmHwcLayer> &layers = display_comp->layers();
+ std::vector<DrmCompositionPlane> &comp_planes =
+ display_comp->composition_planes();
+ std::vector<DrmCompositionRegion> &pre_comp_regions =
+ display_comp->pre_comp_regions();
+
+ bool do_pre_comp = pre_comp_regions.size() > 0;
+ DrmFramebuffer *pre_comp_fb;
+ int pre_comp_layer_index = -1;
+
+ if (do_pre_comp) {
ret = ApplyPreComposite(display_comp);
if (ret)
return ret;
+
+ pre_comp_layer_index = layers.size() - 1;
+ framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
}
DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
@@ -329,30 +421,88 @@
}
}
- std::vector<DrmCompositionLayer> *layers =
- display_comp->GetCompositionLayers();
- for (DrmCompositionLayer &layer : *layers) {
- int acquire_fence = layer.acquire_fence.get();
- if (acquire_fence >= 0) {
- for (int i = 0; i < kAcquireWaitTries; ++i) {
- ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
- if (ret)
- ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
- acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
+ for (DrmCompositionPlane &comp_plane : comp_planes) {
+ DrmPlane *plane = comp_plane.plane;
+ DrmCrtc *crtc = comp_plane.crtc;
+
+ int fb_id = -1;
+ DrmHwcRect<int> display_frame;
+ DrmHwcRect<float> source_crop;
+ uint64_t rotation = 0;
+ switch (comp_plane.source_layer) {
+ case DrmCompositionPlane::kSourceNone:
+ break;
+ case DrmCompositionPlane::kSourcePreComp: {
+ if (!do_pre_comp) {
+ ALOGE(
+ "Can not use pre composite framebuffer with no pre composite "
+ "layers");
+ ret = -EINVAL;
+ goto out;
+ }
+ DrmHwcLayer &layer = layers[pre_comp_layer_index];
+ fb_id = layer.buffer->fb_id;
+ display_frame = layer.display_frame;
+ source_crop = layer.source_crop;
}
- if (ret) {
- ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
- drmModePropertySetFree(pset);
- drm_->DestroyPropertyBlob(blob_id);
- return ret;
+ case DrmCompositionPlane::kSourceSquash:
+ break;
+ default: {
+ if (comp_plane.source_layer >= layers.size()) {
+ ALOGE("Source layer index %zu out of bounds %zu",
+ comp_plane.source_layer, layers.size());
+ break;
+ }
+ DrmHwcLayer &layer = layers[comp_plane.source_layer];
+ if (layer.acquire_fence.get() >= 0) {
+ int acquire_fence = layer.acquire_fence.get();
+ for (int i = 0; i < kAcquireWaitTries; ++i) {
+ ret = sync_wait(acquire_fence, kAcquireWaitTimeoutMs);
+ if (ret)
+ ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
+ acquire_fence, i, ret, (i + 1) * kAcquireWaitTimeoutMs);
+ }
+ if (ret) {
+ ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
+ break;
+ }
+ layer.acquire_fence.Close();
+ }
+ if (!layer.buffer) {
+ ALOGE("Expected a valid framebuffer for pset");
+ break;
+ }
+ fb_id = layer.buffer->fb_id;
+ display_frame = layer.display_frame;
+ source_crop = layer.source_crop;
+ switch (layer.transform) {
+ case DrmHwcTransform::kFlipH:
+ rotation = 1 << DRM_REFLECT_X;
+ break;
+ case DrmHwcTransform::kFlipV:
+ rotation = 1 << DRM_REFLECT_Y;
+ break;
+ case DrmHwcTransform::kRotate90:
+ rotation = 1 << DRM_ROTATE_90;
+ break;
+ case DrmHwcTransform::kRotate180:
+ rotation = 1 << DRM_ROTATE_180;
+ break;
+ case DrmHwcTransform::kRotate270:
+ rotation = 1 << DRM_ROTATE_270;
+ break;
+ case DrmHwcTransform::kIdentity:
+ rotation = 0;
+ break;
+ default:
+ ALOGE("Invalid transform value 0x%x given", layer.transform);
+ break;
+ }
}
- layer.acquire_fence.Close();
}
- DrmPlane *plane = layer.plane;
-
- // Disable the plane if there's no crtc
- if (!layer.crtc) {
+ // Disable the plane if there's no framebuffer
+ if (fb_id < 0) {
ret = drmModePropertySetAdd(pset, plane->id(),
plane->crtc_property().id(), 0) ||
drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
@@ -364,40 +514,6 @@
continue;
}
- if (!layer.buffer) {
- ALOGE("Expected a valid framebuffer for pset");
- ret = -EINVAL;
- break;
- }
-
- uint64_t rotation;
- switch (layer.transform) {
- case DrmHwcTransform::kFlipH:
- rotation = 1 << DRM_REFLECT_X;
- break;
- case DrmHwcTransform::kFlipV:
- rotation = 1 << DRM_REFLECT_Y;
- break;
- case DrmHwcTransform::kRotate90:
- rotation = 1 << DRM_ROTATE_90;
- break;
- case DrmHwcTransform::kRotate180:
- rotation = 1 << DRM_ROTATE_180;
- break;
- case DrmHwcTransform::kRotate270:
- rotation = 1 << DRM_ROTATE_270;
- break;
- case DrmHwcTransform::kIdentity:
- rotation = 0;
- break;
- default:
- ALOGE("Invalid transform value 0x%x given", layer.transform);
- ret = -EINVAL;
- break;
- }
- if (ret)
- break;
-
// TODO: Once we have atomic test, this should fall back to GL
if (rotation && plane->rotation_property().id() == 0) {
ALOGE("Rotation is not supported on plane %d", plane->id());
@@ -407,29 +523,27 @@
ret =
drmModePropertySetAdd(pset, plane->id(), plane->crtc_property().id(),
- layer.crtc->id()) ||
+ crtc->id()) ||
drmModePropertySetAdd(pset, plane->id(), plane->fb_property().id(),
- layer.buffer->fb_id) ||
+ fb_id) ||
drmModePropertySetAdd(pset, plane->id(), plane->crtc_x_property().id(),
- layer.display_frame.left) ||
+ display_frame.left) ||
drmModePropertySetAdd(pset, plane->id(), plane->crtc_y_property().id(),
- layer.display_frame.top) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->crtc_w_property().id(),
- layer.display_frame.right - layer.display_frame.left) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->crtc_h_property().id(),
- layer.display_frame.bottom - layer.display_frame.top) ||
+ display_frame.top) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_w_property().id(),
+ display_frame.right - display_frame.left) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->crtc_h_property().id(),
+ display_frame.bottom - display_frame.top) ||
drmModePropertySetAdd(pset, plane->id(), plane->src_x_property().id(),
- (int)(layer.source_crop.left) << 16) ||
+ (int)(source_crop.left) << 16) ||
drmModePropertySetAdd(pset, plane->id(), plane->src_y_property().id(),
- (int)(layer.source_crop.top) << 16) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->src_w_property().id(),
- (int)(layer.source_crop.right - layer.source_crop.left) << 16) ||
- drmModePropertySetAdd(
- pset, plane->id(), plane->src_h_property().id(),
- (int)(layer.source_crop.bottom - layer.source_crop.top) << 16);
+ (int)(source_crop.top) << 16) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->src_w_property().id(),
+ (int)(source_crop.right - source_crop.left)
+ << 16) ||
+ drmModePropertySetAdd(pset, plane->id(), plane->src_h_property().id(),
+ (int)(source_crop.bottom - source_crop.top)
+ << 16);
if (ret) {
ALOGE("Failed to add plane %d to set", plane->id());
break;
@@ -446,6 +560,7 @@
}
}
+out:
if (!ret) {
ret = drmModePropertySetCommit(drm_->fd(), DRM_MODE_ATOMIC_ALLOW_MODESET,
drm_, pset);
@@ -562,7 +677,7 @@
}
if (active_composition_)
- active_composition_->FinishComposition();
+ active_composition_->SignalCompositionDone();
ret = pthread_mutex_lock(&lock_);
if (ret)
@@ -596,78 +711,6 @@
return empty_ret;
}
-struct DrmDumpLayer {
- int plane_id;
- int crtc_id;
- DrmHwcTransform transform;
- DrmHwcRect<float> source_crop;
- DrmHwcRect<int> display_frame;
-
- DrmDumpLayer(DrmCompositionLayer &rhs)
- : plane_id(rhs.plane->id()),
- crtc_id(rhs.crtc ? rhs.crtc->id() : -1),
- transform(rhs.transform),
- source_crop(rhs.source_crop),
- display_frame(rhs.display_frame) {
- }
-};
-
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);
-
- std::vector<DrmCompositionLayer> *input_layers =
- active_composition_->GetCompositionLayers();
- std::vector<DrmDumpLayer> layers;
- if (active_composition_)
- layers.insert(layers.begin(), input_layers->begin(), input_layers->end());
- else
- ret = -EAGAIN;
-
- 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);
- float fps = num_ms ? (num_frames * 1000.0f) / (num_ms) : 0.0f;
-
- *out << "--DrmDisplayCompositor[" << display_
- << "]: num_frames=" << num_frames << " num_ms=" << num_ms
- << " fps=" << fps << "\n";
-
- dump_last_timestamp_ns_ = cur_ts;
-
- *out << "---- DrmDisplayCompositor Layers: num=" << layers.size() << "\n";
- for (std::vector<DrmDumpLayer>::iterator iter = layers.begin();
- iter != layers.end(); ++iter) {
- *out << "------ DrmDisplayCompositor Layer: plane=" << iter->plane_id
- << " ";
-
- if (iter->crtc_id < 0) {
- *out << "disabled\n";
- continue;
- }
-
- *out << "crtc=" << iter->crtc_id
- << " crtc[x/y/w/h]=" << iter->display_frame.left << "/"
- << iter->display_frame.top << "/"
- << iter->display_frame.right - iter->display_frame.left << "/"
- << iter->display_frame.bottom - iter->display_frame.top << " "
- << " src[x/y/w/h]=" << iter->source_crop.left << "/"
- << iter->source_crop.top << "/"
- << iter->source_crop.right - iter->source_crop.left << "/"
- << iter->source_crop.bottom - iter->source_crop.top
- << " transform=" << (uint32_t)iter->transform << "\n";
- }
}
}
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 89d5b67..22e1efc 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -21,10 +21,13 @@
#include "drmcomposition.h"
#include "drmcompositorworker.h"
#include "drmframebuffer.h"
+#include "seperate_rects.h"
#include <pthread.h>
+#include <memory>
#include <queue>
#include <sstream>
+#include <tuple>
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
@@ -35,6 +38,45 @@
class GLWorkerCompositor;
+class SquashState {
+ public:
+ static const unsigned kHistoryLength = 6;
+ static const unsigned kMaxLayers = 64;
+
+ struct Region {
+ DrmHwcRect<int> rect;
+ std::bitset<kMaxLayers> layer_refs;
+ std::bitset<kHistoryLength> change_history;
+ bool squashed = false;
+ };
+
+ bool is_stable(int region_index) const {
+ return valid_history_ >= kHistoryLength &&
+ regions_[region_index].change_history.none();
+ }
+
+ const std::vector<Region> ®ions() const {
+ return regions_;
+ }
+
+ void Init(DrmHwcLayer *layers, size_t num_layers);
+ void GenerateHistory(DrmHwcLayer *layers,
+ std::vector<bool> &changed_regions) const;
+ void StableRegionsWithMarginalHistory(
+ const std::vector<bool> &changed_regions,
+ std::vector<bool> &stable_regions) const;
+ void RecordHistory(DrmHwcLayer *layers,
+ const std::vector<bool> &changed_regions);
+ void RecordSquashed(const std::vector<bool> &squashed_regions);
+
+ private:
+ size_t generation_number_ = 0;
+ unsigned valid_history_ = 0;
+ std::vector<buffer_handle_t> last_handles_;
+
+ std::vector<Region> regions_;
+};
+
class DrmDisplayCompositor {
public:
DrmDisplayCompositor();
@@ -42,12 +84,19 @@
int Init(DrmResources *drm, int display);
+ std::unique_ptr<DrmDisplayComposition> CreateComposition() const;
int QueueComposition(std::unique_ptr<DrmDisplayComposition> composition);
int Composite();
void Dump(std::ostringstream *out) const;
+ std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
+
bool HaveQueuedComposites() const;
+ SquashState *squash_state() {
+ return NULL;
+ }
+
private:
DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
@@ -56,6 +105,8 @@
static const int kAcquireWaitTries = 5;
static const int kAcquireWaitTimeoutMs = 100;
+ int PrepareFramebuffer(DrmFramebuffer &fb,
+ DrmDisplayComposition *display_comp);
int ApplyPreComposite(DrmDisplayComposition *display_comp);
int ApplyFrame(DrmDisplayComposition *display_comp);
int ApplyDpms(DrmDisplayComposition *display_comp);
diff --git a/glworker.cpp b/glworker.cpp
index 162005c..7ea2a34 100644
--- a/glworker.cpp
+++ b/glworker.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include <string>
#include <sstream>
+#include <unordered_set>
#include <sys/resource.h>
@@ -37,8 +38,6 @@
#include "glworker.h"
-#include "seperate_rects.h"
-
// TODO(zachr): use hwc_drm_bo to turn buffer handles into textures
#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX
#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A
@@ -48,9 +47,6 @@
namespace android {
-typedef seperate_rects::Rect<float> FRect;
-typedef seperate_rects::RectSet<uint64_t, float> FRectSet;
-
// clang-format off
// Column-major order:
// float mat[4] = { 1, 2, 3, 4 } ===
@@ -319,128 +315,97 @@
};
float bounds[4];
- unsigned texture_count;
+ unsigned texture_count = 0;
TextureSource textures[MAX_OVERLAPPING_LAYERS];
-
- RenderingCommand() : texture_count(0) {
- }
};
-static void ConstructCommands(DrmCompositionLayer *layers, size_t num_layers,
- std::vector<RenderingCommand> *commands) {
- std::vector<FRect> in_rects;
- std::vector<FRectSet> out_rects;
- int i;
+static void ConstructCommand(const DrmHwcLayer *layers,
+ const DrmCompositionRegion ®ion,
+ RenderingCommand &cmd) {
+ std::copy_n(region.frame.bounds, 4, cmd.bounds);
- for (unsigned rect_index = 0; rect_index < num_layers; rect_index++) {
- DrmCompositionLayer &layer = layers[rect_index];
- in_rects.emplace_back(layer.display_frame);
- }
+ for (size_t texture_index : region.source_layers) {
+ const DrmHwcLayer &layer = layers[texture_index];
- seperate_frects_64(in_rects, &out_rects);
+ DrmHwcRect<float> display_rect(layer.display_frame);
+ float display_size[2] = {display_rect.bounds[2] - display_rect.bounds[0],
+ display_rect.bounds[3] - display_rect.bounds[1]};
- for (unsigned rect_index = 0; rect_index < out_rects.size(); rect_index++) {
- const FRectSet &out_rect = out_rects[rect_index];
- commands->push_back(RenderingCommand());
- RenderingCommand &cmd = commands->back();
+ float tex_width = layer.buffer->width;
+ float tex_height = layer.buffer->height;
+ DrmHwcRect<float> crop_rect(layer.source_crop.left / tex_width,
+ layer.source_crop.top / tex_height,
+ layer.source_crop.right / tex_width,
+ layer.source_crop.bottom / tex_height);
- for (int i = 0; i < 4; i++)
- cmd.bounds[i] = out_rect.rect.bounds[i];
+ float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
+ crop_rect.bounds[3] - crop_rect.bounds[1]};
- uint64_t tex_set = out_rect.id_set.getBits();
- for (unsigned i = num_layers - 1; tex_set != 0x0; i--) {
- if (tex_set & (0x1 << i)) {
- tex_set &= ~(0x1 << i);
+ RenderingCommand::TextureSource &src = cmd.textures[cmd.texture_count];
+ cmd.texture_count++;
+ src.texture_index = texture_index;
- DrmCompositionLayer &layer = layers[i];
+ bool swap_xy, flip_xy[2];
+ switch (layer.transform) {
+ case DrmHwcTransform::kFlipH:
+ swap_xy = false;
+ flip_xy[0] = true;
+ flip_xy[1] = false;
+ break;
+ case DrmHwcTransform::kFlipV:
+ swap_xy = false;
+ flip_xy[0] = false;
+ flip_xy[1] = true;
+ break;
+ case DrmHwcTransform::kRotate90:
+ swap_xy = true;
+ flip_xy[0] = false;
+ flip_xy[1] = true;
+ break;
+ case DrmHwcTransform::kRotate180:
+ swap_xy = false;
+ flip_xy[0] = true;
+ flip_xy[1] = true;
+ break;
+ case DrmHwcTransform::kRotate270:
+ swap_xy = true;
+ flip_xy[0] = true;
+ flip_xy[1] = false;
+ break;
+ default:
+ ALOGE("Unknown transform for layer: defaulting to identity transform");
+ case DrmHwcTransform::kIdentity:
+ swap_xy = false;
+ flip_xy[0] = false;
+ flip_xy[1] = false;
+ break;
+ }
- FRect display_rect(layer.display_frame);
- float display_size[2] = {
- display_rect.bounds[2] - display_rect.bounds[0],
- display_rect.bounds[3] - display_rect.bounds[1]};
+ if (swap_xy)
+ std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix);
+ else
+ std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix);
- float tex_width = layer.buffer->width;
- float tex_height = layer.buffer->height;
- FRect crop_rect(layer.source_crop.left / tex_width,
- layer.source_crop.top / tex_height,
- layer.source_crop.right / tex_width,
- layer.source_crop.bottom / tex_height);
-
- float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0],
- crop_rect.bounds[3] - crop_rect.bounds[1]};
-
- RenderingCommand::TextureSource &src = cmd.textures[cmd.texture_count];
- cmd.texture_count++;
- src.texture_index = i;
-
- bool swap_xy, flip_xy[2];
- switch (layer.transform) {
- case DrmHwcTransform::kFlipH:
- swap_xy = false;
- flip_xy[0] = true;
- flip_xy[1] = false;
- break;
- case DrmHwcTransform::kFlipV:
- swap_xy = false;
- flip_xy[0] = false;
- flip_xy[1] = true;
- break;
- case DrmHwcTransform::kRotate90:
- swap_xy = true;
- flip_xy[0] = false;
- flip_xy[1] = true;
- break;
- case DrmHwcTransform::kRotate180:
- swap_xy = false;
- flip_xy[0] = true;
- flip_xy[1] = true;
- break;
- case DrmHwcTransform::kRotate270:
- swap_xy = true;
- flip_xy[0] = true;
- flip_xy[1] = false;
- break;
- default:
- ALOGE(
- "Unknown transform for layer: defaulting to identity "
- "transform");
- case DrmHwcTransform::kIdentity:
- swap_xy = false;
- flip_xy[0] = false;
- flip_xy[1] = false;
- break;
- }
-
- if (swap_xy)
- std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix);
- else
- std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix);
-
- for (int j = 0; j < 4; j++) {
- int b = j ^ (swap_xy ? 1 : 0);
- float bound_percent = (cmd.bounds[b] - display_rect.bounds[b % 2]) /
- display_size[b % 2];
- if (flip_xy[j % 2]) {
- src.crop_bounds[j] =
- crop_rect.bounds[j % 2 + 2] - bound_percent * crop_size[j % 2];
- } else {
- src.crop_bounds[j] =
- crop_rect.bounds[j % 2] + bound_percent * crop_size[j % 2];
- }
- }
-
- if (layer.blending == DrmHwcBlending::kNone) {
- src.alpha = src.premult = 1.0f;
- // This layer is opaque. There is no point in using layers below this
- // one.
- break;
- }
-
- src.alpha = layer.alpha / 255.0f;
- src.premult =
- (layer.blending == DrmHwcBlending::kPreMult) ? 1.0f : 0.0f;
+ for (int j = 0; j < 4; j++) {
+ int b = j ^ (swap_xy ? 1 : 0);
+ float bound_percent =
+ (cmd.bounds[b] - display_rect.bounds[b % 2]) / display_size[b % 2];
+ if (flip_xy[j % 2]) {
+ src.crop_bounds[j] =
+ crop_rect.bounds[j % 2 + 2] - bound_percent * crop_size[j % 2];
+ } else {
+ src.crop_bounds[j] =
+ crop_rect.bounds[j % 2] + bound_percent * crop_size[j % 2];
}
}
+
+ if (layer.blending == DrmHwcBlending::kNone) {
+ src.alpha = src.premult = 1.0f;
+ // This layer is opaque. There is no point in using layers below this one.
+ break;
+ }
+
+ src.alpha = layer.alpha / 255.0f;
}
}
@@ -599,16 +564,16 @@
ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError());
}
-int GLWorkerCompositor::Composite(DrmCompositionLayer *layers,
- size_t num_layers,
+int GLWorkerCompositor::Composite(DrmHwcLayer *layers,
+ DrmCompositionRegion *regions,
+ size_t num_regions,
const sp<GraphicBuffer> &framebuffer) {
ATRACE_CALL();
int ret = 0;
- size_t i;
std::vector<AutoEGLImageAndGLTexture> layer_textures;
std::vector<RenderingCommand> commands;
- if (num_layers == 0) {
+ if (num_regions == 0) {
return -EALREADY;
}
@@ -621,10 +586,24 @@
return -EINVAL;
}
- for (i = 0; i < num_layers; i++) {
- DrmCompositionLayer *layer = &layers[i];
+ std::unordered_set<size_t> layers_used_indices;
+ for (size_t region_index = 0; region_index < num_regions; region_index++) {
+ DrmCompositionRegion ®ion = regions[region_index];
+ layers_used_indices.insert(region.source_layers.begin(),
+ region.source_layers.end());
+ commands.emplace_back();
+ ConstructCommand(layers, region, commands.back());
+ }
+
+ for (size_t layer_index = 0; layer_index < MAX_OVERLAPPING_LAYERS;
+ layer_index++) {
+ DrmHwcLayer *layer = &layers[layer_index];
layer_textures.emplace_back();
+
+ if (layers_used_indices.count(layer_index) == 0)
+ continue;
+
ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(),
&layer_textures.back());
@@ -640,8 +619,6 @@
if (ret)
return ret;
- ConstructCommands(layers, num_layers, &commands);
-
glViewport(0, 0, frame_width, frame_height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
diff --git a/glworker.h b/glworker.h
index b3163ce..3201739 100644
--- a/glworker.h
+++ b/glworker.h
@@ -33,7 +33,8 @@
namespace android {
-struct DrmCompositionLayer;
+struct DrmHwcLayer;
+struct DrmCompositionRegion;
class GLWorkerCompositor {
public:
@@ -41,8 +42,8 @@
~GLWorkerCompositor();
int Init();
- int Composite(DrmCompositionLayer *layers, size_t num_layers,
- const sp<GraphicBuffer> &framebuffer);
+ int Composite(DrmHwcLayer *layers, DrmCompositionRegion *regions,
+ size_t num_regions, const sp<GraphicBuffer> &framebuffer);
void Finish();
private: