diff options
-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; }; |