drm_hwcomposer: implement squashing
Change-Id: Ifd4feaa0de303ddfd519d4415ab31d2a72f26022
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
index 09bdba7..e7b02b6 100644
--- a/drmcomposition.cpp
+++ b/drmcomposition.cpp
@@ -80,8 +80,8 @@
continue;
}
- ret = composition_map_[display]->SetLayers(map.layers.data(),
- map.layers.size());
+ ret = composition_map_[display]->SetLayers(
+ map.layers.data(), map.layers.size(), map.geometry_changed);
if (ret)
return ret;
}
diff --git a/drmcomposition.h b/drmcomposition.h
index ed176f1..80a7eea 100644
--- a/drmcomposition.h
+++ b/drmcomposition.h
@@ -34,6 +34,7 @@
struct DrmCompositionDisplayLayersMap {
int display;
+ bool geometry_changed = true;
std::vector<DrmHwcLayer> layers;
DrmCompositionDisplayLayersMap() = default;
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 49bacad..34d879e 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -85,11 +85,13 @@
return ret;
}
-int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers) {
- int ret = 0;
+int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers,
+ bool geometry_changed) {
if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME))
return -EINVAL;
+ geometry_changed_ = geometry_changed;
+
for (size_t layer_index = 0; layer_index < num_layers; layer_index++) {
layers_.emplace_back(std::move(layers[layer_index]));
}
@@ -162,7 +164,7 @@
return out;
}
-static void SeperateLayers(DrmHwcLayer *layers, size_t *used_layers,
+static void SeparateLayers(DrmHwcLayer *layers, size_t *used_layers,
size_t num_used_layers,
DrmHwcRect<int> *exclude_rects,
size_t num_exclude_rects,
@@ -203,82 +205,7 @@
}
}
-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;
- }
-
- 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);
-
- std::vector<bool> stable_regions;
- squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions);
-
- 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();
- }
- }
- }
- }
- }
-
- 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});
- }
-
+int DrmDisplayComposition::CreateAndAssignReleaseFences() {
std::unordered_set<DrmHwcLayer *> squash_layers;
std::unordered_set<DrmHwcLayer *> pre_comp_layers;
std::unordered_set<DrmHwcLayer *> comp_layers;
@@ -329,6 +256,122 @@
return 0;
}
+int DrmDisplayComposition::Plan(SquashState *squash,
+ std::vector<DrmPlane *> *primary_planes,
+ std::vector<DrmPlane *> *overlay_planes) {
+ if (type_ != DRM_COMPOSITION_TYPE_FRAME)
+ return 0;
+
+ 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;
+ }
+
+ bool use_squash_framebuffer = false;
+ // Used to determine which layers were entirely squashed
+ std::vector<int> layer_squash_area(layers_.size(), 0);
+ // Used to avoid rerendering regions that were squashed
+ std::vector<DrmHwcRect<int>> exclude_rects;
+ if (squash != NULL && planes_can_use >= 3) {
+ if (geometry_changed_) {
+ squash->Init(layers_.data(), layers_.size());
+ } else {
+ std::vector<bool> changed_regions;
+ squash->GenerateHistory(layers_.data(), layers_.size(), changed_regions);
+
+ std::vector<bool> stable_regions;
+ squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions);
+
+ // Only if SOME region is stable
+ use_squash_framebuffer =
+ std::find(stable_regions.begin(), stable_regions.end(), true) !=
+ stable_regions.end();
+
+ squash->RecordHistory(layers_.data(), layers_.size(), changed_regions);
+
+ // Changes in which regions are squashed triggers a rerender via
+ // squash_regions.
+ bool render_squash = squash->RecordAndCompareSquashed(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])
+ continue;
+
+ exclude_rects.emplace_back(region.rect);
+
+ if (render_squash) {
+ squash_regions_.emplace_back();
+ squash_regions_.back().frame = region.rect;
+ }
+
+ int frame_area = region.rect.area();
+ // Source layers are sorted front to back i.e. top layer has lowest
+ // index.
+ for (size_t layer_index = layers_.size();
+ layer_index-- > 0; // Yes, I double checked this
+ /* See condition */) {
+ if (!region.layer_refs[layer_index])
+ continue;
+ layer_squash_area[layer_index] += frame_area;
+ if (render_squash)
+ squash_regions_.back().source_layers.push_back(layer_index);
+ }
+ }
+ }
+ }
+
+ 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);
+ }
+
+ if (use_squash_framebuffer)
+ planes_can_use--;
+
+ if (layers_remaining.size() > planes_can_use)
+ planes_can_use--;
+
+ size_t last_composition_layer = 0;
+ for (last_composition_layer = 0;
+ last_composition_layer < layers_remaining.size() && planes_can_use > 0;
+ last_composition_layer++, planes_can_use--) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
+ crtc_, layers_remaining[last_composition_layer]});
+ }
+
+ layers_remaining.erase(layers_remaining.begin(),
+ layers_remaining.begin() + last_composition_layer);
+
+ if (layers_remaining.size() > 0) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
+ crtc_, DrmCompositionPlane::kSourcePreComp});
+
+ SeparateLayers(layers_.data(), layers_remaining.data(),
+ layers_remaining.size(), exclude_rects.data(),
+ exclude_rects.size(), pre_comp_regions_);
+ }
+
+ if (use_squash_framebuffer) {
+ composition_planes_.emplace_back(
+ DrmCompositionPlane{TakePlane(crtc_, primary_planes, overlay_planes),
+ crtc_, DrmCompositionPlane::kSourceSquash});
+ }
+
+ return CreateAndAssignReleaseFences();
+}
+
static const char *DrmCompositionTypeToString(DrmCompositionType type) {
switch (type) {
case DRM_COMPOSITION_TYPE_EMPTY:
diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h
index 2ac93e0..69324fd 100644
--- a/drmdisplaycomposition.h
+++ b/drmdisplaycomposition.h
@@ -65,7 +65,7 @@
int Init(DrmResources *drm, DrmCrtc *crtc, Importer *importer,
uint64_t frame_no);
- int SetLayers(DrmHwcLayer *layers, size_t num_layers);
+ int SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed);
int AddPlaneDisable(DrmPlane *plane);
int SetDpmsMode(uint32_t dpms_mode);
int SetDisplayMode(const DrmMode &display_mode);
@@ -131,6 +131,8 @@
int IncreaseTimelineToPoint(int point);
+ int CreateAndAssignReleaseFences();
+
DrmResources *drm_ = NULL;
DrmCrtc *crtc_ = NULL;
Importer *importer_ = NULL;
@@ -145,6 +147,7 @@
int timeline_squash_done_ = 0;
int timeline_pre_comp_done_ = 0;
+ bool geometry_changed_;
std::vector<DrmHwcLayer> layers_;
std::vector<DrmCompositionRegion> squash_regions_;
std::vector<DrmCompositionRegion> pre_comp_regions_;
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index f238f43..c3042f5 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -63,8 +63,14 @@
}
}
-void SquashState::GenerateHistory(DrmHwcLayer *layers,
+void SquashState::GenerateHistory(DrmHwcLayer *layers, size_t num_layers,
std::vector<bool> &changed_regions) const {
+ changed_regions.resize(regions_.size());
+ if (num_layers != last_handles_.size()) {
+ ALOGE("SquashState::GenerateHistory expected %zu layers but got %zu layers",
+ last_handles_.size(), num_layers);
+ return;
+ }
std::bitset<kMaxLayers> changed_layers;
for (size_t i = 0; i < last_handles_.size(); i++) {
DrmHwcLayer *layer = &layers[i];
@@ -73,7 +79,6 @@
}
}
- changed_regions.resize(regions_.size());
for (size_t i = 0; i < regions_.size(); i++) {
changed_regions[i] = (regions_[i].layer_refs & changed_layers).any();
}
@@ -88,8 +93,19 @@
}
}
-void SquashState::RecordHistory(DrmHwcLayer *layers,
+void SquashState::RecordHistory(DrmHwcLayer *layers, size_t num_layers,
const std::vector<bool> &changed_regions) {
+ if (num_layers != last_handles_.size()) {
+ ALOGE("SquashState::RecordHistory expected %zu layers but got %zu layers",
+ last_handles_.size(), num_layers);
+ return;
+ }
+ if (changed_regions.size() != regions_.size()) {
+ ALOGE("SquashState::RecordHistory expected %zu regions but got %zu regions",
+ regions_.size(), changed_regions.size());
+ return;
+ }
+
for (size_t i = 0; i < last_handles_.size(); i++) {
DrmHwcLayer *layer = &layers[i];
last_handles_[i] = layer->sf_handle;
@@ -103,10 +119,23 @@
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];
+bool SquashState::RecordAndCompareSquashed(
+ const std::vector<bool> &squashed_regions) {
+ if (squashed_regions.size() != regions_.size()) {
+ ALOGE(
+ "SquashState::RecordAndCompareSquashed expected %zu regions but got "
+ "%zu regions",
+ regions_.size(), squashed_regions.size());
+ return false;
}
+ bool changed = false;
+ for (size_t i = 0; i < regions_.size(); i++) {
+ if (regions_[i].squashed != squashed_regions[i]) {
+ regions_[i].squashed = squashed_regions[i];
+ changed = true;
+ }
+ }
+ return changed;
}
void SquashState::Dump(std::ostringstream *out) const {
@@ -137,6 +166,14 @@
}
}
+static bool UsesSquash(const std::vector<DrmCompositionPlane> &comp_planes) {
+ return std::any_of(comp_planes.begin(), comp_planes.end(),
+ [](const DrmCompositionPlane &plane) {
+ return plane.source_layer ==
+ DrmCompositionPlane::kSourceSquash;
+ });
+}
+
DrmDisplayCompositor::DrmDisplayCompositor()
: drm_(NULL),
display_(-1),
@@ -145,6 +182,7 @@
active_(false),
needs_modeset_(false),
framebuffer_index_(0),
+ squash_framebuffer_index_(0),
dump_frames_composited_(0),
dump_last_timestamp_ns_(0) {
struct timespec ts;
@@ -301,6 +339,38 @@
return ret;
}
+int DrmDisplayCompositor::ApplySquash(DrmDisplayComposition *display_comp) {
+ int ret = 0;
+
+ DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_];
+ ret = PrepareFramebuffer(fb, display_comp);
+ if (ret) {
+ ALOGE("Failed to prepare framebuffer for squash %d", ret);
+ return ret;
+ }
+
+ std::vector<DrmCompositionRegion> ®ions = display_comp->squash_regions();
+ ret = pre_compositor_->Composite(display_comp->layers().data(),
+ regions.data(), regions.size(), fb.buffer());
+ pre_compositor_->Finish();
+
+ if (ret) {
+ ALOGE("Failed to squash layers");
+ return ret;
+ }
+
+ ret = display_comp->CreateNextTimelineFence();
+ if (ret <= 0) {
+ ALOGE("Failed to create squash framebuffer release fence %d", ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(ret);
+ display_comp->SignalSquashDone();
+
+ return 0;
+}
+
int DrmDisplayCompositor::ApplyPreComposite(
DrmDisplayComposition *display_comp) {
int ret = 0;
@@ -308,7 +378,7 @@
DrmFramebuffer &fb = framebuffers_[framebuffer_index_];
ret = PrepareFramebuffer(fb, display_comp);
if (ret) {
- ALOGE("Failed to prepare framebuffer for precomposite %d", ret);
+ ALOGE("Failed to prepare framebuffer for pre-composite %d", ret);
return ret;
}
@@ -318,13 +388,13 @@
pre_compositor_->Finish();
if (ret) {
- ALOGE("Failed to composite layers");
+ ALOGE("Failed to pre-composite layers");
return ret;
}
ret = display_comp->CreateNextTimelineFence();
if (ret <= 0) {
- ALOGE("Failed to create pre comp framebuffer release fence %d", ret);
+ ALOGE("Failed to create pre-composite framebuffer release fence %d", ret);
return ret;
}
@@ -374,13 +444,50 @@
std::vector<DrmHwcLayer> &layers = display_comp->layers();
std::vector<DrmCompositionPlane> &comp_planes =
display_comp->composition_planes();
+ std::vector<DrmCompositionRegion> &squash_regions =
+ display_comp->squash_regions();
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;
+ int squash_layer_index = -1;
+ if (squash_regions.size() > 0) {
+ squash_framebuffer_index_ = (squash_framebuffer_index_ + 1) % 2;
+ ret = ApplySquash(display_comp);
+ if (ret)
+ return ret;
+ squash_layer_index = layers.size() - 1;
+ } else {
+ if (UsesSquash(comp_planes)) {
+ DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_];
+ layers.emplace_back();
+ squash_layer_index = layers.size() - 1;
+ DrmHwcLayer &squash_layer = layers.back();
+ ret = squash_layer.buffer.ImportBuffer(fb.buffer()->handle,
+ display_comp->importer());
+ if (ret) {
+ ALOGE("Failed to import old squashed framebuffer %d", ret);
+ return ret;
+ }
+ squash_layer.sf_handle = fb.buffer()->handle;
+ squash_layer.source_crop = DrmHwcRect<float>(
+ 0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
+ squash_layer.display_frame = DrmHwcRect<int>(
+ 0, 0, squash_layer.buffer->width, squash_layer.buffer->height);
+ ret = display_comp->CreateNextTimelineFence();
+
+ if (ret <= 0) {
+ ALOGE("Failed to create squash framebuffer release fence %d", ret);
+ return ret;
+ }
+
+ fb.set_release_fence_fd(ret);
+ ret = 0;
+ }
+ }
+
+ bool do_pre_comp = pre_comp_regions.size() > 0;
+ int pre_comp_layer_index = -1;
if (do_pre_comp) {
ret = ApplyPreComposite(display_comp);
if (ret)
@@ -461,11 +568,18 @@
switch (comp_plane.source_layer) {
case DrmCompositionPlane::kSourceNone:
break;
+ case DrmCompositionPlane::kSourceSquash: {
+ DrmHwcLayer &layer = layers[squash_layer_index];
+ fb_id = layer.buffer->fb_id;
+ display_frame = layer.display_frame;
+ source_crop = layer.source_crop;
+ break;
+ }
case DrmCompositionPlane::kSourcePreComp: {
if (!do_pre_comp) {
ALOGE(
"Can not use pre composite framebuffer with no pre composite "
- "layers");
+ "regions");
ret = -EINVAL;
goto out;
}
@@ -475,8 +589,6 @@
source_crop = layer.source_crop;
break;
}
- case DrmCompositionPlane::kSourceSquash:
- break;
default: {
if (comp_plane.source_layer >= layers.size()) {
ALOGE("Source layer index %zu out of bounds %zu",
@@ -789,6 +901,8 @@
if (active_composition_)
active_composition_->Dump(out);
+ squash_state_.Dump(out);
+
pthread_mutex_unlock(&lock_);
}
}
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index cacaa66..e9b529b 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -40,7 +40,7 @@
class SquashState {
public:
- static const unsigned kHistoryLength = 6;
+ static const unsigned kHistoryLength = 6; // TODO: make this number not magic
static const unsigned kMaxLayers = 64;
struct Region {
@@ -60,14 +60,14 @@
}
void Init(DrmHwcLayer *layers, size_t num_layers);
- void GenerateHistory(DrmHwcLayer *layers,
+ void GenerateHistory(DrmHwcLayer *layers, size_t num_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,
+ void RecordHistory(DrmHwcLayer *layers, size_t num_layers,
const std::vector<bool> &changed_regions);
- void RecordSquashed(const std::vector<bool> &squashed_regions);
+ bool RecordAndCompareSquashed(const std::vector<bool> &squashed_regions);
void Dump(std::ostringstream *out) const;
@@ -96,7 +96,7 @@
bool HaveQueuedComposites() const;
SquashState *squash_state() {
- return NULL;
+ return &squash_state_;
}
private:
@@ -109,6 +109,7 @@
int PrepareFramebuffer(DrmFramebuffer &fb,
DrmDisplayComposition *display_comp);
+ int ApplySquash(DrmDisplayComposition *display_comp);
int ApplyPreComposite(DrmDisplayComposition *display_comp);
int ApplyFrame(DrmDisplayComposition *display_comp);
int ApplyDpms(DrmDisplayComposition *display_comp);
@@ -132,6 +133,10 @@
DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS];
std::unique_ptr<GLWorkerCompositor> pre_compositor_;
+ SquashState squash_state_;
+ int squash_framebuffer_index_;
+ DrmFramebuffer squash_framebuffers_[2];
+
// mutable since we need to acquire in HaveQueuedComposites
mutable pthread_mutex_t lock_;
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index f1d6fbb..7fec244 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -482,6 +482,8 @@
layers_map.emplace_back();
DrmCompositionDisplayLayersMap &map = layers_map.back();
map.display = i;
+ map.geometry_changed =
+ (dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED;
std::vector<size_t> &indices_to_composite = layers_indices[i];
for (size_t j : indices_to_composite) {
hwc_layer_1_t *sf_layer = &dc->hwLayers[j];