summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSunita Nadampalli <sunitan@ti.com>2016-05-13 09:44:12 -0500
committerGerrit Code Review <gerrit2@dlezvx23.ext.ti.com>2016-05-13 09:44:13 -0500
commit46087ebd56a4e2a32eb17f4aef2214badf19ec69 (patch)
tree95b9d4a0c7f87cbf670dbb90decfdc0d6bd7a143
parent81f801a391ecd74e13b8514c4e7c13a8ad71d31b (diff)
parentd836e7d8ddab3d043abdd1c42cf98eb25c8c91d9 (diff)
downloaddra7xx-46087ebd56a4e2a32eb17f4aef2214badf19ec69.tar.gz
Merge "hwc: create and release drm fb helper routines" into d-marshmallow-mr1-release
-rw-r--r--hwcomposer/blitter.h1
-rw-r--r--hwcomposer/display.c244
-rw-r--r--hwcomposer/display.h28
-rw-r--r--hwcomposer/hwc.c7
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);
}
}