1 /*
2 * Copyright (C) 2010-2017 ARM Limited. All rights reserved.
3 *
4 * Copyright (C) 2008 The Android Open Source Project
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include <string.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdlib.h>
23 #include <sys/ioctl.h>
24 #include <linux/fb.h>
25
26 #include <log/log.h>
27 #include <cutils/atomic.h>
28 #include <hardware/hardware.h>
29 #include <hardware/fb.h>
30
31 #include <GLES/gl.h>
32
33 #if GRALLOC_USE_GRALLOC1_API == 1
34 #include <hardware/gralloc1.h>
35 #else
36 #include <hardware/gralloc.h>
37 #endif
38
39 #include "mali_gralloc_module.h"
40 #include "mali_gralloc_private_interface_types.h"
41 #include "mali_gralloc_buffer.h"
42 #include "gralloc_helper.h"
43 #include "gralloc_vsync.h"
44 #include "mali_gralloc_bufferaccess.h"
45 #include "mali_gralloc_ion.h"
46
47 #define STANDARD_LINUX_SCREEN
48
49 // numbers of buffers for page flipping
50 #define NUM_BUFFERS NUM_FB_BUFFERS
51
52 enum
53 {
54 PAGE_FLIP = 0x00000001,
55 };
56
fb_set_swap_interval(struct framebuffer_device_t * dev,int interval)57 static int fb_set_swap_interval(struct framebuffer_device_t *dev, int interval)
58 {
59 if (interval < dev->minSwapInterval)
60 {
61 interval = dev->minSwapInterval;
62 }
63 else if (interval > dev->maxSwapInterval)
64 {
65 interval = dev->maxSwapInterval;
66 }
67
68 private_module_t *m = reinterpret_cast<private_module_t *>(dev->common.module);
69 m->swapInterval = interval;
70
71 if (0 == interval)
72 {
73 gralloc_vsync_disable(dev);
74 }
75 else
76 {
77 gralloc_vsync_enable(dev);
78 }
79
80 return 0;
81 }
82
fb_post(struct framebuffer_device_t * dev,buffer_handle_t buffer)83 static int fb_post(struct framebuffer_device_t *dev, buffer_handle_t buffer)
84 {
85 if (private_handle_t::validate(buffer) < 0)
86 {
87 return -EINVAL;
88 }
89
90 private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(buffer);
91 private_module_t *m = reinterpret_cast<private_module_t *>(dev->common.module);
92
93 if (m->currentBuffer)
94 {
95 mali_gralloc_unlock(m, m->currentBuffer);
96 m->currentBuffer = 0;
97 }
98
99 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)
100 {
101 mali_gralloc_lock(m, buffer, private_module_t::PRIV_USAGE_LOCKED_FOR_POST, -1, -1, -1, -1, NULL);
102
103 int interrupt;
104 m->info.activate = FB_ACTIVATE_VBL;
105 m->info.yoffset = hnd->offset / m->finfo.line_length;
106
107 #ifdef STANDARD_LINUX_SCREEN
108
109 if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1)
110 {
111 AERR("FBIOPAN_DISPLAY failed for fd: %d", m->framebuffer->fd);
112 mali_gralloc_unlock(m, buffer);
113 return -errno;
114 }
115
116 #else /*Standard Android way*/
117
118 if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1)
119 {
120 AERR("FBIOPUT_VSCREENINFO failed for fd: %d", m->framebuffer->fd);
121 mali_gralloc_unlock(m, buffer);
122 return -errno;
123 }
124
125 #endif
126
127 if (0 != gralloc_wait_for_vsync(dev))
128 {
129 AERR("Gralloc wait for vsync failed for fd: %d", m->framebuffer->fd);
130 mali_gralloc_unlock(m, buffer);
131 return -errno;
132 }
133
134 m->currentBuffer = buffer;
135 }
136 else
137 {
138 void *fb_vaddr;
139 void *buffer_vaddr;
140
141 mali_gralloc_lock(m, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY, -1, -1, -1, -1, &fb_vaddr);
142
143 mali_gralloc_lock(m, buffer, GRALLOC_USAGE_SW_READ_RARELY, -1, -1, -1, -1, &buffer_vaddr);
144
145 // If buffer's alignment match framebuffer alignment we can do a direct copy.
146 // If not we must fallback to do an aligned copy of each line.
147 if (hnd->byte_stride == (int)m->finfo.line_length)
148 {
149 memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
150 }
151 else
152 {
153 uintptr_t fb_offset = 0;
154 uintptr_t buffer_offset = 0;
155 unsigned int i;
156
157 for (i = 0; i < m->info.yres; i++)
158 {
159 memcpy((void *)((uintptr_t)fb_vaddr + fb_offset), (void *)((uintptr_t)buffer_vaddr + buffer_offset),
160 m->finfo.line_length);
161
162 fb_offset += m->finfo.line_length;
163 buffer_offset += hnd->byte_stride;
164 }
165 }
166
167 mali_gralloc_unlock(m, buffer);
168 mali_gralloc_unlock(m, m->framebuffer);
169 }
170
171 return 0;
172 }
173
init_frame_buffer_locked(struct private_module_t * module)174 static int init_frame_buffer_locked(struct private_module_t *module)
175 {
176 if (module->framebuffer)
177 {
178 return 0; // Nothing to do, already initialized
179 }
180
181 char const *const device_template[] = { "/dev/graphics/fb%u", "/dev/fb%u", NULL };
182
183 int fd = -1;
184 int i = 0;
185 char name[64];
186
187 while ((fd == -1) && device_template[i])
188 {
189 snprintf(name, 64, device_template[i], 0);
190 fd = open(name, O_RDWR, 0);
191 i++;
192 }
193
194 if (fd < 0)
195 {
196 return -errno;
197 }
198
199 struct fb_fix_screeninfo finfo;
200
201 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
202 {
203 return -errno;
204 }
205
206 struct fb_var_screeninfo info;
207
208 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
209 {
210 return -errno;
211 }
212
213 info.reserved[0] = 0;
214 info.reserved[1] = 0;
215 info.reserved[2] = 0;
216 info.xoffset = 0;
217 info.yoffset = 0;
218 info.activate = FB_ACTIVATE_NOW;
219
220 #ifdef GRALLOC_16_BITS
221 /*
222 * Explicitly request 5/6/5
223 */
224 info.bits_per_pixel = 16;
225 info.red.offset = 11;
226 info.red.length = 5;
227 info.green.offset = 5;
228 info.green.length = 6;
229 info.blue.offset = 0;
230 info.blue.length = 5;
231 info.transp.offset = 0;
232 info.transp.length = 0;
233 #else
234 /*
235 * Explicitly request 8/8/8
236 */
237 info.bits_per_pixel = 32;
238 info.red.offset = 16;
239 info.red.length = 8;
240 info.green.offset = 8;
241 info.green.length = 8;
242 info.blue.offset = 0;
243 info.blue.length = 8;
244 info.transp.offset = 0;
245 info.transp.length = 0;
246 #endif
247
248 /*
249 * Request NUM_BUFFERS screens (at lest 2 for page flipping)
250 */
251 info.yres_virtual = info.yres * NUM_BUFFERS;
252
253 uint32_t flags = PAGE_FLIP;
254
255 if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1)
256 {
257 info.yres_virtual = info.yres;
258 flags &= ~PAGE_FLIP;
259 AWAR("FBIOPUT_VSCREENINFO failed, page flipping not supported fd: %d", fd);
260 }
261
262 if (info.yres_virtual < info.yres * 2)
263 {
264 // we need at least 2 for page-flipping
265 info.yres_virtual = info.yres;
266 flags &= ~PAGE_FLIP;
267 AWAR("page flipping not supported (yres_virtual=%d, requested=%d)", info.yres_virtual, info.yres * 2);
268 }
269
270 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
271 {
272 return -errno;
273 }
274
275 int refreshRate = 0;
276
277 if (info.pixclock > 0)
278 {
279 refreshRate =
280 1000000000000000LLU / (uint64_t(info.upper_margin + info.lower_margin + info.yres + info.hsync_len) *
281 (info.left_margin + info.right_margin + info.xres + info.vsync_len) * info.pixclock);
282 }
283 else
284 {
285 AWAR("fbdev pixclock is zero for fd: %d", fd);
286 }
287
288 if (refreshRate == 0)
289 {
290 refreshRate = 60 * 1000; // 60 Hz
291 }
292
293 if (int(info.width) <= 0 || int(info.height) <= 0)
294 {
295 // the driver doesn't return that information
296 // default to 160 dpi
297 info.width = ((info.xres * 25.4f) / 160.0f + 0.5f);
298 info.height = ((info.yres * 25.4f) / 160.0f + 0.5f);
299 }
300
301 float xdpi = (info.xres * 25.4f) / info.width;
302 float ydpi = (info.yres * 25.4f) / info.height;
303 float fps = refreshRate / 1000.0f;
304
305 AINF("using (fd=%d)\n"
306 "id = %s\n"
307 "xres = %d px\n"
308 "yres = %d px\n"
309 "xres_virtual = %d px\n"
310 "yres_virtual = %d px\n"
311 "bpp = %d\n"
312 "r = %2u:%u\n"
313 "g = %2u:%u\n"
314 "b = %2u:%u\n",
315 fd, finfo.id, info.xres, info.yres, info.xres_virtual, info.yres_virtual, info.bits_per_pixel, info.red.offset,
316 info.red.length, info.green.offset, info.green.length, info.blue.offset, info.blue.length);
317
318 AINF("width = %d mm (%f dpi)\n"
319 "height = %d mm (%f dpi)\n"
320 "refresh rate = %.2f Hz\n",
321 info.width, xdpi, info.height, ydpi, fps);
322
323 if (0 == strncmp(finfo.id, "CLCD FB", 7))
324 {
325 module->dpy_type = MALI_DPY_TYPE_CLCD;
326 }
327 else if (0 == strncmp(finfo.id, "ARM Mali HDLCD", 14))
328 {
329 module->dpy_type = MALI_DPY_TYPE_HDLCD;
330 }
331 else if (0 == strncmp(finfo.id, "ARM HDLCD Control", 16))
332 {
333 module->dpy_type = MALI_DPY_TYPE_HDLCD;
334 }
335 else
336 {
337 module->dpy_type = MALI_DPY_TYPE_UNKNOWN;
338 }
339
340 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
341 {
342 return -errno;
343 }
344
345 if (finfo.smem_len <= 0)
346 {
347 return -errno;
348 }
349
350 module->flags = flags;
351 module->info = info;
352 module->finfo = finfo;
353 module->xdpi = xdpi;
354 module->ydpi = ydpi;
355 module->fps = fps;
356 module->swapInterval = 1;
357
358 /*
359 * map the framebuffer
360 */
361 size_t fbSize = round_up_to_page_size(finfo.line_length * info.yres_virtual);
362 void *vaddr = mmap(0, fbSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
363
364 if (vaddr == MAP_FAILED)
365 {
366 AERR("Error mapping the framebuffer (%s)", strerror(errno));
367 return -errno;
368 }
369
370 memset(vaddr, 0, fbSize);
371
372 // Create a "fake" buffer object for the entire frame buffer memory, and store it in the module
373 module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, fbSize, vaddr,
374 GRALLOC_USAGE_HW_FB, GRALLOC_USAGE_HW_FB, dup(fd), 0);
375
376 module->numBuffers = info.yres_virtual / info.yres;
377 module->bufferMask = 0;
378
379 return 0;
380 }
381
init_frame_buffer(struct private_module_t * module)382 static int init_frame_buffer(struct private_module_t *module)
383 {
384 pthread_mutex_lock(&module->lock);
385 int err = init_frame_buffer_locked(module);
386 pthread_mutex_unlock(&module->lock);
387 return err;
388 }
389
fb_close(struct hw_device_t * device)390 static int fb_close(struct hw_device_t *device)
391 {
392 framebuffer_device_t *dev = reinterpret_cast<framebuffer_device_t *>(device);
393
394 if (dev)
395 {
396 free(dev);
397 }
398
399 return 0;
400 }
401
fb_alloc_framebuffer_dmabuf(private_module_t * m,private_handle_t * hnd)402 static int fb_alloc_framebuffer_dmabuf(private_module_t *m, private_handle_t *hnd)
403 {
404 struct fb_dmabuf_export fb_dma_buf;
405 int res;
406 res = ioctl(m->framebuffer->fd, FBIOGET_DMABUF, &fb_dma_buf);
407
408 if (res == 0)
409 {
410 hnd->share_fd = fb_dma_buf.fd;
411 return 0;
412 }
413 else
414 {
415 AINF("FBIOGET_DMABUF ioctl failed(%d). See gralloc_priv.h and the integration manual for vendor framebuffer "
416 "integration",
417 res);
418 return -1;
419 }
420 }
421
fb_alloc_from_ion_module(mali_gralloc_module * m,size_t buffer_size,uint64_t consumer_usage,uint64_t producer_usage,buffer_handle_t * pHandle)422 static int fb_alloc_from_ion_module(mali_gralloc_module *m, size_t buffer_size, uint64_t consumer_usage,
423 uint64_t producer_usage, buffer_handle_t *pHandle)
424 {
425 buffer_descriptor_t fb_buffer_descriptor;
426 gralloc_buffer_descriptor_t gralloc_buffer_descriptor[1];
427 bool shared = false;
428 int err = 0;
429
430 fb_buffer_descriptor.size = buffer_size;
431 fb_buffer_descriptor.consumer_usage = consumer_usage;
432 fb_buffer_descriptor.producer_usage = producer_usage;
433 gralloc_buffer_descriptor[0] = (gralloc_buffer_descriptor_t)(&fb_buffer_descriptor);
434
435 err = mali_gralloc_ion_allocate(m, gralloc_buffer_descriptor, 1, pHandle, &shared);
436
437 return err;
438 }
439
fb_alloc_framebuffer_locked(mali_gralloc_module * m,uint64_t consumer_usage,uint64_t producer_usage,buffer_handle_t * pHandle,int * stride,int * byte_stride)440 static int fb_alloc_framebuffer_locked(mali_gralloc_module *m, uint64_t consumer_usage, uint64_t producer_usage,
441 buffer_handle_t *pHandle, int *stride, int *byte_stride)
442 {
443 // allocate the framebuffer
444 if (m->framebuffer == NULL)
445 {
446 // initialize the framebuffer, the framebuffer is mapped once and forever.
447 int err = init_frame_buffer_locked(m);
448
449 if (err < 0)
450 {
451 return err;
452 }
453 }
454
455 uint32_t bufferMask = m->bufferMask;
456 const uint32_t numBuffers = m->numBuffers;
457 /* framebufferSize is used for allocating the handle to the framebuffer and refers
458 * to the size of the actual framebuffer.
459 * alignedFramebufferSize is used for allocating a possible internal buffer and
460 * thus need to consider internal alignment requirements. */
461 const size_t framebufferSize = m->finfo.line_length * m->info.yres;
462 const size_t alignedFramebufferSize = GRALLOC_ALIGN(m->finfo.line_length, 64) * m->info.yres;
463
464 *stride = m->info.xres;
465
466 if (numBuffers == 1)
467 {
468 // If we have only one buffer, we never use page-flipping. Instead,
469 // we return a regular buffer which will be memcpy'ed to the main
470 // screen when post is called.
471 uint64_t newConsumerUsage = (consumer_usage & ~GRALLOC_USAGE_HW_FB);
472 uint64_t newProducerUsage = (producer_usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
473 AWAR("fallback to single buffering. Virtual Y-res too small %d", m->info.yres);
474 *byte_stride = GRALLOC_ALIGN(m->finfo.line_length, 64);
475 return fb_alloc_from_ion_module(m, alignedFramebufferSize, newConsumerUsage, newProducerUsage, pHandle);
476 }
477
478 if (bufferMask >= ((1LU << numBuffers) - 1))
479 {
480 // We ran out of buffers, reset bufferMask
481 bufferMask = 0;
482 m->bufferMask = 0;
483 }
484
485 uintptr_t framebufferVaddr = (uintptr_t)m->framebuffer->base;
486
487 // find a free slot
488 for (uint32_t i = 0; i < numBuffers; i++)
489 {
490 if ((bufferMask & (1LU << i)) == 0)
491 {
492 m->bufferMask |= (1LU << i);
493 break;
494 }
495
496 framebufferVaddr += framebufferSize;
497 }
498
499 // The entire framebuffer memory is already mapped, now create a buffer object for parts of this memory
500 private_handle_t *hnd = new private_handle_t(
501 private_handle_t::PRIV_FLAGS_FRAMEBUFFER, framebufferSize, (void *)framebufferVaddr, consumer_usage,
502 producer_usage, dup(m->framebuffer->fd), (framebufferVaddr - (uintptr_t)m->framebuffer->base));
503
504 /*
505 * Perform allocator specific actions. If these fail we fall back to a regular buffer
506 * which will be memcpy'ed to the main screen when fb_post is called.
507 */
508 if (fb_alloc_framebuffer_dmabuf(m, hnd) == -1)
509 {
510 delete hnd;
511 uint64_t newConsumerUsage = (consumer_usage & ~GRALLOC_USAGE_HW_FB);
512 uint64_t newProducerUsage = (producer_usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
513 AERR("Fallback to single buffering. Unable to map framebuffer memory to handle:%p", hnd);
514 *byte_stride = GRALLOC_ALIGN(m->finfo.line_length, 64);
515 return fb_alloc_from_ion_module(m, alignedFramebufferSize, newConsumerUsage, newProducerUsage, pHandle);
516 }
517
518 *pHandle = hnd;
519 *byte_stride = m->finfo.line_length;
520
521 return 0;
522 }
523
fb_alloc_framebuffer(mali_gralloc_module * m,uint64_t consumer_usage,uint64_t producer_usage,buffer_handle_t * pHandle,int * stride,int * byte_stride)524 int fb_alloc_framebuffer(mali_gralloc_module *m, uint64_t consumer_usage, uint64_t producer_usage,
525 buffer_handle_t *pHandle, int *stride, int *byte_stride)
526 {
527 pthread_mutex_lock(&m->lock);
528 int err = fb_alloc_framebuffer_locked(m, consumer_usage, producer_usage, pHandle, stride, byte_stride);
529 pthread_mutex_unlock(&m->lock);
530 return err;
531 }
532
compositionComplete(struct framebuffer_device_t * dev)533 int compositionComplete(struct framebuffer_device_t *dev)
534 {
535 GRALLOC_UNUSED(dev);
536
537 /* By doing a finish here we force the GL driver to start rendering
538 all the drawcalls up to this point, and to wait for the rendering to be complete.*/
539 glFinish();
540 /* The rendering of the backbuffer is now completed.
541 When SurfaceFlinger later does a call to eglSwapBuffer(), the swap will be done
542 synchronously in the same thread, and not asynchronoulsy in a background thread later.
543 The SurfaceFlinger requires this behaviour since it releases the lock on all the
544 SourceBuffers (Layers) after the compositionComplete() function returns.
545 However this "bad" behaviour by SurfaceFlinger should not affect performance,
546 since the Applications that render the SourceBuffers (Layers) still get the
547 full renderpipeline using asynchronous rendering. So they perform at maximum speed,
548 and because of their complexity compared to the Surface flinger jobs, the Surface flinger
549 is normally faster even if it does everyhing synchronous and serial.
550 */
551 return 0;
552 }
553
framebuffer_device_open(hw_module_t const * module,const char * name,hw_device_t ** device)554 int framebuffer_device_open(hw_module_t const *module, const char *name, hw_device_t **device)
555 {
556 int status = -EINVAL;
557
558 GRALLOC_UNUSED(name);
559
560 #if GRALLOC_USE_GRALLOC1_API == 1
561 gralloc1_device_t *gralloc_device;
562 #else
563 alloc_device_t *gralloc_device;
564 #endif
565
566 #if DISABLE_FRAMEBUFFER_HAL == 1
567 AERR("Framebuffer HAL not support/disabled %s",
568 #ifdef MALI_DISPLAY_VERSION
569 "with MALI display enable");
570 #else
571 "");
572 #endif
573 return -ENODEV;
574 #endif
575
576 #if GRALLOC_USE_GRALLOC1_API == 1
577 status = gralloc1_open(module, &gralloc_device);
578 #else
579 status = gralloc_open(module, &gralloc_device);
580 #endif
581
582 if (status < 0)
583 {
584 return status;
585 }
586
587 private_module_t *m = (private_module_t *)module;
588 status = init_frame_buffer(m);
589
590 /* malloc is used instead of 'new' to instantiate the struct framebuffer_device_t
591 * C++11 spec specifies that if a class/struct has a const member,default constructor
592 * is deleted. So, if 'new' is used to instantiate the class/struct, it will throw
593 * error complaining about deleted constructor. Even if the struct is wrapped in a class
594 * it will still try to use the base class constructor to initialize the members, resulting
595 * in error 'deleted constructor'.
596 * This leaves two options
597 * Option 1: initialize the const members at the instantiation time. With {value1, value2 ..}
598 * Which relies on the order of the members, and if members are reordered or a new member is introduced
599 * it will end up assiging wrong value to members. Designated assignment as well has been removed in C++11
600 * Option 2: use malloc instead of 'new' to allocate the class/struct and initialize the members in code.
601 * This is the only maintainable option available.
602 */
603
604 framebuffer_device_t *dev = reinterpret_cast<framebuffer_device_t *>(malloc(sizeof(framebuffer_device_t)));
605
606 /* if either or both of init_frame_buffer() and malloc failed */
607 if ((status < 0) || (!dev))
608 {
609 #if GRALLOC_USE_GRALLOC1_API == 1
610 gralloc1_close(gralloc_device);
611 #else
612 gralloc_close(gralloc_device);
613 #endif
614 (!dev) ? (void)(status = -ENOMEM) : free(dev);
615 return status;
616 }
617
618 memset(dev, 0, sizeof(*dev));
619
620 /* initialize the procs */
621 dev->common.tag = HARDWARE_DEVICE_TAG;
622 dev->common.version = 0;
623 dev->common.module = const_cast<hw_module_t *>(module);
624 dev->common.close = fb_close;
625 dev->setSwapInterval = fb_set_swap_interval;
626 dev->post = fb_post;
627 dev->setUpdateRect = 0;
628 dev->compositionComplete = &compositionComplete;
629
630 int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
631 const_cast<uint32_t &>(dev->flags) = 0;
632 const_cast<uint32_t &>(dev->width) = m->info.xres;
633 const_cast<uint32_t &>(dev->height) = m->info.yres;
634 const_cast<int &>(dev->stride) = stride;
635 #ifdef GRALLOC_16_BITS
636 const_cast<int &>(dev->format) = HAL_PIXEL_FORMAT_RGB_565;
637 #else
638 const_cast<int &>(dev->format) = HAL_PIXEL_FORMAT_BGRA_8888;
639 #endif
640 const_cast<float &>(dev->xdpi) = m->xdpi;
641 const_cast<float &>(dev->ydpi) = m->ydpi;
642 const_cast<float &>(dev->fps) = m->fps;
643 const_cast<int &>(dev->minSwapInterval) = 0;
644 const_cast<int &>(dev->maxSwapInterval) = 1;
645 *device = &dev->common;
646
647 gralloc_vsync_enable(dev);
648
649 return status;
650 }
651