blob: 873b5f4c610fdd729006eeba9468e63a16acb6c5 [file] [log] [blame]
John Stultz16100f62017-05-03 11:12:18 -07001/*
2 * Copyright (C) 2010 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 <cutils/log.h>
27#include <cutils/atomic.h>
28#include <hardware/hardware.h>
29#include <hardware/gralloc.h>
30
31#include <GLES/gl.h>
32
33#include "alloc_device.h"
34#include "gralloc_priv.h"
35#include "gralloc_helper.h"
36#include "gralloc_vsync.h"
37
38#define STANDARD_LINUX_SCREEN
39
40// numbers of buffers for page flipping
41#define NUM_BUFFERS NUM_FB_BUFFERS
42
43enum
44{
45 PAGE_FLIP = 0x00000001,
46};
47
48
49static int fb_set_swap_interval(struct framebuffer_device_t* dev, int interval)
50{
51 if (interval < dev->minSwapInterval)
52 {
53 interval = dev->minSwapInterval;
54 }
55 else if (interval > dev->maxSwapInterval)
56 {
57 interval = dev->maxSwapInterval;
58 }
59
60 private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);
61 m->swapInterval = interval;
62
63 if (0 == interval) gralloc_vsync_disable(dev);
64 else gralloc_vsync_enable(dev);
65
66 return 0;
67}
68
69static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
70{
71 if (private_handle_t::validate(buffer) < 0)
72 {
73 return -EINVAL;
74 }
75
76 private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
77 private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module);
78
79 if (m->currentBuffer)
80 {
81 m->base.unlock(&m->base, m->currentBuffer);
82 m->currentBuffer = 0;
83 }
84
85 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)
86 {
87 m->base.lock(&m->base, buffer, private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
88 0, 0, m->info.xres, m->info.yres, NULL);
89
90 const size_t offset = (uintptr_t)hnd->base - (uintptr_t)m->framebuffer->base;
91 int interrupt;
92 m->info.activate = FB_ACTIVATE_VBL;
93 m->info.yoffset = offset / m->finfo.line_length;
94
95#ifdef STANDARD_LINUX_SCREEN
96 if (ioctl(m->framebuffer->fd, FBIOPAN_DISPLAY, &m->info) == -1)
97 {
98 AERR( "FBIOPAN_DISPLAY failed for fd: %d", m->framebuffer->fd );
99 m->base.unlock(&m->base, buffer);
100 return -errno;
101 }
102#else /*Standard Android way*/
103 if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1)
104 {
105 AERR( "FBIOPUT_VSCREENINFO failed for fd: %d", m->framebuffer->fd );
106 m->base.unlock(&m->base, buffer);
107 return -errno;
108 }
109#endif
110 if ( 0 != gralloc_wait_for_vsync(dev) )
111 {
112 AERR( "Gralloc wait for vsync failed for fd: %d", m->framebuffer->fd );
113 m->base.unlock(&m->base, buffer);
114 return -errno;
115 }
116 m->currentBuffer = buffer;
117 }
118 else
119 {
120 void* fb_vaddr;
121 void* buffer_vaddr;
122
123 m->base.lock(&m->base, m->framebuffer, GRALLOC_USAGE_SW_WRITE_RARELY,
124 0, 0, m->info.xres, m->info.yres, &fb_vaddr);
125
126 m->base.lock(&m->base, buffer, GRALLOC_USAGE_SW_READ_RARELY,
127 0, 0, m->info.xres, m->info.yres, &buffer_vaddr);
128
129 // If buffer's alignment match framebuffer alignment we can do a direct copy.
130 // If not we must fallback to do an aligned copy of each line.
131 if ( hnd->byte_stride == (int)m->finfo.line_length )
132 {
133 memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
134 }
135 else
136 {
137 uintptr_t fb_offset = 0;
138 uintptr_t buffer_offset = 0;
139 unsigned int i;
140
141 for (i = 0; i < m->info.yres; i++)
142 {
143 memcpy((void *)((uintptr_t)fb_vaddr + fb_offset),
144 (void *)((uintptr_t)buffer_vaddr + buffer_offset),
145 m->finfo.line_length);
146
147 fb_offset += m->finfo.line_length;
148 buffer_offset += hnd->byte_stride;
149 }
150 }
151 m->base.unlock(&m->base, buffer);
152 m->base.unlock(&m->base, m->framebuffer);
153 }
154
155 return 0;
156}
157
158int init_frame_buffer_locked(struct private_module_t* module)
159{
160 if (module->framebuffer)
161 {
162 return 0; // Nothing to do, already initialized
163 }
164
165 char const * const device_template[] =
166 {
167 "/dev/graphics/fb%u",
168 "/dev/fb%u",
169 NULL
170 };
171
172 int fd = -1;
173 int i = 0;
174 char name[64];
175
176 while ((fd == -1) && device_template[i])
177 {
178 snprintf(name, 64, device_template[i], 0);
179 fd = open(name, O_RDWR, 0);
180 i++;
181 }
182
183 if (fd < 0)
184 {
185 return -errno;
186 }
187
188 struct fb_fix_screeninfo finfo;
189 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
190 {
191 return -errno;
192 }
193
194 struct fb_var_screeninfo info;
195 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
196 {
197 return -errno;
198 }
199
200 info.reserved[0] = 0;
201 info.reserved[1] = 0;
202 info.reserved[2] = 0;
203 info.xoffset = 0;
204 info.yoffset = 0;
205 info.activate = FB_ACTIVATE_NOW;
206
207#ifdef GRALLOC_16_BITS
208 /*
209 * Explicitly request 5/6/5
210 */
211 info.bits_per_pixel = 16;
212 info.red.offset = 11;
213 info.red.length = 5;
214 info.green.offset = 5;
215 info.green.length = 6;
216 info.blue.offset = 0;
217 info.blue.length = 5;
218 info.transp.offset = 0;
219 info.transp.length = 0;
220#else
221 /*
222 * Explicitly request 8/8/8
223 */
224 info.bits_per_pixel = 32;
225 info.red.offset = 16;
226 info.red.length = 8;
227 info.green.offset = 8;
228 info.green.length = 8;
229 info.blue.offset = 0;
230 info.blue.length = 8;
231 info.transp.offset = 0;
232 info.transp.length = 0;
233#endif
234
235 /*
236 * Request NUM_BUFFERS screens (at lest 2 for page flipping)
237 */
238 info.yres_virtual = info.yres * NUM_BUFFERS;
239
240 uint32_t flags = PAGE_FLIP;
241 if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1)
242 {
243 info.yres_virtual = info.yres;
244 flags &= ~PAGE_FLIP;
245 AWAR( "FBIOPUT_VSCREENINFO failed, page flipping not supported fd: %d", fd );
246 }
247
248 if (info.yres_virtual < info.yres * 2)
249 {
250 // we need at least 2 for page-flipping
251 info.yres_virtual = info.yres;
252 flags &= ~PAGE_FLIP;
253 AWAR( "page flipping not supported (yres_virtual=%d, requested=%d)", info.yres_virtual, info.yres*2 );
254 }
255
256 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
257 {
258 return -errno;
259 }
260
261 int refreshRate = 0;
262 if ( info.pixclock > 0 )
263 {
264 refreshRate = 1000000000000000LLU /
265 (
266 uint64_t( info.upper_margin + info.lower_margin + info.yres + info.hsync_len )
267 * ( info.left_margin + info.right_margin + info.xres + info.vsync_len )
268 * info.pixclock
269 );
270 }
271 else
272 {
273 AWAR( "fbdev pixclock is zero for fd: %d", fd );
274 }
275
276 if (refreshRate == 0)
277 {
278 refreshRate = 60*1000; // 60 Hz
279 }
280
281 if (int(info.width) <= 0 || int(info.height) <= 0)
282 {
283 // the driver doesn't return that information
284 // default to 160 dpi
285 info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
286 info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
287 }
288
289 float xdpi = (info.xres * 25.4f) / info.width;
290 float ydpi = (info.yres * 25.4f) / info.height;
291 float fps = refreshRate / 1000.0f;
292
293 AINF("using (fd=%d)\n"
294 "id = %s\n"
295 "xres = %d px\n"
296 "yres = %d px\n"
297 "xres_virtual = %d px\n"
298 "yres_virtual = %d px\n"
299 "bpp = %d\n"
300 "r = %2u:%u\n"
301 "g = %2u:%u\n"
302 "b = %2u:%u\n",
303 fd,
304 finfo.id,
305 info.xres,
306 info.yres,
307 info.xres_virtual,
308 info.yres_virtual,
309 info.bits_per_pixel,
310 info.red.offset, info.red.length,
311 info.green.offset, info.green.length,
312 info.blue.offset, info.blue.length);
313
314 AINF("width = %d mm (%f dpi)\n"
315 "height = %d mm (%f dpi)\n"
316 "refresh rate = %.2f Hz\n",
317 info.width, xdpi,
318 info.height, ydpi,
319 fps);
320
321 if (0 == strncmp(finfo.id, "CLCD FB", 7))
322 {
323 module->dpy_type = MALI_DPY_TYPE_CLCD;
324 }
325 else if (0 == strncmp(finfo.id, "ARM Mali HDLCD", 14))
326 {
327 module->dpy_type = MALI_DPY_TYPE_HDLCD;
328 }
329 else
330 {
331 module->dpy_type = MALI_DPY_TYPE_UNKNOWN;
332 }
333
334 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
335 {
336 return -errno;
337 }
338
339 if (finfo.smem_len <= 0)
340 {
341 return -errno;
342 }
343
344 module->flags = flags;
345 module->info = info;
346 module->finfo = finfo;
347 module->xdpi = xdpi;
348 module->ydpi = ydpi;
349 module->fps = fps;
350 module->swapInterval = 1;
351
352 /*
353 * map the framebuffer
354 */
355 size_t fbSize = round_up_to_page_size(finfo.line_length * info.yres_virtual);
356 void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
357 if (vaddr == MAP_FAILED)
358 {
359 AERR( "Error mapping the framebuffer (%s)", strerror(errno) );
360 return -errno;
361 }
362
363 memset(vaddr, 0, fbSize);
364
365
366 // Create a "fake" buffer object for the entire frame buffer memory, and store it in the module
367 module->framebuffer = new private_handle_t(private_handle_t::PRIV_FLAGS_FRAMEBUFFER, GRALLOC_USAGE_HW_FB, fbSize, vaddr,
368 0, dup(fd), 0);
369
370 module->numBuffers = info.yres_virtual / info.yres;
371 module->bufferMask = 0;
372
373 return 0;
374}
375
376static int init_frame_buffer(struct private_module_t* module)
377{
378 pthread_mutex_lock(&module->lock);
379 int err = init_frame_buffer_locked(module);
380 pthread_mutex_unlock(&module->lock);
381 return err;
382}
383
384static int fb_close(struct hw_device_t *device)
385{
386 framebuffer_device_t* dev = reinterpret_cast<framebuffer_device_t*>(device);
387 if (dev)
388 {
389 free(dev);
390 }
391 return 0;
392}
393
394int compositionComplete(struct framebuffer_device_t* dev)
395{
396 GRALLOC_UNUSED(dev);
397
398 /* By doing a finish here we force the GL driver to start rendering
399 all the drawcalls up to this point, and to wait for the rendering to be complete.*/
400 glFinish();
401 /* The rendering of the backbuffer is now completed.
402 When SurfaceFlinger later does a call to eglSwapBuffer(), the swap will be done
403 synchronously in the same thread, and not asynchronoulsy in a background thread later.
404 The SurfaceFlinger requires this behaviour since it releases the lock on all the
405 SourceBuffers (Layers) after the compositionComplete() function returns.
406 However this "bad" behaviour by SurfaceFlinger should not affect performance,
407 since the Applications that render the SourceBuffers (Layers) still get the
408 full renderpipeline using asynchronous rendering. So they perform at maximum speed,
409 and because of their complexity compared to the Surface flinger jobs, the Surface flinger
410 is normally faster even if it does everyhing synchronous and serial.
411 */
412 return 0;
413}
414
415int framebuffer_device_open(hw_module_t const* module, const char* name, hw_device_t** device)
416{
417 int status = -EINVAL;
418
419 GRALLOC_UNUSED(name);
420
421 alloc_device_t* gralloc_device;
422#if DISABLE_FRAMEBUFFER_HAL == 1
423 AERR("Framebuffer HAL not support/disabled %s",
424#ifdef MALI_DISPLAY_VERSION
425 "with MALI display enable");
426#else
427 "");
428#endif
429 return -ENODEV;
430#endif
431 status = gralloc_open(module, &gralloc_device);
432 if (status < 0)
433 {
434 return status;
435 }
436
437 private_module_t* m = (private_module_t*)module;
438 status = init_frame_buffer(m);
439
440 /* malloc is used instead of 'new' to instantiate the struct framebuffer_device_t
441 * C++11 spec specifies that if a class/struct has a const member,default constructor
442 * is deleted. So, if 'new' is used to instantiate the class/struct, it will throw
443 * error complaining about deleted constructor. Even if the struct is wrapped in a class
444 * it will still try to use the base class constructor to initialize the members, resulting
445 * in error 'deleted constructor'.
446 * This leaves two options
447 * Option 1: initialize the const members at the instantiation time. With {value1, value2 ..}
448 * Which relies on the order of the members, and if members are reordered or a new member is introduced
449 * it will end up assiging wrong value to members. Designated assignment as well has been removed in C++11
450 * Option 2: use malloc instead of 'new' to allocate the class/struct and initialize the members in code.
451 * This is the only maintainable option available.
452 */
453
454 framebuffer_device_t *dev = reinterpret_cast<framebuffer_device_t*> (malloc(sizeof(framebuffer_device_t)));
455
456 /* if either or both of init_frame_buffer() and malloc failed */
457 if ((status < 0) || (!dev))
458 {
459 gralloc_close(gralloc_device);
460 (!dev)? (void)(status = -ENOMEM) : free(dev);
461 return status;
462 }
463
464 memset(dev, 0, sizeof(*dev));
465
466 /* initialize the procs */
467 dev->common.tag = HARDWARE_DEVICE_TAG;
468 dev->common.version = 0;
469 dev->common.module = const_cast<hw_module_t*>(module);
470 dev->common.close = fb_close;
471 dev->setSwapInterval = fb_set_swap_interval;
472 dev->post = fb_post;
473 dev->setUpdateRect = 0;
474 dev->compositionComplete = &compositionComplete;
475
476 int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
477 const_cast<uint32_t&>(dev->flags) = 0;
478 const_cast<uint32_t&>(dev->width) = m->info.xres;
479 const_cast<uint32_t&>(dev->height) = m->info.yres;
480 const_cast<int&>(dev->stride) = stride;
481#ifdef GRALLOC_16_BITS
482 const_cast<int&>(dev->format) = HAL_PIXEL_FORMAT_RGB_565;
483#else
484 const_cast<int&>(dev->format) = HAL_PIXEL_FORMAT_BGRA_8888;
485#endif
486 const_cast<float&>(dev->xdpi) = m->xdpi;
487 const_cast<float&>(dev->ydpi) = m->ydpi;
488 const_cast<float&>(dev->fps) = m->fps;
489 const_cast<int&>(dev->minSwapInterval) = 0;
490 const_cast<int&>(dev->maxSwapInterval) = 1;
491 *device = &dev->common;
492
493 gralloc_vsync_enable(dev);
494
495 return status;
496}