diff options
author | Tapani Pälli <tapani.palli@intel.com> | 2013-04-15 09:10:09 +0300 |
---|---|---|
committer | Tapani Pälli <tapani.palli@intel.com> | 2013-04-15 13:25:55 +0300 |
commit | b201e98a1cbdf217e52da2cf503beb3b21c2e173 (patch) | |
tree | ae9d8f127a660fa22d3ef52c3413e3c47e919ea8 | |
parent | 4b3db54505933738ec33f92ec7e2c5304cb18325 (diff) | |
download | external_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>
-rw-r--r-- | gralloc.c | 3 | ||||
-rw-r--r-- | gralloc_drm.h | 5 | ||||
-rw-r--r-- | gralloc_drm_kms.c | 151 | ||||
-rw-r--r-- | gralloc_drm_priv.h | 25 |
4 files changed, 183 insertions, 1 deletions
@@ -352,6 +352,9 @@ struct drm_module_t HAL_MODULE_INFO_SYM = { .unlock = drm_mod_unlock, .perform = drm_mod_perform }, + .hwc_reserve_plane = gralloc_drm_reserve_plane, + .hwc_disable_planes = gralloc_drm_disable_planes, + .mutex = PTHREAD_MUTEX_INITIALIZER, .drm = NULL }; diff --git a/gralloc_drm.h b/gralloc_drm.h index 891526f..8554cf7 100644 --- a/gralloc_drm.h +++ b/gralloc_drm.h @@ -136,6 +136,11 @@ int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo); void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo); int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo); +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); +void gralloc_drm_disable_planes(struct gralloc_drm_t *mod); + #ifdef __cplusplus } #endif 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) { diff --git a/gralloc_drm_priv.h b/gralloc_drm_priv.h index dc7d505..eb4338c 100644 --- a/gralloc_drm_priv.h +++ b/gralloc_drm_priv.h @@ -49,6 +49,25 @@ enum hdmi_output_mode { struct gralloc_drm_plane_t { drmModePlane *drm_plane; + + /* plane has been set to display a layer */ + uint32_t active; + + /* handle to display */ + buffer_handle_t handle; + + /* position, crop and scale */ + uint32_t src_x; + uint32_t src_y; + uint32_t src_w; + uint32_t src_h; + uint32_t dst_x; + uint32_t dst_y; + uint32_t dst_w; + uint32_t dst_h; + + /* previous buffer, for refcounting */ + struct gralloc_drm_bo_t *prev; }; struct gralloc_drm_output @@ -106,6 +125,12 @@ struct gralloc_drm_t { struct drm_module_t { gralloc_module_t base; + /* HWC plane API */ + int (*hwc_reserve_plane) (struct gralloc_drm_t *mod, 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); + void (*hwc_disable_planes) (struct gralloc_drm_t *mod); + pthread_mutex_t mutex; struct gralloc_drm_t *drm; }; |