drm_hwcomposer: Handle HWC_SKIP_LAYER properly
Instead of ignoring skip layers, set all layers between the first
and last skip layer as HWC_FRAMEBUFFER in prepare(). In set(), substitute
the HWC_FRAMEBUFFER_TARGET in place of those layers.
Bug: 25366235
Test: Tested with gmail modal and rotation
Change-Id: Ife0fd569caf505263b00e5d0e8217a339aa09031
Signed-off-by: Sean Paul <seanpaul@chromium.org>
diff --git a/hwcomposer.cpp b/hwcomposer.cpp
index 4b01e79..f19407a 100644
--- a/hwcomposer.cpp
+++ b/hwcomposer.cpp
@@ -326,6 +326,10 @@
buff[buff_len - 1] = '\0';
}
+static bool hwc_skip_layer(const std::pair<int, int> &indices, int i) {
+ return indices.first >= 0 && i >= indices.first && i <= indices.second;
+}
+
static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays,
hwc_display_contents_1_t **display_contents) {
struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common;
@@ -345,11 +349,26 @@
}
}
+ // Since we can't composite HWC_SKIP_LAYERs by ourselves, we'll let SF
+ // handle all layers in between the first and last skip layers. So find the
+ // outer indices and mark everything in between as HWC_FRAMEBUFFER
+ std::pair<int, int> skip_layer_indices(-1, -1);
int num_layers = display_contents[i]->numHwLayers;
- for (int j = 0; j < num_layers; j++) {
+ for (int j = 0; !use_framebuffer_target && j < num_layers; ++j) {
hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
- if (!use_framebuffer_target) {
+ if (!(layer->flags & HWC_SKIP_LAYER))
+ continue;
+
+ if (skip_layer_indices.first == -1)
+ skip_layer_indices.first = j;
+ skip_layer_indices.second = j;
+ }
+
+ for (int j = 0; j < num_layers; ++j) {
+ hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j];
+
+ if (!use_framebuffer_target && !hwc_skip_layer(skip_layer_indices, j)) {
if (layer->compositionType == HWC_FRAMEBUFFER)
layer->compositionType = HWC_OVERLAY;
} else {
@@ -425,17 +444,37 @@
int framebuffer_target_index = -1;
for (size_t j = 0; j < num_dc_layers; ++j) {
hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
+ if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) {
+ framebuffer_target_index = j;
+ break;
+ }
+ }
+
+ for (size_t j = 0; j < num_dc_layers; ++j) {
+ hwc_layer_1_t *sf_layer = &dc->hwLayers[j];
display_contents.layers.emplace_back();
DrmHwcLayer &layer = display_contents.layers.back();
- if (sf_layer->flags & HWC_SKIP_LAYER)
+ // In prepare() we marked all layers FRAMEBUFFER between SKIP_LAYER's.
+ // This means we should insert the FB_TARGET layer in the composition
+ // stack at the location of the first skip layer, and ignore the rest.
+ if (sf_layer->flags & HWC_SKIP_LAYER) {
+ if (framebuffer_target_index < 0)
+ continue;
+ int idx = framebuffer_target_index;
+ framebuffer_target_index = -1;
+ hwc_layer_1_t *fbt_layer = &dc->hwLayers[idx];
+ if (!fbt_layer->handle || (fbt_layer->flags & HWC_SKIP_LAYER)) {
+ ALOGE("Invalid HWC_FRAMEBUFFER_TARGET with HWC_SKIP_LAYER present");
+ continue;
+ }
+ indices_to_composite.push_back(idx);
continue;
+ }
if (sf_layer->compositionType == HWC_OVERLAY)
indices_to_composite.push_back(j);
- if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET)
- framebuffer_target_index = j;
layer.acquire_fence.Set(sf_layer->acquireFenceFd);
sf_layer->acquireFenceFd = -1;
@@ -450,6 +489,9 @@
layer.release_fence = OutputFd(&sf_layer->releaseFenceFd);
}
+ // This is a catch-all in case we get a frame without any overlay layers, or
+ // skip layers, but with a value fb_target layer. This _shouldn't_ happen,
+ // but it's not ruled out by the hwc specification
if (indices_to_composite.empty() && framebuffer_target_index >= 0) {
hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index];
if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) {