summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hwcomposer/display.c256
-rw-r--r--hwcomposer/display.h12
-rw-r--r--hwcomposer/hwc.c87
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;