OSDN Git Service

gralloc: introduce planeresources
[android-x86/external-drm_gralloc.git] / gralloc_drm_kms.c
index 77115b3..2d9bca1 100644 (file)
@@ -33,6 +33,8 @@
 #include "gralloc_drm.h"
 #include "gralloc_drm_priv.h"
 
+#include <drm_fourcc.h>
+
 /*
  * Return true if a bo needs fb.
  */
@@ -43,21 +45,72 @@ int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
 }
 
 /*
+ * Modify pitches, offsets and handles according to
+ * the format and return corresponding drm format value
+ */
+static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
+       uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
+{
+       memset(pitches, 0, 4 * sizeof(uint32_t));
+       memset(offsets, 0, 4 * sizeof(uint32_t));
+       memset(handles, 0, 4 * sizeof(uint32_t));
+
+       pitches[0] = bo->handle->stride;
+       handles[0] = bo->fb_handle;
+
+       switch(bo->handle->format) {
+               case HAL_PIXEL_FORMAT_RGB_888:
+               case HAL_PIXEL_FORMAT_RGBX_8888:
+               case HAL_PIXEL_FORMAT_BGRA_8888:
+                       return DRM_FORMAT_ARGB8888;
+               case HAL_PIXEL_FORMAT_RGBA_8888:
+                       return DRM_FORMAT_RGBA8888;
+               case HAL_PIXEL_FORMAT_RGB_565:
+                       return DRM_FORMAT_RGB565;
+               case HAL_PIXEL_FORMAT_YV12:
+
+                       // U and V stride are half of Y plane
+                       pitches[2] = pitches[0]/2;
+                       pitches[1] = pitches[0]/2;
+
+                       // like I420 but U and V are in reverse order
+                       offsets[2] = offsets[0] +
+                               pitches[0] * bo->handle->height;
+                       offsets[1] = offsets[2] +
+                               pitches[2] * bo->handle->height/2;
+
+                       handles[1] = handles[2] = handles[0];
+
+                       return DRM_FORMAT_YUV420;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+
+/*
  * Add a fb object for a bo.
  */
 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
 {
-       uint8_t bpp;
+       uint32_t pitches[4];
+       uint32_t offsets[4];
+       uint32_t handles[4];
 
        if (bo->fb_id)
                return 0;
 
-       bpp = gralloc_drm_get_bpp(bo->handle->format) * 8;
+       int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
 
-       return drmModeAddFB(bo->drm->fd,
-                       bo->handle->width, bo->handle->height, bpp, bpp,
-                       bo->handle->stride, bo->fb_handle,
-                       (uint32_t *) &bo->fb_id);
+       if (drm_format == 0) {
+               ALOGE("error resolving drm format");
+               return -EINVAL;
+       }
+
+       return drmModeAddFB2(bo->drm->fd,
+               bo->handle->width, bo->handle->height,
+               drm_format, handles, pitches, offsets,
+               (uint32_t *) &bo->fb_id, 0);
 }
 
 /*
@@ -81,14 +134,12 @@ static int drm_kms_set_crtc(struct gralloc_drm_t *drm, int fb_id)
        ret = drmModeSetCrtc(drm->fd, drm->crtc_id, fb_id,
                        0, 0, &drm->connector_id, 1, &drm->mode);
        if (ret) {
-               LOGE("failed to set crtc");
+               ALOGE("failed to set crtc");
                return ret;
        }
 
-#ifdef DRM_MODE_FEATURE_DIRTYFB
-       if (drm->mode_dirty_fb)
+       if (drm->mode_quirk_vmwgfx)
                ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
-#endif
 
        return ret;
 }
@@ -122,7 +173,7 @@ static int drm_kms_page_flip(struct gralloc_drm_t *drm,
                drm->waiting_flip = 0;
                if (drm->next_front) {
                        /* record an error and break */
-                       LOGE("drmHandleEvent returned without flipping");
+                       ALOGE("drmHandleEvent returned without flipping");
                        drm->current_front = drm->next_front;
                        drm->next_front = NULL;
                }
@@ -134,7 +185,7 @@ static int drm_kms_page_flip(struct gralloc_drm_t *drm,
        ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id,
                        DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
        if (ret)
-               LOGE("failed to perform page flip");
+               ALOGE("failed to perform page flip");
        else
                drm->next_front = bo;
 
@@ -150,6 +201,9 @@ static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
        drmVBlank vbl;
        int ret;
 
+       if (drm->mode_quirk_vmwgfx)
+               return;
+
        flip = !!flip;
 
        memset(&vbl, 0, sizeof(vbl));
@@ -161,7 +215,7 @@ static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
        /* get the current vblank */
        ret = drmWaitVBlank(drm->fd, &vbl);
        if (ret) {
-               LOGW("failed to get vblank");
+               ALOGW("failed to get vblank");
                return;
        }
 
@@ -187,7 +241,7 @@ static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
 
                ret = drmWaitVBlank(drm->fd, &vbl);
                if (ret) {
-                       LOGW("failed to wait vblank");
+                       ALOGW("failed to wait vblank");
                        return;
                }
        }
@@ -204,7 +258,7 @@ int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
        int ret;
 
        if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
-               LOGE("unable to post bo %p without fb", bo);
+               ALOGE("unable to post bo %p without fb", bo);
                return -EINVAL;
        }
 
