2 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
3 * Copyright (C) 2010-2011 LunarG Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 #define LOG_TAG "GRALLOC-KMS"
26 #include <cutils/properties.h>
27 #include <cutils/log.h>
33 #include "gralloc_drm.h"
34 #include "gralloc_drm_priv.h"
37 * Return true if a bo needs fb.
39 int gralloc_drm_bo_need_fb(const struct gralloc_drm_bo_t *bo)
41 return ((bo->handle->usage & GRALLOC_USAGE_HW_FB) &&
42 bo->drm->swap_mode != DRM_SWAP_COPY);
46 * Add a fb object for a bo.
48 int gralloc_drm_bo_add_fb(struct gralloc_drm_bo_t *bo)
55 bpp = gralloc_drm_get_bpp(bo->handle->format) * 8;
57 return drmModeAddFB(bo->drm->fd,
58 bo->handle->width, bo->handle->height, bpp, bpp,
59 bo->handle->stride, bo->fb_handle,
60 (uint32_t *) &bo->fb_id);
64 * Remove a fb object for a bo.
66 void gralloc_drm_bo_rm_fb(struct gralloc_drm_bo_t *bo)
69 drmModeRmFB(bo->drm->fd, bo->fb_id);
77 static int drm_kms_set_crtc(struct gralloc_drm_t *drm, int fb_id)
81 ret = drmModeSetCrtc(drm->fd, drm->crtc_id, fb_id,
82 0, 0, &drm->connector_id, 1, &drm->mode);
84 LOGE("failed to set crtc");
88 #ifdef DRM_MODE_FEATURE_DIRTYFB
89 if (drm->mode_dirty_fb)
90 ret = drmModeDirtyFB(drm->fd, fb_id, &drm->clip, 1);
97 * Callback for a page flip event.
99 static void page_flip_handler(int fd, unsigned int sequence,
100 unsigned int tv_sec, unsigned int tv_usec,
103 struct gralloc_drm_t *drm = (struct gralloc_drm_t *) user_data;
105 /* ack the last scheduled flip */
106 drm->current_front = drm->next_front;
107 drm->next_front = NULL;
111 * Schedule a page flip.
113 static int drm_kms_page_flip(struct gralloc_drm_t *drm,
114 struct gralloc_drm_bo_t *bo)
118 /* there is another flip pending */
119 while (drm->next_front) {
120 drm->waiting_flip = 1;
121 drmHandleEvent(drm->fd, &drm->evctx);
122 drm->waiting_flip = 0;
123 if (drm->next_front) {
124 /* record an error and break */
125 LOGE("drmHandleEvent returned without flipping");
126 drm->current_front = drm->next_front;
127 drm->next_front = NULL;
134 ret = drmModePageFlip(drm->fd, drm->crtc_id, bo->fb_id,
135 DRM_MODE_PAGE_FLIP_EVENT, (void *) drm);
137 LOGE("failed to perform page flip");
139 drm->next_front = bo;
145 * Wait for the next post.
147 static void drm_kms_wait_for_post(struct gralloc_drm_t *drm, int flip)
149 unsigned int current, target;
155 memset(&vbl, 0, sizeof(vbl));
156 vbl.request.type = DRM_VBLANK_RELATIVE;
157 if (drm->vblank_secondary)
158 vbl.request.type |= DRM_VBLANK_SECONDARY;
159 vbl.request.sequence = 0;
161 /* get the current vblank */
162 ret = drmWaitVBlank(drm->fd, &vbl);
164 LOGW("failed to get vblank");
168 current = vbl.reply.sequence;
172 target = drm->last_swap + drm->swap_interval - flip;
174 /* wait for vblank */
175 if (current < target || !flip) {
176 memset(&vbl, 0, sizeof(vbl));
177 vbl.request.type = DRM_VBLANK_ABSOLUTE;
178 if (drm->vblank_secondary)
179 vbl.request.type |= DRM_VBLANK_SECONDARY;
181 vbl.request.type |= DRM_VBLANK_NEXTONMISS;
182 if (target < current)
186 vbl.request.sequence = target;
188 ret = drmWaitVBlank(drm->fd, &vbl);
190 LOGW("failed to wait vblank");
195 drm->last_swap = vbl.reply.sequence + flip;
199 * Post a bo. This is not thread-safe.
201 int gralloc_drm_bo_post(struct gralloc_drm_bo_t *bo)
203 struct gralloc_drm_t *drm = bo->drm;
206 if (!bo->fb_id && drm->swap_mode != DRM_SWAP_COPY) {
207 LOGE("unable to post bo %p without fb", bo);
211 /* TODO spawn a thread to avoid waiting and race */
213 if (drm->first_post) {
214 if (drm->swap_mode == DRM_SWAP_COPY) {
215 struct gralloc_drm_bo_t *dst;
217 dst = (drm->next_front) ?
220 drm->drv->copy(drm->drv, dst, bo, 0, 0,
226 drm_kms_wait_for_post(drm, 0);
227 ret = drm_kms_set_crtc(drm, bo->fb_id);
230 drm->current_front = bo;
231 if (drm->next_front == bo)
232 drm->next_front = NULL;
238 switch (drm->swap_mode) {
240 if (drm->swap_interval > 1)
241 drm_kms_wait_for_post(drm, 1);
242 ret = drm_kms_page_flip(drm, bo);
243 if (drm->next_front) {
245 * wait if the driver says so or the current front
246 * will be written by CPU
248 if (drm->mode_sync_flip ||
249 (drm->current_front->handle->usage &
250 GRALLOC_USAGE_SW_WRITE_MASK))
251 drm_kms_page_flip(drm, NULL);
255 drm_kms_wait_for_post(drm, 0);
256 drm->drv->copy(drm->drv, drm->current_front,
262 case DRM_SWAP_SETCRTC:
263 drm_kms_wait_for_post(drm, 0);
264 ret = drm_kms_set_crtc(drm, bo->fb_id);
265 drm->current_front = bo;
276 static struct gralloc_drm_t *drm_singleton;
278 static void on_signal(int sig)
280 struct sigaction act;
282 /* wait the pending flip */
283 if (drm_singleton && drm_singleton->next_front) {
284 /* there is race, but this function is hacky enough to ignore that */
285 if (drm_singleton->waiting_flip)
286 usleep(100 * 1000); /* 100ms */
288 drm_kms_page_flip(drm_singleton, NULL);
294 static void drm_kms_init_features(struct gralloc_drm_t *drm)
296 const char *swap_mode;
298 /* call to the driver here, after KMS has been initialized */
299 drm->drv->init_kms_features(drm->drv, drm);
301 if (drm->swap_mode == DRM_SWAP_FLIP) {
302 struct sigaction act;
304 memset(&drm->evctx, 0, sizeof(drm->evctx));
305 drm->evctx.version = DRM_EVENT_CONTEXT_VERSION;
306 drm->evctx.page_flip_handler = page_flip_handler;
309 * XXX GPU tends to freeze if the program is terminiated with a
310 * flip pending. What is the right way to handle the
313 sigemptyset(&act.sa_mask);
314 act.sa_handler = on_signal;
316 sigaction(SIGINT, &act, NULL);
317 sigaction(SIGTERM, &act, NULL);
321 else if (drm->swap_mode == DRM_SWAP_COPY) {
322 struct gralloc_drm_bo_t *front;
325 /* create the real front buffer */
326 front = gralloc_drm_bo_create(drm,
330 GRALLOC_USAGE_HW_FB);
331 if (front && gralloc_drm_bo_add_fb(front)) {
332 gralloc_drm_bo_destroy(front);
336 /* abuse next_front */
338 drm->next_front = front;
340 drm->swap_mode = DRM_SWAP_SETCRTC;
343 switch (drm->swap_mode) {
350 case DRM_SWAP_SETCRTC:
351 swap_mode = "set-crtc";
358 LOGD("will use %s for fb posting", swap_mode);
361 static drmModeModeInfoPtr find_mode(drmModeConnectorPtr connector, int *bpp)
363 char value[PROPERTY_VALUE_MAX];
364 drmModeModeInfoPtr mode;
366 int xres = 0, yres = 0;
368 if (property_get("debug.drm.mode", value, NULL)) {
369 char *p = value, *end;
371 /* parse <xres>x<yres>[@<bpp>] */
372 if (sscanf(value, "%dx%d@%d", &xres, &yres, bpp) != 3) {
374 if (sscanf(value, "%dx%d", &xres, &yres) != 2)
384 for (i = 0; i < connector->count_modes; i++) {
385 drmModeModeInfoPtr m = &connector->modes[i];
389 tmp = (m->hdisplay - xres) * (m->hdisplay - xres) +
390 (m->vdisplay - yres) * (m->vdisplay - yres);
393 /* use the first preferred mode */
394 tmp = (m->type & DRM_MODE_TYPE_PREFERRED) ? 0 : dist;
405 /* fallback to the first mode */
407 mode = &connector->modes[0];
415 * Initialize KMS with a connector.
417 static int drm_kms_init_with_connector(struct gralloc_drm_t *drm,
418 drmModeConnectorPtr connector)
420 drmModeEncoderPtr encoder;
421 drmModeModeInfoPtr mode;
424 if (!connector->count_modes)
427 encoder = drmModeGetEncoder(drm->fd, connector->encoders[0]);
431 for (i = 0; i < drm->resources->count_crtcs; i++) {
432 if (encoder->possible_crtcs & (1 << i))
435 drmModeFreeEncoder(encoder);
436 if (i == drm->resources->count_crtcs)
439 drm->crtc_id = drm->resources->crtcs[i];
440 drm->connector_id = connector->connector_id;
442 mode = find_mode(connector, &bpp);
446 drm->fb_format = HAL_PIXEL_FORMAT_RGB_565;
450 drm->fb_format = HAL_PIXEL_FORMAT_BGRA_8888;
454 if (connector->mmWidth && connector->mmHeight) {
455 drm->xdpi = (drm->mode.hdisplay * 25.4 / connector->mmWidth);
456 drm->ydpi = (drm->mode.vdisplay * 25.4 / connector->mmHeight);
463 #ifdef DRM_MODE_FEATURE_DIRTYFB
466 drm->clip.x2 = drm->mode.hdisplay;
467 drm->clip.y2 = drm->mode.vdisplay;
476 int gralloc_drm_init_kms(struct gralloc_drm_t *drm)
483 drm->resources = drmModeGetResources(drm->fd);
484 if (!drm->resources) {
485 LOGE("failed to get modeset resources");
489 /* find the crtc/connector/mode to use */
490 for (i = 0; i < drm->resources->count_connectors; i++) {
491 drmModeConnectorPtr connector;
493 connector = drmModeGetConnector(drm->fd,
494 drm->resources->connectors[i]);
496 if (connector->connection == DRM_MODE_CONNECTED) {
497 if (!drm_kms_init_with_connector(drm,
502 drmModeFreeConnector(connector);
505 if (i == drm->resources->count_connectors) {
506 LOGE("failed to find a valid crtc/connector/mode combination");
507 drmModeFreeResources(drm->resources);
508 drm->resources = NULL;
513 drm_kms_init_features(drm);
520 * Initialize a framebuffer device with KMS info.
522 void gralloc_drm_get_kms_info(struct gralloc_drm_t *drm,
523 struct framebuffer_device_t *fb)
525 *((uint32_t *) &fb->flags) = 0x0;
526 *((uint32_t *) &fb->width) = drm->mode.hdisplay;
527 *((uint32_t *) &fb->height) = drm->mode.vdisplay;
528 *((int *) &fb->stride) = drm->mode.hdisplay;
529 *((float *) &fb->fps) = drm->mode.vrefresh;
531 *((int *) &fb->format) = drm->fb_format;
532 *((float *) &fb->xdpi) = drm->xdpi;
533 *((float *) &fb->ydpi) = drm->ydpi;
534 *((int *) &fb->minSwapInterval) = drm->swap_interval;
535 *((int *) &fb->maxSwapInterval) = drm->swap_interval;
539 * Return true if fb posting is pipelined.
541 int gralloc_drm_is_kms_pipelined(struct gralloc_drm_t *drm)
543 return (drm->swap_mode != DRM_SWAP_SETCRTC);