OSDN Git Service

Best fit the external display
[android-x86/external-drm_gralloc.git] / gralloc_drm_kms.c
1 /*
2  * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3  * Copyright (C) 2010-2011 LunarG Inc.
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
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.
22  */
23
24 #define LOG_TAG "GRALLOC-KMS"
25
26 #include <cutils/properties.h>
27 #include <cutils/log.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <poll.h>
34 #include <math.h>
35 #include "gralloc_drm.h"
36 #include "gralloc_drm_priv.h"
37 #include <hardware_legacy/uevent.h>
38
39 #include <drm_fourcc.h>
40
41 struct uevent {
42         const char *action;
43         const char *path;
44         const char *subsystem;
45         const char *device_name;
46         int major;
47         int minor;
48         int hotplug;
49         int switchstate;
50 };
51
52 static void parse_event(const char *msg, struct uevent *uevent)
53 {
54         uevent->action = "";
55         uevent->path = "";
56         uevent->subsystem = "";
57         uevent->major = -1;
58         uevent->minor = -1;
59         uevent->device_name = "";
60         uevent->hotplug = 0;
61         uevent->switchstate = -1;
62
63         while (*msg) {
64                 if (!strncmp(msg, "ACTION=", 7)) {
65                         msg += 7;
66                         uevent->action = msg;
67                 } else if (!strncmp(msg, "DEVPATH=", 8)) {
68                         msg += 8;
69                         uevent->path = msg;
70                 } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
71                         msg += 10;
72                         uevent->subsystem = msg;
73                 } else if (!strncmp(msg, "MAJOR=", 6)) {
74                         msg += 6;
75                         uevent->major = atoi(msg);
76                 } else if (!strncmp(msg, "MINOR=", 6)) {
77                         msg += 6;
78                         uevent->minor = atoi(msg);
79                 } else if (!strncmp(msg, "DEVNAME=", 8)) {
80                         msg += 8;
81                         uevent->device_name = msg;
82                 } else if (!strncmp(msg, "HOTPLUG=1", 9)) {
83                         msg += 9;
84                         uevent->hotplug = 1;
85                 } else if (!strncmp(msg, "SWITCH_STATE=", 13)) {
86                         msg += 13;
87                         uevent->switchstate = atoi(msg);
88                 }
89
90                 /* advance to after the next \0 */
91                 while (*msg++)
92                         ;
93         }
94 }
95
96 /*
97  * Return true if a bo needs fb.
98  */
99 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
100 {
101         return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
102                 bo->drm->swap_mode != DRM_SWAP_COPY);
103 }
104
105 static unsigned int drm_format_from_hal(int hal_format)
106 {
107         switch(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_RGBA8888;
115                 case HAL_PIXEL_FORMAT_RGB_565:
116                         return DRM_FORMAT_RGB565;
117                 case HAL_PIXEL_FORMAT_YV12:
118                         return DRM_FORMAT_YUV420;
119                 case HAL_PIXEL_FORMAT_DRM_NV12:
120                         return DRM_FORMAT_NV12;
121                 default:
122                         return 0;
123         }
124 }
125
126 /*
127  * Modify pitches, offsets and handles according to
128  * the format and return corresponding drm format value
129  */
130 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
131         uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
132 {
133         struct gralloc_drm_t *drm = bo->drm;
134
135         pitches[0] = bo->handle->stride;
136         handles[0] = bo->fb_handle;
137
138         /* driver takes care of HW specific padding, alignment etc. */
139         if (drm->drv->resolve_format)
140                 drm->drv->resolve_format(drm->drv, bo,
141                         pitches, offsets, handles);
142
143         return drm_format_from_hal(bo->handle->format);
144 }
145
146 /*
147  * Returns planes that are supported for a particular format
148  */
149 unsigned int planes_for_format(struct gralloc_drm_t *drm,
150         int hal_format)
151 {
152         unsigned int i, j, mask = 0;
153         unsigned int drm_format = drm_format_from_hal(hal_format);
154         struct gralloc_drm_plane_t *plane = drm->planes;
155
156         /* no planes available */
157         if (!plane)
158                 return 0;
159
160         /* iterate through planes, mark those that match format */
161         for (i=0; i<drm->plane_resources->count_planes; i++, plane++)
162                 for (j=0; j<plane->drm_plane->count_formats; j++)
163                         if (plane->drm_plane->formats[j] == drm_format)
164                                 mask |= (1U << plane->drm_plane->plane_id);
165
166         return mask;
167 }
168
169 /*
170  * Add a fb object for a bo.
171  */
172 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
173 {
174         uint32_t pitches[4] = { 0, 0, 0, 0 };
175         uint32_t offsets[4] = { 0, 0, 0, 0 };
176         uint32_t handles[4] = { 0, 0, 0, 0 };
177
178         if (bo->fb_id)
179                 return 0;
180
181         int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
182
183         if (drm_format == 0) {
184                 ALOGE("error resolving drm format");
185                 return -EINVAL;
186         }
187
188         return drmModeAddFB2(bo->drm->fd,
189                 bo->handle->width, bo->handle->height,
190                 drm_format, handles, pitches, offsets,
191                 (uint32_t *) &bo->fb_id, 0);
192 }
193
194 /*
195  * Remove a fb object for a bo.
196  */
197 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
198 {
199         if (bo->fb_id) {
200                 drmModeRmFB(bo->drm->fd, bo->fb_id);
201                 bo->fb_id = 0;
202         }
203 }
204
205 /*
206  * Program CRTC.
207  */
208 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
209         struct gralloc_drm_output *output, int fb_id)
210 {
211         int ret;
212
213         ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
214                         0, 0, &output->connector_id, 1, &output->mode);
215         if (ret) {
216                 ALOGE("failed to set crtc (%s) (crtc_id %d, fb_id %d, conn %d, mode %dx%d)",
217                         strerror(errno), output->crtc_id, fb_id, output->connector_id,
218                         output->mode.hdisplay, output->mode.vdisplay);
219                 return ret;
220         }
221
222         if (drm->mode_quirk_vmwgfx)
223                 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
224
225         return ret;
226 }
227
228 /*
229  * Callback for a page flip event.
230  */
231 static void page_flip_handler(int fd, unsigned int sequence,
232                 unsigned int tv_sec, unsigned int tv_usec,
233                 void *user_data)
234 {
235         struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
236
237         /* ack the last scheduled flip */
238         drm->current_front = drm->next_front;
239         drm->next_front = NULL;
240 }
241
242 /*
243  * Set a plane.
244  */
245 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
246         struct gralloc_drm_plane_t *plane)
247 {
248         struct gralloc_drm_bo_t *bo = NULL;
249         int err;
250
251         if (plane->handle)
252                 bo = gralloc_drm_bo_from_handle(plane->handle);
253
254         // create a framebuffer if does not exist
255         if (bo && bo->fb_id == 0) {
256                 err = gralloc_drm_bo_add_fb(bo);
257                 if (err) {
258                         ALOGE("%s: could not create drm fb, (%s)",
259                                 __func__, strerror(-err));
260                         return err;
261                 }
262         }
263
264         err = drmModeSetPlane(drm->fd,
265                 plane->drm_plane->plane_id,
266                 drm->primary.crtc_id,
267                 bo ? bo->fb_id : 0,
268                 0, // flags
269                 plane->dst_x,
270                 plane->dst_y,
271                 plane->dst_w,
272                 plane->dst_h,
273                 plane->src_x << 16,
274                 plane->src_y << 16,
275                 plane->src_w << 16,
276                 plane->src_h << 16);
277
278         if (err) {
279                 /* clear plane_mask so that this buffer won't be tried again */
280                 struct gralloc_drm_handle_t *drm_handle =
281                         (struct gralloc_drm_handle_t *) plane->handle;
282                 drm_handle->plane_mask = 0;
283
284                 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
285                         strerror(-err),
286                         plane->drm_plane->plane_id,
287                         drm->primary.crtc_id,
288                         bo ? bo->fb_id : 0);
289         }
290
291         if (plane->prev)
292                 gralloc_drm_bo_decref(plane->prev);
293
294         if (bo)
295                 bo->refcount++;
296
297         plane->prev = bo;
298
299         return err;
300 }
301
302 /*
303  * Returns if a particular plane is supported with the implementation
304  */
305 static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
306         const struct gralloc_drm_plane_t *plane)
307 {
308         /* Planes are only supported on primary pipe for now */
309         return plane->drm_plane->possible_crtcs & (1 << drm->primary.pipe);
310 }
311
312 /*
313  * Sets all the active planes to be displayed.
314  */
315 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
316 {
317         struct gralloc_drm_plane_t *plane = drm->planes;
318         unsigned int i;
319         for (i = 0; i < drm->plane_resources->count_planes;
320                 i++, plane++) {
321                 /* plane is not in use at all */
322                 if (!plane->active && !plane->handle)
323                         continue;
324
325                 /* plane is active, safety check if it is supported */
326                 if (!is_plane_supported(drm, plane))
327                         ALOGE("%s: plane %d is not supported",
328                                  __func__, plane->drm_plane->plane_id);
329
330                 /*
331                  * Disable overlay if it is not active
332                  * or if there is error during setplane
333                  */
334                 if (!plane->active)
335                         plane->handle = 0;
336
337                 if (gralloc_drm_bo_setplane(drm, plane))
338                         plane->active = 0;
339         }
340 }
341
342 /*
343  * Interface for HWC, used to reserve a plane for a layer.
344  */
345 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
346         buffer_handle_t handle,
347         uint32_t id,
348         uint32_t dst_x,
349         uint32_t dst_y,
350         uint32_t dst_w,
351         uint32_t dst_h,
352         uint32_t src_x,
353         uint32_t src_y,
354         uint32_t src_w,
355         uint32_t src_h)
356 {
357         int j;
358         struct gralloc_drm_handle_t *drm_handle =
359                 gralloc_drm_handle(handle);
360         int plane_count = drm->plane_resources->count_planes;
361         struct gralloc_drm_plane_t *plane = drm->planes;
362
363         /* no supported planes for this handle */
364         if (!drm_handle->plane_mask) {
365                 ALOGE("%s: buffer %p cannot be shown on a plane\n",
366                         __func__, drm_handle);
367                 return -EINVAL;
368         }
369
370         for (j = 0; j < plane_count; j++, plane++) {
371
372                 /*
373                  * handle may be suitable to be shown on a plane, in
374                  * addition we need to check that this particular plane
375                  * is supported by the current implementation
376                  */
377                 if (!is_plane_supported(drm, plane))
378                         continue;
379
380                 /* if plane is available and can support this buffer */
381                 if (!plane->active &&
382                         drm_handle->plane_mask &
383                         (1U << plane->drm_plane->plane_id)) {
384
385                         plane->dst_x = dst_x;
386                         plane->dst_y = dst_y;
387                         plane->dst_w = dst_w;
388                         plane->dst_h = dst_h;
389                         plane->src_x = src_x;
390                         plane->src_y = src_y;
391                         plane->src_w = src_w;
392                         plane->src_h = src_h;
393                         plane->handle = handle;
394                         plane->id = id;
395                         plane->active = 1;
396
397                         return 0;
398                 }
399         }
400
401         /* no free planes available */
402         return -EBUSY;
403 }
404
405 /*
406  * Interface for HWC, used to disable all the overlays. Plane id
407  * is also set to 0 as it should be mappable to a particular layer only
408  * if it has been reserved with 'reserve_plane'.
409  */
410 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
411 {
412         struct gralloc_drm_plane_t *plane = drm->planes;
413         unsigned int i;
414
415         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
416                 plane->active = 0;
417                 plane->id = 0;
418         }
419 }
420
421 /*
422  * Interface for HWC, used to change handle of a reserved plane.
423  */
424 int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
425         uint32_t id, buffer_handle_t handle)
426 {
427         struct gralloc_drm_plane_t *plane = drm->planes;
428         unsigned i;
429
430         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
431                 if (plane->active && plane->id == id) {
432                         plane->handle = handle;
433                         return 0;
434                 }
435
436         return -EINVAL;
437 }
438
439 static int drm_kms_blit_to_hdmi(struct gralloc_drm_t *drm, struct gralloc_drm_bo_t *bo)
440 {
441         int ret = 0;
442         if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo) {
443
444                 int dst_x1 = 0, dst_y1 = 0;
445
446                 if (drm->hdmi.bo->handle->width > bo->handle->width)
447                         dst_x1 = (drm->hdmi.bo->handle->width - bo->handle->width) / 2;
448                 if (drm->hdmi.bo->handle->height > bo->handle->height)
449                         dst_y1 = (drm->hdmi.bo->handle->height - bo->handle->height) / 2;
450
451                 drm->drv->blit(drm->drv, drm->hdmi.bo, bo,
452                                 dst_x1, dst_y1,
453                                 dst_x1 + bo->handle->width,
454                                 dst_y1 + bo->handle->height,
455                                 0, 0, bo->handle->width, bo->handle->height);
456
457                 ret = drmModePageFlip(drm->fd, drm->hdmi.crtc_id, drm->hdmi.bo->fb_id, 0, NULL);
458                 if (ret && errno != EBUSY)
459                         ALOGE("failed to perform page flip for hdmi (%s) (crtc %d fb %d))",
460                                         strerror(errno), drm->hdmi.crtc_id, drm->hdmi.bo->fb_id);
461         }
462
463         return ret;
464 }
465
466 /*
467  * Schedule a page flip.
468  */
469 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
470                 struct gralloc_drm_bo_t *bo)
471 {
472         int ret;
473
474         /* there is another flip pending */
475         while (drm->next_front) {
476                 drm->waiting_flip = 1;
477                 drmHandleEvent(drm->fd, &drm->evctx);
478                 drm->waiting_flip = 0;
479                 if (drm->next_front) {
480                         /* record an error and break */
481                         ALOGE("drmHandleEvent returned without flipping");
482                         drm->current_front = drm->next_front;
483                         drm->next_front = NULL;
484                 }
485         }
486
487         if (!bo)
488                 return 0;
489
490         pthread_mutex_lock(&drm->hdmi_mutex);
491         drm_kms_blit_to_hdmi(drm, bo);
492         pthread_mutex_unlock(&drm->hdmi_mutex);
493
494         /* set planes to be displayed */
495         gralloc_drm_set_planes(drm);
496
497         ret = drmModePageFlip(drm->fd, drm->primary.crtc_id, bo->fb_id,
498                         DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
499         if (ret) {
500                 ALOGE("failed to perform page flip for primary (%s) (crtc %d fb %d))",
501                         strerror(errno), drm->primary.crtc_id, bo->fb_id);
502                 /* try to set mode for next frame */
503                 if (errno != EBUSY)
504                         drm->first_post = 1;
505         }
506         else
507                 drm->next_front = bo;
508
509         return ret;
510 }
511
512 /*
513  * Wait for the next post.
514  */
515 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
516 {
517         unsigned int current, target;
518         drmVBlank vbl;
519         int ret;
520
521         if (drm->mode_quirk_vmwgfx)
522                 return;
523
524         flip = !!flip;
525
526         memset(&vbl, 0, sizeof(vbl));
527         vbl.request.type = DRM_VBLANK_RELATIVE;
528         if (drm->vblank_secondary)
529                 vbl.request.type |= DRM_VBLANK_SECONDARY;
530         vbl.request.sequence = 0;
531
532         /* get the current vblank */
533         ret = drmWaitVBlank(drm->fd, &vbl);
534         if (ret) {
535                 ALOGW("failed to get vblank");
536                 return;
537         }
538
539         current = vbl.reply.sequence;
540         if (drm->first_post)
541                 target = current;
542         else
543                 target = drm->last_swap + drm->swap_interval - flip;
544
545         /* wait for vblank */
546         if (current < target || !flip) {
547                 memset(&vbl, 0, sizeof(vbl));
548                 vbl.request.type = DRM_VBLANK_ABSOLUTE;
549                 if (drm->vblank_secondary)
550                         vbl.request.type |= DRM_VBLANK_SECONDARY;
551                 if (!flip) {
552                         vbl.request.type |= DRM_VBLANK_NEXTONMISS;
553                         if (target < current)
554                                 target = current;
555                 }
556
557                 vbl.request.sequence = target;
558
559                 ret = drmWaitVBlank(drm->fd, &vbl);
560                 if (ret) {
561                         ALOGW("failed to wait vblank");
562                         return;
563                 }
564         }
565
566         drm->last_swap = vbl.reply.sequence + flip;
567 }
568
569 /*
570  * Post a bo.  This is not thread-safe.
571  */
572 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
573 {
574         struct gralloc_drm_t *drm = bo->drm;
575         int ret;
576
577         if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
578                 ALOGE("unable to post bo %p without fb", bo);
579                 return -EINVAL;
580         }
581
582         /* TODO spawn a thread to avoid waiting and race */
583
584         if (drm->first_post) {
585                 if (drm->swap_mode == DRM_SWAP_COPY) {
586                         struct gralloc_drm_bo_t *dst;
587
588                         dst = (drm->next_front) ?
589                                 drm->next_front :
590                                 drm->current_front;
591                         drm->drv->blit(drm->drv, dst, bo, 0, 0,
592                                         bo->handle->width,
593                                         bo->handle->height,
594                                         0, 0,
595                                         bo->handle->width,
596                                         bo->handle->height);
597                         bo = dst;
598                 }
599
600                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
601                 if (!ret) {
602                         drm->first_post = 0;
603                         drm->current_front = bo;
604                         if (drm->next_front == bo)
605                                 drm->next_front = NULL;
606                 }
607
608                 pthread_mutex_lock(&drm->hdmi_mutex);
609                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
610                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
611                 pthread_mutex_unlock(&drm->hdmi_mutex);
612
613                 return ret;
614         }
615
616         switch (drm->swap_mode) {
617         case DRM_SWAP_FLIP:
618                 if (drm->swap_interval > 1)
619                         drm_kms_wait_for_post(drm, 1);
620                 ret = drm_kms_page_flip(drm, bo);
621                 if (drm->next_front) {
622                         /*
623                          * wait if the driver says so or the current front
624                          * will be written by CPU
625                          */
626                         if (drm->mode_sync_flip ||
627                             (drm->current_front->handle->usage &
628                              GRALLOC_USAGE_SW_WRITE_MASK))
629                                 drm_kms_page_flip(drm, NULL);
630                 }
631                 break;
632         case DRM_SWAP_COPY:
633                 drm_kms_wait_for_post(drm, 0);
634                 drm->drv->blit(drm->drv, drm->current_front,
635                                 bo, 0, 0,
636                                 bo->handle->width,
637                                 bo->handle->height,
638                                 0, 0,
639                                 bo->handle->width,
640                                 bo->handle->height);
641                 if (drm->mode_quirk_vmwgfx)
642                         ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
643                 ret = 0;
644                 break;
645         case DRM_SWAP_SETCRTC:
646                 drm_kms_wait_for_post(drm, 0);
647                 ret = drm_kms_set_crtc(drm, &drm->primary, bo->fb_id);
648
649                 pthread_mutex_lock(&drm->hdmi_mutex);
650                 if (drm->hdmi.active && drm->hdmi_mode == HDMI_CLONED && drm->hdmi.bo)
651                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
652                 pthread_mutex_unlock(&drm->hdmi_mutex);
653
654                 drm->current_front = bo;
655                 break;
656         default:
657                 /* no-op */
658                 ret = 0;
659                 break;
660         }
661
662         return ret;
663 }
664
665 static struct gralloc_drm_t *drm_singleton;
666
667 static void on_signal(int sig)
668 {
669         struct gralloc_drm_t *drm = drm_singleton;
670
671         /* wait the pending flip */
672         if (drm && drm->swap_mode == DRM_SWAP_FLIP && drm->next_front) {
673                 /* there is race, but this function is hacky enough to ignore that */
674                 if (drm_singleton->waiting_flip)
675                         usleep(100 * 1000); /* 100ms */
676                 else
677                         drm_kms_page_flip(drm_singleton, NULL);
678         }
679
680         exit(-1);
681 }
682
683 static void drm_kms_init_features(struct gralloc_drm_t *drm)
684 {
685         const char *swap_mode;
686
687         /* call to the driver here, after KMS has been initialized */
688         drm->drv->init_kms_features(drm->drv, drm);
689
690         if (drm->swap_mode == DRM_SWAP_FLIP) {
691                 struct sigaction act;
692
693                 memset(&drm->evctx, 0, sizeof(drm->evctx));
694                 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
695                 drm->evctx.page_flip_handler = page_flip_handler;
696
697                 /*
698                  * XXX GPU tends to freeze if the program is terminiated with a
699                  * flip pending.  What is the right way to handle the
700                  * situation?
701                  */
702                 sigemptyset(&act.sa_mask);
703                 act.sa_handler = on_signal;
704                 act.sa_flags = 0;
705                 sigaction(SIGINT, &act, NULL);
706                 sigaction(SIGTERM, &act, NULL);
707
708                 drm_singleton = drm;
709         }
710         else if (drm->swap_mode == DRM_SWAP_COPY) {
711                 struct gralloc_drm_bo_t *front;
712                 int stride;
713
714                 /* create the real front buffer */
715                 front = gralloc_drm_bo_create(drm,
716                                               drm->primary.mode.hdisplay,
717                                               drm->primary.mode.vdisplay,
718                                               drm->primary.fb_format,
719                                               GRALLOC_USAGE_HW_FB);
720                 if (front && gralloc_drm_bo_add_fb(front)) {
721                         gralloc_drm_bo_decref(front);
722                         front = NULL;
723                 }
724
725                 /* abuse next_front */
726                 if (front)
727                         drm->next_front = front;
728                 else
729                         drm->swap_mode = DRM_SWAP_SETCRTC;
730         }
731
732         switch (drm->swap_mode) {
733         case DRM_SWAP_FLIP:
734                 swap_mode = "flip";
735                 break;
736         case DRM_SWAP_COPY:
737                 swap_mode = "copy";
738                 break;
739         case DRM_SWAP_SETCRTC:
740                 swap_mode = "set-crtc";
741                 break;
742         default:
743                 swap_mode = "no-op";
744                 break;
745         }
746
747         ALOGD("will use %s for fb posting", swap_mode);
748 }
749
750 #define MARGIN_PERCENT 1.8   /* % of active vertical image*/
751 #define CELL_GRAN 8.0   /* assumed character cell granularity*/
752 #define MIN_PORCH 1 /* minimum front porch   */
753 #define V_SYNC_RQD 3 /* width of vsync in lines   */
754 #define H_SYNC_PERCENT 8.0   /* width of hsync as % of total line */
755 #define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
756 #define M 600.0 /* blanking formula gradient */
757 #define C 40.0  /* blanking formula offset   */
758 #define K 128.0 /* blanking formula scaling factor   */
759 #define J 20.0  /* blanking formula scaling factor   */
760 /* C' and M' are part of the Blanking Duty Cycle computation */
761 #define C_PRIME   (((C - J) * K / 256.0) + J)
762 #define M_PRIME   (K / 256.0 * M)
763
764 static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
765 {
766         float h_pixels_rnd;
767         float v_lines_rnd;
768         float v_field_rate_rqd;
769         float top_margin;
770         float bottom_margin;
771         float interlace;
772         float h_period_est;
773         float vsync_plus_bp;
774         float v_back_porch;
775         float total_v_lines;
776         float v_field_rate_est;
777         float h_period;
778         float v_field_rate;
779         float v_frame_rate;
780         float left_margin;
781         float right_margin;
782         float total_active_pixels;
783         float ideal_duty_cycle;
784         float h_blank;
785         float total_pixels;
786         float pixel_freq;
787         float h_freq;
788
789         float h_sync;
790         float h_front_porch;
791         float v_odd_front_porch_lines;
792         int interlaced = 0;
793         int margins = 0;
794
795         drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
796
797         h_pixels_rnd = rint((float) h_pixels / CELL_GRAN) * CELL_GRAN;
798         v_lines_rnd = interlaced ? rint((float) v_lines) / 2.0 : rint((float) v_lines);
799         v_field_rate_rqd = interlaced ? (freq * 2.0) : (freq);
800         top_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
801         bottom_margin = margins ? rint(MARGIN_PERCENT / 100.0 * v_lines_rnd) : (0.0);
802         interlace = interlaced ? 0.5 : 0.0;
803         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);
804         vsync_plus_bp = rint(MIN_VSYNC_PLUS_BP / h_period_est);
805         v_back_porch = vsync_plus_bp - V_SYNC_RQD;
806         total_v_lines = v_lines_rnd + top_margin + bottom_margin + vsync_plus_bp + interlace + MIN_PORCH;
807         v_field_rate_est = 1.0 / h_period_est / total_v_lines * 1000000.0;
808         h_period = h_period_est / (v_field_rate_rqd / v_field_rate_est);
809         v_field_rate = 1.0 / h_period / total_v_lines * 1000000.0;
810         v_frame_rate = interlaced ? v_field_rate / 2.0 : v_field_rate;
811         left_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
812         right_margin = margins ? rint(h_pixels_rnd * MARGIN_PERCENT / 100.0 / CELL_GRAN) * CELL_GRAN : 0.0;
813         total_active_pixels = h_pixels_rnd + left_margin + right_margin;
814         ideal_duty_cycle = C_PRIME - (M_PRIME * h_period / 1000.0);
815         h_blank = rint(total_active_pixels * ideal_duty_cycle / (100.0 - ideal_duty_cycle) / (2.0 * CELL_GRAN)) * (2.0 * CELL_GRAN);
816         total_pixels = total_active_pixels + h_blank;
817         pixel_freq = total_pixels / h_period;
818         h_freq = 1000.0 / h_period;
819         h_sync = rint(H_SYNC_PERCENT / 100.0 * total_pixels / CELL_GRAN) * CELL_GRAN;
820         h_front_porch = (h_blank / 2.0) - h_sync;
821         v_odd_front_porch_lines = MIN_PORCH + interlace;
822
823         m->clock = ceil(pixel_freq) * 1000;
824         m->hdisplay = (int) (h_pixels_rnd);
825         m->hsync_start = (int) (h_pixels_rnd + h_front_porch);
826         m->hsync_end = (int) (h_pixels_rnd + h_front_porch + h_sync);
827         m->htotal = (int) (total_pixels);
828         m->hskew = 0;
829         m->vdisplay = (int) (v_lines_rnd);
830         m->vsync_start = (int) (v_lines_rnd + v_odd_front_porch_lines);
831         m->vsync_end = (int) (int) (v_lines_rnd + v_odd_front_porch_lines + V_SYNC_RQD);
832         m->vtotal = (int) (total_v_lines);
833         m->vscan = 0;
834         m->vrefresh = freq;
835         m->flags = 10;
836         m->type = 64;
837
838         return (m);
839 }
840
841 static int mode_distance_best_fit(
842                 int xres_base,
843                 int yres_base,
844                 int xres,
845                 int yres,
846                 double prefered_aspect)
847 {
848         const double eps = 0.3;
849
850         if (xres_base > xres || yres_base > yres) {
851                 // if the res cannot cover base res, return max int
852                 return INT_MAX;
853         } else if (fabs((double) xres / yres - prefered_aspect) > eps) {
854                 // if the aspect is too different with prefered_aspect, return max int
855                 return INT_MAX;
856         } else {
857                 return (xres - xres_base) * (xres - xres_base) +
858                                 (yres - yres_base) * (yres - yres_base) +
859                                 ((xres / yres) - prefered_aspect) * ((xres / yres) - prefered_aspect);
860         }
861 }
862
863 static int mode_distance_closest(int xres_base, int yres_base, int xres, int yres) {
864         return (xres - xres_base) * (xres - xres_base) +
865                         (yres - yres_base) * (yres - yres_base);
866 }
867
868 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp, drmModeModeInfoPtr primary_mode)
869 {
870         char value[PROPERTY_VALUE_MAX];
871         drmModeModeInfoPtr mode;
872         int dist, i;
873         int xres = 0, yres = 0, rate = 0;
874         int forcemode = 0;
875         int bestfit = 0;
876
877         if (property_get("debug.drm.mode", value, NULL)) {
878                 char *p = value, *end;
879
880                 /* parse <xres>x<yres>[@<bpp>] */
881                 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
882                         *bpp = 0;
883                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
884                                 xres = yres = 0;
885                 }
886
887                 if ((xres && yres) || *bpp) {
888                         ALOGI("will find the closest match for %dx%d@%d",
889                                         xres, yres, *bpp);
890                 }
891         } else if (property_get("debug.drm.mode.force", value, NULL)) {
892                 char *p = value, *end;
893                 *bpp = 0;
894
895                 /* parse <xres>x<yres>[@<refreshrate>] */
896                 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
897                         rate = 60;
898                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
899                                 xres = yres = 0;
900                 }
901
902                 if (xres && yres && rate) {
903                         ALOGI("will use %dx%d@%dHz", xres, yres, rate);
904                         forcemode = 1;
905                 }
906         } else if (primary_mode != NULL) {
907                 xres = primary_mode->hdisplay;
908                 yres = primary_mode->vdisplay;
909                 *bpp = 0;
910                 bestfit = 1;
911                 ALOGI("will find the best fit for %dx%d", xres, yres);
912         } else {
913                 *bpp = 0;
914         }
915
916         dist = INT_MAX;
917
918         if (forcemode)
919                 mode = generate_mode(xres, yres, rate);
920         else {
921                 mode = NULL;
922                 for (i = 0; i < connector->count_modes; i++) {
923                         drmModeModeInfoPtr m = &connector->modes[i];
924                         int tmp;
925
926                         if (xres && yres) {
927                                 if (bestfit) {
928                                         tmp = mode_distance_best_fit(
929                                                         xres,
930                                                         yres,
931                                                         m->hdisplay,
932                                                         m->vdisplay,
933                                                         (double) connector->modes[0].hdisplay / connector->modes[0].vdisplay);
934                                 } else {
935                                         tmp = mode_distance_closest(xres, yres, m->hdisplay, m->vdisplay);
936                                 }
937                         }
938                         else {
939                                 /* use the first preferred mode */
940                                 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
941                         }
942
943                         if (tmp < dist) {
944                                 mode = m;
945                                 dist = tmp;
946                                 if (!dist)
947                                         break;
948                         }
949                 }
950         }
951
952         /* fallback to the first mode */
953         if (!mode)
954                 mode = &connector->modes[0];
955
956         ALOGI("Established mode:");
957         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);
958         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);
959         ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
960
961         *bpp /= 8;
962
963         return mode;
964 }
965
966 static int used_crtcs = 0;
967
968 /*
969  * Initialize KMS with a connector.
970  */
971 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
972                 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
973 {
974         drmModeEncoderPtr encoder;
975         drmModeModeInfoPtr mode;
976         int bpp, i;
977
978         if (!connector->count_modes)
979                 return -EINVAL;
980
981         encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
982         if (!encoder)
983                 return -EINVAL;
984
985         /* find first possible crtc which is not used yet */
986         for (i = 0; i < drm->resources->count_crtcs; i++) {
987                 if (encoder->possible_crtcs & (1 << i) &&
988                         (used_crtcs & (1 << i)) != (1 << i))
989                         break;
990         }
991
992         used_crtcs |= (1 << i);
993
994         drmModeFreeEncoder(encoder);
995         if (i == drm->resources->count_crtcs)
996                 return -EINVAL;
997
998         output->bo = NULL;
999         output->crtc_id = drm->resources->crtcs[i];
1000         output->connector_id = connector->connector_id;
1001         output->pipe = i;
1002
1003         /* print connector info */
1004         if (connector->count_modes > 1) {
1005                 ALOGI("there are %d modes on connector 0x%x, type %d",
1006                                 connector->count_modes,
1007                                 connector->connector_id,
1008                                 connector->connector_type);
1009                 for (i = 0; i < connector->count_modes; i++)
1010                         ALOGI("  %s", connector->modes[i].name);
1011         }
1012         else {
1013                 ALOGI("there is one mode on connector 0x%d: %s",
1014                                 connector->connector_id,
1015                                 connector->modes[0].name);
1016         }
1017
1018         if (property_get_bool("persist.remixos.disp_best_fit", 1) && output != &drm->primary) {
1019                 mode = find_mode(connector, &bpp, &drm->primary.mode);
1020         } else {
1021                 mode = find_mode(connector, &bpp, NULL);
1022         }
1023
1024         ALOGI("the best mode is %s", mode->name);
1025
1026         output->mode = *mode;
1027         switch (bpp) {
1028         case 2:
1029                 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
1030                 break;
1031         case 4:
1032         default:
1033                 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
1034                 break;
1035         }
1036
1037         if (connector->mmWidth && connector->mmHeight) {
1038                 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
1039                 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
1040         }
1041         else {
1042                 output->xdpi = 75;
1043                 output->ydpi = 75;
1044         }
1045
1046 #ifdef DRM_MODE_FEATURE_DIRTYFB
1047         drm->clip.x1 = 0;
1048         drm->clip.y1 = 0;
1049         drm->clip.x2 = output->mode.hdisplay;
1050         drm->clip.y2 = output->mode.vdisplay;
1051 #endif
1052
1053         return 0;
1054 }
1055
1056
1057 /*
1058  * Fetch a connector of particular type
1059  */
1060 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
1061         uint32_t type)
1062 {
1063         int i;
1064
1065         if (!drm->resources)
1066                 return NULL;
1067
1068         for (i = 0; i < drm->resources->count_connectors; i++) {
1069                 drmModeConnectorPtr connector =
1070                         connector = drmModeGetConnector(drm->fd,
1071                                 drm->resources->connectors[i]);
1072                 if (connector) {
1073                         if (connector->connector_type == type &&
1074                                 connector->connection == DRM_MODE_CONNECTED)
1075                                 return connector;
1076                         drmModeFreeConnector(connector);
1077                 }
1078         }
1079         return NULL;
1080 }
1081
1082
1083 /*
1084  * Initializes hdmi output with a connector and allocates
1085  * a private framebuffer for it. This is called on startup if
1086  * hdmi cable is connected and also on hotplug events.
1087  */
1088 static int init_hdmi_output(struct gralloc_drm_t *drm,
1089         drmModeConnectorPtr connector)
1090 {
1091         drm_kms_init_with_connector(drm, &drm->hdmi, connector);
1092
1093         ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
1094                 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
1095
1096         drm->hdmi.bo = gralloc_drm_bo_create(drm,
1097                 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
1098                 drm->hdmi.fb_format,
1099                 GRALLOC_USAGE_HW_RENDER);
1100
1101         int err = gralloc_drm_bo_add_fb(drm->hdmi.bo);
1102         if (err) {
1103                 ALOGE("%s: could not create drm fb, (%s)",
1104                         __func__, strerror(-err));
1105                 return err;
1106         }
1107
1108         drm->hdmi_mode = HDMI_CLONED;
1109         drm->hdmi.active = 1;
1110
1111         return 0;
1112 }
1113
1114
1115 /*
1116  * Thread that listens to uevents and checks if hdmi state changes
1117  */
1118 static void *hdmi_observer(void *data)
1119 {
1120         static char uevent_desc[4096];
1121         drmModeConnectorPtr hdmi;
1122         struct gralloc_drm_t *drm =
1123                 (struct gralloc_drm_t *) data;
1124         struct uevent event;
1125
1126         uevent_init();
1127
1128         memset(uevent_desc, 0, sizeof(uevent_desc));
1129
1130         while(1) {
1131
1132                 /* this polls */
1133                 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1134                 if (!len) continue;
1135
1136                 parse_event(uevent_desc, &event);
1137                 ALOGD_IF(0, "event { '%s', '%s', '%s', %d, %d, %d, %d }\n",
1138                                 event.action, event.path, event.subsystem,
1139                                 event.major, event.minor,
1140                                 event.switchstate, event.hotplug);
1141
1142                 if (!strcmp(event.path, "devices/virtual/switch/hdmi")) {
1143                         if (event.switchstate != -1) {
1144                                 pthread_mutex_lock(&drm->hdmi_mutex);
1145
1146                                 if (event.switchstate) {
1147                                         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1148                                         if (hdmi) {
1149                                                 ALOGD("init hdmi on switch_state event");
1150                                                 init_hdmi_output(drm, hdmi);
1151
1152                                                 /* will trigger modeset */
1153                                                 drm->first_post = 1;
1154
1155                                                 drmModeFreeConnector(hdmi);
1156                                         }
1157                                 } else {
1158                                         drm->hdmi.active = 0;
1159                                         used_crtcs &= ~(1 << drm->hdmi.pipe);
1160
1161                                         ALOGD("destroy hdmi private buffer");
1162                                         gralloc_drm_bo_decref(drm->hdmi.bo);
1163                                         drm->hdmi.bo = NULL;
1164                                 }
1165
1166                                 pthread_mutex_unlock(&drm->hdmi_mutex);
1167                         }
1168                 } else if (!strcmp(event.subsystem, "drm") &&
1169                                 !strcmp(event.device_name, "dri/card0") && event.hotplug) {
1170                         pthread_mutex_lock(&drm->hdmi_mutex);
1171
1172                         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1173                         if (hdmi && !drm->hdmi.active) {
1174                                 ALOGD("init hdmi on hotplug event");
1175                                 if (!init_hdmi_output(drm, hdmi)) {
1176                                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
1177                                 }
1178
1179                                 /* will trigger modeset */
1180                                 drm->first_post = 1;
1181                         } else if (!hdmi && drm->hdmi.active) {
1182                                 drm->hdmi.active = 0;
1183                                 used_crtcs &= ~(1 << drm->hdmi.pipe);
1184
1185                                 ALOGD("destroy hdmi private buffer");
1186                                 gralloc_drm_bo_decref(drm->hdmi.bo);
1187                                 drm->hdmi.bo = NULL;
1188                         }
1189
1190                         if (hdmi)
1191                                 drmModeFreeConnector(hdmi);
1192
1193                         pthread_mutex_unlock(&drm->hdmi_mutex);
1194                 }
1195         }
1196
1197         pthread_exit(NULL);
1198         return 0;
1199 }
1200
1201
1202 /*
1203  * Initialize KMS.
1204  */
1205 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1206 {
1207         drmModeConnectorPtr lvds, hdmi;
1208         int i, ret;
1209
1210         if (drm->resources)
1211                 return 0;
1212
1213         drm->resources = drmModeGetResources(drm->fd);
1214         if (!drm->resources) {
1215                 ALOGE("failed to get modeset resources");
1216                 return -EINVAL;
1217         }
1218
1219         drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1220         if (!drm->plane_resources) {
1221                 ALOGD("no planes found from drm resources");
1222         } else {
1223                 unsigned int i, j;
1224
1225                 ALOGD("supported drm planes and formats");
1226                 /* fill a helper structure for hwcomposer */
1227                 drm->planes = calloc(drm->plane_resources->count_planes,
1228                         sizeof(struct gralloc_drm_plane_t));
1229
1230                 for (i = 0; i < drm->plane_resources->count_planes; i++) {
1231                         drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
1232                                 drm->plane_resources->planes[i]);
1233
1234                         ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
1235                         for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
1236                                 ALOGD("    format %c%c%c%c",
1237                                         (drm->planes[i].drm_plane->formats[j]),
1238                                         (drm->planes[i].drm_plane->formats[j])>>8,
1239                                         (drm->planes[i].drm_plane->formats[j])>>16,
1240                                         (drm->planes[i].drm_plane->formats[j])>>24);
1241                 }
1242         }
1243
1244         /* find the crtc/connector/mode to use */
1245         lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1246         if (lvds) {
1247                 drm_kms_init_with_connector(drm, &drm->primary, lvds);
1248                 drmModeFreeConnector(lvds);
1249                 drm->primary.active = 1;
1250         }
1251
1252         /* if still no connector, find first connected connector and try it */
1253         if (!drm->primary.active) {
1254
1255                 for (i = 0; i < drm->resources->count_connectors; i++) {
1256                         drmModeConnectorPtr connector;
1257
1258                         connector = drmModeGetConnector(drm->fd,
1259                                         drm->resources->connectors[i]);
1260                         if (connector) {
1261                                 if (connector->connection == DRM_MODE_CONNECTED) {
1262                                         if (!drm_kms_init_with_connector(drm,
1263                                                         &drm->primary, connector))
1264                                                 break;
1265                                 }
1266
1267                                 drmModeFreeConnector(connector);
1268                         }
1269                 }
1270                 if (i == drm->resources->count_connectors) {
1271                         ALOGE("failed to find a valid crtc/connector/mode combination");
1272                         drmModeFreeResources(drm->resources);
1273                         drm->resources = NULL;
1274
1275                         return -EINVAL;
1276                 }
1277         }
1278
1279         /* HDMI mirror mode need driver support for blitting. which is not implemented for
1280                 drivers other than intel. skip HDMI detection for them to avoid crash
1281         */
1282         if (!drm->drv->blit)
1283                 goto skip_hdmi_modes;
1284
1285         /* check if hdmi is connected already */
1286         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1287         if (hdmi) {
1288
1289                 if (hdmi->connector_id == drm->primary.connector_id) {
1290                         /* special case: our primary connector is hdmi */
1291                         ALOGD("hdmi is the primary connector");
1292                         goto skip_hdmi_modes;
1293                 }
1294
1295                 ALOGD("init hdmi on startup");
1296                 init_hdmi_output(drm, hdmi);
1297
1298                 drmModeFreeConnector(hdmi);
1299         }
1300
1301         /* launch hdmi observer thread */
1302         pthread_mutex_init(&drm->hdmi_mutex, NULL);
1303         pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1304
1305 skip_hdmi_modes:
1306
1307         drm_kms_init_features(drm);
1308         drm->first_post = 1;
1309
1310         return 0;
1311 }
1312
1313 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1314 {
1315         switch (drm->swap_mode) {
1316         case DRM_SWAP_FLIP:
1317                 drm_kms_page_flip(drm, NULL);
1318                 break;
1319         case DRM_SWAP_COPY:
1320                 {
1321                         struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1322                                 &drm->current_front : &drm->next_front;
1323
1324                         if (*bo)
1325                                 gralloc_drm_bo_decref(*bo);
1326                         *bo = NULL;
1327                 }
1328                 break;
1329         default:
1330                 break;
1331         }
1332
1333         /* restore crtc? */
1334
1335         if (drm->resources) {
1336                 drmModeFreeResources(drm->resources);
1337                 drm->resources = NULL;
1338         }
1339
1340         if (drm->planes) {
1341                 unsigned int i;
1342                 for (i = 0; i < drm->plane_resources->count_planes; i++)
1343                         drmModeFreePlane(drm->planes[i].drm_plane);
1344                 free(drm->planes);
1345                 drm->planes = NULL;
1346         }
1347
1348         if (drm->plane_resources) {
1349                 drmModeFreePlaneResources(drm->plane_resources);
1350                 drm->plane_resources = NULL;
1351         }
1352
1353         /* destroy private buffer of hdmi output */
1354         if (drm->hdmi.bo)
1355                 gralloc_drm_bo_decref(drm->hdmi.bo);
1356
1357         drm_singleton = NULL;
1358 }
1359
1360 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1361 {
1362         return (drm->resources != NULL);
1363 }
1364
1365 /*
1366  * Initialize a framebuffer device with KMS info.
1367  */
1368 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1369                 struct framebuffer_device_t *fb)
1370 {
1371         *((uint32_t *) &fb->flags) = 0x0;
1372         *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
1373         *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
1374         *((int *)      &fb->stride) = drm->primary.mode.hdisplay;
1375         *((float *)    &fb->fps) = drm->primary.mode.vrefresh;
1376
1377         *((int *)      &fb->format) = drm->primary.fb_format;
1378         *((float *)    &fb->xdpi) = drm->primary.xdpi;
1379         *((float *)    &fb->ydpi) = drm->primary.ydpi;
1380         *((int *)      &fb->minSwapInterval) = drm->swap_interval;
1381         *((int *)      &fb->maxSwapInterval) = drm->swap_interval;
1382 }
1383
1384 /*
1385  * Return true if fb posting is pipelined.
1386  */
1387 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1388 {
1389         return (drm->swap_mode != DRM_SWAP_SETCRTC);
1390 }