summaryrefslogtreecommitdiffstats
path: root/gralloc_drm_kms.c
diff options
context:
space:
mode:
authorTapani Pälli <tapani.palli@intel.com>2013-04-15 09:10:09 +0300
committerTapani Pälli <tapani.palli@intel.com>2013-04-15 13:25:55 +0300
commitb201e98a1cbdf217e52da2cf503beb3b21c2e173 (patch)
treeae9d8f127a660fa22d3ef52c3413e3c47e919ea8 /gralloc_drm_kms.c
parent4b3db54505933738ec33f92ec7e2c5304cb18325 (diff)
downloadexternal_drm_gralloc-b201e98a1cbdf217e52da2cf503beb3b21c2e173.zip
external_drm_gralloc-b201e98a1cbdf217e52da2cf503beb3b21c2e173.tar.gz
external_drm_gralloc-b201e98a1cbdf217e52da2cf503beb3b21c2e173.tar.bz2
gralloc: plane support
patch introduces API between hwcomposer and gralloc, hwcomposer can reserve an overlay plane to be used by a particular layer in prepare hook, drmModeSetPlane for each plane gets called later when post() gets called by the eglSwapBuffers (from hwcomposer set), this can be later changed to use atomic modesetting code and drm properties to make one 'atomic flip' for graphics + planes. Change-Id: I3b7d179b285e43eb19fdc3b4c7ce093f3ba6aade Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Diffstat (limited to 'gralloc_drm_kms.c')
-rw-r--r--gralloc_drm_kms.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/gralloc_drm_kms.c b/gralloc_drm_kms.c
index 0680bf0..4eb3dfa 100644
--- a/gralloc_drm_kms.c
+++ b/gralloc_drm_kms.c
@@ -104,7 +104,7 @@ unsigned int planes_for_format(struct gralloc_drm_t *drm,
for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
for (j=0; j<plane->drm_plane->count_formats; j++)
if (plane->drm_plane->formats[j] == drm_format)
- mask |= (2 << plane->drm_plane->plane_id);
+ mask |= (1U << plane->drm_plane->plane_id);
return mask;
}
@@ -183,6 +183,152 @@ static void page_flip_handler(int fd, unsigned int sequence,
}
/*
+ * Set a plane.
+ */
+static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
+ struct gralloc_drm_plane_t *plane)
+{
+ struct gralloc_drm_bo_t *bo = NULL;
+ int err;
+
+ if (plane->handle)
+ bo = gralloc_drm_bo_from_handle(plane->handle);
+
+ // create a framebuffer if does not exist
+ if (bo && bo->fb_id == 0) {
+ err = gralloc_drm_bo_add_fb(bo);
+ if (err) {
+ ALOGE("%s: could not create drm fb, (%s)",
+ __func__, strerror(-err));
+ return err;
+ }
+ }
+
+ err = drmModeSetPlane(drm->fd,
+ plane->drm_plane->plane_id,
+ drm->primary.crtc_id,
+ bo ? bo->fb_id : 0,
+ 0, // flags
+ plane->dst_x,
+ plane->dst_y,
+ plane->dst_w,
+ plane->dst_h,
+ plane->src_x << 16,
+ plane->src_y << 16,
+ plane->src_w << 16,
+ plane->src_h << 16);
+
+ if (err) {
+ /* clear plane_mask so that this buffer won't be tried again */
+ struct gralloc_drm_handle_t *drm_handle =
+ (struct gralloc_drm_handle_t *) plane->handle;
+ drm_handle->plane_mask = 0;
+
+ ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
+ strerror(-err),
+ plane->drm_plane->plane_id,
+ drm->primary.crtc_id,
+ bo ? bo->fb_id : 0);
+ }
+
+ if (plane->prev)
+ gralloc_drm_bo_decref(plane->prev);
+
+ if (bo)
+ bo->refcount++;
+
+ plane->prev = bo;
+
+ return err;
+}
+
+/*
+ * Sets all the active planes to be displayed.
+ */
+static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
+{
+ struct gralloc_drm_plane_t *plane = drm->planes;
+ unsigned int i;
+ for (i = 0; i < drm->plane_resources->count_planes;
+ i++, plane++) {
+ /*
+ * Disable overlay if it is not active
+ * or if there is error during setplane
+ */
+ if (!plane->active)
+ plane->handle = 0;
+
+ if (gralloc_drm_bo_setplane(drm, plane))
+ plane->active = 0;
+ }
+}
+
+/*
+ * Interface for HWC, used to reserve a plane for a layer.
+ */
+int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
+ buffer_handle_t handle,
+ uint32_t dst_x,
+ uint32_t dst_y,
+ uint32_t dst_w,
+ uint32_t dst_h,
+ uint32_t src_x,
+ uint32_t src_y,
+ uint32_t src_w,
+ uint32_t src_h)
+{
+ unsigned int i, j;
+ struct gralloc_drm_handle_t *drm_handle =
+ gralloc_drm_handle(handle);
+ int plane_count = drm->plane_resources->count_planes;
+ struct gralloc_drm_plane_t *plane = drm->planes;
+
+ /* no supported planes for this handle */
+ if (!drm_handle->plane_mask) {
+ ALOGE("%s: buffer %p cannot be shown on a plane\n",
+ __func__, drm_handle);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < plane_count; j++, plane++) {
+ /* if plane is available and can support this buffer */
+ if (!plane->active &&
+ drm_handle->plane_mask &
+ (1U << plane->drm_plane->plane_id)) {
+
+ plane->dst_x = dst_x;
+ plane->dst_y = dst_y;
+ plane->dst_w = dst_w;
+ plane->dst_h = dst_h;
+ plane->src_x = src_x;
+ plane->src_y = src_y;
+ plane->src_w = src_w;
+ plane->src_h = src_h;
+ plane->handle = handle;
+ plane->active = 1;
+
+ return 0;
+ }
+ }
+
+ /* no free planes available */
+ return -EBUSY;
+}
+
+/*
+ * Interface for HWC, used to disable all the overlays.
+ */
+void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
+{
+ struct gralloc_drm_plane_t *plane = drm->planes;
+ unsigned int i;
+
+ for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
+ plane->active = 0;
+}
+
+
+/*
* Schedule a page flip.
*/
static int drm_kms_page_flip(struct gralloc_drm_t *drm,
@@ -229,6 +375,9 @@ static int drm_kms_page_flip(struct gralloc_drm_t *drm,
}
pthread_mutex_unlock(&drm->hdmi_mutex);
+ /* set planes to be displayed */
+ gralloc_drm_set_planes(drm);
+
ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
if (ret) {