@@ -223,7 +277,6 @@ int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
                        bo = dst;
                }
 
-               drm_kms_wait_for_post(drm, 0);
                ret = drm_kms_set_crtc(drm, bo->fb_id);
                if (!ret) {
                        drm->first_post = 0;
@@ -257,6 +310,8 @@ int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
                                bo, 0, 0,
                                bo->handle->width,
                                bo->handle->height);
+               if (drm->mode_quirk_vmwgfx)
+                       ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
                ret = 0;
                break;
        case DRM_SWAP_SETCRTC:
@@ -277,18 +332,18 @@ static struct gralloc_drm_t *drm_singleton;
 
 static void on_signal(int sig)
 {
-   struct sigaction act;
-
-   /* wait the pending flip */
-   if (drm_singleton && drm_singleton->next_front) {
-      /* there is race, but this function is hacky enough to ignore that */
-      if (drm_singleton->waiting_flip)
-         usleep(100 * 1000); /* 100ms */
-      else
-         drm_kms_page_flip(drm_singleton, NULL);
-   }
-
-   exit(-1);
+       struct gralloc_drm_t *drm = drm_singleton;
+
+       /* wait the pending flip */
+       if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
+               /* there is race, but this function is hacky enough to ignore that */
+               if (drm_singleton->waiting_flip)
+                       usleep(100 * 1000); /* 100ms */
+               else
+                       drm_kms_page_flip(drm_singleton, NULL);
+       }
+
+       exit(-1);
 }
 
 static void drm_kms_init_features(struct gralloc_drm_t *drm)
@@ -329,7 +384,7 @@ static void drm_kms_init_features(struct gralloc_drm_t *drm)
                                              drm->fb_format,
                                              GRALLOC_USAGE_HW_FB);
                if (front && gralloc_drm_bo_add_fb(front)) {
-                       gralloc_drm_bo_destroy(front);
+                       gralloc_drm_bo_decref(front);
                        front = NULL;
                }
 
@@ -355,7 +410,7 @@ static void drm_kms_init_features(struct gralloc_drm_t *drm)
                break;
        }
 
-       LOGD("will use %s for fb posting", swap_mode);
+       ALOGD("will use %s for fb posting", swap_mode);
 }
 
 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
@@ -374,6 +429,11 @@ static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
                        if (sscanf(value, "%dx%d", &xres, &yres) != 2)
                                xres = yres = 0;
                }
