summaryrefslogtreecommitdiffstats
path: root/hwc/rgz_2d.c
diff options
context:
space:
mode:
Diffstat (limited to 'hwc/rgz_2d.c')
-rw-r--r--hwc/rgz_2d.c359
1 files changed, 277 insertions, 82 deletions
diff --git a/hwc/rgz_2d.c b/hwc/rgz_2d.c
index 94407c1..49d557c 100644
--- a/hwc/rgz_2d.c
+++ b/hwc/rgz_2d.c
@@ -86,8 +86,7 @@ static int rgz_handle_to_stride(IMG_native_handle_t *h);
#define IS_BVCMD(params) (params->op == RGZ_OUT_BVCMD_REGION || params->op == RGZ_OUT_BVCMD_PAINT)
-/* Number of framebuffers to track */
-#define RGZ_NUM_FB 2
+#define RECT_INTERSECTS(a, b) (((a).bottom > (b).top) && ((a).top < (b).bottom) && ((a).right > (b).left) && ((a).left < (b).right))
/* Buffer indexes used to distinguish background and layers with the clear fb hint */
#define RGZ_BACKGROUND_BUFFIDX -2
@@ -886,32 +885,7 @@ static int rgz_bunique(int *a, int len)
return unique;
}
-static int rgz_hwc_layer_sortbyy(rgz_layer_t *ra, int rsz, int *out, int *width, int screen_height)
-{
- int outsz = 0;
- int i;
- *width = 0;
- for (i = 0; i < rsz; i++) {
- hwc_layer_t *layer = &ra[i].hwc_layer;
- /* Maintain regions inside display boundaries */
- int top = layer->displayFrame.top;
- int bottom = layer->displayFrame.bottom;
- out[outsz++] = max(0, top);
- out[outsz++] = min(bottom, screen_height);
- int right = layer->displayFrame.right;
- *width = *width > right ? *width : right;
- }
- rgz_bsort(out, outsz);
- return outsz;
-}
-
-static int rgz_hwc_intersects(blit_rect_t *a, hwc_rect_t *b)
-{
- return ((a->bottom > b->top) && (a->top < b->bottom) &&
- (a->right > b->left) && (a->left < b->right));
-}
-
-static void rgz_gen_blitregions(blit_hregion_t *hregion, int screen_width)
+static void rgz_gen_blitregions(rgz_t *rgz, blit_hregion_t *hregion, int screen_width)
{
/*
* 1. Get the offsets (left/right positions) of each layer within the
@@ -924,13 +898,19 @@ static void rgz_gen_blitregions(blit_hregion_t *hregion, int screen_width)
int offsets[RGZ_SUBREGIONMAX];
int noffsets=0;
int l, r;
+
+ /*
+ * Add damaged region, then all layers. We are guaranteed to not go outside
+ * of offsets array boundaries at this point.
+ */
+ offsets[noffsets++] = rgz->damaged_area.left;
+ offsets[noffsets++] = rgz->damaged_area.right;
+
for (l = 0; l < hregion->nlayers; l++) {
hwc_layer_t *layer = &hregion->rgz_layers[l]->hwc_layer;
/* Make sure the subregion is not outside the boundaries of the screen */
- int left = layer->displayFrame.left;
- int right = layer->displayFrame.right;
- offsets[noffsets++] = max(0, left);
- offsets[noffsets++] = min(right, screen_width);
+ offsets[noffsets++] = max(0, layer->displayFrame.left);
+ offsets[noffsets++] = min(layer->displayFrame.right, screen_width);
}
rgz_bsort(offsets, noffsets);
noffsets = rgz_bunique(offsets, noffsets);
@@ -947,7 +927,7 @@ static void rgz_gen_blitregions(blit_hregion_t *hregion, int screen_width)
subregion.left, subregion.right);
for (l = 0; l < hregion->nlayers; l++) {
hwc_layer_t *layer = &hregion->rgz_layers[l]->hwc_layer;
- if (rgz_hwc_intersects(&subregion, &layer->displayFrame)) {
+ if (RECT_INTERSECTS(subregion, layer->displayFrame)) {
hregion->blitrects[l][r] = subregion;
@@ -1017,31 +997,210 @@ static void rgz_delete_region_data(rgz_t *rgz){
rgz->state &= ~RGZ_REGION_DATA;
}
-static void rgz_handle_dirty_region(rgz_t *rgz, int reset_counters)
+static rgz_fb_state_t* get_prev_fb_state(rgz_t *rgz)
+{
+ return &rgz->fb_states[rgz->fb_state_idx];
+}
+
+static rgz_fb_state_t* get_next_fb_state(rgz_t *rgz)
+{
+ rgz->fb_state_idx = (rgz->fb_state_idx + 1) % RGZ_NUM_FB;
+ return &rgz->fb_states[rgz->fb_state_idx];
+}
+
+static void rgz_add_to_damaged_area(rgz_in_params_t *params, rgz_layer_t *rgz_layer,
+ blit_rect_t *damaged_area)
+{
+ struct bvsurfgeom *screen_geom = params->data.hwc.dstgeom;
+ hwc_layer_t *layer = &rgz_layer->hwc_layer;
+
+ blit_rect_t screen_rect;
+ screen_rect.left = screen_rect.top = 0;
+ screen_rect.right = screen_geom->width;
+ screen_rect.bottom = screen_geom->height;
+
+ /* Ignore the layer rectangle if it doesn't intersect the screen */
+ if (!RECT_INTERSECTS(screen_rect, layer->displayFrame))
+ return;
+
+ /* Clip the layer rectangle to the screen geometry */
+ blit_rect_t layer_rect;
+ rgz_get_displayframe_rect(layer, &layer_rect);
+ layer_rect.left = max(0, layer_rect.left);
+ layer_rect.top = max(0, layer_rect.top);
+ layer_rect.right = min(screen_rect.right, layer_rect.right);
+ layer_rect.bottom = min(screen_rect.bottom, layer_rect.bottom);
+
+ /* Then add the rectangle to the damage area */
+ if (empty_rect(damaged_area)) {
+ /* Adding for the first time */
+ damaged_area->left = layer_rect.left;
+ damaged_area->top = layer_rect.top;
+ damaged_area->right = layer_rect.right;
+ damaged_area->bottom = layer_rect.bottom;
+ } else {
+ /* Grow current damaged area */
+ damaged_area->left = min(damaged_area->left, layer_rect.left);
+ damaged_area->top = min(damaged_area->top, layer_rect.top);
+ damaged_area->right = max(damaged_area->right, layer_rect.right);
+ damaged_area->bottom = max(damaged_area->bottom, layer_rect.bottom);
+ }
+}
+
+/* Search a layer with the specified identity in the passed array */
+static rgz_layer_t* rgz_find_layer(rgz_layer_t *rgz_layers, int rgz_layerno,
+ uint32_t layer_identity)
{
int i;
+ for (i = 0; i < rgz_layerno; i++) {
+ rgz_layer_t *rgz_layer = &rgz_layers[i];
+ /* Ignore background layer, it has no identity */
+ if (rgz_layer->buffidx == RGZ_BACKGROUND_BUFFIDX)
+ continue;
+ if (rgz_layer->identity == layer_identity)
+ return rgz_layer;
+ }
+ return NULL;
+}
+
+/* Determines if two layers with the same identity have changed its own window content */
+static int rgz_has_layer_content_changed(rgz_layer_t *cur_rgz_layer, rgz_layer_t *prev_rgz_layer)
+{
+ hwc_layer_t *cur_hwc_layer = &cur_rgz_layer->hwc_layer;
+ hwc_layer_t *prev_hwc_layer = &prev_rgz_layer->hwc_layer;
+
+ /* The background has no identity and never changes */
+ if (cur_rgz_layer->buffidx == RGZ_BACKGROUND_BUFFIDX &&
+ prev_rgz_layer->buffidx == RGZ_BACKGROUND_BUFFIDX)
+ return 0;
+
+ if (cur_rgz_layer->identity != prev_rgz_layer->identity) {
+ OUTE("%s: Invalid input, layer identities differ (current=%d, prev=%d)",
+ __func__, cur_rgz_layer->identity, prev_rgz_layer->identity);
+ return 1;
+ }
+
+ /* If the layer has the clear fb hint we don't care about the content */
+ if (cur_rgz_layer->buffidx == RGZ_CLEARHINT_BUFFIDX &&
+ prev_rgz_layer->buffidx == RGZ_CLEARHINT_BUFFIDX)
+ return 0;
+
+ /* Check if the layer content has changed */
+ if (cur_hwc_layer->handle != prev_hwc_layer->handle ||
+ cur_hwc_layer->transform != prev_hwc_layer->transform ||
+ cur_hwc_layer->sourceCrop.top != prev_hwc_layer->sourceCrop.top ||
+ cur_hwc_layer->sourceCrop.left != prev_hwc_layer->sourceCrop.left ||
+ cur_hwc_layer->sourceCrop.bottom != prev_hwc_layer->sourceCrop.bottom ||
+ cur_hwc_layer->sourceCrop.right != prev_hwc_layer->sourceCrop.right)
+ return 1;
+
+ return 0;
+}
+
+/* Determines if two layers with the same identity have changed their screen position */
+static int rgz_has_layer_frame_moved(rgz_layer_t *cur_rgz_layer, rgz_layer_t *target_rgz_layer)
+{
+ hwc_layer_t *cur_hwc_layer = &cur_rgz_layer->hwc_layer;
+ hwc_layer_t *target_hwc_layer = &target_rgz_layer->hwc_layer;
+
+ if (cur_rgz_layer->identity != target_rgz_layer->identity) {
+ OUTE("%s: Invalid input, layer identities differ (current=%d, target=%d)",
+ __func__, cur_rgz_layer->identity, target_rgz_layer->identity);
+ return 1;
+ }
+
+ if (cur_hwc_layer->displayFrame.top != target_hwc_layer->displayFrame.top ||
+ cur_hwc_layer->displayFrame.left != target_hwc_layer->displayFrame.left ||
+ cur_hwc_layer->displayFrame.bottom != target_hwc_layer->displayFrame.bottom ||
+ cur_hwc_layer->displayFrame.right != target_hwc_layer->displayFrame.right)
+ return 1;
+
+ return 0;
+}
+
+static void rgz_handle_dirty_region(rgz_t *rgz, rgz_in_params_t *params,
+ rgz_fb_state_t* prev_fb_state, rgz_fb_state_t* target_fb_state)
+{
+ /* Reset damaged area */
+ bzero(&rgz->damaged_area, sizeof(rgz->damaged_area));
+
+ int i;
rgz_fb_state_t *cur_fb_state = &rgz->cur_fb_state;
+
for (i = 0; i < cur_fb_state->rgz_layerno; i++) {
- rgz_layer_t *rgz_layer = &cur_fb_state->rgz_layers[i];
- void *new_handle;
+ rgz_layer_t *cur_rgz_layer = &cur_fb_state->rgz_layers[i];
+ rgz_layer_t *prev_rgz_layer = NULL;
+ int layer_changed = 0;
- /*
- * We don't care about the handle for background and layers with the
- * clear fb hint, but we want to maintain a layer state for dirty
- * region handling.
- */
- if (rgz_layer->buffidx == RGZ_BACKGROUND_BUFFIDX ||
- rgz_layer->buffidx == RGZ_CLEARHINT_BUFFIDX)
- new_handle = (void*)0x1;
- else
- new_handle = (void*)rgz_layer->hwc_layer.handle;
+ if (i == 0) {
+ /*
+ * Background is always zero, no need to search for it. If the previous state
+ * is empty reset the dirty count for the background layer.
+ */
+ if (prev_fb_state->rgz_layerno)
+ prev_rgz_layer = &prev_fb_state->rgz_layers[0];
+ } else {
+ /* Find out if this layer was present in the previous frame */
+ prev_rgz_layer = rgz_find_layer(prev_fb_state->rgz_layers,
+ prev_fb_state->rgz_layerno, cur_rgz_layer->identity);
+ }
- if (reset_counters || new_handle != rgz_layer->dirty_hndl) {
- rgz_layer->dirty_count = RGZ_NUM_FB;
- rgz_layer->dirty_hndl = new_handle;
+ /* Check if the layer is new or if the content changed from the previous frame */
+ if (prev_rgz_layer && !rgz_has_layer_content_changed(cur_rgz_layer, prev_rgz_layer)) {
+ /* Copy previous dirty count */
+ cur_rgz_layer->dirty_count = prev_rgz_layer->dirty_count;
+ cur_rgz_layer->dirty_count -= cur_rgz_layer->dirty_count ? 1 : 0;
} else
- rgz_layer->dirty_count -= rgz_layer->dirty_count ? 1 : 0;
+ cur_rgz_layer->dirty_count = RGZ_NUM_FB;
+
+ /* If the layer is new, redraw the layer area */
+ if (!prev_rgz_layer) {
+ rgz_add_to_damaged_area(params, cur_rgz_layer, &rgz->damaged_area);
+ continue;
+ }
+
+ /* Nothing more to do with the background layer */
+ if (i == 0)
+ continue;
+
+ /* Find out if the layer is present in the target frame */
+ rgz_layer_t *target_rgz_layer = rgz_find_layer(target_fb_state->rgz_layers,
+ target_fb_state->rgz_layerno, cur_rgz_layer->identity);
+ if (target_rgz_layer) {
+ /* Find out if the window size and position are different from the target frame */
+ if (rgz_has_layer_frame_moved(cur_rgz_layer, target_rgz_layer)) {
+ /*
+ * Redraw both layer areas. This will effectively clear the area where
+ * this layer was in the target frame and force to draw the new layer
+ * location.
+ */
+ rgz_add_to_damaged_area(params, cur_rgz_layer, &rgz->damaged_area);
+ rgz_add_to_damaged_area(params, target_rgz_layer, &rgz->damaged_area);
+ cur_rgz_layer->dirty_count = RGZ_NUM_FB;
+ }
+ } else {
+ /* If the layer is not in the target just draw it's new location */
+ rgz_add_to_damaged_area(params, cur_rgz_layer, &rgz->damaged_area);
+ }
+ }
+
+ /*
+ * Add to damage area layers missing from the target frame to the current frame
+ * ignoring the background
+ */
+ for (i = 1; i < target_fb_state->rgz_layerno; i++) {
+ rgz_layer_t *target_rgz_layer = &target_fb_state->rgz_layers[i];
+
+ rgz_layer_t *cur_rgz_layer = rgz_find_layer(cur_fb_state->rgz_layers,
+ cur_fb_state->rgz_layerno, target_rgz_layer->identity);
+
+ /* Layers present in the target have been handled already in the loop above */
+ if (cur_rgz_layer)
+ continue;
+
+ /* The target layer is not present in the current frame, redraw its area */
+ rgz_add_to_damaged_area(params, target_rgz_layer, &rgz->damaged_area);
}
}
@@ -1051,11 +1210,14 @@ static void rgz_add_background_layer(rgz_fb_state_t *fb_state)
rgz_layer_t *rgz_layer = &fb_state->rgz_layers[0];
rgz_layer->hwc_layer = bg_layer;
rgz_layer->buffidx = RGZ_BACKGROUND_BUFFIDX;
+ /* Set dummy handle to maintain dirty region state */
+ rgz_layer->hwc_layer.handle = (void*) 0x1;
}
static int rgz_in_hwccheck(rgz_in_params_t *p, rgz_t *rgz)
{
hwc_layer_t *layers = p->data.hwc.layers;
+ hwc_layer_extended_t *extlayers = p->data.hwc.extlayers;
int layerno = p->data.hwc.layerno;
rgz->state &= ~RGZ_STATE_INIT;
@@ -1101,6 +1263,7 @@ static int rgz_in_hwccheck(rgz_in_params_t *p, rgz_t *rgz)
possible_blit < RGZ_INPUT_MAXLAYERS) {
rgz_layer_t *rgz_layer = &cur_fb_state->rgz_layers[possible_blit+1];
rgz_layer->hwc_layer = layers[l];
+ rgz_layer->identity = extlayers[l].identity;
rgz_layer->buffidx = memidx++;
possible_blit++;
}
@@ -1115,8 +1278,11 @@ static int rgz_in_hwccheck(rgz_in_params_t *p, rgz_t *rgz)
* fb hint is present, mark this layer to identify it.
*/
rgz_layer_t *rgz_layer = &cur_fb_state->rgz_layers[possible_blit+1];
- rgz_layer->buffidx = RGZ_CLEARHINT_BUFFIDX;
rgz_layer->hwc_layer = layers[l];
+ rgz_layer->identity = extlayers[l].identity;
+ rgz_layer->buffidx = RGZ_CLEARHINT_BUFFIDX;
+ /* Set dummy handle to maintain dirty region state */
+ rgz_layer->hwc_layer.handle = (void*) 0x1;
possible_blit++;
}
}
@@ -1126,25 +1292,26 @@ static int rgz_in_hwccheck(rgz_in_params_t *p, rgz_t *rgz)
return -1;
}
- int blit_layers = possible_blit + 1; /* Account for background layer */
- int reset_dirty_counters = cur_fb_state->rgz_layerno != blit_layers ? 1 : 0;
- /*
- * The layers we are going to blit differ in number from the previous frame,
- * we can't trust anymore the region data, calculate it again
- */
- if (reset_dirty_counters)
- rgz_delete_region_data(rgz);
-
rgz->state |= RGZ_STATE_INIT;
- cur_fb_state->rgz_layerno = blit_layers;
+ cur_fb_state->rgz_layerno = possible_blit + 1; /* Account for background layer */
+
+ /* Get the target and previous frame geometries */
+ rgz_fb_state_t* prev_fb_state = get_prev_fb_state(rgz);
+ rgz_fb_state_t* target_fb_state = get_next_fb_state(rgz);
- rgz_handle_dirty_region(rgz, reset_dirty_counters);
+ /* Modifiy dirty counters and create the damaged region */
+ rgz_handle_dirty_region(rgz, p, prev_fb_state, target_fb_state);
+
+ /* Copy the current geometry to use it in the next frame */
+ memcpy(target_fb_state->rgz_layers, cur_fb_state->rgz_layers, sizeof(rgz_layer_t) * cur_fb_state->rgz_layerno);
+ target_fb_state->rgz_layerno = cur_fb_state->rgz_layerno;
return RGZ_ALL;
}
static int rgz_in_hwc(rgz_in_params_t *p, rgz_t *rgz)
{
+ int i, j;
int yentries[RGZ_SUBREGIONMAX];
int dispw; /* widest layer */
int screen_width = p->data.hwc.dstgeom->width;
@@ -1156,15 +1323,37 @@ static int rgz_in_hwc(rgz_in_params_t *p, rgz_t *rgz)
return -1;
}
- /* If there is already region data avoid parsing it again */
- if (rgz->state & RGZ_REGION_DATA) {
- return 0;
+ /*
+ * Figure out if there is enough space to store the top-bottom coordinates
+ * of each layer including the damaged area
+ */
+ if (((cur_fb_state->rgz_layerno + 1) * 2) > RGZ_SUBREGIONMAX) {
+ OUTE("%s: Not enough space to store top-bottom coordinates of each layer (max %d, needed %d*2)",
+ __func__, RGZ_SUBREGIONMAX, cur_fb_state->rgz_layerno + 1);
+ return -1;
}
- /* Find the horizontal regions */
- int ylen = rgz_hwc_layer_sortbyy(cur_fb_state->rgz_layers, cur_fb_state->rgz_layerno,
- yentries, &dispw, screen_height);
+ /* Delete the previous region data */
+ rgz_delete_region_data(rgz);
+
+ /*
+ * Find the horizontal regions, add damaged area first which is already
+ * inside display boundaries
+ */
+ int ylen = 0;
+ yentries[ylen++] = rgz->damaged_area.top;
+ yentries[ylen++] = rgz->damaged_area.bottom;
+ dispw = rgz->damaged_area.right;
+ /* Add the top and bottom coordinates of each layer */
+ for (i = 0; i < cur_fb_state->rgz_layerno; i++) {
+ hwc_layer_t *layer = &cur_fb_state->rgz_layers[i].hwc_layer;
+ /* Maintain regions inside display boundaries */
+ yentries[ylen++] = max(0, layer->displayFrame.top);
+ yentries[ylen++] = min(layer->displayFrame.bottom, screen_height);
+ dispw = dispw > layer->displayFrame.right ? dispw : layer->displayFrame.right;
+ }
+ rgz_bsort(yentries, ylen);
ylen = rgz_bunique(yentries, ylen);
/* at this point we have an array of horizontal regions */
@@ -1180,7 +1369,6 @@ static int rgz_in_hwc(rgz_in_params_t *p, rgz_t *rgz)
ALOGD_IF(debug, "Allocated %d regions (sz = %d), layerno = %d", rgz->nhregions,
rgz->nhregions * sizeof(blit_hregion_t), cur_fb_state->rgz_layerno);
- int i, j;
for (i = 0; i < rgz->nhregions; i++) {
hregions[i].rect.top = yentries[i];
hregions[i].rect.bottom = yentries[i+1];
@@ -1190,7 +1378,7 @@ static int rgz_in_hwc(rgz_in_params_t *p, rgz_t *rgz)
hregions[i].nlayers = 0;
for (j = 0; j < cur_fb_state->rgz_layerno; j++) {
hwc_layer_t *layer = &cur_fb_state->rgz_layers[j].hwc_layer;
- if (rgz_hwc_intersects(&hregions[i].rect, &layer->displayFrame)) {
+ if (RECT_INTERSECTS(hregions[i].rect, layer->displayFrame)) {
int l = hregions[i].nlayers++;
hregions[i].rgz_layers[l] = &cur_fb_state->rgz_layers[j];
}
@@ -1199,7 +1387,7 @@ static int rgz_in_hwc(rgz_in_params_t *p, rgz_t *rgz)
/* Calculate blit regions */
for (i = 0; i < rgz->nhregions; i++) {
- rgz_gen_blitregions(&hregions[i], screen_width);
+ rgz_gen_blitregions(rgz, &hregions[i], screen_width);
ALOGD_IF(debug, "hregion %3d: nsubregions %d", i, hregions[i].nsubregions);
ALOGD_IF(debug, " : %d to %d: ",
hregions[i].rect.top, hregions[i].rect.bottom);
@@ -1470,7 +1658,8 @@ static void rgz_batch_entry(struct rgz_blt_entry* e, unsigned int flag, unsigned
e->bp.batchflags |= set;
}
-static int rgz_hwc_subregion_blit(blit_hregion_t *hregion, int sidx, rgz_out_params_t *params)
+static int rgz_hwc_subregion_blit(blit_hregion_t *hregion, int sidx, rgz_out_params_t *params,
+ blit_rect_t *damaged_area)
{
static int loaded = 0;
if (!loaded)
@@ -1487,17 +1676,23 @@ static int rgz_hwc_subregion_blit(blit_hregion_t *hregion, int sidx, rgz_out_par
}
/* Determine if this region is dirty */
- int dirty = 0, dirtylix = lix;
- while (dirtylix != -1) {
- rgz_layer_t *rgz_layer = hregion->rgz_layers[dirtylix];
- if (rgz_layer->dirty_count){
- /* One of the layers is dirty, we need to generate blits for this subregion */
- dirty = 1;
- break;
+ int dirty = 0;
+ blit_rect_t *subregion_rect = &hregion->blitrects[lix][sidx];
+ if (RECT_INTERSECTS(*damaged_area, *subregion_rect)) {
+ /* The subregion intersects the damaged area, draw unconditionally */
+ dirty = 1;
+ } else {
+ int dirtylix = lix;
+ while (dirtylix != -1) {
+ rgz_layer_t *rgz_layer = hregion->rgz_layers[dirtylix];
+ if (rgz_layer->dirty_count){
+ /* One of the layers is dirty, we need to generate blits for this subregion */
+ dirty = 1;
+ break;
+ }
+ dirtylix = get_layer_ops_next(hregion, sidx, dirtylix);
}
- dirtylix = get_layer_ops_next(hregion, sidx, dirtylix);
}
-
if (!dirty)
return 0;
@@ -1664,7 +1859,7 @@ static int rgz_out_region(rgz_t *rgz, rgz_out_params_t *params)
}
for (s = 0; s < hregion->nsubregions; s++) {
ALOGD_IF(debug, "h[%d] -> [%d]", i, s);
- if (rgz_hwc_subregion_blit(hregion, s, params))
+ if (rgz_hwc_subregion_blit(hregion, s, params, &rgz->damaged_area))
return -1;
}
}