diff options
author | Sunita Nadampalli <sunitan@ti.com> | 2016-05-13 09:44:12 -0500 |
---|---|---|
committer | Gerrit Code Review <gerrit2@dlezvx23.ext.ti.com> | 2016-05-13 09:44:13 -0500 |
commit | 46087ebd56a4e2a32eb17f4aef2214badf19ec69 (patch) | |
tree | 95b9d4a0c7f87cbf670dbb90decfdc0d6bd7a143 | |
parent | 81f801a391ecd74e13b8514c4e7c13a8ad71d31b (diff) | |
parent | d836e7d8ddab3d043abdd1c42cf98eb25c8c91d9 (diff) | |
download | dra7xx-46087ebd56a4e2a32eb17f4aef2214badf19ec69.tar.gz |
Merge "hwc: create and release drm fb helper routines" into d-marshmallow-mr1-release
-rw-r--r-- | hwcomposer/blitter.h | 1 | ||||
-rw-r--r-- | hwcomposer/display.c | 244 | ||||
-rw-r--r-- | hwcomposer/display.h | 28 | ||||
-rw-r--r-- | hwcomposer/hwc.c | 7 |
4 files changed, 207 insertions, 73 deletions
diff --git a/hwcomposer/blitter.h b/hwcomposer/blitter.h index 4729fdf..06fcc3f 100644 --- a/hwcomposer/blitter.h +++ b/hwcomposer/blitter.h @@ -56,6 +56,7 @@ typedef struct blit_device buffer_handle_t (*get_fb_handle)(struct blit_device *device, int idx); + int (*set_fb_fence)(struct blit_device *device, int idx, int fence); } blit_device_t; diff --git a/hwcomposer/display.c b/hwcomposer/display.c index 8f9a5bd..b29c4d3 100644 --- a/hwcomposer/display.c +++ b/hwcomposer/display.c @@ -50,7 +50,8 @@ enum { EXT_HFLIP = (1 << 2), /* flip l-r on output (after rotation) */ }; -int timeline_create_fence(timeline_info_t *timeline, unsigned relative) +int timeline_create_fence(timeline_info_t *timeline, + const char *name, unsigned relative) { int fd; unsigned new_pt; @@ -58,7 +59,7 @@ int timeline_create_fence(timeline_info_t *timeline, unsigned relative) pthread_mutex_lock(&timeline->lock); new_pt = timeline->signaled_fences + relative; - fd = sw_sync_fence_create(timeline->timeline, "retire fence", new_pt); + fd = sw_sync_fence_create(timeline->timeline, name, new_pt); pthread_mutex_unlock(&timeline->lock); @@ -544,8 +545,19 @@ static void page_flip_handler(int fd, unsigned frame, unsigned int sec, unsigned int usec, void *data) { display_t *display = (display_t *)data; + kms_display_t *kdisp = &display->disp_link; timeline_inc(&display->retire_sync); + + /* if there is new buffer that would have got posted here, + * release the old buffer + */ + if (kdisp->fb_bufs.updated) { + int ret = 0; + kdisp->fb_bufs.updated = false; + ret = display_release_drm_fd(display, &kdisp->fb_bufs.current); + kdisp->fb_bufs.current = kdisp->fb_bufs.next; + } } /* @@ -741,6 +753,116 @@ close: return -1; } +int display_create_drm_fb(display_t *display, buffer_handle_t handle, + void *plane_data, drm_fb_info_t *fb_info) +{ + int ret = 0; + IMG_native_handle_t *img_hnd; + kms_display_t *kdisp; + int drm_fd; + composition_t *comp; + + uint32_t gem_handle; + + if (!display || !fb_info || !handle) + return EINVAL; + if (fb_info->bo[0]) { + ALOGE("existing handle needs to be closed first"); + return EINVAL; + } + kdisp = &display->disp_link; + drm_fd = kdisp->ctx->drm_fd; + comp = &display->composition; + img_hnd = (IMG_native_handle_t *)handle; + + ret = drmPrimeFDToHandle(drm_fd, img_hnd->fd[0], &gem_handle); + if (ret) { + ALOGE("Failed to get drm bo from handle"); + return ret; + } + + memset(fb_info, 0, sizeof(drm_fb_info_t)); + fb_info->width = img_hnd->iWidth; + fb_info->height = img_hnd->iHeight; + fb_info->format = convert_hal_to_drm_format(img_hnd->iFormat, true); + fb_info->pitches[0] = img_hnd->iWidth * 4; + fb_info->bo[0] = gem_handle; + fb_info->offsets[0] = 0; + + if (!plane_data) { + /* this fb is for overlay plane */ + struct drm_mode_set_plane *ovl = plane_data; + + switch (fb_info->format) { + case DRM_FORMAT_NV12: + fb_info->bo[1] = gem_handle; + + fb_info->pitches[0] = ALIGN(img_hnd->iWidth, 32); + fb_info->pitches[1] = fb_info->pitches[0]; + + fb_info->offsets[0] = ALIGN(ovl->src_x + + (img_hnd->iWidth * ovl->src_y), 32); + fb_info->offsets[1] = ALIGN(img_hnd->iWidth * + (img_hnd->iHeight + (ovl->src_y/2)) + + ovl->src_x, 32); + break; + case DRM_FORMAT_ARGB8888: + break; + default: + ALOGE("Bad format for overlay"); + memset(fb_info, 0, sizeof(drm_fb_info_t)); + return EINVAL; + } + } + + ret = drmModeAddFB2(drm_fd, fb_info->width, fb_info->height, + fb_info->format, fb_info->bo, fb_info->pitches, + fb_info->offsets, &fb_info->fb_id, 0); + if (ret) { + ALOGE("Could not create drm fb %d", ret); + memset(fb_info, 0, sizeof(drm_fb_info_t)); + return ret; + } + + return ret; +} + +int display_release_drm_fd(display_t *display, drm_fb_info_t *fb_info) +{ + int ret = 0; + int drm_fd = 0; + struct drm_gem_close close_args; + + if (!display || !fb_info) + return EINVAL; + + drm_fd = display->disp_link.ctx->drm_fd; + + if (fb_info->fb_id) { + if (drmModeRmFB(drm_fd, fb_info->fb_id)) { + ALOGE("Failed to remove drm fb"); + } + } + + memset(&close_args, 0, sizeof(struct drm_gem_close)); + /* currently we are only using one handle in our implementation + * so clean. ideally need to loop through the four handles and close + * each one of it. + */ + if (fb_info->bo[0]) { + close_args.handle = fb_info->bo[0]; + ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args); + if (ret) { + return ret; + } else { + memset(fb_info, 0, sizeof(drm_fb_info_t)); + + return 0; + } + } + return errno; +} + int update_display(omap_hwc_device_t *ctx, int disp, hwc_display_contents_1_t *list) { @@ -751,15 +873,13 @@ int update_display(omap_hwc_device_t *ctx, int disp, uint32_t nv12_bo[4] = { 0, 0 , 0 ,0}; drmModeFBPtr lastFBPtr; struct drm_gem_close close_args; - uint32_t handle; + drm_fb_info_t fb_info = { 0 }; + int fence_fd; display_t *display = ctx->displays[disp]; - kms_display_t *kdisp = &(ctx->displays[disp]->disp_link); - - display_t *disp_instance = ctx->displays[disp]; - hwc_display_contents_1_t *disp_data = disp_instance->contents; + kms_display_t *kdisp = &display->disp_link; - composition_t *comp = &disp_instance->composition; + composition_t *comp = &display->composition; struct drm_mode_set_plane *ovr = &comp->plane_info[0]; if (!kdisp->con) @@ -777,30 +897,26 @@ int update_display(omap_hwc_device_t *ctx, int disp, return -EINVAL; } - IMG_native_handle_t const *hnd; + buffer_handle_t hnd; if (ctx->blitter && ctx->displays[disp]->composition.use_blitter) { - hnd = - (IMG_native_handle_t const *)ctx->blitter->get_fb_handle(ctx->blitter, disp); + hnd = ctx->blitter->get_fb_handle(ctx->blitter, disp); } else { - hnd = (IMG_native_handle_t const *)(target->handle); + hnd = target->handle; if(target->acquireFenceFd > 0) { ret = sync_wait(target->acquireFenceFd, 1000); if (ret < 0) { ALOGE ("%s: sync_wait failed. errno: %d errstr = %s", __FUNCTION__, errno, strerror (errno)); + /* waited too long, need to exit maybe the previous flip + * failed causing this one to wait on the next flip + */ + return -EBUSY; } + close(target->acquireFenceFd); + target->acquireFenceFd = -1; } - target->releaseFenceFd = - timeline_create_fence(&display->retire_sync, - kdisp->is_crtc_set ? TWO_FLIP_EVENTS : ONE_FLIP_EVENT); } - /* we currently make no distinction between release and retire fences, - * and use a single fence to signal them. - */ - list->retireFenceFd = timeline_create_fence(&display->retire_sync, - kdisp->is_crtc_set? TWO_FLIP_EVENTS : ONE_FLIP_EVENT); - width = hnd->iWidth; - height = hnd->iHeight; + width = ((IMG_native_handle_t *)hnd)->iWidth; if (!(ctx->displays[disp]->composition.use_blitter)) { if( is_lcd_display(ctx, disp)) { @@ -808,21 +924,10 @@ int update_display(omap_hwc_device_t *ctx, int disp, } } - uint32_t bo[4] = { 0 }; - uint32_t pitch[4] = { width * 4}; //stride - uint32_t offset[4] = { 0 }; - - /*FIXME: Get gem handle from dma buf fd */ - ret = drmPrimeFDToHandle (ctx->drm_fd, hnd->fd[0], &bo[0]); - if (ret) { - ALOGE("Failed to get fd for DUMB buffer %s", strerror(errno)); - return ret; - } - - ret = drmModeAddFB2(ctx->drm_fd, width, height, DRM_FORMAT_ARGB8888, - bo, pitch, offset, &fb, 0); + ret = display_create_drm_fb(display, hnd, NULL, + &fb_info); if (ret) { - ALOGE("cannot create framebuffer (%d): %m\n",errno); + ALOGE("Failed to create fb"); return ret; } @@ -834,21 +939,53 @@ int update_display(omap_hwc_device_t *ctx, int disp, * FIXME: Should we move this someplace else? */ if (!kdisp->is_crtc_set) { - ret = drmModeSetCrtc(ctx->drm_fd, kdisp->crtc_id, fb, 0, 0, + ret = drmModeSetCrtc(ctx->drm_fd, kdisp->crtc_id, fb_info.fb_id, 0, 0, &kdisp->con->connector_id, 1, kdisp->mode); if (ret) { ALOGE("cannot set CRTC for connector %u (%d): %m\n", kdisp->con->connector_id, ret); return ret; } kdisp->is_crtc_set = true; + fence_fd = timeline_create_fence(&display->retire_sync, "hwc_retire_fence1", + ONE_FLIP_EVENT); + kdisp->fb_bufs.current = fb_info; + kdisp->fb_bufs.updated = false; + } else { - ret = drmModePageFlip(ctx->drm_fd, kdisp->crtc_id, fb, + fence_fd = timeline_create_fence(&display->retire_sync, "hwc_retire_fence2", + TWO_FLIP_EVENTS); + ret = drmModePageFlip(ctx->drm_fd, kdisp->crtc_id, fb_info.fb_id, DRM_MODE_PAGE_FLIP_EVENT, display); if (ret) { ALOGE("cannot flip on connector %d", kdisp->crtc_id); - goto fence_cleanup; + close(fence_fd); + fence_fd = -1; + goto fb_cleanup; } + kdisp->fb_bufs.next = fb_info; + kdisp->fb_bufs.updated = true; + } + + /* we scheduled flip, assign release and retire fences, currently we make + * no distinction between release and retire fences and they both get + * signaled at the same time. + * - Display retire fence + * - overlay layer release fence + * - fb target release fence + */ + list->retireFenceFd = dup(fence_fd); + for (i = 0; i < list->numHwLayers; i++) { + if (list->hwLayers[i].compositionType == HWC_OVERLAY) { + list->hwLayers[i].releaseFenceFd = dup(fence_fd); + } + } + if (comp->use_blitter) { + ctx->blitter->set_fb_fence(ctx->blitter, disp, dup(fence_fd)); + } else { + target->releaseFenceFd = dup(fence_fd); } + close(fence_fd); + fence_fd = -1; if ((kdisp->last_plane_fb != 0) && is_lcd_display(ctx, disp)) { @@ -860,7 +997,7 @@ int update_display(omap_hwc_device_t *ctx, int disp, ret = drmIoctl(ctx->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args); if(ret) { - ALOGE("Failed to release buffer handles: 0x%x 0x%x", + ALOGE("Failed to release buffer handles: 0x%x 0x%x", kdisp->last_plane_bo, kdisp->last_plane_fb, ret); return ret; } @@ -869,28 +1006,13 @@ int update_display(omap_hwc_device_t *ctx, int disp, kdisp->last_plane_fb = ovr->fb_id; kdisp->last_plane_bo = nv12_bo[0]; + return 0; - /* Clean up */ - if (kdisp->last_fb) { - lastFBPtr = drmModeGetFB(ctx->drm_fd, kdisp->last_fb); - handle = lastFBPtr->handle; - drmModeRmFB(ctx->drm_fd, kdisp->last_fb); - struct drm_gem_close close_args; - close_args.handle = handle; - ret = drmIoctl(ctx->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args); - if(ret) { - ALOGE("Failed to release buffer (Handle = 0x%x): %d\n", handle, ret); - return ret; - } - } - - kdisp->last_fb = fb; +fb_cleanup: + ret = display_release_drm_fd(display, &fb_info); + return ret; - return 0; fence_cleanup: - /* flip failed, release all the release and retire fences as they - * wont be signaled - */ for (i = 0; i < list->numHwLayers; i++) { hwc_layer_1_t *layer = &list->hwLayers[i]; if (layer->releaseFenceFd >= 0) { @@ -1492,10 +1614,8 @@ int set_nv12_planes(omap_hwc_device_t *hwc_dev, uint32_t *bo, uint32_t width, in __FUNCTION__, errno, strerror (errno)); } } - layer->releaseFenceFd = - timeline_create_fence(&display->retire_sync, TWO_FLIP_EVENTS); - ret = drmPrimeFDToHandle (hwc_dev->drm_fd, layer->handle->data[0], &bo[0]); + ret = drmPrimeFDToHandle (hwc_dev->drm_fd, layer->handle->data[0], &bo[0]); if (ret) { ALOGE("Failed to get fd for DUMB buffer 1 %s", strerror(errno)); goto fence_cleanup; diff --git a/hwcomposer/display.h b/hwcomposer/display.h index 52c8b05..d3a6a7d 100644 --- a/hwcomposer/display.h +++ b/hwcomposer/display.h @@ -134,12 +134,31 @@ struct composition { struct drm_mode_set_plane plane_info[4]; /* for now DRM only reserves */ /* vid1/vid2 as planes */ - + drmModePlane planes[4]; /* TODO: Rename to dss_pipeline_planes to */ - /* from the above drm plane info distinguish */ + /* from the above drm plane info distinguish */ }; typedef struct composition composition_t; +struct drm_fb_info { + uint32_t width; + uint32_t height; + uint32_t format; + uint32_t bo[4]; + uint32_t pitches[4]; + uint32_t offsets[4]; + uint32_t fb_id; + void *priv; +}; +typedef struct drm_fb_info drm_fb_info_t; + +struct fb_buffers { + drm_fb_info_t current; + drm_fb_info_t next; + bool updated; +}; +typedef struct fb_buffers fb_buffers_t; + typedef struct kms_display { drmModeConnectorPtr con; drmModeEncoderPtr enc; @@ -149,7 +168,8 @@ typedef struct kms_display { drmModeModeInfoPtr mode; drmEventContext evctx; drmModeFB fb; - uint32_t last_fb; + + fb_buffers_t fb_bufs; uint32_t last_plane_fb; uint32_t last_plane_bo; int vsync_on; @@ -271,7 +291,7 @@ int get_external_display_id(omap_hwc_device_t *hwc_dev); bool is_hdmi_display(omap_hwc_device_t *hwc_dev, int disp); bool is_external_display_mirroring(omap_hwc_device_t *hwc_dev, int disp); -int timeline_create_fence(timeline_info_t *timeline, unsigned relative); +int timeline_create_fence(timeline_info_t *timeline, const char *name, unsigned relative); void timeline_inc(timeline_info_t *timeline); #endif diff --git a/hwcomposer/hwc.c b/hwcomposer/hwc.c index e172f03..83e0d46 100644 --- a/hwcomposer/hwc.c +++ b/hwcomposer/hwc.c @@ -434,13 +434,6 @@ static int hwc_set_for_display(omap_hwc_device_t *hwc_dev, int disp, hwc_display ALOGE("%s(%d): blitter set retured error %d", __FUNCTION__, __LINE__, err); } - - fence_fd = timeline_create_fence(&display->retire_sync, 2); - for (i = 0; i < list->numHwLayers - 1; i++) { - hwc_layer_1_t *layer = &list->hwLayers[i]; - layer->releaseFenceFd = dup(fence_fd); - } - close(fence_fd); } } |