summaryrefslogtreecommitdiffstats
path: root/hwc
diff options
context:
space:
mode:
Diffstat (limited to 'hwc')
-rw-r--r--hwc/rgz_2d.c330
1 files changed, 235 insertions, 95 deletions
diff --git a/hwc/rgz_2d.c b/hwc/rgz_2d.c
index 96c4374..ca259c2 100644
--- a/hwc/rgz_2d.c
+++ b/hwc/rgz_2d.c
@@ -313,8 +313,149 @@ static void rgz_get_displayframe_rect(hwc_layer_t *layer, blit_rect_t *res_rect)
res_rect->right = layer->displayFrame.right;
}
+/*
+ * Returns a clock-wise rotated view of the inner rectangle relative to
+ * the outer rectangle. The inner rectangle must be contained in the outer
+ * rectangle and coordinates must be relative to the top,left corner of the outer
+ * rectangle.
+ */
+static void rgz_get_rotated_view(blit_rect_t *outer_rect, blit_rect_t *inner_rect,
+ blit_rect_t *res_rect, int orientation)
+{
+ int outer_width = WIDTH(*outer_rect);
+ int outer_height = HEIGHT(*outer_rect);
+ int inner_width = WIDTH(*inner_rect);
+ int inner_height = HEIGHT(*inner_rect);
+ int delta_top = inner_rect->top - outer_rect->top;
+ int delta_left = inner_rect->left - outer_rect->left;
+
+ /* Normalize the angle */
+ orientation = (orientation % 360) + 360;
+
+ /*
+ * Calculate the top,left offset of the inner rectangle inside the outer
+ * rectangle depending on the tranformation value.
+ */
+ switch(orientation % 360) {
+ case 0:
+ res_rect->left = delta_left;
+ res_rect->top = delta_top;
+ break;
+ case 180:
+ res_rect->left = outer_width - inner_width - delta_left;
+ res_rect->top = outer_height - inner_height - delta_top;
+ break;
+ case 90:
+ res_rect->left = outer_height - inner_height - delta_top;
+ res_rect->top = delta_left;
+ break;
+ case 270:
+ res_rect->left = delta_top;
+ res_rect->top = outer_width - inner_width - delta_left;
+ break;
+ default:
+ OUTE("Invalid transform value %d", orientation);
+ }
+
+ if (orientation % 180)
+ swap(inner_width, inner_height);
+
+ res_rect->right = res_rect->left + inner_width;
+ res_rect->bottom = res_rect->top + inner_height;
+}
+
+static void rgz_get_src_rect(hwc_layer_t* layer, blit_rect_t *subregion_rect, blit_rect_t *res_rect)
+{
+ if (rgz_hwc_scaled(layer)) {
+ /*
+ * If the layer is scaled we use the whole cropping rectangle from the
+ * source and just move the clipping rectangle for the region we want to
+ * blit, this is done to prevent any artifacts when blitting subregions of
+ * a scaled layer.
+ */
+ res_rect->top = layer->sourceCrop.top;
+ res_rect->left = layer->sourceCrop.left;
+ res_rect->bottom = layer->sourceCrop.bottom;
+ res_rect->right = layer->sourceCrop.right;
+ return;
+ }
+
+ blit_rect_t display_frame;
+ rgz_get_displayframe_rect(layer, &display_frame);
+
+ /*
+ * Get the rotated subregion rectangle with respect to the display frame.
+ * In order to get this correctly we need to take in account the HWC
+ * orientation is clock-wise so to return to the 0 degree view we need to
+ * rotate counter-clock wise the orientation. For example, if the
+ * orientation is 90 we need to rotate -90 to return to a 0 degree view.
+ */
+ int src_orientation = 0 - rgz_get_orientation(layer->transform);
+ rgz_get_rotated_view(&display_frame, subregion_rect, res_rect, src_orientation);
+
+ /*
+ * In order to translate the resulting rectangle relative to the cropping
+ * rectangle the only thing left is account for the offset (result is already
+ * rotated).
+ */
+ res_rect->left += layer->sourceCrop.left;
+ res_rect->right += layer->sourceCrop.left;
+ res_rect->top += layer->sourceCrop.top;
+ res_rect->bottom += layer->sourceCrop.top;
+}
+
+/*
+ * Convert a destination geometry and rectangle to a specified rotated view.
+ * Since clipping rectangle is relative to the destination geometry it will be
+ * rotated as well.
+ */
+static void rgz_rotate_dst(struct rgz_blt_entry* e, int dst_orientation)
+{
+ struct bvsurfgeom *dstgeom = &e->dstgeom;
+ struct bvrect *dstrect = &e->bp.dstrect;
+ struct bvrect *cliprect = &e->bp.cliprect;
+
+ /*
+ * Create a rectangle that represents the destination geometry (outter
+ * rectangle), destination and clipping rectangles (inner rectangles).
+ */
+ blit_rect_t dstgeom_r;
+ dstgeom_r.top = dstgeom_r.left = 0;
+ dstgeom_r.bottom = dstgeom->height;
+ dstgeom_r.right = dstgeom->width;
+
+ blit_rect_t dstrect_r;
+ dstrect_r.top = dstrect->top;
+ dstrect_r.left = dstrect->left;
+ dstrect_r.bottom = dstrect->top + dstrect->height;
+ dstrect_r.right = dstrect->left + dstrect->width;
+
+ blit_rect_t cliprect_r;
+ cliprect_r.top = cliprect->top;
+ cliprect_r.left = cliprect->left;
+ cliprect_r.bottom = cliprect->top + cliprect->height;
+ cliprect_r.right = cliprect->left + cliprect->width;
+
+ /* Get the CW rotated view of the destination rectangle */
+ blit_rect_t res_rect;
+ rgz_get_rotated_view(&dstgeom_r, &dstrect_r, &res_rect, dst_orientation);
+ dstrect->left = res_rect.left;
+ dstrect->top = res_rect.top;
+ dstrect->width = WIDTH(res_rect);
+ dstrect->height = HEIGHT(res_rect);
+
+ rgz_get_rotated_view(&dstgeom_r, &cliprect_r, &res_rect, dst_orientation);
+ cliprect->left = res_rect.left;
+ cliprect->top = res_rect.top;
+ cliprect->width = WIDTH(res_rect);
+ cliprect->height = HEIGHT(res_rect);
+
+ if (dst_orientation % 180)
+ swap(e->dstgeom.width, e->dstgeom.height);
+}
+
static void rgz_set_dst_data(rgz_out_params_t *params, blit_rect_t *subregion_rect,
- struct rgz_blt_entry* e)
+ struct rgz_blt_entry* e, int dst_orientation)
{
struct bvsurfgeom *screen_geom;
rgz_get_screen_info(params, &screen_geom);
@@ -324,17 +465,56 @@ static void rgz_set_dst_data(rgz_out_params_t *params, blit_rect_t *subregion_re
e->dstgeom.format = screen_geom->format;
e->dstgeom.width = screen_geom->width;
e->dstgeom.height = screen_geom->height;
- e->dstgeom.orientation = screen_geom->orientation;
+ e->dstgeom.orientation = dst_orientation;
e->dstgeom.virtstride = DSTSTRIDE(screen_geom);
e->bp.dstrect.left = subregion_rect->left;
e->bp.dstrect.top = subregion_rect->top;
e->bp.dstrect.width = WIDTH(*subregion_rect);
e->bp.dstrect.height = HEIGHT(*subregion_rect);
+
+ /* Give a rotated buffer representation of the destination if requested */
+ if (e->dstgeom.orientation)
+ rgz_rotate_dst(e, dst_orientation);
+}
+
+/* Convert a source geometry and rectangle to a specified rotated view */
+static void rgz_rotate_src(struct rgz_blt_entry* e, int src_orientation, int is_src2)
+{
+ struct bvsurfgeom *srcgeom = is_src2 ? &e->src2geom : &e->src1geom;
+ struct bvrect *srcrect = is_src2 ? &e->bp.src2rect : &e->bp.src1rect;
+
+ /*
+ * Create a rectangle that represents the source geometry (outter rectangle),
+ * source rectangle (inner rectangle).
+ */
+ blit_rect_t srcgeom_r;
+ srcgeom_r.top = srcgeom_r.left = 0;
+ srcgeom_r.bottom = srcgeom->height;
+ srcgeom_r.right = srcgeom->width;
+
+ blit_rect_t srcrect_r;
+ srcrect_r.top = srcrect->top;
+ srcrect_r.left = srcrect->left;
+ srcrect_r.bottom = srcrect->top + srcrect->height;
+ srcrect_r.right = srcrect->left + srcrect->width;
+
+ /* Get the CW rotated view of the source rectangle */
+ blit_rect_t res_rect;
+ rgz_get_rotated_view(&srcgeom_r, &srcrect_r, &res_rect, src_orientation);
+
+ srcrect->left = res_rect.left;
+ srcrect->top = res_rect.top;
+ srcrect->width = WIDTH(res_rect);
+ srcrect->height = HEIGHT(res_rect);
+
+ if (src_orientation % 180)
+ swap(srcgeom->width, srcgeom->height);
}
static void rgz_set_src_data(rgz_out_params_t *params, rgz_layer_t *rgz_layer,
- blit_rect_t *subregion_rect, struct rgz_blt_entry* e, int is_src2)
+ blit_rect_t *subregion_rect, struct rgz_blt_entry* e, int src_orientation,
+ int is_src2)
{
hwc_layer_t *hwc_layer = rgz_layer->hwc_layer;
struct bvbuffdesc *srcdesc = is_src2 ? &e->src2desc : &e->src1desc;
@@ -349,10 +529,7 @@ static void rgz_set_src_data(rgz_out_params_t *params, rgz_layer_t *rgz_layer,
srcgeom->format = hal_to_ocd(handle->iFormat);
srcgeom->width = handle->iWidth;
srcgeom->height = handle->iHeight;
- srcgeom->orientation = rgz_get_orientation(hwc_layer->transform);
srcgeom->virtstride = HANDLE_TO_STRIDE(handle);
- if (hwc_layer->transform & HAL_TRANSFORM_ROT_90)
- swap(srcgeom->width, srcgeom->height);
/* Find out what portion of the src we want to use for the blit */
blit_rect_t res_rect;
@@ -361,6 +538,13 @@ static void rgz_set_src_data(rgz_out_params_t *params, rgz_layer_t *rgz_layer,
srcrect->top = res_rect.top;
srcrect->width = WIDTH(res_rect);
srcrect->height = HEIGHT(res_rect);
+
+ /* Give a rotated buffer representation of this source if requested */
+ if (src_orientation) {
+ srcgeom->orientation = src_orientation;
+ rgz_rotate_src(e, src_orientation, is_src2);
+ } else
+ srcgeom->orientation = 0;
}
/*
@@ -397,6 +581,12 @@ static void rgz_set_src2_is_dst(rgz_out_params_t *params, struct rgz_blt_entry*
e->bp.src2rect = e->bp.dstrect;
}
+static int rgz_is_layer_nv12(hwc_layer_t *layer)
+{
+ IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle;
+ return is_NV12(handle->iFormat);
+}
+
/*
* Configure the scaling mode according to the layer format
*/
@@ -406,8 +596,7 @@ static void rgz_cfg_scale_mode(struct rgz_blt_entry* e, hwc_layer_t *layer)
* TODO: Revisit scaling mode assignment later, output between GPU and GC320
* seem different
*/
- IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle;
- e->bp.scalemode = is_NV12(handle->iFormat) ? BVSCALE_9x9_TAP : BVSCALE_BILINEAR;
+ e->bp.scalemode = rgz_is_layer_nv12(layer) ? BVSCALE_9x9_TAP : BVSCALE_BILINEAR;
}
/*
@@ -431,9 +620,12 @@ static struct rgz_blt_entry* rgz_hwc_subregion_copy(rgz_out_params_t *params,
} else
tmp_rect = *subregion_rect;
- rgz_set_src_data(params, rgz_src1, &tmp_rect, e, 0);
- rgz_set_dst_data(params, &tmp_rect, e);
+ int src1_orientation = rgz_get_orientation(hwc_src1->transform);
+ int dst_orientation = 0;
+
+ rgz_set_src_data(params, rgz_src1, &tmp_rect, e, src1_orientation, 0);
rgz_set_clip_rect(params, subregion_rect, e);
+ rgz_set_dst_data(params, &tmp_rect, e, dst_orientation);
if((e->src1geom.format == OCDFMT_BGR124) ||
(e->src1geom.format == OCDFMT_RGB124) ||
@@ -466,9 +658,12 @@ static struct rgz_blt_entry* rgz_hwc_subregion_blend(rgz_out_params_t *params,
} else
tmp_rect = *subregion_rect;
- rgz_set_src_data(params, rgz_src1, &tmp_rect, e, 0);
- rgz_set_dst_data(params, &tmp_rect, e);
+ int src1_orientation = rgz_get_orientation(hwc_src1->transform);
+ int dst_orientation = 0;
+
+ rgz_set_src_data(params, rgz_src1, &tmp_rect, e, src1_orientation, 0);
rgz_set_clip_rect(params, subregion_rect, e);
+ rgz_set_dst_data(params, &tmp_rect, e, dst_orientation);
if (rgz_src2) {
/*
@@ -478,8 +673,15 @@ static struct rgz_blt_entry* rgz_hwc_subregion_blend(rgz_out_params_t *params,
hwc_layer_t *hwc_src2 = rgz_src2->hwc_layer;
if (rgz_hwc_scaled(hwc_src2))
OUTE("src2 layer %p has scaling, this is not supported", hwc_src2);
+ /*
+ * We shouldn't receive a NV12 buffer as src2 at this point, this is an
+ * invalid parameter for the blend request
+ */
+ if (rgz_is_layer_nv12(hwc_src2))
+ OUTE("invalid input layer, src2 layer %p is NV12", hwc_src2);
e->bp.flags |= rgz_get_flip_flags(hwc_src2->transform, 1);
- rgz_set_src_data(params, rgz_src2, subregion_rect, e, 1);
+ int src2_orientation = rgz_get_orientation(hwc_src2->transform);
+ rgz_set_src_data(params, rgz_src2, subregion_rect, e, src2_orientation, 1);
} else
rgz_set_src2_is_dst(params, e);
@@ -525,8 +727,8 @@ static void rgz_out_clrdst(rgz_out_params_t *params, blit_rect_t *rect)
clear_rect.bottom = screen_geom->height;
}
- rgz_set_dst_data(params, &clear_rect, e);
rgz_set_clip_rect(params, &clear_rect, e);
+ rgz_set_dst_data(params, &clear_rect, e, 0);
}
static int rgz_out_bvcmd_paint(rgz_t *rgz, rgz_out_params_t *params)
@@ -1212,72 +1414,19 @@ static int rgz_hwc_layer_blit(rgz_out_params_t *params, rgz_layer_t *rgz_layer)
return 0;
}
-/*
- * Calculate the src rectangle on the basis of the layer display, source crop
- * and subregion rectangles. Additionally any rotation will be taken in
- * account. The resulting rectangle is written in res_rect.
- */
-static void rgz_get_src_rect(hwc_layer_t* layer, blit_rect_t *subregion_rect, blit_rect_t *res_rect)
+static int rgz_can_blend_together(hwc_layer_t* src1_layer, hwc_layer_t* src2_layer)
{
- IMG_native_handle_t *handle = (IMG_native_handle_t *)layer->handle;
- int res_left = 0;
- int res_top = 0;
- int delta_left;
- int delta_top;
- int res_width;
- int res_height;
-
- /*
- * If the layer is scaled we use the whole cropping rectangle from the
- * source and just move the clipping rectangle for the region we want to
- * blit, this is done to prevent any artifacts when blitting subregions of
- * a scaled layer. If there is a transform, adjust the width and height
- * accordingly to match the rotated buffer geometry.
- */
- if (rgz_hwc_scaled(layer)) {
- delta_top = 0;
- delta_left = 0;
- res_width = WIDTH(layer->sourceCrop);
- res_height = HEIGHT(layer->sourceCrop);
- if (layer->transform & HAL_TRANSFORM_ROT_90)
- swap(res_width , res_height);
- } else {
- delta_top = subregion_rect->top - layer->displayFrame.top;
- delta_left = subregion_rect->left - layer->displayFrame.left;
- res_width = WIDTH(*subregion_rect);
- res_height = HEIGHT(*subregion_rect);
- }
+ /* If any layer is scaled we cannot blend both layers in one blit */
+ if (rgz_hwc_scaled(src1_layer) || rgz_hwc_scaled(src2_layer))
+ return 0;
- /*
- * Calculate the top, left offset from the source cropping rectangle
- * depending on the rotation
- */
- switch(layer->transform) {
- case 0:
- res_left = layer->sourceCrop.left + delta_left;
- res_top = layer->sourceCrop.top + delta_top;
- break;
- case HAL_TRANSFORM_ROT_90:
- res_left = handle->iHeight - layer->sourceCrop.bottom + delta_left;
- res_top = layer->sourceCrop.left + delta_top;
- break;
- case HAL_TRANSFORM_ROT_180:
- res_left = handle->iWidth - layer->sourceCrop.right + delta_left;
- res_top = handle->iHeight - layer->sourceCrop.bottom + delta_top;
- break;
- case HAL_TRANSFORM_ROT_270:
- res_left = layer->sourceCrop.top + delta_left;
- res_top = handle->iWidth - layer->sourceCrop.right + delta_top;
- break;
- default:
- OUTE("Invalid transform value %d", layer->transform);
- }
+ /* NV12 buffers don't have alpha information on it */
+ IMG_native_handle_t *src1_hndl = (IMG_native_handle_t *)src1_layer->handle;
+ IMG_native_handle_t *src2_hndl = (IMG_native_handle_t *)src2_layer->handle;
+ if (is_NV12(src1_hndl->iFormat) || is_NV12(src2_hndl->iFormat))
+ return 0;
- /* Resulting rectangle has the subregion dimensions */
- res_rect->left = res_left;
- res_rect->top = res_top;
- res_rect->right = res_left + res_width;
- res_rect->bottom = res_top + res_height;
+ return 1;
}
static void rgz_batch_entry(struct rgz_blt_entry* e, unsigned int flag, unsigned int set)
@@ -1359,36 +1508,28 @@ static int rgz_hwc_subregion_blit(blit_hregion_t *hregion, int sidx, rgz_out_par
* We save a read and a write from the FB if we blend the bottom
* two layers, we can do this only if both layers are not scaled
*/
- int first_batchflags = 0;
- if (!rgz_hwc_scaled(hregion->rgz_layers[lix]->hwc_layer) &&
- !rgz_hwc_scaled(hregion->rgz_layers[s2lix]->hwc_layer)) {
- e = rgz_hwc_subregion_blend(params, rect, hregion->rgz_layers[lix],
- hregion->rgz_layers[s2lix]);
- first_batchflags |= BVBATCH_SRC2;
- } else {
+ rgz_layer_t *rgz_src1 = hregion->rgz_layers[lix];
+ rgz_layer_t *rgz_src2 = hregion->rgz_layers[s2lix];
+ if (rgz_can_blend_together(rgz_src1->hwc_layer, rgz_src2->hwc_layer))
+ e = rgz_hwc_subregion_blend(params, rect, rgz_src1, rgz_src2);
+ else {
/* Return index to the first operation and make a copy of the first layer */
lix = s2lix;
e = rgz_hwc_subregion_copy(params, rect, hregion->rgz_layers[lix]);
- first_batchflags |= BVBATCH_OP | BVBATCH_SRC2;
}
rgz_batch_entry(e, BVFLAG_BATCH_BEGIN, 0);
/* Rest of layers blended with FB */
- int first = 1;
while((lix = get_layer_ops_next(hregion, sidx, lix)) != -1) {
- int batchflags = 0;
e = rgz_hwc_subregion_blend(params, rect, hregion->rgz_layers[lix], NULL);
- if (first) {
- first = 0;
- batchflags |= first_batchflags;
- }
/*
* TODO: This will work when scaling is introduced, however we need
* to think on a better way to optimize this.
*/
- batchflags |= BVBATCH_SRC1 | BVBATCH_SRC1RECT_ORIGIN| BVBATCH_SRC1RECT_SIZE |
- BVBATCH_DSTRECT_ORIGIN | BVBATCH_DSTRECT_SIZE | BVBATCH_SRC2RECT_ORIGIN |
- BVBATCH_SRC2RECT_SIZE | BVBATCH_SCALE;
+ int batchflags = BVBATCH_SRC1 | BVBATCH_SRC1RECT_ORIGIN| BVBATCH_SRC1RECT_SIZE |
+ BVBATCH_DST | BVBATCH_DSTRECT_ORIGIN | BVBATCH_DSTRECT_SIZE |
+ BVBATCH_SRC2 | BVBATCH_SRC2RECT_ORIGIN | BVBATCH_SRC2RECT_SIZE |
+ BVBATCH_OP | BVBATCH_SCALE | BVBATCH_CLIPRECT;
rgz_batch_entry(e, BVFLAG_BATCH_CONTINUE, batchflags);
}
@@ -1623,7 +1764,6 @@ int rgz_get_screengeometry(int fd, struct bvsurfgeom *geom, int fmt)
geom->height = fb_varinfo.yres;
geom->virtstride = fb_fixinfo.line_length;
geom->format = hal_to_ocd(fmt);
- /* Always set to 0, src buffers will contain rotation values as needed */
geom->orientation = 0;
return 0;
}