+
+               if ((xres && yres) || *bpp) {
+                       ALOGI("will find the closest match for %dx%d@%d",
+                                       xres, yres, *bpp);
+               }
        }
        else {
                *bpp = 0;
@@ -439,7 +499,24 @@ static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
        drm->crtc_id = drm->resources->crtcs[i];
        drm->connector_id = connector->connector_id;
 
+       /* print connector info */
+       if (connector->count_modes > 1) {
+               ALOGI("there are %d modes on connector 0x%x",
+                               connector->count_modes,
+                               connector->connector_id);
+               for (i = 0; i < connector->count_modes; i++)
+                       ALOGI("  %s", connector->modes[i].name);
+       }
+       else {
+               ALOGI("there is one mode on connector 0x%d: %s",
+                               connector->connector_id,
+                               connector->modes[0].name);
+       }
+
        mode = find_mode(connector, &bpp);
+
+       ALOGI("the best mode is %s", mode->name);
+
        drm->mode = *mode;
        switch (bpp) {
        case 2:
@@ -482,10 +559,36 @@ int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
 
        drm->resources = drmModeGetResources(drm->fd);
        if (!drm->resources) {
-               LOGE("failed to get modeset resources");
+               ALOGE("failed to get modeset resources");
                return -EINVAL;
        }
 
+       drm->plane_resources = drmModeGetPlaneResources(drm->fd);
+       if (!drm->plane_resources) {
+               ALOGD("no planes found from drm resources");
+       } else {
+               ALOGD("supported drm planes and formats");
+               /* fill a helper structure for hwcomposer */
+               drm->planes = calloc(drm->plane_resources->count_planes,
+                       sizeof(struct gralloc_drm_plane_t));
+
+               for (i = 0; i < drm->plane_resources->count_planes; i++) {
+
+                       unsigned int j;
+
+                       drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
+                               drm->plane_resources->planes[i]);
+
+                       ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
+                       for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
+                               ALOGD("    format %c%c%c%c",
+                                       (drm->planes[i].drm_plane->formats[j]),
+                                       (drm->planes[i].drm_plane->formats[j])>>8,
+                                       (drm->planes[i].drm_plane->formats[j])>>16,
+                                       (drm->planes[i].drm_plane->formats[j])>>24);
+               }
+       }
+
        /* find the crtc/connector/mode to use */
        for (i = 0; i < drm->resources->count_connectors; i++) {
                drmModeConnectorPtr connector;
@@ -503,7 +606,7 @@ int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
                }
        }
        if (i == drm->resources->count_connectors) {
-               LOGE("failed to find a valid crtc/connector/mode combination");
+               ALOGE("failed to find a valid crtc/connector/mode combination");
                drmModeFreeResources(drm->resources);
                drm->resources = NULL;
 
@@ -516,6 +619,54 @@ int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
        return 0;
 }
 
+void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
+{
+       switch (drm->swap_mode) {
+       case DRM_SWAP_FLIP:
+               drm_kms_page_flip(drm, NULL);
+               break;
+       case DRM_SWAP_COPY:
+               {
+                       struct gralloc_drm_bo_t **bo = (drm->current_front) ?
+                               &drm->current_front : &drm->next_front;
+
+                       if (*bo)
+                               gralloc_drm_bo_decref(*bo);
+                       *bo = NULL;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* restore crtc? */
+
+       if (drm->resources) {
+               drmModeFreeResources(drm->resources);
+               drm->resources = NULL;
+       }
+
+       if (drm->planes) {
+               unsigned int i;
+               for (i = 0; i < drm->plane_resources->count_planes; i++)
+                       drmModeFreePlane(drm->planes[i].drm_plane);
+               free(drm->planes);
+               drm->planes = NULL;
+       }
+
+       if (drm->plane_resources) {
+               drmModeFreePlaneResources(drm->plane_resources);
+               drm->plane_resources = NULL;
+       }
+
+       drm_singleton = NULL;
+}
+
+int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
+{
+       return (drm->resources != NULL);
+}
+
 /*
  * Initialize a framebuffer device with KMS info.
  */