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>
35 #include "gralloc_drm.h"
36 #include "gralloc_drm_priv.h"
37 #include <hardware_legacy/uevent.h>
39 #include <drm_fourcc.h>
44 const char *subsystem;
45 const char *device_name;
52 static void parse_event(const char *msg, struct uevent *uevent)
56 uevent->subsystem = "";
59 uevent->device_name = "";
61 uevent->switchstate = -1;
64 if (!strncmp(msg, "ACTION=", 7)) {
67 } else if (!strncmp(msg, "DEVPATH=", 8)) {
70 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
72 uevent->subsystem = msg;
73 } else if (!strncmp(msg, "MAJOR=", 6)) {
75 uevent->major = atoi(msg);
76 } else if (!strncmp(msg, "MINOR=", 6)) {
78 uevent->minor = atoi(msg);
79 } else if (!strncmp(msg, "DEVNAME=", 8)) {
81 uevent->device_name = msg;
82 } else if (!strncmp(msg, "HOTPLUG=1", 9)) {
85 } else if (!strncmp(msg, "SWITCH_STATE=", 13)) {
87 uevent->switchstate = atoi(msg);
90 /* advance to after the next \0 */
97 * Return true if a bo needs fb.
99 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
101 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
102 bo->drm->swap_mode != DRM_SWAP_COPY);
105 static unsigned int drm_format_from_hal(int hal_format)
108 case HAL_PIXEL_FORMAT_RGB_888:
109 case HAL_PIXEL_FORMAT_BGRA_8888:
110 return DRM_FORMAT_XRGB8888;
111 case HAL_PIXEL_FORMAT_RGBX_8888:
112 return DRM_FORMAT_XBGR8888;
113 case HAL_PIXEL_FORMAT_RGBA_8888:
114 // return DRM_FORMAT_ABGR8888;
115 return DRM_FORMAT_XBGR8888;
116 case HAL_PIXEL_FORMAT_RGB_565:
117 return DRM_FORMAT_RGB565;
118 case HAL_PIXEL_FORMAT_YV12:
119 return DRM_FORMAT_YUV420;
120 case HAL_PIXEL_FORMAT_DRM_NV12:
121 return DRM_FORMAT_NV12;
128 * Modify pitches, offsets and handles according to
129 * the format and return corresponding drm format value
131 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
132 uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
134 struct gralloc_drm_t *drm = bo->drm;
136 pitches[0] = bo->handle->stride;
137 handles[0] = bo->fb_handle;
139 /* driver takes care of HW specific padding, alignment etc. */
140 if (drm->drv->resolve_format)
141 drm->drv->resolve_format(drm->drv, bo,
142 pitches, offsets, handles);
144 return drm_format_from_hal(bo->handle->format);
148 * Returns planes that are supported for a particular format
150 unsigned int planes_for_format(struct gralloc_drm_t *drm,
153 unsigned int i, j, mask = 0;
154 unsigned int drm_format = drm_format_from_hal(hal_format);
155 struct gralloc_drm_plane_t *plane = drm->planes;
157 /* no planes available */
161 /* iterate through planes, mark those that match format */
162 for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
163 for (j=0; j<plane->drm_plane->count_formats; j++)
164 if (plane->drm_plane->formats[j] == drm_format)
165 mask |= (1U << plane->drm_plane->plane_id);
171 * Add a fb object for a bo.
173 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
175 uint32_t pitches[4] = { 0, 0, 0, 0 };
176 uint32_t offsets[4] = { 0, 0, 0, 0 };
177 uint32_t handles[4] = { 0, 0, 0, 0 };
182 int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
184 if (drm_format == 0) {
185 ALOGE("error resolving drm format");
189 return drmModeAddFB2(bo->drm->fd,
190 bo->handle->width, bo->handle->height,
191 drm_format, handles, pitches, offsets,
192 (uint32_t *) &bo->fb_id, 0);
196 * Remove a fb object for a bo.
198 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
201 drmModeRmFB(bo->drm->fd, bo->fb_id);
209 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
210 struct gralloc_drm_output *output, int fb_id)
214 ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
215 0, 0, &output->connector_id, 1, &output->mode);
217 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
218 strerror(errno), output->crtc_id, fb_id, output->connector_id,
219 output->mode.hdisplay, output->mode.vdisplay);
223 if (drm->mode_quirk_vmwgfx)
224 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
230 * Callback for a page flip event.
232 static void page_flip_handler(int fd, unsigned int sequence,
233 unsigned int tv_sec, unsigned int tv_usec,
236 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
238 /* ack the last scheduled flip */
239 drm->current_front = drm->next_front;
240 drm->next_front = NULL;
246 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
247 struct gralloc_drm_plane_t *plane)
249 struct gralloc_drm_bo_t *bo = NULL;
253 bo = gralloc_drm_bo_from_handle(plane->handle);
255 // create a framebuffer if does not exist
256 if (bo && bo->fb_id == 0) {
257 err = gralloc_drm_bo_add_fb(bo);
259 ALOGE("%s: could not create drm fb, (%s)",
260 __func__, strerror(-err));
265 err = drmModeSetPlane(drm->fd,
266 plane->drm_plane->plane_id,
267 drm->primary->crtc_id,
280 /* clear plane_mask so that this buffer won't be tried again */
281 struct gralloc_drm_handle_t *drm_handle =
282 (struct gralloc_drm_handle_t *) plane->handle;
283 drm_handle->plane_mask = 0;
285 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
287 plane->drm_plane->plane_id,
288 drm->primary->crtc_id,
293 gralloc_drm_bo_decref(plane->prev);
304 * Returns if a particular plane is supported with the implementation
306 static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
307 const struct gralloc_drm_plane_t *plane)
309 /* Planes are only supported on primary pipe for now */
310 return plane->drm_plane->possible_crtcs & (1 << drm->primary->pipe);
314 * Sets all the active planes to be displayed.
316 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
318 struct gralloc_drm_plane_t *plane = drm->planes;
320 for (i = 0; i < drm->plane_resources->count_planes;
322 /* plane is not in use at all */
323 if (!plane->active && !plane->handle)
326 /* plane is active, safety check if it is supported */
327 if (!is_plane_supported(drm, plane))
328 ALOGE("%s: plane %d is not supported",
329 __func__, plane->drm_plane->plane_id);
332 * Disable overlay if it is not active
333 * or if there is error during setplane
338 if (gralloc_drm_bo_setplane(drm, plane))
344 * Interface for HWC, used to reserve a plane for a layer.
346 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
347 buffer_handle_t handle,
359 struct gralloc_drm_handle_t *drm_handle =
360 gralloc_drm_handle(handle);
361 int plane_count = drm->plane_resources->count_planes;
362 struct gralloc_drm_plane_t *plane = drm->planes;
364 /* no supported planes for this handle */
365 if (!drm_handle->plane_mask) {
366 ALOGE("%s: buffer %p cannot be shown on a plane\n",
367 __func__, drm_handle);
371 for (j = 0; j < plane_count; j++, plane++) {
374 * handle may be suitable to be shown on a plane, in
375 * addition we need to check that this particular plane
376 * is supported by the current implementation
378 if (!is_plane_supported(drm, plane))
381 /* if plane is available and can support this buffer */
382 if (!plane->active &&
383 drm_handle->plane_mask &
384 (1U << plane->drm_plane->plane_id)) {
386 plane->dst_x = dst_x;
387 plane->dst_y = dst_y;
388 plane->dst_w = dst_w;
389 plane->dst_h = dst_h;
390 plane->src_x = src_x;
391 plane->src_y = src_y;
392 plane->src_w = src_w;
393 plane->src_h = src_h;
394 plane->handle = handle;
402 /* no free planes available */
407 * Interface for HWC, used to disable all the overlays. Plane id
408 * is also set to 0 as it should be mappable to a particular layer only
409 * if it has been reserved with 'reserve_plane'.
411 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
413 struct gralloc_drm_plane_t *plane = drm->planes;
416 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
423 * Interface for HWC, used to change handle of a reserved plane.
425 int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
426 uint32_t id, buffer_handle_t handle)
428 struct gralloc_drm_plane_t *plane = drm->planes;
431 for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
432 if (plane->active && plane->id == id) {
433 plane->handle = handle;
440 static int drm_kms_blit_to_mirror_connectors(struct gralloc_drm_t *drm, struct gralloc_drm_bo_t *bo)
443 for (int i = 1; i < drm->output_capacity; i++) {
444 struct gralloc_drm_output *output = &drm->outputs[i];
446 if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo) {
448 int dst_x1 = 0, dst_y1 = 0;
450 if (output->bo->handle->width > bo->handle->width)
451 dst_x1 = (output->bo->handle->width - bo->handle->width) / 2;
452 if (output->bo->handle->height > bo->handle->height)
453 dst_y1 = (output->bo->handle->height - bo->handle->height) / 2;
455 drm->drv->blit(drm->drv, output->bo, bo,
457 dst_x1 + bo->handle->width,
458 dst_y1 + bo->handle->height,
459 0, 0, bo->handle->width, bo->handle->height);
461 ret = drmModePageFlip(drm->fd, output->crtc_id, output->bo->fb_id, 0, NULL);
462 if (ret && errno != EBUSY)
463 ALOGE("failed to perform page flip for output (%s) (crtc %d fb %d))",
464 strerror(errno), output->crtc_id, output->bo->fb_id);
472 * Schedule a page flip.
474 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
475 struct gralloc_drm_bo_t *bo)
479 /* there is another flip pending */
480 while (drm->next_front) {
481 drm->waiting_flip = 1;
482 drmHandleEvent(drm->fd, &drm->evctx);
483 drm->waiting_flip = 0;
484 if (drm->next_front) {
485 /* record an error and break */
486 ALOGE("drmHandleEvent returned without flipping");
487 drm->current_front = drm->next_front;
488 drm->next_front = NULL;
495 pthread_mutex_lock(&drm->outputs_mutex);
496 drm_kms_blit_to_mirror_connectors(drm, bo);
497 pthread_mutex_unlock(&drm->outputs_mutex);
499 /* set planes to be displayed */
500 gralloc_drm_set_planes(drm);
502 ret = drmModePageFlip(drm->fd, drm->primary->crtc_id, bo->fb_id,
503 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
505 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
506 strerror(errno), drm->primary->crtc_id, bo->fb_id);
507 /* try to set mode for next frame */
512 drm->next_front = bo;
518 * Wait for the next post.
520 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
522 unsigned int current, target;
526 if (drm->mode_quirk_vmwgfx)
531 memset(&vbl, 0, sizeof(vbl));
532 vbl.request.type = DRM_VBLANK_RELATIVE;
533 if (drm->vblank_secondary)
534 vbl.request.type |= DRM_VBLANK_SECONDARY;
535 vbl.request.sequence = 0;
537 /* get the current vblank */
538 ret = drmWaitVBlank(drm->fd, &vbl);
540 ALOGW("failed to get vblank");
544 current = vbl.reply.sequence;
548 target = drm->last_swap + drm->swap_interval - flip;
550 /* wait for vblank */
551 if (current < target || !flip) {
552 memset(&vbl, 0, sizeof(vbl));
553 vbl.request.type = DRM_VBLANK_ABSOLUTE;
554 if (drm->vblank_secondary)
555 vbl.request.type |= DRM_VBLANK_SECONDARY;
557 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
558 if (target < current)
562 vbl.request.sequence = target;
564 ret = drmWaitVBlank(drm->fd, &vbl);
566 ALOGW("failed to wait vblank");
571 drm->last_swap = vbl.reply.sequence + flip;
575 * Post a bo. This is not thread-safe.
577 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
579 struct gralloc_drm_t *drm = bo->drm;
582 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
583 ALOGE("unable to post bo %p without fb", bo);
587 /* TODO spawn a thread to avoid waiting and race */
589 if (drm->first_post) {
590 if (drm->swap_mode == DRM_SWAP_COPY) {
591 struct gralloc_drm_bo_t *dst;
593 dst = (drm->next_front) ?
596 drm->drv->blit(drm->drv, dst, bo, 0, 0,
605 ret = drm_kms_set_crtc(drm, drm->primary, bo->fb_id);
608 drm->current_front = bo;
609 if (drm->next_front == bo)
610 drm->next_front = NULL;
613 pthread_mutex_lock(&drm->outputs_mutex);
614 for (int i = 1; i < drm->output_capacity; i++) {
615 struct gralloc_drm_output *output = &drm->outputs[i];
616 if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo)
617 drm_kms_set_crtc(drm, output, output->bo->fb_id);
619 pthread_mutex_unlock(&drm->outputs_mutex);
624 switch (drm->swap_mode) {
626 if (drm->swap_interval > 1)
627 drm_kms_wait_for_post(drm, 1);
628 ret = drm_kms_page_flip(drm, bo);
629 if (drm->next_front) {
631 * wait if the driver says so or the current front
632 * will be written by CPU
634 if (drm->mode_sync_flip ||
635 (drm->current_front->handle->usage &
636 GRALLOC_USAGE_SW_WRITE_MASK))
637 drm_kms_page_flip(drm, NULL);
641 drm_kms_wait_for_post(drm, 0);
642 drm->drv->blit(drm->drv, drm->current_front,
649 if (drm->mode_quirk_vmwgfx)
650 ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
653 case DRM_SWAP_SETCRTC:
654 drm_kms_wait_for_post(drm, 0);
655 ret = drm_kms_set_crtc(drm, drm->primary, bo->fb_id);
657 pthread_mutex_lock(&drm->outputs_mutex);
658 for (int i = 1; i < drm->output_capacity; i++) {
659 struct gralloc_drm_output *output = &drm->outputs[i];
660 if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo)
661 drm_kms_set_crtc(drm, output, output->bo->fb_id);
663 pthread_mutex_unlock(&drm->outputs_mutex);
665 drm->current_front = bo;
676 static struct gralloc_drm_t *drm_singleton;
678 static void on_signal(int sig)
680 struct gralloc_drm_t *drm = drm_singleton;
682 /* wait the pending flip */
683 if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
684 /* there is race, but this function is hacky enough to ignore that */
685 if (drm_singleton->waiting_flip)
686 usleep(100 * 1000); /* 100ms */
688 drm_kms_page_flip(drm_singleton, NULL);
694 static void drm_kms_init_features(struct gralloc_drm_t *drm)
696 const char *swap_mode;
698 /* call to the driver here, after KMS has been initialized */
699 drm->drv->init_kms_features(drm->drv, drm);
701 if (drm->swap_mode == DRM_SWAP_FLIP) {
702 struct sigaction act;
704 memset(&drm->evctx, 0, sizeof(drm->evctx));
705 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
706 drm->evctx.page_flip_handler = page_flip_handler;
709 * XXX GPU tends to freeze if the program is terminiated with a
710 * flip pending. What is the right way to handle the
713 sigemptyset(&act.sa_mask);
714 act.sa_handler = on_signal;
716 sigaction(SIGINT, &act, NULL);
717 sigaction(SIGTERM, &act, NULL);
721 else if (drm->swap_mode == DRM_SWAP_COPY) {
722 struct gralloc_drm_bo_t *front;
725 /* create the real front buffer */
726 front = gralloc_drm_bo_create(drm,
727 drm->primary->mode.hdisplay,
728 drm->primary->mode.vdisplay,
729 drm->primary->fb_format,
730 GRALLOC_USAGE_HW_FB);
731 if (front && gralloc_drm_bo_add_fb(front)) {
732 gralloc_drm_bo_decref(front);
736 /* abuse next_front */
738 drm->next_front = front;
740 drm->swap_mode = DRM_SWAP_SETCRTC;
743 switch (drm->swap_mode) {
750 case DRM_SWAP_SETCRTC:
751 swap_mode = "set-crtc";
758 ALOGD("will use %s for fb posting", swap_mode);
761 #define MARGIN_PERCENT 1.8 /* % of active vertical image*/
762 #define CELL_GRAN 8.0 /* assumed character cell granularity*/
763 #define MIN_PORCH 1 /* minimum front porch */
764 #define V_SYNC_RQD 3 /* width of vsync in lines */
765 #define H_SYNC_PERCENT 8.0 /* width of hsync as % of total line */
766 #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
767 #define M 600.0 /* blanking formula gradient */
768 #define C 40.0 /* blanking formula offset */
769 #define K 128.0 /* blanking formula scaling factor */
770 #define J 20.0 /* blanking formula scaling factor */
771 /* C' and M' are part of the Blanking Duty Cycle computation */
772 #define C_PRIME (((C - J) * K / 256.0) + J)
773 #define M_PRIME (K / 256.0 * M)
775 static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
779 float v_field_rate_rqd;
787 float v_field_rate_est;
793 float total_active_pixels;
794 float ideal_duty_cycle;
802 float v_odd_front_porch_lines;
806 drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
808 h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
809 v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
810 v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
811 top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
812 bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
813 interlace = interlaced ? 0.5 : 0.0;
814 h_period_est = (((1.0 / v_field_rate_rqd) - (MIN_VSYNC_PLUS_BP / 1000000.0)) / (v_lines_rnd + (2 * top_margin) + MIN_PORCH + interlace) * 1000000.0);
815 vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
816 v_back_porch = vsync_plus_bp - V_SYNC_RQD;
817 total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
818 v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
819 h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
820 v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
821 v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
822 left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
823 right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
824 total_active_pixels = h_pixels_rnd + left_margin + right_margin;
825 ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
826 h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
827 total_pixels = total_active_pixels + h_blank;
828 pixel_freq = total_pixels / h_period;
829 h_freq = 1000.0 / h_period;
830 h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
831 h_front_porch = (h_blank / 2.0) - h_sync;
832 v_odd_front_porch_lines = MIN_PORCH + interlace;
834 m->clock = ceil(pixel_freq) * 1000;
835 m->hdisplay = (int) (h_pixels_rnd);
836 m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
837 m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
838 m->htotal = (int) (total_pixels);
840 m->vdisplay = (int) (v_lines_rnd);
841 m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
842 m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
843 m->vtotal = (int) (total_v_lines);
852 static int mode_distance_best_fit(
857 double prefered_aspect)
859 const double eps = 0.3;
861 if (xres_base > xres || yres_base > yres) {
862 // if the res cannot cover base res, return max int
864 } else if (fabs((double) xres / yres - prefered_aspect) > eps) {
865 // if the aspect is too different with prefered_aspect, return max int
868 return (xres - xres_base) * (xres - xres_base) +
869 (yres - yres_base) * (yres - yres_base) +
870 ((xres / yres) - prefered_aspect) * ((xres / yres) - prefered_aspect);
874 static int mode_distance_closest(int xres_base, int yres_base, int xres, int yres) {
875 return (xres - xres_base) * (xres - xres_base) +
876 (yres - yres_base) * (yres - yres_base);
879 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp, drmModeModeInfoPtr primary_mode)
881 char value[PROPERTY_VALUE_MAX];
882 drmModeModeInfoPtr mode;
884 int xres = 0, yres = 0, rate = 0;
888 if (property_get("debug.drm.mode", value, NULL)) {
889 char *p = value, *end;
891 /* parse <xres>x<yres>[@<bpp>] */
892 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
894 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
898 if ((xres && yres) || *bpp) {
899 ALOGI("will find the closest match for %dx%d@%d",
902 } else if (property_get("debug.drm.mode.force", value, NULL)) {
903 char *p = value, *end;
906 /* parse <xres>x<yres>[@<refreshrate>] */
907 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
909 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
913 if (xres && yres && rate) {
914 ALOGI("will use %dx%d@%dHz", xres, yres, rate);
917 } else if (primary_mode != NULL) {
918 xres = primary_mode->hdisplay;
919 yres = primary_mode->vdisplay;
922 ALOGI("will find the best fit for %dx%d", xres, yres);
930 mode = generate_mode(xres, yres, rate);
933 for (i = 0; i < connector->count_modes; i++) {
934 drmModeModeInfoPtr m = &connector->modes[i];
939 tmp = mode_distance_best_fit(
944 (double) connector->modes[0].hdisplay / connector->modes[0].vdisplay);
946 tmp = mode_distance_closest(xres, yres, m->hdisplay, m->vdisplay);
950 /* use the first preferred mode */
951 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
963 /* fallback to the first mode */
965 mode = &connector->modes[0];
967 ALOGI("Established mode:");
968 ALOGI("clock: %d, hdisplay: %d, hsync_start: %d, hsync_end: %d, htotal: %d, hskew: %d", mode->clock, mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal, mode->hskew);
969 ALOGI("vdisplay: %d, vsync_start: %d, vsync_end: %d, vtotal: %d, vscan: %d, vrefresh: %d", mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->vscan, mode->vrefresh);
970 ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
977 static int used_crtcs = 0;
980 * Initialize KMS with a connector.
982 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
983 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
985 drmModeEncoderPtr encoder;
986 drmModeModeInfoPtr mode;
989 if (!connector->count_modes)
992 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
996 /* find first possible crtc which is not used yet */
997 for (i = 0; i < drm->resources->count_crtcs; i++) {
998 if (encoder->possible_crtcs & (1 << i) &&
999 (used_crtcs & (1 << i)) != (1 << i))
1003 used_crtcs |= (1 << i);
1005 drmModeFreeEncoder(encoder);
1006 if (i == drm->resources->count_crtcs)
1010 output->crtc_id = drm->resources->crtcs[i];
1011 output->connector_id = connector->connector_id;
1014 /* print connector info */
1015 if (connector->count_modes > 1) {
1016 ALOGI("there are %d modes on connector 0x%x, type %d",
1017 connector->count_modes,
1018 connector->connector_id,
1019 connector->connector_type);
1020 for (i = 0; i < connector->count_modes; i++)
1021 ALOGI(" %s", connector->modes[i].name);
1024 ALOGI("there is one mode on connector 0x%d: %s",
1025 connector->connector_id,
1026 connector->modes[0].name);
1029 if (drm->primary && output != drm->primary && property_get_bool("persist.remixos.disp_best_fit", 1)) {
1030 mode = find_mode(connector, &bpp, &drm->primary->mode);
1032 mode = find_mode(connector, &bpp, NULL);
1035 ALOGI("the best mode is %s", mode->name);
1037 output->mode = *mode;
1040 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
1044 output->fb_format = HAL_PIXEL_FORMAT_RGBA_8888;
1048 if (connector->mmWidth && connector->mmHeight) {
1049 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
1050 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
1057 #ifdef DRM_MODE_FEATURE_DIRTYFB
1060 drm->clip.x2 = output->mode.hdisplay;
1061 drm->clip.y2 = output->mode.vdisplay;
1067 static struct gralloc_drm_output*
1068 drm_kms_init_with_new_connector(struct gralloc_drm_t *drm, drmModeConnectorPtr connector)
1070 struct gralloc_drm_output *output = NULL;
1072 for (int i=0;i<drm->output_capacity;i++) {
1073 if (!drm->outputs[i].active) {
1074 output = &drm->outputs[i];
1079 if (output && !drm_kms_init_with_connector(drm, output, connector)) {
1080 drm->output_count++;
1082 if (!drm->primary) {
1083 drm->primary = output;
1092 * Fetch a connector of particular type
1094 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
1099 if (!drm->resources)
1102 for (i = 0; i < drm->resources->count_connectors; i++) {
1103 drmModeConnectorPtr connector = drmModeGetConnector(drm->fd,
1104 drm->resources->connectors[i]);
1106 if (connector->connector_type == type &&
1107 connector->connection == DRM_MODE_CONNECTED)
1109 drmModeFreeConnector(connector);
1117 * Initializes external output with a connector and allocates
1118 * a private framebuffer for it. This is called on startup if
1119 * external cable is connected and also on hotplug events.
1121 static int init_external_output(struct gralloc_drm_t *drm,
1122 drmModeConnectorPtr connector)
1124 struct gralloc_drm_output *output;
1125 output = drm_kms_init_with_new_connector(drm, connector);
1127 ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
1128 __func__, output->mode.hdisplay, output->mode.vdisplay);
1130 output->bo = gralloc_drm_bo_create(drm,
1131 output->mode.hdisplay, output->mode.vdisplay,
1133 GRALLOC_USAGE_HW_RENDER);
1135 int err = gralloc_drm_bo_add_fb(output->bo);
1137 ALOGE("%s: could not create drm fb, (%s)",
1138 __func__, strerror(-err));
1142 output->output_mode = DRM_OUTPUT_CLONED;
1145 /* This is a hack to workaround mirror mode render error */
1146 drm_kms_set_crtc(drm, output, output->bo->fb_id);
1152 static int init_connectors(struct gralloc_drm_t *drm)
1154 if (!drm->resources)
1157 for (int i = 0; i<drm->resources->count_connectors; i++) {
1158 drmModeConnectorPtr connector = drmModeGetConnector(drm->fd,
1159 drm->resources->connectors[i]);
1161 if (connector->connection == DRM_MODE_CONNECTED &&
1162 connector->connector_id != drm->primary->connector_id) {
1163 init_external_output(drm, connector);
1164 } else if (connector->connection == DRM_MODE_DISCONNECTED) {
1165 for (int j = 1; j < drm->output_capacity; j++) {
1166 if (drm->outputs[j].connector_id == connector->connector_id && drm->outputs[j].active) {
1167 drm->outputs[j].active = 0;
1168 used_crtcs &= ~(1 << drm->outputs[j].pipe);
1169 gralloc_drm_bo_decref(drm->outputs[j].bo);
1170 drm->outputs[j].bo = NULL;
1175 drmModeFreeConnector(connector);
1184 * Thread that listens to uevents and checks if hdmi state changes
1186 static void *extcon_observer(void *data)
1188 static char uevent_desc[4096];
1189 drmModeConnectorPtr hdmi;
1190 struct gralloc_drm_t *drm =
1191 (struct gralloc_drm_t *) data;
1192 struct uevent event;
1196 memset(uevent_desc, 0, sizeof(uevent_desc));
1201 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1204 parse_event(uevent_desc, &event);
1205 ALOGD_IF(0, "event { '%s', '%s', '%s', %d, %d, %d, %d }\n",
1206 event.action, event.path, event.subsystem,
1207 event.major, event.minor,
1208 event.switchstate, event.hotplug);
1210 if (!strcmp(event.path, "devices/virtual/switch/hdmi")) {
1211 if (event.switchstate != -1) {
1212 pthread_mutex_lock(&drm->outputs_mutex);
1214 init_connectors(drm);
1216 /* will trigger modeset */
1217 drm->first_post = 1;
1219 pthread_mutex_unlock(&drm->outputs_mutex);
1221 } else if (!strcmp(event.subsystem, "drm") &&
1222 !strcmp(event.device_name, "dri/card0") && event.hotplug) {
1223 pthread_mutex_lock(&drm->outputs_mutex);
1225 init_connectors(drm);
1227 /* will trigger modeset */
1228 drm->first_post = 1;
1230 pthread_mutex_unlock(&drm->outputs_mutex);
1242 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1244 drmModeConnectorPtr lvds;
1250 drm->resources = drmModeGetResources(drm->fd);
1251 if (!drm->resources) {
1252 ALOGE("failed to get modeset resources");
1256 drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1257 if (!drm->plane_resources) {
1258 ALOGD("no planes found from drm resources");
1262 ALOGD("supported drm planes and formats");
1263 /* fill a helper structure for hwcomposer */
1264 drm->planes = calloc(drm->plane_resources->count_planes,
1265 sizeof(struct gralloc_drm_plane_t));
1267 for (i = 0; i < drm->plane_resources->count_planes; i++) {
1268 drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
1269 drm->plane_resources->planes[i]);
1271 ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
1272 for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
1273 ALOGD(" format %c%c%c%c",
1274 (drm->planes[i].drm_plane->formats[j]),
1275 (drm->planes[i].drm_plane->formats[j])>>8,
1276 (drm->planes[i].drm_plane->formats[j])>>16,
1277 (drm->planes[i].drm_plane->formats[j])>>24);
1281 drm->output_capacity = drm->resources->count_connectors;
1282 drm->output_count = 0;
1284 drm->outputs = malloc(sizeof(*drm->outputs) * drm->output_capacity);
1285 memset(drm->outputs, 0, sizeof(*drm->outputs) * drm->output_capacity);
1287 /* find the crtc/connector/mode to use */
1288 lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1290 drm_kms_init_with_new_connector(drm, lvds);
1291 drmModeFreeConnector(lvds);
1294 /* if still no connector, find first connected connector and try it */
1295 if (!drm->primary) {
1297 for (i = 0; i < drm->resources->count_connectors; i++) {
1298 drmModeConnectorPtr connector;
1300 connector = drmModeGetConnector(drm->fd,
1301 drm->resources->connectors[i]);
1303 if (connector->connection == DRM_MODE_CONNECTED) {
1304 if (drm_kms_init_with_new_connector(drm, connector))
1308 drmModeFreeConnector(connector);
1311 if (i == drm->resources->count_connectors) {
1312 ALOGE("failed to find a valid crtc/connector/mode combination");
1313 drmModeFreeResources(drm->resources);
1314 drm->resources = NULL;
1320 /* Mirror mode need driver support for blitting. which is not implemented for
1321 drivers other than intel. skip external detection for them to avoid crash
1323 if (drm->drv->blit) {
1324 init_connectors(drm);
1326 /* launch external display observer thread */
1327 pthread_mutex_init(&drm->outputs_mutex, NULL);
1328 pthread_create(&drm->hotplug_thread, NULL, extcon_observer, drm);
1331 drm_kms_init_features(drm);
1332 drm->first_post = 1;
1337 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1339 switch (drm->swap_mode) {
1341 drm_kms_page_flip(drm, NULL);
1345 struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1346 &drm->current_front : &drm->next_front;
1349 gralloc_drm_bo_decref(*bo);
1359 if (drm->resources) {
1360 drmModeFreeResources(drm->resources);
1361 drm->resources = NULL;
1366 for (i = 0; i < drm->plane_resources->count_planes; i++)
1367 drmModeFreePlane(drm->planes[i].drm_plane);
1372 if (drm->plane_resources) {
1373 drmModeFreePlaneResources(drm->plane_resources);
1374 drm->plane_resources = NULL;
1377 /* destroy private buffer of external output */
1378 for (int i = 1; i < drm->output_capacity; i++)
1379 if (drm->outputs[i].bo)
1380 gralloc_drm_bo_decref(drm->outputs[i].bo);
1384 drm_singleton = NULL;
1387 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1389 return (drm->resources != NULL);
1393 * Initialize a framebuffer device with KMS info.
1395 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1396 struct framebuffer_device_t *fb)
1398 *((uint32_t *) &fb->flags) = 0x0;
1399 *((uint32_t *) &fb->width) = drm->primary->mode.hdisplay;
1400 *((uint32_t *) &fb->height) = drm->primary->mode.vdisplay;
1401 *((int *) &fb->stride) = drm->primary->mode.hdisplay;
1402 *((float *) &fb->fps) = drm->primary->mode.vrefresh;
1404 *((int *) &fb->format) = drm->primary->fb_format;
1405 *((float *) &fb->xdpi) = drm->primary->xdpi;
1406 *((float *) &fb->ydpi) = drm->primary->ydpi;
1407 *((int *) &fb->minSwapInterval) = drm->swap_interval;
1408 *((int *) &fb->maxSwapInterval) = drm->swap_interval;
1412 * Return true if fb posting is pipelined.
1414 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1416 return (drm->swap_mode != DRM_SWAP_SETCRTC);