OSDN Git Service

Change default pixel format to RGBA8888
[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_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;
122                 default:
123                         return 0;
124         }
125 }
126
127 /*
128  * Modify pitches, offsets and handles according to
129  * the format and return corresponding drm format value
130  */
131 static int resolve_drm_format(struct gralloc_drm_bo_t *bo,
132         uint32_t *pitches, uint32_t *offsets, uint32_t *handles)
133 {
134         struct gralloc_drm_t *drm = bo->drm;
135
136         pitches[0] = bo->handle->stride;
137         handles[0] = bo->fb_handle;
138
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);
143
144         return drm_format_from_hal(bo->handle->format);
145 }
146
147 /*
148  * Returns planes that are supported for a particular format
149  */
150 unsigned int planes_for_format(struct gralloc_drm_t *drm,
151         int hal_format)
152 {
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;
156
157         /* no planes available */
158         if (!plane)
159                 return 0;
160
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);
166
167         return mask;
168 }
169
170 /*
171  * Add a fb object for a bo.
172  */
173 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
174 {
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 };
178
179         if (bo->fb_id)
180                 return 0;
181
182         int drm_format = resolve_drm_format(bo, pitches, offsets, handles);
183
184         if (drm_format == 0) {
185                 ALOGE("error resolving drm format");
186                 return -EINVAL;
187         }
188
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);
193 }
194
195 /*
196  * Remove a fb object for a bo.
197  */
198 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
199 {
200         if (bo->fb_id) {
201                 drmModeRmFB(bo->drm->fd, bo->fb_id);
202                 bo->fb_id = 0;
203         }
204 }
205
206 /*
207  * Program CRTC.
208  */
209 static int drm_kms_set_crtc(struct gralloc_drm_t *drm,
210         struct gralloc_drm_output *output, int fb_id)
211 {
212         int ret;
213
214         ret = drmModeSetCrtc(drm->fd, output->crtc_id, fb_id,
215                         0, 0, &output->connector_id, 1, &output->mode);
216         if (ret) {
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);
220                 return ret;
221         }
222
223         if (drm->mode_quirk_vmwgfx)
224                 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
225
226         return ret;
227 }
228
229 /*
230  * Callback for a page flip event.
231  */
232 static void page_flip_handler(int fd, unsigned int sequence,
233                 unsigned int tv_sec, unsigned int tv_usec,
234                 void *user_data)
235 {
236         struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
237
238         /* ack the last scheduled flip */
239         drm->current_front = drm->next_front;
240         drm->next_front = NULL;
241 }
242
243 /*
244  * Set a plane.
245  */
246 static int gralloc_drm_bo_setplane(struct gralloc_drm_t *drm,
247         struct gralloc_drm_plane_t *plane)
248 {
249         struct gralloc_drm_bo_t *bo = NULL;
250         int err;
251
252         if (plane->handle)
253                 bo = gralloc_drm_bo_from_handle(plane->handle);
254
255         // create a framebuffer if does not exist
256         if (bo && bo->fb_id == 0) {
257                 err = gralloc_drm_bo_add_fb(bo);
258                 if (err) {
259                         ALOGE("%s: could not create drm fb, (%s)",
260                                 __func__, strerror(-err));
261                         return err;
262                 }
263         }
264
265         err = drmModeSetPlane(drm->fd,
266                 plane->drm_plane->plane_id,
267                 drm->primary->crtc_id,
268                 bo ? bo->fb_id : 0,
269                 0, // flags
270                 plane->dst_x,
271                 plane->dst_y,
272                 plane->dst_w,
273                 plane->dst_h,
274                 plane->src_x << 16,
275                 plane->src_y << 16,
276                 plane->src_w << 16,
277                 plane->src_h << 16);
278
279         if (err) {
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;
284
285                 ALOGE("drmModeSetPlane : error (%s) (plane %d crtc %d fb %d)",
286                         strerror(-err),
287                         plane->drm_plane->plane_id,
288                         drm->primary->crtc_id,
289                         bo ? bo->fb_id : 0);
290         }
291
292         if (plane->prev)
293                 gralloc_drm_bo_decref(plane->prev);
294
295         if (bo)
296                 bo->refcount++;
297
298         plane->prev = bo;
299
300         return err;
301 }
302
303 /*
304  * Returns if a particular plane is supported with the implementation
305  */
306 static unsigned is_plane_supported(const struct gralloc_drm_t *drm,
307         const struct gralloc_drm_plane_t *plane)
308 {
309         /* Planes are only supported on primary pipe for now */
310         return plane->drm_plane->possible_crtcs & (1 << drm->primary->pipe);
311 }
312
313 /*
314  * Sets all the active planes to be displayed.
315  */
316 static void gralloc_drm_set_planes(struct gralloc_drm_t *drm)
317 {
318         struct gralloc_drm_plane_t *plane = drm->planes;
319         unsigned int i;
320         for (i = 0; i < drm->plane_resources->count_planes;
321                 i++, plane++) {
322                 /* plane is not in use at all */
323                 if (!plane->active && !plane->handle)
324                         continue;
325
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);
330
331                 /*
332                  * Disable overlay if it is not active
333                  * or if there is error during setplane
334                  */
335                 if (!plane->active)
336                         plane->handle = 0;
337
338                 if (gralloc_drm_bo_setplane(drm, plane))
339                         plane->active = 0;
340         }
341 }
342
343 /*
344  * Interface for HWC, used to reserve a plane for a layer.
345  */
346 int gralloc_drm_reserve_plane(struct gralloc_drm_t *drm,
347         buffer_handle_t handle,
348         uint32_t id,
349         uint32_t dst_x,
350         uint32_t dst_y,
351         uint32_t dst_w,
352         uint32_t dst_h,
353         uint32_t src_x,
354         uint32_t src_y,
355         uint32_t src_w,
356         uint32_t src_h)
357 {
358         int j;
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;
363
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);
368                 return -EINVAL;
369         }
370
371         for (j = 0; j < plane_count; j++, plane++) {
372
373                 /*
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
377                  */
378                 if (!is_plane_supported(drm, plane))
379                         continue;
380
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)) {
385
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;
395                         plane->id = id;
396                         plane->active = 1;
397
398                         return 0;
399                 }
400         }
401
402         /* no free planes available */
403         return -EBUSY;
404 }
405
406 /*
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'.
410  */
411 void gralloc_drm_disable_planes(struct gralloc_drm_t *drm)
412 {
413         struct gralloc_drm_plane_t *plane = drm->planes;
414         unsigned int i;
415
416         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++) {
417                 plane->active = 0;
418                 plane->id = 0;
419         }
420 }
421
422 /*
423  * Interface for HWC, used to change handle of a reserved plane.
424  */
425 int gralloc_drm_set_plane_handle(struct gralloc_drm_t *drm,
426         uint32_t id, buffer_handle_t handle)
427 {
428         struct gralloc_drm_plane_t *plane = drm->planes;
429         unsigned i;
430
431         for (i = 0; i < drm->plane_resources->count_planes; i++, plane++)
432                 if (plane->active && plane->id == id) {
433                         plane->handle = handle;
434                         return 0;
435                 }
436
437         return -EINVAL;
438 }
439
440 static int drm_kms_blit_to_mirror_connectors(struct gralloc_drm_t *drm, struct gralloc_drm_bo_t *bo)
441 {
442         int ret = 0;
443         for (int i = 1; i < drm->output_capacity; i++) {
444                 struct gralloc_drm_output *output = &drm->outputs[i];
445
446                 if (output->active && output->output_mode == DRM_OUTPUT_CLONED && output->bo) {
447
448                         int dst_x1 = 0, dst_y1 = 0;
449
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;
454
455                         drm->drv->blit(drm->drv, output->bo, bo,
456                                         dst_x1, dst_y1,
457                                         dst_x1 + bo->handle->width,
458                                         dst_y1 + bo->handle->height,
459                                         0, 0, bo->handle->width, bo->handle->height);
460
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);
465                 }
466         }
467
468         return ret;
469 }
470
471 /*
472  * Schedule a page flip.
473  */
474 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
475                 struct gralloc_drm_bo_t *bo)
476 {
477         int ret;
478
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;
489                 }
490         }
491
492         if (!bo)
493                 return 0;
494
495         pthread_mutex_lock(&drm->outputs_mutex);
496         drm_kms_blit_to_mirror_connectors(drm, bo);
497         pthread_mutex_unlock(&drm->outputs_mutex);
498
499         /* set planes to be displayed */
500         gralloc_drm_set_planes(drm);
501
502         ret = drmModePageFlip(drm->fd, drm->primary->crtc_id, bo->fb_id,
503                         DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
504         if (ret) {
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 */
508                 if (errno != EBUSY)
509                         drm->first_post = 1;
510         }
511         else
512                 drm->next_front = bo;
513
514         return ret;
515 }
516
517 /*
518  * Wait for the next post.
519  */
520 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
521 {
522         unsigned int current, target;
523         drmVBlank vbl;
524         int ret;
525
526         if (drm->mode_quirk_vmwgfx)
527                 return;
528
529         flip = !!flip;
530
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;
536
537         /* get the current vblank */
538         ret = drmWaitVBlank(drm->fd, &vbl);
539         if (ret) {
540                 ALOGW("failed to get vblank");
541                 return;
542         }
543
544         current = vbl.reply.sequence;
545         if (drm->first_post)
546                 target = current;
547         else
548                 target = drm->last_swap + drm->swap_interval - flip;
549
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;
556                 if (!flip) {
557                         vbl.request.type |= DRM_VBLANK_NEXTONMISS;
558                         if (target < current)
559                                 target = current;
560                 }
561
562                 vbl.request.sequence = target;
563
564                 ret = drmWaitVBlank(drm->fd, &vbl);
565                 if (ret) {
566                         ALOGW("failed to wait vblank");
567                         return;
568                 }
569         }
570
571         drm->last_swap = vbl.reply.sequence + flip;
572 }
573
574 /*
575  * Post a bo.  This is not thread-safe.
576  */
577 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
578 {
579         struct gralloc_drm_t *drm = bo->drm;
580         int ret;
581
582         if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
583                 ALOGE("unable to post bo %p without fb", bo);
584                 return -EINVAL;
585         }
586
587         /* TODO spawn a thread to avoid waiting and race */
588
589         if (drm->first_post) {
590                 if (drm->swap_mode == DRM_SWAP_COPY) {
591                         struct gralloc_drm_bo_t *dst;
592
593                         dst = (drm->next_front) ?
594                                 drm->next_front :
595                                 drm->current_front;
596                         drm->drv->blit(drm->drv, dst, bo, 0, 0,
597                                         bo->handle->width,
598                                         bo->handle->height,
599                                         0, 0,
600                                         bo->handle->width,
601                                         bo->handle->height);
602                         bo = dst;
603                 }
604
605                 ret = drm_kms_set_crtc(drm, drm->primary, bo->fb_id);
606                 if (!ret) {
607                         drm->first_post = 0;
608                         drm->current_front = bo;
609                         if (drm->next_front == bo)
610                                 drm->next_front = NULL;
611                 }
612
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);
618                 }
619                 pthread_mutex_unlock(&drm->outputs_mutex);
620
621                 return ret;
622         }
623
624         switch (drm->swap_mode) {
625         case DRM_SWAP_FLIP:
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) {
630                         /*
631                          * wait if the driver says so or the current front
632                          * will be written by CPU
633                          */
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);
638                 }
639                 break;
640         case DRM_SWAP_COPY:
641                 drm_kms_wait_for_post(drm, 0);
642                 drm->drv->blit(drm->drv, drm->current_front,
643                                 bo, 0, 0,
644                                 bo->handle->width,
645                                 bo->handle->height,
646                                 0, 0,
647                                 bo->handle->width,
648                                 bo->handle->height);
649                 if (drm->mode_quirk_vmwgfx)
650                         ret = drmModeDirtyFB(drm->fd, drm->current_front->fb_id, &drm->clip, 1);
651                 ret = 0;
652                 break;
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);
656
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);
662                 }
663                 pthread_mutex_unlock(&drm->outputs_mutex);
664
665                 drm->current_front = bo;
666                 break;
667         default:
668                 /* no-op */
669                 ret = 0;
670                 break;
671         }
672
673         return ret;
674 }
675
676 static struct gralloc_drm_t *drm_singleton;
677
678 static void on_signal(int sig)
679 {
680         struct gralloc_drm_t *drm = drm_singleton;
681
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 */
687                 else
688                         drm_kms_page_flip(drm_singleton, NULL);
689         }
690
691         exit(-1);
692 }
693
694 static void drm_kms_init_features(struct gralloc_drm_t *drm)
695 {
696         const char *swap_mode;
697
698         /* call to the driver here, after KMS has been initialized */
699         drm->drv->init_kms_features(drm->drv, drm);
700
701         if (drm->swap_mode == DRM_SWAP_FLIP) {
702                 struct sigaction act;
703
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;
707
708                 /*
709                  * XXX GPU tends to freeze if the program is terminiated with a
710                  * flip pending.  What is the right way to handle the
711                  * situation?
712                  */
713                 sigemptyset(&act.sa_mask);
714                 act.sa_handler = on_signal;
715                 act.sa_flags = 0;
716                 sigaction(SIGINT, &act, NULL);
717                 sigaction(SIGTERM, &act, NULL);
718
719                 drm_singleton = drm;
720         }
721         else if (drm->swap_mode == DRM_SWAP_COPY) {
722                 struct gralloc_drm_bo_t *front;
723                 int stride;
724
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);
733                         front = NULL;
734                 }
735
736                 /* abuse next_front */
737                 if (front)
738                         drm->next_front = front;
739                 else
740                         drm->swap_mode = DRM_SWAP_SETCRTC;
741         }
742
743         switch (drm->swap_mode) {
744         case DRM_SWAP_FLIP:
745                 swap_mode = "flip";
746                 break;
747         case DRM_SWAP_COPY:
748                 swap_mode = "copy";
749                 break;
750         case DRM_SWAP_SETCRTC:
751                 swap_mode = "set-crtc";
752                 break;
753         default:
754                 swap_mode = "no-op";
755                 break;
756         }
757
758         ALOGD("will use %s for fb posting", swap_mode);
759 }
760
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)
774
775 static drmModeModeInfoPtr generate_mode(int h_pixels, int v_lines, float freq)
776 {
777         float h_pixels_rnd;
778         float v_lines_rnd;
779         float v_field_rate_rqd;
780         float top_margin;
781         float bottom_margin;
782         float interlace;
783         float h_period_est;
784         float vsync_plus_bp;
785         float v_back_porch;
786         float total_v_lines;
787         float v_field_rate_est;
788         float h_period;
789         float v_field_rate;
790         float v_frame_rate;
791         float left_margin;
792         float right_margin;
793         float total_active_pixels;
794         float ideal_duty_cycle;
795         float h_blank;
796         float total_pixels;
797         float pixel_freq;
798         float h_freq;
799
800         float h_sync;
801         float h_front_porch;
802         float v_odd_front_porch_lines;
803         int interlaced = 0;
804         int margins = 0;
805
806         drmModeModeInfoPtr m = malloc(sizeof(drmModeModeInfo));
807
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;
833
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);
839         m->hskew = 0;
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);
844         m->vscan = 0;
845         m->vrefresh = freq;
846         m->flags = 10;
847         m->type = 64;
848
849         return (m);
850 }
851
852 static int mode_distance_best_fit(
853                 int xres_base,
854                 int yres_base,
855                 int xres,
856                 int yres,
857                 double prefered_aspect)
858 {
859         const double eps = 0.3;
860
861         if (xres_base > xres || yres_base > yres) {
862                 // if the res cannot cover base res, return max int
863                 return INT_MAX;
864         } else if (fabs((double) xres / yres - prefered_aspect) > eps) {
865                 // if the aspect is too different with prefered_aspect, return max int
866                 return INT_MAX;
867         } else {
868                 return (xres - xres_base) * (xres - xres_base) +
869                                 (yres - yres_base) * (yres - yres_base) +
870                                 ((xres / yres) - prefered_aspect) * ((xres / yres) - prefered_aspect);
871         }
872 }
873
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);
877 }
878
879 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp, drmModeModeInfoPtr primary_mode)
880 {
881         char value[PROPERTY_VALUE_MAX];
882         drmModeModeInfoPtr mode;
883         int dist, i;
884         int xres = 0, yres = 0, rate = 0;
885         int forcemode = 0;
886         int bestfit = 0;
887
888         if (property_get("debug.drm.mode", value, NULL)) {
889                 char *p = value, *end;
890
891                 /* parse <xres>x<yres>[@<bpp>] */
892                 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
893                         *bpp = 0;
894                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
895                                 xres = yres = 0;
896                 }
897
898                 if ((xres && yres) || *bpp) {
899                         ALOGI("will find the closest match for %dx%d@%d",
900                                         xres, yres, *bpp);
901                 }
902         } else if (property_get("debug.drm.mode.force", value, NULL)) {
903                 char *p = value, *end;
904                 *bpp = 0;
905
906                 /* parse <xres>x<yres>[@<refreshrate>] */
907                 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
908                         rate = 60;
909                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
910                                 xres = yres = 0;
911                 }
912
913                 if (xres && yres && rate) {
914                         ALOGI("will use %dx%d@%dHz", xres, yres, rate);
915                         forcemode = 1;
916                 }
917         } else if (primary_mode != NULL) {
918                 xres = primary_mode->hdisplay;
919                 yres = primary_mode->vdisplay;
920                 *bpp = 0;
921                 bestfit = 1;
922                 ALOGI("will find the best fit for %dx%d", xres, yres);
923         } else {
924                 *bpp = 0;
925         }
926
927         dist = INT_MAX;
928
929         if (forcemode)
930                 mode = generate_mode(xres, yres, rate);
931         else {
932                 mode = NULL;
933                 for (i = 0; i < connector->count_modes; i++) {
934                         drmModeModeInfoPtr m = &connector->modes[i];
935                         int tmp;
936
937                         if (xres && yres) {
938                                 if (bestfit) {
939                                         tmp = mode_distance_best_fit(
940                                                         xres,
941                                                         yres,
942                                                         m->hdisplay,
943                                                         m->vdisplay,
944                                                         (double) connector->modes[0].hdisplay / connector->modes[0].vdisplay);
945                                 } else {
946                                         tmp = mode_distance_closest(xres, yres, m->hdisplay, m->vdisplay);
947                                 }
948                         }
949                         else {
950                                 /* use the first preferred mode */
951                                 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
952                         }
953
954                         if (tmp < dist) {
955                                 mode = m;
956                                 dist = tmp;
957                                 if (!dist)
958                                         break;
959                         }
960                 }
961         }
962
963         /* fallback to the first mode */
964         if (!mode)
965                 mode = &connector->modes[0];
966
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);
971
972         *bpp /= 8;
973
974         return mode;
975 }
976
977 static int used_crtcs = 0;
978
979 /*
980  * Initialize KMS with a connector.
981  */
982 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
983                 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
984 {
985         drmModeEncoderPtr encoder;
986         drmModeModeInfoPtr mode;
987         int bpp, i;
988
989         if (!connector->count_modes)
990                 return -EINVAL;
991
992         encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
993         if (!encoder)
994                 return -EINVAL;
995
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))
1000                         break;
1001         }
1002
1003         used_crtcs |= (1 << i);
1004
1005         drmModeFreeEncoder(encoder);
1006         if (i == drm->resources->count_crtcs)
1007                 return -EINVAL;
1008
1009         output->bo = NULL;
1010         output->crtc_id = drm->resources->crtcs[i];
1011         output->connector_id = connector->connector_id;
1012         output->pipe = i;
1013
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);
1022         }
1023         else {
1024                 ALOGI("there is one mode on connector 0x%d: %s",
1025                                 connector->connector_id,
1026                                 connector->modes[0].name);
1027         }
1028
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);
1031         } else {
1032                 mode = find_mode(connector, &bpp, NULL);
1033         }
1034
1035         ALOGI("the best mode is %s", mode->name);
1036
1037         output->mode = *mode;
1038         switch (bpp) {
1039         case 2:
1040                 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
1041                 break;
1042         case 4:
1043         default:
1044                 output->fb_format = HAL_PIXEL_FORMAT_RGBA_8888;
1045                 break;
1046         }
1047
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);
1051         }
1052         else {
1053                 output->xdpi = 75;
1054                 output->ydpi = 75;
1055         }
1056
1057 #ifdef DRM_MODE_FEATURE_DIRTYFB
1058         drm->clip.x1 = 0;
1059         drm->clip.y1 = 0;
1060         drm->clip.x2 = output->mode.hdisplay;
1061         drm->clip.y2 = output->mode.vdisplay;
1062 #endif
1063
1064         return 0;
1065 }
1066
1067 static struct gralloc_drm_output*
1068 drm_kms_init_with_new_connector(struct gralloc_drm_t *drm, drmModeConnectorPtr connector)
1069 {
1070         struct gralloc_drm_output *output = NULL;
1071
1072         for (int i=0;i<drm->output_capacity;i++) {
1073                 if (!drm->outputs[i].active) {
1074                         output = &drm->outputs[i];
1075                         break;
1076                 }
1077         }
1078
1079         if (output && !drm_kms_init_with_connector(drm, output, connector)) {
1080                 drm->output_count++;
1081                 output->active = 1;
1082                 if (!drm->primary) {
1083                         drm->primary = output;
1084                 }
1085         }
1086
1087         return output;
1088 }
1089
1090
1091 /*
1092  * Fetch a connector of particular type
1093  */
1094 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
1095         uint32_t type)
1096 {
1097         int i;
1098
1099         if (!drm->resources)
1100                 return NULL;
1101
1102         for (i = 0; i < drm->resources->count_connectors; i++) {
1103                 drmModeConnectorPtr connector = drmModeGetConnector(drm->fd,
1104                                 drm->resources->connectors[i]);
1105                 if (connector) {
1106                         if (connector->connector_type == type &&
1107                                 connector->connection == DRM_MODE_CONNECTED)
1108                                 return connector;
1109                         drmModeFreeConnector(connector);
1110                 }
1111         }
1112         return NULL;
1113 }
1114
1115
1116 /*
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.
1120  */
1121 static int init_external_output(struct gralloc_drm_t *drm,
1122         drmModeConnectorPtr connector)
1123 {
1124         struct gralloc_drm_output *output;
1125         output = drm_kms_init_with_new_connector(drm, connector);
1126
1127         ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
1128                 __func__, output->mode.hdisplay, output->mode.vdisplay);
1129
1130         output->bo = gralloc_drm_bo_create(drm,
1131                 output->mode.hdisplay, output->mode.vdisplay,
1132                 output->fb_format,
1133                 GRALLOC_USAGE_HW_RENDER);
1134
1135         int err = gralloc_drm_bo_add_fb(output->bo);
1136         if (err) {
1137                 ALOGE("%s: could not create drm fb, (%s)",
1138                         __func__, strerror(-err));
1139                 return err;
1140         }
1141
1142         output->output_mode = DRM_OUTPUT_CLONED;
1143         output->active = 1;
1144
1145         /* This is a hack to workaround mirror mode render error */
1146         drm_kms_set_crtc(drm, output, output->bo->fb_id);
1147
1148         return 0;
1149 }
1150
1151
1152 static int init_connectors(struct gralloc_drm_t *drm)
1153 {
1154         if (!drm->resources)
1155                 return -1;
1156
1157         for (int i = 0; i<drm->resources->count_connectors; i++) {
1158                 drmModeConnectorPtr connector = drmModeGetConnector(drm->fd,
1159                                 drm->resources->connectors[i]);
1160                 if (connector) {
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;
1171                                                 break;
1172                                         }
1173                                 }
1174                         }
1175                         drmModeFreeConnector(connector);
1176                 }
1177         }
1178
1179         return 0;
1180 }
1181
1182
1183 /*
1184  * Thread that listens to uevents and checks if hdmi state changes
1185  */
1186 static void *extcon_observer(void *data)
1187 {
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;
1193
1194         uevent_init();
1195
1196         memset(uevent_desc, 0, sizeof(uevent_desc));
1197
1198         while(1) {
1199
1200                 /* this polls */
1201                 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1202                 if (!len) continue;
1203
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);
1209
1210                 if (!strcmp(event.path, "devices/virtual/switch/hdmi")) {
1211                         if (event.switchstate != -1) {
1212                                 pthread_mutex_lock(&drm->outputs_mutex);
1213
1214                                 init_connectors(drm);
1215
1216                                 /* will trigger modeset */
1217                                 drm->first_post = 1;
1218
1219                                 pthread_mutex_unlock(&drm->outputs_mutex);
1220                         }
1221                 } else if (!strcmp(event.subsystem, "drm") &&
1222                                 !strcmp(event.device_name, "dri/card0") && event.hotplug) {
1223                         pthread_mutex_lock(&drm->outputs_mutex);
1224
1225                         init_connectors(drm);
1226
1227                         /* will trigger modeset */
1228                         drm->first_post = 1;
1229
1230                         pthread_mutex_unlock(&drm->outputs_mutex);
1231                 }
1232         }
1233
1234         pthread_exit(NULL);
1235         return 0;
1236 }
1237
1238
1239 /*
1240  * Initialize KMS.
1241  */
1242 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1243 {
1244         drmModeConnectorPtr lvds;
1245         int i, ret;
1246
1247         if (drm->resources)
1248                 return 0;
1249
1250         drm->resources = drmModeGetResources(drm->fd);
1251         if (!drm->resources) {
1252                 ALOGE("failed to get modeset resources");
1253                 return -EINVAL;
1254         }
1255
1256         drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1257         if (!drm->plane_resources) {
1258                 ALOGD("no planes found from drm resources");
1259         } else {
1260                 unsigned int i, j;
1261
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));
1266
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]);
1270
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);
1278                 }
1279         }
1280
1281         drm->output_capacity = drm->resources->count_connectors;
1282         drm->output_count = 0;
1283
1284         drm->outputs = malloc(sizeof(*drm->outputs) * drm->output_capacity);
1285         memset(drm->outputs, 0, sizeof(*drm->outputs) * drm->output_capacity);
1286
1287         /* find the crtc/connector/mode to use */
1288         lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1289         if (lvds) {
1290                 drm_kms_init_with_new_connector(drm, lvds);
1291                 drmModeFreeConnector(lvds);
1292         }
1293
1294         /* if still no connector, find first connected connector and try it */
1295         if (!drm->primary) {
1296
1297                 for (i = 0; i < drm->resources->count_connectors; i++) {
1298                         drmModeConnectorPtr connector;
1299
1300                         connector = drmModeGetConnector(drm->fd,
1301                                         drm->resources->connectors[i]);
1302                         if (connector) {
1303                                 if (connector->connection == DRM_MODE_CONNECTED) {
1304                                         if (drm_kms_init_with_new_connector(drm, connector))
1305                                                 break;
1306                                 }
1307
1308                                 drmModeFreeConnector(connector);
1309                         }
1310                 }
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;
1315
1316                         return -EINVAL;
1317                 }
1318         }
1319
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
1322         */
1323         if (drm->drv->blit) {
1324                 init_connectors(drm);
1325
1326                 /* launch external display observer thread */
1327                 pthread_mutex_init(&drm->outputs_mutex, NULL);
1328                 pthread_create(&drm->hotplug_thread, NULL, extcon_observer, drm);
1329         }
1330
1331         drm_kms_init_features(drm);
1332         drm->first_post = 1;
1333
1334         return 0;
1335 }
1336
1337 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1338 {
1339         switch (drm->swap_mode) {
1340         case DRM_SWAP_FLIP:
1341                 drm_kms_page_flip(drm, NULL);
1342                 break;
1343         case DRM_SWAP_COPY:
1344                 {
1345                         struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1346                                 &drm->current_front : &drm->next_front;
1347
1348                         if (*bo)
1349                                 gralloc_drm_bo_decref(*bo);
1350                         *bo = NULL;
1351                 }
1352                 break;
1353         default:
1354                 break;
1355         }
1356
1357         /* restore crtc? */
1358
1359         if (drm->resources) {
1360                 drmModeFreeResources(drm->resources);
1361                 drm->resources = NULL;
1362         }
1363
1364         if (drm->planes) {
1365                 unsigned int i;
1366                 for (i = 0; i < drm->plane_resources->count_planes; i++)
1367                         drmModeFreePlane(drm->planes[i].drm_plane);
1368                 free(drm->planes);
1369                 drm->planes = NULL;
1370         }
1371
1372         if (drm->plane_resources) {
1373                 drmModeFreePlaneResources(drm->plane_resources);
1374                 drm->plane_resources = NULL;
1375         }
1376
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);
1381
1382         free(drm->outputs);
1383
1384         drm_singleton = NULL;
1385 }
1386
1387 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1388 {
1389         return (drm->resources != NULL);
1390 }
1391
1392 /*
1393  * Initialize a framebuffer device with KMS info.
1394  */
1395 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1396                 struct framebuffer_device_t *fb)
1397 {
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;
1403
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;
1409 }
1410
1411 /*
1412  * Return true if fb posting is pipelined.
1413  */
1414 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1415 {
1416         return (drm->swap_mode != DRM_SWAP_SETCRTC);
1417 }