diff options
-rw-r--r-- | hwcomposer/display.c | 256 | ||||
-rw-r--r-- | hwcomposer/display.h | 12 | ||||
-rw-r--r-- | hwcomposer/hwc.c | 87 |
3 files changed, 205 insertions, 150 deletions
diff --git a/hwcomposer/display.c b/hwcomposer/display.c index fc6e594..38b56eb 100644 --- a/hwcomposer/display.c +++ b/hwcomposer/display.c @@ -140,6 +140,24 @@ static int crop_plane_to_rect(struct hwc_rect vis_rect, struct drm_mode_set_plan return 0; } +void reset_drm_plane(drm_plane_props_t *plane) +{ + plane->crtc_x = 0; + plane->crtc_y = 0; + plane->crtc_w = 0; + plane->crtc_h = 0; + + plane->src_x = 0; + plane->src_y = 0; + plane->src_w = 0; + plane->src_h = 0; + + plane->layer = NULL; + plane->fb_info = (const drm_fb_info_t){ 0 }; + plane->zorder = 0; + plane->pre_mult_alpha = 0; +} + void adjust_drm_plane_to_layer(hwc_layer_1_t const *layer, int zorder, drm_plane_props_t *plane) { @@ -167,6 +185,11 @@ void adjust_drm_plane_to_layer(hwc_layer_1_t const *layer, int zorder, plane->zorder = zorder; plane->layer = layer; + + if (layer->blending == HWC_BLENDING_PREMULT) + plane->pre_mult_alpha = 1; + else + plane->pre_mult_alpha = 0; } void adjust_drm_plane_to_display(omap_hwc_device_t *hwc_dev, int disp, struct drm_mode_set_plane *plane) @@ -251,40 +274,27 @@ bool can_dss_render_all_layers(omap_hwc_device_t *hwc_dev, int disp) bool support_bgr = is_lcd_display(hwc_dev, disp); bool tform = false; - return false; -#if 0 - return !hwc_dev->force_sgx && - /* Must have at least one layer if using composition bypass to get sync object */ - layer_stats->composable && - layer_stats->composable <= comp->avail_ovls && - layer_stats->composable == layer_stats->count && - layer_stats->scaled <= comp->scaling_ovls && - layer_stats->nv12 <= comp->scaling_ovls && - /* Fits into TILER slot */ - layer_stats->mem1d_total <= comp->tiler1d_slot_size && - /* We cannot clone non-NV12 transformed layers */ - (!tform || (layer_stats->nv12 == layer_stats->composable)) && - /* Only LCD can display BGR */ - (layer_stats->bgr == 0 || (layer_stats->rgb == 0 && - (support_bgr && !layer_stats->nv12)) || !hwc_dev->flags_rgb_order) && - /* If nv12_only flag is set DSS should only render NV12 */ - (!hwc_dev->flags_nv12_only || (layer_stats->bgr == 0 && layer_stats->rgb == 0)); -#endif + if (disp) + return false; + + if (layer_stats->count > comp->avail_ovls + 1) + return false; + + if (layer_stats->composable != layer_stats->count) + return false; + + if (!hwc_dev->force_sgx && + (layer_stats->scaled + layer_stats->nv12) <= comp->scaling_ovls) { + ALOGE("DSS can compose all layers"); + return true; + } + + return true; } bool can_dss_render_layer(omap_hwc_device_t *hwc_dev, int disp, hwc_layer_1_t *layer) { - display_t *display = hwc_dev->displays[disp]; - composition_t *comp = &display->composition; - bool tform = false; - - return is_composable_layer(hwc_dev, disp, layer) && - /* Cannot rotate non-NV12 layers on external display */ - (!tform || is_nv12_layer(layer)) && - /* Skip non-NV12 layers if also using SGX (if nv12_only flag is set) */ - (!hwc_dev->flags_nv12_only || (!comp->use_sgx || is_nv12_layer(layer))) && - /* Make sure RGB ordering is consistent (if rgb_order flag is set) */ - (!(comp->swap_rb ? is_rgb_layer(layer) : is_bgr_layer(layer)) || !hwc_dev->flags_rgb_order); + return is_composable_layer(hwc_dev, disp, layer); } @@ -545,17 +555,20 @@ static void page_flip_handler(int fd, unsigned frame, unsigned int sec, { display_t *display = (display_t *)data; kms_display_t *kdisp = &display->disp_link; + int i = 0; 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; + for (i = 0; i < DSS_AVAILABLE_PIPES; i++) { + if (kdisp->fb_bufs[i].updated) { + int ret = 0; + kdisp->fb_bufs[i].updated = false; + ret = display_release_drm_fd(display, &kdisp->fb_bufs[i].current); + kdisp->fb_bufs[i].current = kdisp->fb_bufs[i].next; + } } pthread_mutex_lock(&display->lock); @@ -693,6 +706,8 @@ int init_primary_display(omap_hwc_device_t *hwc_dev) display->mgr_ix = 0; display->blanked = true; + display_assign_pipes_for_composition(display, HWC_DISPLAY_PRIMARY); + display->retire_sync.timeline = sw_sync_timeline_create(); if (display->retire_sync.timeline == -1) { ALOGE("Failed to create sync timeline"); @@ -910,26 +925,87 @@ static int display_configure_pipes(display_t *display) kms_display_t *kdisp = &display->disp_link; composition_t *comp = &display->composition; omap_hwc_device_t *hwc_dev = kdisp->ctx; + uint32_t i = 0; if (!kdisp->is_crtc_set) return 0; - if (comp->plane_info[0].layer) { - drm_fb_info_t fb_info = { 0 }; - err = display_create_drm_fb(display, comp->plane_info[0].layer->handle, - (void *)&comp->plane_info[0], &fb_info); - if (err) { - ALOGE("Error create drm fb %d (%s)", err, strerror(err)); - return err; - } - err = drmModeAtomicAddProperty(kdisp->atomic_req, kdisp->plane_id, - 14, fb_info.fb_id); - /* This returns -EINVAL or -ENOMEM on error */ - if (err == -EINVAL || err == -ENOMEM) { - ALOGE("Failed to add property %d (%s)", errno, strerror(errno)); - return err; + for (i = 0; i < comp->used_ovls; i++) { + if (comp->plane_info[i].layer) { + drm_fb_info_t fb_info = { 0 }; + drm_plane_props_t *plane_info = &comp->plane_info[i]; + + ALOGE("Configuring pipe %d", i); + + err = display_create_drm_fb(display, plane_info->layer->handle, + (void *)plane_info, &fb_info); + if (err) { + ALOGE("Plane %d: Error in creating drm fb: %d (%s)", i, + err, strerror(err)); + return err; + } + err = drmModeAtomicAddProperty(kdisp->atomic_req, + plane_info->plane_id, 14, fb_info.fb_id); + /* This returns -EINVAL or -ENOMEM on error */ + if (err == -EINVAL || err == -ENOMEM) { + ALOGE("Failed to add property %d (%s)", errno, strerror(errno)); + return err; + } + plane_info->fb_info = fb_info; + ALOGE("Created drm fb for plane %d", i); + + /* region where the layer is displayed */ + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 10, plane_info->crtc_x); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting crtc_x"); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 11, plane_info->crtc_y); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting crtc_y"); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 12, plane_info->crtc_w); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting crtc_w"); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 13, plane_info->crtc_h); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting crtc_h"); + + /* region of the source to be displayed */ + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 6, plane_info->src_x << 16); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting src_x"); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 7, plane_info->src_y << 16); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting src_y"); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 8, plane_info->src_w << 16); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting src_w"); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 9, plane_info->src_h << 16); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting src_h"); + + /* z-order, blending, and rotation */ + ALOGE("Assigning zorder %d to plane %d", + plane_info->zorder, i); + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 24, plane_info->zorder); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting zorder"); + + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 26, comp->plane_info[i].pre_mult_alpha); + + err = drmModeAtomicAddProperty(kdisp->atomic_req, plane_info->plane_id, + 15, plane_info->crtc_id); + if (err == -EINVAL || err == -ENOMEM) + ALOGE("Failed setting crtc_id"); } - comp->plane_info[0].fb_info = fb_info; } return err; } @@ -939,11 +1015,7 @@ int update_display(omap_hwc_device_t *ctx, int disp, { int ret = 0; int i = 0; - int width = 0, height = 0; uint32_t fb = 0; - uint32_t nv12_bo[4] = { 0, 0 , 0 ,0}; - drmModeFBPtr lastFBPtr; - struct drm_gem_close close_args; drm_fb_info_t fb_info = { 0 }; int fence_fd; @@ -970,13 +1042,6 @@ int update_display(omap_hwc_device_t *ctx, int disp, close(target->acquireFenceFd); target->acquireFenceFd = -1; } - width = ((IMG_native_handle_t *)hnd)->iWidth; - - if (!(ctx->displays[disp]->composition.use_blitter)) { - if( is_lcd_display(ctx, disp)) { - //set_nv12_planes(ctx, &nv12_bo, width, disp); - } - } /* * On first up, we need to connect crtc to a connector and we do this by @@ -1015,8 +1080,8 @@ int update_display(omap_hwc_device_t *ctx, int disp, 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; + kdisp->fb_bufs[0].current = fb_info; + kdisp->fb_bufs[0].updated = false; } else { pthread_mutex_lock(&display->lock); @@ -1033,7 +1098,8 @@ int update_display(omap_hwc_device_t *ctx, int disp, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, display); if (ret) { - ALOGE("cannot do atomic commit on plane %d", kdisp->plane_id); + ALOGE("cannot do atomic commit %d (%s): %d", + errno, strerror(errno), ret); pthread_mutex_unlock(&display->lock); close(fence_fd); fence_fd = -1; @@ -1042,8 +1108,10 @@ int update_display(omap_hwc_device_t *ctx, int disp, drmModeAtomicFree(kdisp->atomic_req); - kdisp->fb_bufs.next = comp->plane_info[0].fb_info; - kdisp->fb_bufs.updated = true; + for (i = 0; i < DSS_AVAILABLE_PIPES; i++) { + kdisp->fb_bufs[i].next = comp->plane_info[i].fb_info; + kdisp->fb_bufs[i].updated = true; + } display->is_flip_pending = true; pthread_mutex_unlock(&display->lock); } @@ -1069,25 +1137,6 @@ int update_display(omap_hwc_device_t *ctx, int disp, close(fence_fd); fence_fd = -1; - if ((kdisp->last_plane_fb != 0) && is_lcd_display(ctx, disp)) - { - lastFBPtr = drmModeGetFB(ctx->drm_fd, kdisp->last_plane_fb); - drmModeRmFB(ctx->drm_fd, kdisp->last_plane_fb ); - close_args.handle = kdisp->last_plane_bo; - ret = drmIoctl(ctx->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args); - close_args.handle = lastFBPtr->handle; - ret = drmIoctl(ctx->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args); - - if(ret) { - ALOGE("Failed to release buffer handles: 0x%x 0x%x", - kdisp->last_plane_bo, kdisp->last_plane_fb, ret); - return ret; - } - } - - kdisp->last_plane_fb = ovr->fb_id; - kdisp->last_plane_bo = nv12_bo[0]; - return 0; fb_cleanup: @@ -1210,6 +1259,8 @@ int add_external_hdmi_display(omap_hwc_device_t *hwc_dev) display->mgr_ix = 1; display->blanked = true; + display_assign_pipes_for_composition(display, HWC_DISPLAY_EXTERNAL); + display->retire_sync.timeline = sw_sync_timeline_create(); if (display->retire_sync.timeline == -1) { ALOGE("Failed to create sync timeline"); @@ -1583,6 +1634,41 @@ void free_displays(omap_hwc_device_t *hwc_dev) free_display(hwc_dev->displays[i]); } +int display_assign_pipes_for_composition(display_t *display, int disp) +{ + int err = 0; + kms_display_t *kdisp = &display->disp_link; + composition_t *comp = &display->composition; + omap_hwc_device_t *hwc_dev = kdisp->ctx; + drmModePlaneRes *planes_res; + drmModePlanePtr plane; + int i = 0; + int count = 0; + uint32_t display_mask = 1 << disp; + + planes_res = drmModeGetPlaneResources(hwc_dev->drm_fd); + if (!planes_res) { + ALOGE("failed to get plane"); + return -EINVAL; + } + + for (i = 0; i < planes_res->count_planes; i++) { + plane = drmModeGetPlane(hwc_dev->drm_fd, planes_res->planes[i]); + + if (display_mask & plane->possible_crtcs) { + comp->plane_info[count].plane_id = plane->plane_id; + comp->plane_info[count].crtc_id = kdisp->crtc_id; + ALOGI("Display %d - Overlay %d: plane_id: %d crtc_id: %d", + disp, count, plane->plane_id, kdisp->crtc_id); + count++; + } + drmModeFreePlane(plane); + } + + drmModeFreePlaneResources(planes_res); + return 0; +} + int get_plane_resource(omap_hwc_device_t *hwc_dev, int disp) { int err = 0; diff --git a/hwcomposer/display.h b/hwcomposer/display.h index 634fcd4..fae2236 100644 --- a/hwcomposer/display.h +++ b/hwcomposer/display.h @@ -35,6 +35,9 @@ #define MAX_COMPOSITION_LAYERS MAX_COMPOSITION_BUFFERS #define HWC_DISPLAY_SECONDARY HWC_DISPLAY_EXTERNAL+1 +#define DSS_AVAILABLE_PIPES 4 +#define DSS_NONSCALING_PIPES 1 + /* Kludge * The MAX_DSS_OVERLAYS should be 4, as supported by DSS HW. * It has been reduced to 2 for the case when the primary display @@ -132,6 +135,7 @@ typedef struct drm_fb_info drm_fb_info_t; struct drm_plane_props { hwc_layer_1_t *layer; + uint32_t plane_id; uint32_t crtc_id; uint32_t crtc_x; uint32_t crtc_y; @@ -165,7 +169,7 @@ struct composition { uint32_t scaling_ovls; /* # of overlays available with scaling caps */ uint32_t used_ovls; /* # of overlays used in composition */ - drm_plane_props_t plane_info[4]; + drm_plane_props_t plane_info[DSS_AVAILABLE_PIPES]; drmModePlane planes[4]; /* TODO: Rename to dss_pipeline_planes to */ /* from the above drm plane info distinguish */ @@ -191,9 +195,7 @@ typedef struct kms_display { int plane_id; drmModeAtomicReqPtr atomic_req; - fb_buffers_t fb_bufs; - uint32_t last_plane_fb; - uint32_t last_plane_bo; + fb_buffers_t fb_bufs[DSS_AVAILABLE_PIPES]; int vsync_on; struct omap_hwc_device *ctx; } kms_display_t; @@ -312,6 +314,8 @@ bool can_dss_scale(omap_hwc_device_t *hwc_dev, uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h, bool is_2d, dss_platform_info_t *limits, uint32_t pclk); +int display_assign_pipes_for_composition(display_t *disp, int disp_index); + int add_external_hdmi_display(omap_hwc_device_t *hwc_dev); void remove_external_hdmi_display(omap_hwc_device_t *hwc_dev); int get_external_display_id(omap_hwc_device_t *hwc_dev); diff --git a/hwcomposer/hwc.c b/hwcomposer/hwc.c index d14ba79..d5c4845 100644 --- a/hwcomposer/hwc.c +++ b/hwcomposer/hwc.c @@ -82,76 +82,38 @@ static void showfps(void) static void reserve_overlays_for_displays(omap_hwc_device_t *hwc_dev) { display_t *primary_display = hwc_dev->displays[HWC_DISPLAY_PRIMARY]; - uint32_t ovl_ix_base = OMAP_DSS_GFX; - uint32_t max_overlays = MAX_DSS_OVERLAYS; - uint32_t num_nonscaling_overlays = NUM_NONSCALING_OVERLAYS; + display_t *hdmi_display = hwc_dev->displays[HWC_DISPLAY_EXTERNAL]; + composition_t *primary_comp = &primary_display->composition; + uint32_t max_pipes = DSS_AVAILABLE_PIPES; + uint32_t avail_gfx_pipes = DSS_NONSCALING_PIPES; - /* (see comment in display.h for MAX_DSS_OVERLAYS definition) - * If an external display is present, we allow for 4 overlays so - * that at least one overlay can be used for DSS composition of a - * single layer/plane. + /* TODO: omapdrm currently assigns GFX and VID1 pipes to primary and HDMI + * displays statically. Ideally we should be able to pick the pipe to + * the display as per the composition needs. */ - if (hwc_dev->displays[HWC_DISPLAY_EXTERNAL]) - max_overlays = 4; - - /* If FB is not same resolution as LCD don't use GFX overlay. */ if (primary_display->transform.scaling) { - ovl_ix_base = OMAP_DSS_VIDEO1; - max_overlays -= num_nonscaling_overlays; - num_nonscaling_overlays = 0; + ALOGE("Fatal error: scaling is not supported for primary display"); + exit(-1); } - /* - * We cannot atomically switch overlays from one display to another. First, they - * have to be disabled, and the disabling has to take effect on the current display. - * We keep track of the available number of overlays here. - */ - uint32_t max_primary_overlays = max_overlays - hwc_dev->last_ext_ovls; - uint32_t max_external_overlays = max_overlays - hwc_dev->last_int_ovls; - - composition_t *primary_comp = &primary_display->composition; - - primary_comp->tiler1d_slot_size = hwc_dev->tiler1d_slot_size; - primary_comp->ovl_ix_base = ovl_ix_base; - primary_comp->wanted_ovls = max_overlays; - primary_comp->avail_ovls = max_primary_overlays; - primary_comp->scaling_ovls = primary_comp->avail_ovls - num_nonscaling_overlays; - primary_comp->used_ovls = 0; + max_pipes -= 2; + avail_gfx_pipes = 0; - int ext_disp = get_external_display_id(hwc_dev); + primary_comp->ovl_ix_base = OMAP_DSS_GFX; + primary_comp->wanted_ovls = max_pipes; + primary_comp->avail_ovls = max_pipes; + primary_comp->scaling_ovls = max_pipes - avail_gfx_pipes; - if (ext_disp < 0) - return; - - display_t *ext_display = hwc_dev->displays[ext_disp]; - - /* - * For primary display we must reserve at least one overlay for FB, plus an extra - * overlay for each protected layer. - */ - layer_statistics_t *primary_layer_stats = &primary_display->layer_stats; - uint32_t min_primary_overlays = - MIN(1 + primary_layer_stats->protected, max_overlays); - - /* Share available overlays between primary and external displays. */ - primary_comp->wanted_ovls = MAX(max_overlays / 2, min_primary_overlays); - primary_comp->avail_ovls = MIN(max_primary_overlays, primary_comp->wanted_ovls); - - /* - * We may not have enough overlays on the external display. We "reserve" them here but - * may not do external composition for the first frame while the overlays required for - * it are cleared. - */ - composition_t *ext_comp = &ext_display->composition; - - ext_comp->tiler1d_slot_size = hwc_dev->tiler1d_slot_size; - ext_comp->wanted_ovls = max_overlays - primary_comp->wanted_ovls; - ext_comp->avail_ovls = MIN(max_external_overlays, ext_comp->wanted_ovls); - ext_comp->scaling_ovls = ext_comp->avail_ovls; - ext_comp->used_ovls = 0; - ext_comp->ovl_ix_base = MAX_DSS_OVERLAYS - ext_comp->avail_ovls; + /* Not enough overlays, no DSS composition on secondary display. */ + if (hdmi_display) { + composition_t *hdmi_comp = &hdmi_display->composition; + hdmi_comp->ovl_ix_base = OMAP_DSS_VIDEO1; + hdmi_comp->wanted_ovls = max_pipes; + hdmi_comp->avail_ovls = 0; + primary_comp->scaling_ovls = 0; + } } static void hwc_check_blitter_composition(omap_hwc_device_t *hwc_dev, int disp) @@ -196,6 +158,9 @@ static void hwc_check_dss_composition(omap_hwc_device_t *hwc_dev, int disp) if (list->numHwLayers == 1) return; + for (i = 0; i < 4; i++) + reset_drm_plane(&comp->plane_info[i]); + if (can_dss_render_all_layers(hwc_dev, disp)) { comp->use_dss = true; comp->use_sgx = false; |