2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2010-2011 LunarG Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 #define LOG_TAG "GRALLOC-KMS"
26 #include <cutils/properties.h>
27 #include <cutils/log.h>
33 #include "gralloc_drm.h"
34 #include "gralloc_drm_priv.h"
36 #include <drm_fourcc.h>
39 * Return true if a bo needs fb.
41 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
43 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
44 bo->drm->swap_mode != DRM_SWAP_COPY);
47 static unsigned int drm_format_from_hal(int hal_format)
50 case HAL_PIXEL_FORMAT_RGB_888:
51 case HAL_PIXEL_FORMAT_RGBX_8888:
52 case HAL_PIXEL_FORMAT_BGRA_8888:
53 return DRM_FORMAT_XRGB8888;
54 case HAL_PIXEL_FORMAT_RGBA_8888:
55 return DRM_FORMAT_RGBA8888;
56 case HAL_PIXEL_FORMAT_RGB_565:
57 return DRM_FORMAT_RGB565;
58 case HAL_PIXEL_FORMAT_YV12:
59 return DRM_FORMAT_YUV420;
66 * Modify pitches, offsets and handles according to
67 * the format and return corresponding drm format value
69 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
70 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
72 memset(pitches, 0, 4 * sizeof(uint32_t));
73 memset(offsets, 0, 4 * sizeof(uint32_t));
74 memset(handles, 0, 4 * sizeof(uint32_t));
76 pitches[0] = bo->handle->stride;
77 handles[0] = bo->fb_handle;
79 int format = drm_format_from_hal(bo->handle->format);
81 // handle 'special formats'
82 switch(bo->handle->format) {
83 case HAL_PIXEL_FORMAT_YV12:
85 // U and V stride are half of Y plane
86 pitches[2] = pitches[0]/2;
87 pitches[1] = pitches[0]/2;
89 // like I420 but U and V are in reverse order
90 offsets[2] = offsets[0] +
91 pitches[0] * bo->handle->height;
92 offsets[1] = offsets[2] +
93 pitches[2] * bo->handle->height/2;
95 handles[1] = handles[2] = handles[0];
101 * Add a fb object for a bo.
103 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
112 int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
114 if (drm_format == 0) {
115 ALOGE("error resolving drm format");
119 return drmModeAddFB2(bo->drm->fd,
120 bo->handle->width, bo->handle->height,
121 drm_format, handles, pitches, offsets,
122 (uint32_t *) &bo->fb_id, 0);
126 * Remove a fb object for a bo.
128 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
131 drmModeRmFB(bo->drm->fd, bo->fb_id);
139 static int drm_kms_set_crtc(struct gralloc_drm_t *drm, int fb_id)
143 ret = drmModeSetCrtc(drm->fd, drm->crtc_id, fb_id,
144 0, 0, &drm->connector_id, 1, &drm->mode);
146 ALOGE("failed to set crtc");
150 if (drm->mode_quirk_vmwgfx)
151 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
157 * Callback for a page flip event.
159 static void page_flip_handler(int fd, unsigned int sequence,
160 unsigned int tv_sec, unsigned int tv_usec,
163 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
165 /* ack the last scheduled flip */
166 drm->current_front = drm->next_front;
167 drm->next_front = NULL;
171 * Schedule a page flip.
173 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
174 struct gralloc_drm_bo_t *bo)
178 /* there is another flip pending */
179 while (drm->next_front) {
180 drm->waiting_flip = 1;
181 drmHandleEvent(drm->fd, &drm->evctx);
182 drm->waiting_flip = 0;
183 if (drm->next_front) {
184 /* record an error and break */
185 ALOGE("drmHandleEvent returned without flipping");
186 drm->current_front = drm->next_front;
187 drm->next_front = NULL;
194 ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id,
195 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
197 ALOGE("failed to perform page flip");
199 drm->next_front = bo;
205 * Wait for the next post.
207 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
209 unsigned int current, target;
213 if (drm->mode_quirk_vmwgfx)
218 memset(&vbl, 0, sizeof(vbl));
219 vbl.request.type = DRM_VBLANK_RELATIVE;
220 if (drm->vblank_secondary)
221 vbl.request.type |= DRM_VBLANK_SECONDARY;
222 vbl.request.sequence = 0;
224 /* get the current vblank */
225 ret = drmWaitVBlank(drm->fd, &vbl);
227 ALOGW("failed to get vblank");
231 current = vbl.reply.sequence;
235 target = drm->last_swap + drm->swap_interval - flip;
237 /* wait for vblank */
238 if (current < target || !flip) {
239 memset(&vbl, 0, sizeof(vbl));
240 vbl.request.type = DRM_VBLANK_ABSOLUTE;
241 if (drm->vblank_secondary)
242 vbl.request.type |= DRM_VBLANK_SECONDARY;
244 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
245 if (target < current)
249 vbl.request.sequence = target;
251 ret = drmWaitVBlank(drm->fd, &vbl);
253 ALOGW("failed to wait vblank");
258 drm->last_swap = vbl.reply.sequence + flip;
262 * Post a bo. This is not thread-safe.
264 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
266 struct gralloc_drm_t *drm = bo->drm;
269 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
270 ALOGE("unable to post bo %p without fb", bo);
274 /* TODO spawn a thread to avoid waiting and race */
276 if (drm->first_post) {
277 if (drm->swap_mode == DRM_SWAP_COPY) {
278 struct gralloc_drm_bo_t *dst;
280 dst = (drm->next_front) ?
283 drm->drv->copy(drm->drv, dst, bo, 0, 0,
289 ret = drm_kms_set_crtc(drm, bo->fb_id);
292 drm->current_front = bo;
293 if (drm->next_front == bo)
294 drm->next_front = NULL;
300 switch (drm->swap_mode) {
302 if (drm->swap_interval > 1)
303 drm_kms_wait_for_post(drm, 1);
304 ret = drm_kms_page_flip(drm, bo);
305 if (drm->next_front) {
307 * wait if the driver says so or the current front
308 * will be written by CPU
310 if (drm->mode_sync_flip ||
311 (drm->current_front->handle->usage &
312 GRALLOC_USAGE_SW_WRITE_MASK))
313 drm_kms_page_flip(drm, NULL);
317 drm_kms_wait_for_post(drm, 0);
318 drm->drv->copy(drm->drv, drm->current_front,
322 if (drm->mode_quirk_vmwgfx)
323 ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
326 case DRM_SWAP_SETCRTC:
327 drm_kms_wait_for_post(drm, 0);
328 ret = drm_kms_set_crtc(drm, bo->fb_id);
329 drm->current_front = bo;
340 static struct gralloc_drm_t *drm_singleton;
342 static void on_signal(int sig)
344 struct gralloc_drm_t *drm = drm_singleton;
346 /* wait the pending flip */
347 if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
348 /* there is race, but this function is hacky enough to ignore that */
349 if (drm_singleton->waiting_flip)
350 usleep(100 * 1000); /* 100ms */
352 drm_kms_page_flip(drm_singleton, NULL);
358 static void drm_kms_init_features(struct gralloc_drm_t *drm)
360 const char *swap_mode;
362 /* call to the driver here, after KMS has been initialized */
363 drm->drv->init_kms_features(drm->drv, drm);
365 if (drm->swap_mode == DRM_SWAP_FLIP) {
366 struct sigaction act;
368 memset(&drm->evctx, 0, sizeof(drm->evctx));
369 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
370 drm->evctx.page_flip_handler = page_flip_handler;
373 * XXX GPU tends to freeze if the program is terminiated with a
374 * flip pending. What is the right way to handle the
377 sigemptyset(&act.sa_mask);
378 act.sa_handler = on_signal;
380 sigaction(SIGINT, &act, NULL);
381 sigaction(SIGTERM, &act, NULL);
385 else if (drm->swap_mode == DRM_SWAP_COPY) {
386 struct gralloc_drm_bo_t *front;
389 /* create the real front buffer */
390 front = gralloc_drm_bo_create(drm,
394 GRALLOC_USAGE_HW_FB);
395 if (front && gralloc_drm_bo_add_fb(front)) {
396 gralloc_drm_bo_decref(front);
400 /* abuse next_front */
402 drm->next_front = front;
404 drm->swap_mode = DRM_SWAP_SETCRTC;
407 switch (drm->swap_mode) {
414 case DRM_SWAP_SETCRTC:
415 swap_mode = "set-crtc";
422 ALOGD("will use %s for fb posting", swap_mode);
425 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
427 char value[PROPERTY_VALUE_MAX];
428 drmModeModeInfoPtr mode;
430 int xres = 0, yres = 0;
432 if (property_get("debug.drm.mode", value, NULL)) {
433 char *p = value, *end;
435 /* parse <xres>x<yres>[@<bpp>] */
436 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
438 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
442 if ((xres && yres) || *bpp) {
443 ALOGI("will find the closest match for %dx%d@%d",
453 for (i = 0; i < connector->count_modes; i++) {
454 drmModeModeInfoPtr m = &connector->modes[i];
458 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
459 (m->vdisplay - yres) * (m->vdisplay - yres);
462 /* use the first preferred mode */
463 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
474 /* fallback to the first mode */
476 mode = &connector->modes[0];
484 * Initialize KMS with a connector.
486 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
487 drmModeConnectorPtr connector)
489 drmModeEncoderPtr encoder;
490 drmModeModeInfoPtr mode;
493 if (!connector->count_modes)
496 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
500 for (i = 0; i < drm->resources->count_crtcs; i++) {
501 if (encoder->possible_crtcs & (1 << i))
504 drmModeFreeEncoder(encoder);
505 if (i == drm->resources->count_crtcs)
508 drm->crtc_id = drm->resources->crtcs[i];
509 drm->connector_id = connector->connector_id;
511 /* print connector info */
512 if (connector->count_modes > 1) {
513 ALOGI("there are %d modes on connector 0x%x",
514 connector->count_modes,
515 connector->connector_id);
516 for (i = 0; i < connector->count_modes; i++)
517 ALOGI(" %s", connector->modes[i].name);
520 ALOGI("there is one mode on connector 0x%d: %s",
521 connector->connector_id,
522 connector->modes[0].name);
525 mode = find_mode(connector, &bpp);
527 ALOGI("the best mode is %s", mode->name);
532 drm->fb_format = HAL_PIXEL_FORMAT_RGB_565;
536 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
540 if (connector->mmWidth && connector->mmHeight) {
541 drm->xdpi = (drm->mode.hdisplay * 25.4 / connector->mmWidth);
542 drm->ydpi = (drm->mode.vdisplay * 25.4 / connector->mmHeight);
549 #ifdef DRM_MODE_FEATURE_DIRTYFB
552 drm->clip.x2 = drm->mode.hdisplay;
553 drm->clip.y2 = drm->mode.vdisplay;
562 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
569 drm->resources = drmModeGetResources(drm->fd);
570 if (!drm->resources) {
571 ALOGE("failed to get modeset resources");
575 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
576 if (!drm->plane_resources) {
577 ALOGD("no planes found from drm resources");
579 ALOGD("supported drm planes and formats");
580 /* fill a helper structure for hwcomposer */
581 drm->planes = calloc(drm->plane_resources->count_planes,
582 sizeof(struct gralloc_drm_plane_t));
584 for (i = 0; i < drm->plane_resources->count_planes; i++) {
588 drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
589 drm->plane_resources->planes[i]);
591 ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
592 for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
593 ALOGD(" format %c%c%c%c",
594 (drm->planes[i].drm_plane->formats[j]),
595 (drm->planes[i].drm_plane->formats[j])>>8,
596 (drm->planes[i].drm_plane->formats[j])>>16,
597 (drm->planes[i].drm_plane->formats[j])>>24);
601 /* find the crtc/connector/mode to use */
602 for (i = 0; i < drm->resources->count_connectors; i++) {
603 drmModeConnectorPtr connector;
605 connector = drmModeGetConnector(drm->fd,
606 drm->resources->connectors[i]);
608 if (connector->connection == DRM_MODE_CONNECTED) {
609 if (!drm_kms_init_with_connector(drm,
614 drmModeFreeConnector(connector);
617 if (i == drm->resources->count_connectors) {
618 ALOGE("failed to find a valid crtc/connector/mode combination");
619 drmModeFreeResources(drm->resources);
620 drm->resources = NULL;
625 drm_kms_init_features(drm);
631 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
633 switch (drm->swap_mode) {
635 drm_kms_page_flip(drm, NULL);
639 struct gralloc_drm_bo_t **bo = (drm->current_front) ?
640 &drm->current_front : &drm->next_front;
643 gralloc_drm_bo_decref(*bo);
653 if (drm->resources) {
654 drmModeFreeResources(drm->resources);
655 drm->resources = NULL;
660 for (i = 0; i < drm->plane_resources->count_planes; i++)
661 drmModeFreePlane(drm->planes[i].drm_plane);
666 if (drm->plane_resources) {
667 drmModeFreePlaneResources(drm->plane_resources);
668 drm->plane_resources = NULL;
671 drm_singleton = NULL;
674 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
676 return (drm->resources != NULL);
680 * Initialize a framebuffer device with KMS info.
682 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
683 struct framebuffer_device_t *fb)
685 *((uint32_t *) &fb->flags) = 0x0;
686 *((uint32_t *) &fb->width) = drm->mode.hdisplay;
687 *((uint32_t *) &fb->height) = drm->mode.vdisplay;
688 *((int *) &fb->stride) = drm->mode.hdisplay;
689 *((float *) &fb->fps) = drm->mode.vrefresh;
691 *((int *) &fb->format) = drm->fb_format;
692 *((float *) &fb->xdpi) = drm->xdpi;
693 *((float *) &fb->ydpi) = drm->ydpi;
694 *((int *) &fb->minSwapInterval) = drm->swap_interval;
695 *((int *) &fb->maxSwapInterval) = drm->swap_interval;
699 * Return true if fb posting is pipelined.
701 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
703 return (drm->swap_mode != DRM_SWAP_SETCRTC);