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>
34 #include "gralloc_drm.h"
35 #include "gralloc_drm_priv.h"
36 #include <hardware_legacy/uevent.h>
38 #include <drm_fourcc.h>
41 * Return true if a bo needs fb.
43 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
45 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
46 bo->drm->swap_mode != DRM_SWAP_COPY);
49 static unsigned int drm_format_from_hal(int hal_format)
52 case HAL_PIXEL_FORMAT_RGB_888:
53 case HAL_PIXEL_FORMAT_RGBX_8888:
54 case HAL_PIXEL_FORMAT_BGRA_8888:
55 return DRM_FORMAT_XRGB8888;
56 case HAL_PIXEL_FORMAT_RGBA_8888:
57 return DRM_FORMAT_RGBA8888;
58 case HAL_PIXEL_FORMAT_RGB_565:
59 return DRM_FORMAT_RGB565;
60 case HAL_PIXEL_FORMAT_YV12:
61 return DRM_FORMAT_YUV420;
62 case HAL_PIXEL_FORMAT_DRM_NV12:
63 return DRM_FORMAT_NV12;
70 * Modify pitches, offsets and handles according to
71 * the format and return corresponding drm format value
73 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
74 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
76 memset(pitches, 0, 4 * sizeof(uint32_t));
77 memset(offsets, 0, 4 * sizeof(uint32_t));
78 memset(handles, 0, 4 * sizeof(uint32_t));
80 pitches[0] = bo->handle->stride;
81 handles[0] = bo->fb_handle;
83 int format = drm_format_from_hal(bo->handle->format);
85 // handle 'special formats'
86 switch(bo->handle->format) {
87 case HAL_PIXEL_FORMAT_YV12:
89 // U and V stride are half of Y plane
90 pitches[2] = pitches[0]/2;
91 pitches[1] = pitches[0]/2;
93 // like I420 but U and V are in reverse order
94 offsets[2] = offsets[0] +
95 pitches[0] * bo->handle->height;
96 offsets[1] = offsets[2] +
97 pitches[2] * bo->handle->height/2;
99 handles[1] = handles[2] = handles[0];
102 case HAL_PIXEL_FORMAT_DRM_NV12:
104 // U and V are interleaved in 2nd plane
105 pitches[1] = pitches[0];
106 offsets[1] = offsets[0] +
107 pitches[0] * bo->handle->height;
108 handles[1] = handles[0];
115 * Add a fb object for a bo.
117 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
126 int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
128 if (drm_format == 0) {
129 ALOGE("error resolving drm format");
133 return drmModeAddFB2(bo->drm->fd,
134 bo->handle->width, bo->handle->height,
135 drm_format, handles, pitches, offsets,
136 (uint32_t *) &bo->fb_id, 0);
140 * Remove a fb object for a bo.
142 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
145 drmModeRmFB(bo->drm->fd, bo->fb_id);
153 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
154 struct gralloc_drm_output *output, int fb_id)
158 ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
159 0, 0, &output->connector_id, 1, &output->mode);
161 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
162 strerror(errno), output->crtc_id, fb_id, output->connector_id,
163 output->mode.hdisplay, output->mode.vdisplay);
167 if (drm->mode_quirk_vmwgfx)
168 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
174 * Callback for a page flip event.
176 static void page_flip_handler(int fd, unsigned int sequence,
177 unsigned int tv_sec, unsigned int tv_usec,
180 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
182 /* ack the last scheduled flip */
183 drm->current_front = drm->next_front;
184 drm->next_front = NULL;
188 * Schedule a page flip.
190 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
191 struct gralloc_drm_bo_t *bo)
195 /* there is another flip pending */
196 while (drm->next_front) {
197 drm->waiting_flip = 1;
198 drmHandleEvent(drm->fd, &drm->evctx);
199 drm->waiting_flip = 0;
200 if (drm->next_front) {
201 /* record an error and break */
202 ALOGE("drmHandleEvent returned without flipping");
203 drm->current_front = drm->next_front;
204 drm->next_front = NULL;
211 pthread_mutex_lock(&drm->hdmi_mutex);
212 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED) {
213 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, bo->fb_id, 0, NULL);
214 if (ret && errno != EBUSY)
215 ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
216 strerror(errno), drm->hdmi.crtc_id, bo->fb_id);
218 pthread_mutex_unlock(&drm->hdmi_mutex);
220 ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
221 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
223 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
224 strerror(errno), drm->primary.crtc_id, bo->fb_id);
225 /* try to set mode for next frame */
230 drm->next_front = bo;
236 * Wait for the next post.
238 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
240 unsigned int current, target;
244 if (drm->mode_quirk_vmwgfx)
249 memset(&vbl, 0, sizeof(vbl));
250 vbl.request.type = DRM_VBLANK_RELATIVE;
251 if (drm->vblank_secondary)
252 vbl.request.type |= DRM_VBLANK_SECONDARY;
253 vbl.request.sequence = 0;
255 /* get the current vblank */
256 ret = drmWaitVBlank(drm->fd, &vbl);
258 ALOGW("failed to get vblank");
262 current = vbl.reply.sequence;
266 target = drm->last_swap + drm->swap_interval - flip;
268 /* wait for vblank */
269 if (current < target || !flip) {
270 memset(&vbl, 0, sizeof(vbl));
271 vbl.request.type = DRM_VBLANK_ABSOLUTE;
272 if (drm->vblank_secondary)
273 vbl.request.type |= DRM_VBLANK_SECONDARY;
275 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
276 if (target < current)
280 vbl.request.sequence = target;
282 ret = drmWaitVBlank(drm->fd, &vbl);
284 ALOGW("failed to wait vblank");
289 drm->last_swap = vbl.reply.sequence + flip;
293 * Post a bo. This is not thread-safe.
295 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
297 struct gralloc_drm_t *drm = bo->drm;
300 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
301 ALOGE("unable to post bo %p without fb", bo);
305 /* TODO spawn a thread to avoid waiting and race */
307 if (drm->first_post) {
308 if (drm->swap_mode == DRM_SWAP_COPY) {
309 struct gralloc_drm_bo_t *dst;
311 dst = (drm->next_front) ?
314 drm->drv->copy(drm->drv, dst, bo, 0, 0,
320 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
323 drm->current_front = bo;
324 if (drm->next_front == bo)
325 drm->next_front = NULL;
328 pthread_mutex_lock(&drm->hdmi_mutex);
329 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED)
330 drm_kms_set_crtc(drm, &drm->hdmi, bo->fb_id);
331 pthread_mutex_unlock(&drm->hdmi_mutex);
336 switch (drm->swap_mode) {
338 if (drm->swap_interval > 1)
339 drm_kms_wait_for_post(drm, 1);
340 ret = drm_kms_page_flip(drm, bo);
341 if (drm->next_front) {
343 * wait if the driver says so or the current front
344 * will be written by CPU
346 if (drm->mode_sync_flip ||
347 (drm->current_front->handle->usage &
348 GRALLOC_USAGE_SW_WRITE_MASK))
349 drm_kms_page_flip(drm, NULL);
353 drm_kms_wait_for_post(drm, 0);
354 drm->drv->copy(drm->drv, drm->current_front,
358 if (drm->mode_quirk_vmwgfx)
359 ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
362 case DRM_SWAP_SETCRTC:
363 drm_kms_wait_for_post(drm, 0);
364 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
366 pthread_mutex_lock(&drm->hdmi_mutex);
367 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED)
368 drm_kms_set_crtc(drm, &drm->hdmi, bo->fb_id);
369 pthread_mutex_unlock(&drm->hdmi_mutex);
371 drm->current_front = bo;
382 static struct gralloc_drm_t *drm_singleton;
384 static void on_signal(int sig)
386 struct gralloc_drm_t *drm = drm_singleton;
388 /* wait the pending flip */
389 if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
390 /* there is race, but this function is hacky enough to ignore that */
391 if (drm_singleton->waiting_flip)
392 usleep(100 * 1000); /* 100ms */
394 drm_kms_page_flip(drm_singleton, NULL);
400 static void drm_kms_init_features(struct gralloc_drm_t *drm)
402 const char *swap_mode;
404 /* call to the driver here, after KMS has been initialized */
405 drm->drv->init_kms_features(drm->drv, drm);
407 if (drm->swap_mode == DRM_SWAP_FLIP) {
408 struct sigaction act;
410 memset(&drm->evctx, 0, sizeof(drm->evctx));
411 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
412 drm->evctx.page_flip_handler = page_flip_handler;
415 * XXX GPU tends to freeze if the program is terminiated with a
416 * flip pending. What is the right way to handle the
419 sigemptyset(&act.sa_mask);
420 act.sa_handler = on_signal;
422 sigaction(SIGINT, &act, NULL);
423 sigaction(SIGTERM, &act, NULL);
427 else if (drm->swap_mode == DRM_SWAP_COPY) {
428 struct gralloc_drm_bo_t *front;
431 /* create the real front buffer */
432 front = gralloc_drm_bo_create(drm,
433 drm->primary.mode.hdisplay,
434 drm->primary.mode.vdisplay,
435 drm->primary.fb_format,
436 GRALLOC_USAGE_HW_FB);
437 if (front && gralloc_drm_bo_add_fb(front)) {
438 gralloc_drm_bo_decref(front);
442 /* abuse next_front */
444 drm->next_front = front;
446 drm->swap_mode = DRM_SWAP_SETCRTC;
449 switch (drm->swap_mode) {
456 case DRM_SWAP_SETCRTC:
457 swap_mode = "set-crtc";
464 ALOGD("will use %s for fb posting", swap_mode);
467 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
469 char value[PROPERTY_VALUE_MAX];
470 drmModeModeInfoPtr mode;
472 int xres = 0, yres = 0;
474 if (property_get("debug.drm.mode", value, NULL)) {
475 char *p = value, *end;
477 /* parse <xres>x<yres>[@<bpp>] */
478 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
480 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
484 if ((xres && yres) || *bpp) {
485 ALOGI("will find the closest match for %dx%d@%d",
495 for (i = 0; i < connector->count_modes; i++) {
496 drmModeModeInfoPtr m = &connector->modes[i];
500 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
501 (m->vdisplay - yres) * (m->vdisplay - yres);
504 /* use the first preferred mode */
505 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
516 /* fallback to the first mode */
518 mode = &connector->modes[0];
526 * Initialize KMS with a connector.
528 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
529 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
531 drmModeEncoderPtr encoder;
532 drmModeModeInfoPtr mode;
533 static int used_crtcs = 0;
536 if (!connector->count_modes)
539 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
543 /* find first possible crtc which is not used yet */
544 for (i = 0; i < drm->resources->count_crtcs; i++) {
545 if (encoder->possible_crtcs & (1 << i) &&
546 (used_crtcs & (1 << i)) != (1 << i))
550 used_crtcs |= (1 << i);
552 drmModeFreeEncoder(encoder);
553 if (i == drm->resources->count_crtcs)
556 output->crtc_id = drm->resources->crtcs[i];
557 output->connector_id = connector->connector_id;
559 /* print connector info */
560 if (connector->count_modes > 1) {
561 ALOGI("there are %d modes on connector 0x%x",
562 connector->count_modes,
563 connector->connector_id);
564 for (i = 0; i < connector->count_modes; i++)
565 ALOGI(" %s", connector->modes[i].name);
568 ALOGI("there is one mode on connector 0x%d: %s",
569 connector->connector_id,
570 connector->modes[0].name);
573 mode = find_mode(connector, &bpp);
575 ALOGI("the best mode is %s", mode->name);
577 output->mode = *mode;
580 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
584 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
588 if (connector->mmWidth && connector->mmHeight) {
589 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
590 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
597 #ifdef DRM_MODE_FEATURE_DIRTYFB
600 drm->clip.x2 = output->mode.hdisplay;
601 drm->clip.y2 = output->mode.vdisplay;
609 * Fetch a connector of particular type
611 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
619 for (i = 0; i < drm->resources->count_connectors; i++) {
620 drmModeConnectorPtr connector =
621 connector = drmModeGetConnector(drm->fd,
622 drm->resources->connectors[i]);
624 if (connector->connector_type == type &&
625 connector->connection == DRM_MODE_CONNECTED)
627 drmModeFreeConnector(connector);
635 * Thread that listens to uevents and checks if hdmi state changes
637 static void *hdmi_observer(void *data)
639 static char uevent_desc[4096];
640 drmModeConnectorPtr hdmi;
641 struct gralloc_drm_t *drm =
642 (struct gralloc_drm_t *) data;
646 memset(uevent_desc, 0, sizeof(uevent_desc));
651 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
653 if(len && strstr(uevent_desc, "devices/virtual/switch/hdmi")) {
655 /* check what changed */
656 const char *prop = uevent_desc + strlen(uevent_desc) + 1;
660 const char *state = strstr(prop, "SWITCH_STATE=");
662 unsigned int value = 0;
663 state += strlen("SWITCH_STATE=");
666 pthread_mutex_lock(&drm->hdmi_mutex);
669 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
671 drm_kms_init_with_connector(drm, &drm->hdmi, hdmi);
672 drmModeFreeConnector(hdmi);
674 /* will trigger modeset */
677 /* HACK, assume same mode for now */
678 memcpy(&drm->hdmi.mode, &drm->primary.mode,
679 sizeof(drmModeModeInfo));
681 drm->hdmi_mode = HDMI_CLONED;
682 drm->hdmi.active = 1;
683 pthread_mutex_unlock(&drm->hdmi_mutex);
687 drm->hdmi.active = 0;
688 pthread_mutex_unlock(&drm->hdmi_mutex);
692 pthread_mutex_unlock(&drm->hdmi_mutex);
695 /* next property/value pair */
696 prop += strlen(prop) + 1;
697 if (prop - uevent_desc >= len)
711 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
713 drmModeConnectorPtr lvds, hdmi;
719 drm->resources = drmModeGetResources(drm->fd);
720 if (!drm->resources) {
721 ALOGE("failed to get modeset resources");
725 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
726 if (!drm->plane_resources) {
727 ALOGD("no planes found from drm resources");
729 ALOGD("supported drm planes and formats");
730 /* fill a helper structure for hwcomposer */
731 drm->planes = calloc(drm->plane_resources->count_planes,
732 sizeof(struct gralloc_drm_plane_t));
734 for (i = 0; i < drm->plane_resources->count_planes; i++) {
738 drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
739 drm->plane_resources->planes[i]);
741 ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
742 for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
743 ALOGD(" format %c%c%c%c",
744 (drm->planes[i].drm_plane->formats[j]),
745 (drm->planes[i].drm_plane->formats[j])>>8,
746 (drm->planes[i].drm_plane->formats[j])>>16,
747 (drm->planes[i].drm_plane->formats[j])>>24);
751 /* find the crtc/connector/mode to use */
752 lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
754 drm_kms_init_with_connector(drm, &drm->primary, lvds);
755 drmModeFreeConnector(lvds);
756 drm->primary.active = 1;
759 /* if still no connector, find first connected connector and try it */
760 if (!drm->primary.active) {
762 for (i = 0; i < drm->resources->count_connectors; i++) {
763 drmModeConnectorPtr connector;
765 connector = drmModeGetConnector(drm->fd,
766 drm->resources->connectors[i]);
768 if (connector->connection == DRM_MODE_CONNECTED) {
769 if (!drm_kms_init_with_connector(drm,
770 &drm->primary, connector))
774 drmModeFreeConnector(connector);
777 if (i == drm->resources->count_connectors) {
778 ALOGE("failed to find a valid crtc/connector/mode combination");
779 drmModeFreeResources(drm->resources);
780 drm->resources = NULL;
786 /* check if hdmi is connected already */
787 hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
790 if (hdmi->connector_id == drm->primary.connector_id) {
791 /* special case: our primary connector is hdmi */
792 goto skip_hdmi_modes;
795 drm_kms_init_with_connector(drm, &drm->hdmi, hdmi);
796 drmModeFreeConnector(hdmi);
798 /* HACK, assume same mode for now */
799 memcpy(&drm->hdmi.mode, &drm->primary.mode,
800 sizeof(drmModeModeInfo));
802 drm->hdmi_mode = HDMI_CLONED;
803 drm->hdmi.active = 1;
806 /* launch hdmi observer thread */
807 pthread_mutex_init(&drm->hdmi_mutex, NULL);
808 pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
812 drm_kms_init_features(drm);
818 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
820 switch (drm->swap_mode) {
822 drm_kms_page_flip(drm, NULL);
826 struct gralloc_drm_bo_t **bo = (drm->current_front) ?
827 &drm->current_front : &drm->next_front;
830 gralloc_drm_bo_decref(*bo);
840 if (drm->resources) {
841 drmModeFreeResources(drm->resources);
842 drm->resources = NULL;
847 for (i = 0; i < drm->plane_resources->count_planes; i++)
848 drmModeFreePlane(drm->planes[i].drm_plane);
853 if (drm->plane_resources) {
854 drmModeFreePlaneResources(drm->plane_resources);
855 drm->plane_resources = NULL;
858 drm_singleton = NULL;
861 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
863 return (drm->resources != NULL);
867 * Initialize a framebuffer device with KMS info.
869 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
870 struct framebuffer_device_t *fb)
872 *((uint32_t *) &fb->flags) = 0x0;
873 *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
874 *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
875 *((int *) &fb->stride) = drm->primary.mode.hdisplay;
876 *((float *) &fb->fps) = drm->primary.mode.vrefresh;
878 *((int *) &fb->format) = drm->primary.fb_format;
879 *((float *) &fb->xdpi) = drm->primary.xdpi;
880 *((float *) &fb->ydpi) = drm->primary.ydpi;
881 *((int *) &fb->minSwapInterval) = drm->swap_interval;
882 *((int *) &fb->maxSwapInterval) = drm->swap_interval;
886 * Return true if fb posting is pipelined.
888 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
890 return (drm->swap_mode != DRM_SWAP_SETCRTC);