OSDN Git Service

Revert "TEMP HACK: make non-standalone surfaceflinger work"
[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 drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
842 {
843         char value[PROPERTY_VALUE_MAX];
844         drmModeModeInfoPtr mode;
845         int dist, i;
846         int xres = 0, yres = 0, rate = 0;
847         int forcemode = 0;
848
849         if (property_get("debug.drm.mode", value, NULL)) {
850                 char *p = value, *end;
851
852                 /* parse <xres>x<yres>[@<bpp>] */
853                 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
854                         *bpp = 0;
855                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
856                                 xres = yres = 0;
857                 }
858
859                 if ((xres && yres) || *bpp) {
860                         ALOGI("will find the closest match for %dx%d@%d",
861                                         xres, yres, *bpp);
862                 }
863         } else if (property_get("debug.drm.mode.force", value, NULL)) {
864                 char *p = value, *end;
865                 *bpp = 0;
866
867                 /* parse <xres>x<yres>[@<refreshrate>] */
868                 if (sscanf(value, "%dx%d@%d", &xres, &yres, &rate) != 3) {
869                         rate = 60;
870                         if (sscanf(value, "%dx%d", &xres, &yres) != 2)
871                                 xres = yres = 0;
872                 }
873
874                 if (xres && yres && rate) {
875                         ALOGI("will use %dx%d@%dHz", xres, yres, rate);
876                         forcemode = 1;
877                 }
878         } else {
879                 *bpp = 0;
880         }
881
882         dist = INT_MAX;
883
884         if (forcemode)
885                 mode = generate_mode(xres, yres, rate);
886         else {
887                 mode = NULL;
888                 for (i = 0; i < connector->count_modes; i++) {
889                         drmModeModeInfoPtr m = &connector->modes[i];
890                         int tmp;
891
892                         if (xres && yres) {
893                                 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
894                                         (m->vdisplay - yres) * (m->vdisplay - yres);
895                         }
896                         else {
897                                 /* use the first preferred mode */
898                                 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
899                         }
900
901                         if (tmp < dist) {
902                                 mode = m;
903                                 dist = tmp;
904                                 if (!dist)
905                                         break;
906                         }
907                 }
908         }
909
910         /* fallback to the first mode */
911         if (!mode)
912                 mode = &connector->modes[0];
913
914         ALOGI("Established mode:");
915         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);
916         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);
917         ALOGI("flags: %d, type: %d, name %s", mode->flags, mode->type, mode->name);
918
919         *bpp /= 8;
920
921         return mode;
922 }
923
924 /*
925  * Initialize KMS with a connector.
926  */
927 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
928                 struct gralloc_drm_output *output, drmModeConnectorPtr connector)
929 {
930         drmModeEncoderPtr encoder;
931         drmModeModeInfoPtr mode;
932         static int used_crtcs = 0;
933         int bpp, i;
934
935         if (!connector->count_modes)
936                 return -EINVAL;
937
938         encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
939         if (!encoder)
940                 return -EINVAL;
941
942         /* find first possible crtc which is not used yet */
943         for (i = 0; i < drm->resources->count_crtcs; i++) {
944                 if (encoder->possible_crtcs & (1 << i) &&
945                         (used_crtcs & (1 << i)) != (1 << i))
946                         break;
947         }
948
949         used_crtcs |= (1 << i);
950
951         drmModeFreeEncoder(encoder);
952         if (i == drm->resources->count_crtcs)
953                 return -EINVAL;
954
955         output->bo = NULL;
956         output->crtc_id = drm->resources->crtcs[i];
957         output->connector_id = connector->connector_id;
958         output->pipe = i;
959
960         /* print connector info */
961         if (connector->count_modes > 1) {
962                 ALOGI("there are %d modes on connector 0x%x, type %d",
963                                 connector->count_modes,
964                                 connector->connector_id,
965                                 connector->connector_type);
966                 for (i = 0; i < connector->count_modes; i++)
967                         ALOGI("  %s", connector->modes[i].name);
968         }
969         else {
970                 ALOGI("there is one mode on connector 0x%d: %s",
971                                 connector->connector_id,
972                                 connector->modes[0].name);
973         }
974
975         mode = find_mode(connector, &bpp);
976
977         ALOGI("the best mode is %s", mode->name);
978
979         output->mode = *mode;
980         switch (bpp) {
981         case 2:
982                 output->fb_format = HAL_PIXEL_FORMAT_RGB_565;
983                 break;
984         case 4:
985         default:
986                 output->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
987                 break;
988         }
989
990         if (connector->mmWidth && connector->mmHeight) {
991                 output->xdpi = (output->mode.hdisplay * 25.4 / connector->mmWidth);
992                 output->ydpi = (output->mode.vdisplay * 25.4 / connector->mmHeight);
993         }
994         else {
995                 output->xdpi = 75;
996                 output->ydpi = 75;
997         }
998
999 #ifdef DRM_MODE_FEATURE_DIRTYFB
1000         drm->clip.x1 = 0;
1001         drm->clip.y1 = 0;
1002         drm->clip.x2 = output->mode.hdisplay;
1003         drm->clip.y2 = output->mode.vdisplay;
1004 #endif
1005
1006         return 0;
1007 }
1008
1009
1010 /*
1011  * Fetch a connector of particular type
1012  */
1013 static drmModeConnectorPtr fetch_connector(struct gralloc_drm_t *drm,
1014         uint32_t type)
1015 {
1016         int i;
1017
1018         if (!drm->resources)
1019                 return NULL;
1020
1021         for (i = 0; i < drm->resources->count_connectors; i++) {
1022                 drmModeConnectorPtr connector =
1023                         connector = drmModeGetConnector(drm->fd,
1024                                 drm->resources->connectors[i]);
1025                 if (connector) {
1026                         if (connector->connector_type == type &&
1027                                 connector->connection == DRM_MODE_CONNECTED)
1028                                 return connector;
1029                         drmModeFreeConnector(connector);
1030                 }
1031         }
1032         return NULL;
1033 }
1034
1035
1036 /*
1037  * Initializes hdmi output with a connector and allocates
1038  * a private framebuffer for it. This is called on startup if
1039  * hdmi cable is connected and also on hotplug events.
1040  */
1041 static int init_hdmi_output(struct gralloc_drm_t *drm,
1042         drmModeConnectorPtr connector)
1043 {
1044         drm_kms_init_with_connector(drm, &drm->hdmi, connector);
1045
1046         ALOGD("%s, allocate private buffer for hdmi [%dx%d]",
1047                 __func__, drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay);
1048
1049         drm->hdmi.bo = gralloc_drm_bo_create(drm,
1050                 drm->hdmi.mode.hdisplay, drm->hdmi.mode.vdisplay,
1051                 drm->hdmi.fb_format,
1052                 GRALLOC_USAGE_HW_RENDER);
1053
1054         int err = gralloc_drm_bo_add_fb(drm->hdmi.bo);
1055         if (err) {
1056                 ALOGE("%s: could not create drm fb, (%s)",
1057                         __func__, strerror(-err));
1058                 return err;
1059         }
1060
1061         drm->hdmi_mode = HDMI_CLONED;
1062         drm->hdmi.active = 1;
1063
1064         return 0;
1065 }
1066
1067
1068 /*
1069  * Thread that listens to uevents and checks if hdmi state changes
1070  */
1071 static void *hdmi_observer(void *data)
1072 {
1073         static char uevent_desc[4096];
1074         drmModeConnectorPtr hdmi;
1075         struct gralloc_drm_t *drm =
1076                 (struct gralloc_drm_t *) data;
1077         struct uevent event;
1078
1079         uevent_init();
1080
1081         memset(uevent_desc, 0, sizeof(uevent_desc));
1082
1083         while(1) {
1084
1085                 /* this polls */
1086                 int len = uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
1087                 if (!len) continue;
1088
1089                 parse_event(uevent_desc, &event);
1090                 ALOGD_IF(0, "event { '%s', '%s', '%s', %d, %d, %d, %d }\n",
1091                                 event.action, event.path, event.subsystem,
1092                                 event.major, event.minor,
1093                                 event.switchstate, event.hotplug);
1094
1095                 if (!strcmp(event.path, "devices/virtual/switch/hdmi")) {
1096                         if (event.switchstate != -1) {
1097                                 pthread_mutex_lock(&drm->hdmi_mutex);
1098
1099                                 if (event.switchstate) {
1100                                         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1101                                         if (hdmi) {
1102                                                 ALOGD("init hdmi on switch_state event");
1103                                                 init_hdmi_output(drm, hdmi);
1104
1105                                                 /* will trigger modeset */
1106                                                 drm->first_post = 1;
1107
1108                                                 drmModeFreeConnector(hdmi);
1109                                         }
1110                                 } else {
1111                                         drm->hdmi.active = 0;
1112
1113                                         ALOGD("destroy hdmi private buffer");
1114                                         gralloc_drm_bo_decref(drm->hdmi.bo);
1115                                         drm->hdmi.bo = NULL;
1116                                 }
1117
1118                                 pthread_mutex_unlock(&drm->hdmi_mutex);
1119                         }
1120                 } else if (!strcmp(event.subsystem, "drm") &&
1121                                 !strcmp(event.device_name, "dri/card0") && event.hotplug) {
1122                         pthread_mutex_lock(&drm->hdmi_mutex);
1123
1124                         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1125                         if (hdmi && !drm->hdmi.active) {
1126                                 ALOGD("init hdmi on hotplug event");
1127                                 if (!init_hdmi_output(drm, hdmi)) {
1128                                         drm_kms_set_crtc(drm, &drm->hdmi, drm->hdmi.bo->fb_id);
1129                                 }
1130
1131                                 /* will trigger modeset */
1132                                 drm->first_post = 1;
1133                         } else if (!hdmi && drm->hdmi.active) {
1134                                 drm->hdmi.active = 0;
1135
1136                                 ALOGD("destroy hdmi private buffer");
1137                                 gralloc_drm_bo_decref(drm->hdmi.bo);
1138                                 drm->hdmi.bo = NULL;
1139                         }
1140
1141                         if (hdmi)
1142                                 drmModeFreeConnector(hdmi);
1143
1144                         pthread_mutex_unlock(&drm->hdmi_mutex);
1145                 }
1146         }
1147
1148         pthread_exit(NULL);
1149         return 0;
1150 }
1151
1152
1153 /*
1154  * Initialize KMS.
1155  */
1156 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
1157 {
1158         drmModeConnectorPtr lvds, hdmi;
1159         int i, ret;
1160
1161         if (drm->resources)
1162                 return 0;
1163
1164         drm->resources = drmModeGetResources(drm->fd);
1165         if (!drm->resources) {
1166                 ALOGE("failed to get modeset resources");
1167                 return -EINVAL;
1168         }
1169
1170         drm->plane_resources = drmModeGetPlaneResources(drm->fd);
1171         if (!drm->plane_resources) {
1172                 ALOGD("no planes found from drm resources");
1173         } else {
1174                 unsigned int i, j;
1175
1176                 ALOGD("supported drm planes and formats");
1177                 /* fill a helper structure for hwcomposer */
1178                 drm->planes = calloc(drm->plane_resources->count_planes,
1179                         sizeof(struct gralloc_drm_plane_t));
1180
1181                 for (i = 0; i < drm->plane_resources->count_planes; i++) {
1182                         drm->planes[i].drm_plane = drmModeGetPlane(drm->fd,
1183                                 drm->plane_resources->planes[i]);
1184
1185                         ALOGD("plane id %d", drm->planes[i].drm_plane->plane_id);
1186                         for (j = 0; j < drm->planes[i].drm_plane->count_formats; j++)
1187                                 ALOGD("    format %c%c%c%c",
1188                                         (drm->planes[i].drm_plane->formats[j]),
1189                                         (drm->planes[i].drm_plane->formats[j])>>8,
1190                                         (drm->planes[i].drm_plane->formats[j])>>16,
1191                                         (drm->planes[i].drm_plane->formats[j])>>24);
1192                 }
1193         }
1194
1195         /* find the crtc/connector/mode to use */
1196         lvds = fetch_connector(drm, DRM_MODE_CONNECTOR_LVDS);
1197         if (lvds) {
1198                 drm_kms_init_with_connector(drm, &drm->primary, lvds);
1199                 drmModeFreeConnector(lvds);
1200                 drm->primary.active = 1;
1201         }
1202
1203         /* if still no connector, find first connected connector and try it */
1204         if (!drm->primary.active) {
1205
1206                 for (i = 0; i < drm->resources->count_connectors; i++) {
1207                         drmModeConnectorPtr connector;
1208
1209                         connector = drmModeGetConnector(drm->fd,
1210                                         drm->resources->connectors[i]);
1211                         if (connector) {
1212                                 if (connector->connection == DRM_MODE_CONNECTED) {
1213                                         if (!drm_kms_init_with_connector(drm,
1214                                                         &drm->primary, connector))
1215                                                 break;
1216                                 }
1217
1218                                 drmModeFreeConnector(connector);
1219                         }
1220                 }
1221                 if (i == drm->resources->count_connectors) {
1222                         ALOGE("failed to find a valid crtc/connector/mode combination");
1223                         drmModeFreeResources(drm->resources);
1224                         drm->resources = NULL;
1225
1226                         return -EINVAL;
1227                 }
1228         }
1229
1230
1231         /* check if hdmi is connected already */
1232         hdmi = fetch_connector(drm, DRM_MODE_CONNECTOR_HDMIA);
1233         if (hdmi) {
1234
1235                 if (hdmi->connector_id == drm->primary.connector_id) {
1236                         /* special case: our primary connector is hdmi */
1237                         ALOGD("hdmi is the primary connector");
1238                         goto skip_hdmi_modes;
1239                 }
1240
1241                 ALOGD("init hdmi on startup");
1242                 init_hdmi_output(drm, hdmi);
1243
1244                 drmModeFreeConnector(hdmi);
1245         }
1246
1247         /* launch hdmi observer thread */
1248         pthread_mutex_init(&drm->hdmi_mutex, NULL);
1249         pthread_create(&drm->hdmi_hotplug_thread, NULL, hdmi_observer, drm);
1250
1251 skip_hdmi_modes:
1252
1253         drm_kms_init_features(drm);
1254         drm->first_post = 1;
1255
1256         return 0;
1257 }
1258
1259 void gralloc_drm_fini_kms(struct gralloc_drm_t *drm)
1260 {
1261         switch (drm->swap_mode) {
1262         case DRM_SWAP_FLIP:
1263                 drm_kms_page_flip(drm, NULL);
1264                 break;
1265         case DRM_SWAP_COPY:
1266                 {
1267                         struct gralloc_drm_bo_t **bo = (drm->current_front) ?
1268                                 &drm->current_front : &drm->next_front;
1269
1270                         if (*bo)
1271                                 gralloc_drm_bo_decref(*bo);
1272                         *bo = NULL;
1273                 }
1274                 break;
1275         default:
1276                 break;
1277         }
1278
1279         /* restore crtc? */
1280
1281         if (drm->resources) {
1282                 drmModeFreeResources(drm->resources);
1283                 drm->resources = NULL;
1284         }
1285
1286         if (drm->planes) {
1287                 unsigned int i;
1288                 for (i = 0; i < drm->plane_resources->count_planes; i++)
1289                         drmModeFreePlane(drm->planes[i].drm_plane);
1290                 free(drm->planes);
1291                 drm->planes = NULL;
1292         }
1293
1294         if (drm->plane_resources) {
1295                 drmModeFreePlaneResources(drm->plane_resources);
1296                 drm->plane_resources = NULL;
1297         }
1298
1299         /* destroy private buffer of hdmi output */
1300         if (drm->hdmi.bo)
1301                 gralloc_drm_bo_decref(drm->hdmi.bo);
1302
1303         drm_singleton = NULL;
1304 }
1305
1306 int gralloc_drm_is_kms_initialized(struct gralloc_drm_t *drm)
1307 {
1308         return (drm->resources != NULL);
1309 }
1310
1311 /*
1312  * Initialize a framebuffer device with KMS info.
1313  */
1314 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
1315                 struct framebuffer_device_t *fb)
1316 {
1317         *((uint32_t *) &fb->flags) = 0x0;
1318         *((uint32_t *) &fb->width) = drm->primary.mode.hdisplay;
1319         *((uint32_t *) &fb->height) = drm->primary.mode.vdisplay;
1320         *((int *)      &fb->stride) = drm->primary.mode.hdisplay;
1321         *((float *)    &fb->fps) = drm->primary.mode.vrefresh;
1322
1323         *((int *)      &fb->format) = drm->primary.fb_format;
1324         *((float *)    &fb->xdpi) = drm->primary.xdpi;
1325         *((float *)    &fb->ydpi) = drm->primary.ydpi;
1326         *((int *)      &fb->minSwapInterval) = drm->swap_interval;
1327         *((int *)      &fb->maxSwapInterval) = drm->swap_interval;
1328 }
1329
1330 /*
1331  * Return true if fb posting is pipelined.
1332  */
1333 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
1334 {
1335         return (drm->swap_mode != DRM_SWAP_SETCRTC);
1336 }