blob: 84ea6e0eaca15deb0dfaa05ead030d1f1a36e3db [file] [log] [blame]
Ethan Yonkerfbb43532015-12-28 21:54:50 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdbool.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21#include <errno.h>
22
23#include <fcntl.h>
24#include <stdio.h>
25
26#include <sys/cdefs.h>
27#include <sys/ioctl.h>
28#include <sys/mman.h>
29#include <sys/types.h>
30
31#include <linux/fb.h>
32#include <linux/kd.h>
33
34#ifdef MSM_BSP
35#include <linux/msm_mdp.h>
36#include <linux/msm_ion.h>
37#endif
38
39#include "minui.h"
40#include "graphics.h"
41#include <pixelflinger/pixelflinger.h>
42
43#define MDP_V4_0 400
44#define MAX_DISPLAY_DIM 2048
45
46static GRSurface* overlay_init(minui_backend*);
47static GRSurface* overlay_flip(minui_backend*);
48static void overlay_blank(minui_backend*, bool);
49static void overlay_exit(minui_backend*);
50
51static GRSurface gr_framebuffer;
52static GRSurface* gr_draw = NULL;
53static int displayed_buffer;
54
55static fb_var_screeninfo vi;
56static int fb_fd = -1;
57static bool isMDP5 = false;
58static int leftSplit = 0;
59static int rightSplit = 0;
60#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
61
62static size_t frame_size = 0;
63
64#ifdef MSM_BSP
65typedef struct {
66 unsigned char *mem_buf;
67 int size;
68 int ion_fd;
69 int mem_fd;
70 struct ion_handle_data handle_data;
71} memInfo;
72
73//Left and right overlay id
74static int overlayL_id = MSMFB_NEW_REQUEST;
75static int overlayR_id = MSMFB_NEW_REQUEST;
76
77static memInfo mem_info;
78
79static int map_mdp_pixel_format()
80{
81 if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGB_565)
82 return MDP_RGB_565;
83 else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_BGRA_8888)
84 return MDP_BGRA_8888;
85 else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGBA_8888)
86 return MDP_RGBA_8888;
87 else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGBX_8888)
88 return MDP_RGBA_8888;
89 printf("No known pixel format for map_mdp_pixel_format, defaulting to MDP_RGB_565.\n");
90 return MDP_RGB_565;
91}
92#endif // MSM_BSP
93
94static minui_backend my_backend = {
95 .init = overlay_init,
96 .flip = overlay_flip,
97 .blank = overlay_blank,
98 .exit = overlay_exit,
99};
100
101bool target_has_overlay(char *version)
102{
103 int ret;
104 int mdp_version;
105 bool overlay_supported = false;
106
107 if (strlen(version) >= 8) {
108 if(!strncmp(version, "msmfb", strlen("msmfb"))) {
109 char str_ver[4];
110 memcpy(str_ver, version + strlen("msmfb"), 3);
111 str_ver[3] = '\0';
112 mdp_version = atoi(str_ver);
113 if (mdp_version >= MDP_V4_0) {
114 overlay_supported = true;
115 }
116 } else if (!strncmp(version, "mdssfb", strlen("mdssfb"))) {
117 overlay_supported = true;
118 isMDP5 = true;
119 }
120 }
121
122 return overlay_supported;
123}
124
125minui_backend* open_overlay() {
126 fb_fix_screeninfo fi;
127 int fd;
128
129 fd = open("/dev/graphics/fb0", O_RDWR);
130 if (fd < 0) {
131 perror("open_overlay cannot open fb0");
132 return NULL;
133 }
134
135 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
136 perror("failed to get fb0 info");
137 close(fd);
138 return NULL;
139 }
140
141 if (target_has_overlay(fi.id)) {
142#ifdef MSM_BSP
143 close(fd);
144 return &my_backend;
145#else
146 printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id);
147#endif
148 }
149 close(fd);
150 return NULL;
151}
152
153static void overlay_blank(minui_backend* backend __unused, bool blank)
154{
155#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
156 int fd;
157 char brightness[4];
158 snprintf(brightness, 4, "%03d", TW_MAX_BRIGHTNESS/2);
159
160 fd = open(TW_BRIGHTNESS_PATH, O_RDWR);
161 if (fd < 0) {
162 perror("cannot open LCD backlight");
163 return;
164 }
165 write(fd, blank ? "000" : brightness, 3);
166 close(fd);
AdrianDC2948b6f2016-02-07 03:44:44 +0100167
168#ifdef TW_SECONDARY_BRIGHTNESS_PATH
169 fd = open(TW_SECONDARY_BRIGHTNESS_PATH, O_RDWR);
170 if (fd < 0) {
171 perror("cannot open LCD backlight 2");
172 return;
173 }
174 write(fd, blank ? "000" : brightness, 3);
175 close(fd);
176#endif
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100177#else
178 int ret;
179
180 ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
181 if (ret < 0)
182 perror("ioctl(): blank");
183#endif
184}
185
186#ifdef MSM_BSP
187void setDisplaySplit(void) {
188 char split[64] = {0};
189 if (!isMDP5)
190 return;
191 FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
192 if (fp) {
193 //Format "left right" space as delimiter
194 if(fread(split, sizeof(char), 64, fp)) {
195 leftSplit = atoi(split);
196 printf("Left Split=%d\n",leftSplit);
197 char *rght = strpbrk(split, " ");
198 if (rght)
199 rightSplit = atoi(rght + 1);
200 printf("Right Split=%d\n", rightSplit);
201 }
202 } else {
203 printf("Failed to open mdss_fb_split node\n");
204 }
205 if (fp)
206 fclose(fp);
207}
208
209int getLeftSplit(void) {
210 //Default even split for all displays with high res
211 int lSplit = vi.xres / 2;
212
213 //Override if split published by driver
214 if (leftSplit)
215 lSplit = leftSplit;
216
217 return lSplit;
218}
219
220int getRightSplit(void) {
221 return rightSplit;
222}
223
224int free_ion_mem(void) {
225 int ret = 0;
226
227 if (mem_info.mem_buf)
228 munmap(mem_info.mem_buf, mem_info.size);
229
230 if (mem_info.ion_fd >= 0) {
231 ret = ioctl(mem_info.ion_fd, ION_IOC_FREE, &mem_info.handle_data);
232 if (ret < 0)
233 perror("free_mem failed ");
234 }
235
236 if (mem_info.mem_fd >= 0)
237 close(mem_info.mem_fd);
238 if (mem_info.ion_fd >= 0)
239 close(mem_info.ion_fd);
240
241 memset(&mem_info, 0, sizeof(mem_info));
242 mem_info.mem_fd = -1;
243 mem_info.ion_fd = -1;
244 return 0;
245}
246
247int alloc_ion_mem(unsigned int size)
248{
249 int result;
250 struct ion_fd_data fd_data;
251 struct ion_allocation_data ionAllocData;
252
253 mem_info.ion_fd = open("/dev/ion", O_RDWR|O_DSYNC);
254 if (mem_info.ion_fd < 0) {
255 perror("ERROR: Can't open ion ");
256 return -errno;
257 }
258
259 ionAllocData.flags = 0;
260 ionAllocData.len = size;
261 ionAllocData.align = sysconf(_SC_PAGESIZE);
262#ifdef NEW_ION_HEAP
263 ionAllocData.heap_id_mask =
264#else
265 ionAllocData.heap_mask =
266#endif
267 ION_HEAP(ION_IOMMU_HEAP_ID) |
268 ION_HEAP(ION_SYSTEM_CONTIG_HEAP_ID);
269
270 result = ioctl(mem_info.ion_fd, ION_IOC_ALLOC, &ionAllocData);
271 if(result){
272 perror("ION_IOC_ALLOC Failed ");
273 close(mem_info.ion_fd);
274 return result;
275 }
276
277 fd_data.handle = ionAllocData.handle;
278 mem_info.handle_data.handle = ionAllocData.handle;
279 result = ioctl(mem_info.ion_fd, ION_IOC_MAP, &fd_data);
280 if (result) {
281 perror("ION_IOC_MAP Failed ");
282 free_ion_mem();
283 return result;
284 }
285 mem_info.mem_buf = (unsigned char *)mmap(NULL, size, PROT_READ |
286 PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
287 mem_info.mem_fd = fd_data.fd;
288
289 if (!mem_info.mem_buf) {
290 perror("ERROR: mem_buf MAP_FAILED ");
291 free_ion_mem();
292 return -ENOMEM;
293 }
294
295 return 0;
296}
297
298bool isDisplaySplit(void) {
299 if (vi.xres > MAX_DISPLAY_DIM)
300 return true;
301 //check if right split is set by driver
302 if (getRightSplit())
303 return true;
304
305 return false;
306}
307
308int allocate_overlay(int fd, GRSurface gr_fb)
309{
310 int ret = 0;
311
312 if (!isDisplaySplit()) {
313 // Check if overlay is already allocated
314 if (MSMFB_NEW_REQUEST == overlayL_id) {
315 struct mdp_overlay overlayL;
316
317 memset(&overlayL, 0 , sizeof (struct mdp_overlay));
318
319 /* Fill Overlay Data */
320 overlayL.src.width = ALIGN(gr_fb.width, 32);
321 overlayL.src.height = gr_fb.height;
322 overlayL.src.format = map_mdp_pixel_format();
323 overlayL.src_rect.w = gr_fb.width;
324 overlayL.src_rect.h = gr_fb.height;
325 overlayL.dst_rect.w = gr_fb.width;
326 overlayL.dst_rect.h = gr_fb.height;
327 overlayL.alpha = 0xFF;
xadro7509bc52016-01-30 21:30:12 +0100328#ifdef BOARD_HAS_FLIPPED_SCREEN
329 overlayL.flags = MDP_ROT_180;
330#endif
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100331 overlayL.transp_mask = MDP_TRANSP_NOP;
332 overlayL.id = MSMFB_NEW_REQUEST;
333 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
334 if (ret < 0) {
335 perror("Overlay Set Failed");
336 return ret;
337 }
338 overlayL_id = overlayL.id;
339 }
340 } else {
341 float xres = vi.xres;
342 int lSplit = getLeftSplit();
343 float lSplitRatio = lSplit / xres;
344 float lCropWidth = gr_fb.width * lSplitRatio;
345 int lWidth = lSplit;
346 int rWidth = gr_fb.width - lSplit;
347 int height = gr_fb.height;
348
349 if (MSMFB_NEW_REQUEST == overlayL_id) {
350
351 struct mdp_overlay overlayL;
352
353 memset(&overlayL, 0 , sizeof (struct mdp_overlay));
354
355 /* Fill OverlayL Data */
356 overlayL.src.width = ALIGN(gr_fb.width, 32);
357 overlayL.src.height = gr_fb.height;
358 overlayL.src.format = map_mdp_pixel_format();
359 overlayL.src_rect.x = 0;
360 overlayL.src_rect.y = 0;
361 overlayL.src_rect.w = lCropWidth;
362 overlayL.src_rect.h = gr_fb.height;
363 overlayL.dst_rect.x = 0;
364 overlayL.dst_rect.y = 0;
365 overlayL.dst_rect.w = lWidth;
366 overlayL.dst_rect.h = height;
367 overlayL.alpha = 0xFF;
xadro7509bc52016-01-30 21:30:12 +0100368#ifdef BOARD_HAS_FLIPPED_SCREEN
369 overlayL.flags = MDP_ROT_180;
370#endif
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100371 overlayL.transp_mask = MDP_TRANSP_NOP;
372 overlayL.id = MSMFB_NEW_REQUEST;
373 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
374 if (ret < 0) {
375 perror("OverlayL Set Failed");
376 return ret;
377 }
378 overlayL_id = overlayL.id;
379 }
380 if (MSMFB_NEW_REQUEST == overlayR_id) {
381 struct mdp_overlay overlayR;
382
383 memset(&overlayR, 0 , sizeof (struct mdp_overlay));
384
385 /* Fill OverlayR Data */
386 overlayR.src.width = ALIGN(gr_fb.width, 32);
387 overlayR.src.height = gr_fb.height;
388 overlayR.src.format = map_mdp_pixel_format();
389 overlayR.src_rect.x = lCropWidth;
390 overlayR.src_rect.y = 0;
391 overlayR.src_rect.w = gr_fb.width - lCropWidth;
392 overlayR.src_rect.h = gr_fb.height;
393 overlayR.dst_rect.x = 0;
394 overlayR.dst_rect.y = 0;
395 overlayR.dst_rect.w = rWidth;
396 overlayR.dst_rect.h = height;
397 overlayR.alpha = 0xFF;
xadro7509bc52016-01-30 21:30:12 +0100398#ifdef BOARD_HAS_FLIPPED_SCREEN
399 overlayR.flags = MDSS_MDP_RIGHT_MIXER | MDP_ROT_180;
400#else
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100401 overlayR.flags = MDSS_MDP_RIGHT_MIXER;
xadro7509bc52016-01-30 21:30:12 +0100402#endif
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100403 overlayR.transp_mask = MDP_TRANSP_NOP;
404 overlayR.id = MSMFB_NEW_REQUEST;
405 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayR);
406 if (ret < 0) {
407 perror("OverlayR Set Failed");
408 return ret;
409 }
410 overlayR_id = overlayR.id;
411 }
412
413 }
414 return 0;
415}
416
417int overlay_display_frame(int fd, void* data, size_t size)
418{
419 int ret = 0;
420 struct msmfb_overlay_data ovdataL, ovdataR;
421 struct mdp_display_commit ext_commit;
422
423 if (!isDisplaySplit()) {
424 if (overlayL_id == MSMFB_NEW_REQUEST) {
425 perror("display_frame failed, no overlay\n");
426 return -EINVAL;
427 }
428
429 memcpy(mem_info.mem_buf, data, size);
430
431 memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
432
433 ovdataL.id = overlayL_id;
434 ovdataL.data.flags = 0;
435 ovdataL.data.offset = 0;
436 ovdataL.data.memory_id = mem_info.mem_fd;
437 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
438 if (ret < 0) {
439 perror("overlay_display_frame failed, overlay play Failed\n");
440 printf("%i, %i, %i, %i\n", ret, fb_fd, fd, errno);
441 return ret;
442 }
443 } else {
444
445 if (overlayL_id == MSMFB_NEW_REQUEST) {
446 perror("display_frame failed, no overlayL \n");
447 return -EINVAL;
448 }
449
450 memcpy(mem_info.mem_buf, data, size);
451
452 memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
453
454 ovdataL.id = overlayL_id;
455 ovdataL.data.flags = 0;
456 ovdataL.data.offset = 0;
457 ovdataL.data.memory_id = mem_info.mem_fd;
458 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
459 if (ret < 0) {
460 perror("overlay_display_frame failed, overlayL play Failed\n");
461 return ret;
462 }
463
464 if (overlayR_id == MSMFB_NEW_REQUEST) {
465 perror("display_frame failed, no overlayR \n");
466 return -EINVAL;
467 }
468 memset(&ovdataR, 0, sizeof(struct msmfb_overlay_data));
469
470 ovdataR.id = overlayR_id;
471 ovdataR.data.flags = 0;
472 ovdataR.data.offset = 0;
473 ovdataR.data.memory_id = mem_info.mem_fd;
474 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataR);
475 if (ret < 0) {
476 perror("overlay_display_frame failed, overlayR play Failed\n");
477 return ret;
478 }
479 }
480 memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
481 ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
482 ext_commit.wait_for_finish = 1;
483 ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
484 if (ret < 0) {
485 perror("overlay_display_frame failed, overlay commit Failed\n!");
486 }
487
488 return ret;
489}
490
491static GRSurface* overlay_flip(minui_backend* backend __unused) {
492#if defined(RECOVERY_BGRA)
493 // In case of BGRA, do some byte swapping
494 unsigned int idx;
495 unsigned char tmp;
496 unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data;
497 for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes);
498 idx += 4) {
499 tmp = ucfb_vaddr[idx];
500 ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2];
501 ucfb_vaddr[idx + 2] = tmp;
502 }
503#endif
504 // Copy from the in-memory surface to the framebuffer.
505 overlay_display_frame(fb_fd, gr_draw->data, frame_size);
506 return gr_draw;
507}
508
509int free_overlay(int fd)
510{
511 int ret = 0;
512 struct mdp_display_commit ext_commit;
513
514 if (!isDisplaySplit()) {
515 if (overlayL_id != MSMFB_NEW_REQUEST) {
516 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
517 if (ret) {
518 perror("Overlay Unset Failed");
519 overlayL_id = MSMFB_NEW_REQUEST;
520 return ret;
521 }
522 }
523 } else {
524
525 if (overlayL_id != MSMFB_NEW_REQUEST) {
526 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
527 if (ret) {
528 perror("OverlayL Unset Failed");
529 }
530 }
531
532 if (overlayR_id != MSMFB_NEW_REQUEST) {
533 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id);
534 if (ret) {
535 perror("OverlayR Unset Failed");
536 overlayR_id = MSMFB_NEW_REQUEST;
537 return ret;
538 }
539 }
540 }
541 memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
542 ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
543 ext_commit.wait_for_finish = 1;
544 ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
545 if (ret < 0) {
546 perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!");
547 overlayL_id = MSMFB_NEW_REQUEST;
548 overlayR_id = MSMFB_NEW_REQUEST;
549 return ret;
550 }
551 overlayL_id = MSMFB_NEW_REQUEST;
552 overlayR_id = MSMFB_NEW_REQUEST;
553
554 return 0;
555}
556
557static GRSurface* overlay_init(minui_backend* backend) {
558 int fd = open("/dev/graphics/fb0", O_RDWR);
559 if (fd == -1) {
560 perror("cannot open fb0");
561 return NULL;
562 }
563
564 fb_fix_screeninfo fi;
565 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
566 perror("failed to get fb0 info");
567 close(fd);
568 return NULL;
569 }
570
571 if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
572 perror("failed to get fb0 info");
573 close(fd);
574 return NULL;
575 }
576
577 // We print this out for informational purposes only, but
578 // throughout we assume that the framebuffer device uses an RGBX
579 // pixel format. This is the case for every development device I
580 // have access to. For some of those devices (eg, hammerhead aka
581 // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
582 // different format (XBGR) but actually produces the correct
583 // results on the display when you write RGBX.
584 //
585 // If you have a device that actually *needs* another pixel format
586 // (ie, BGRX, or 565), patches welcome...
587
588 printf("fb0 reports (possibly inaccurate):\n"
589 " vi.bits_per_pixel = %d\n"
590 " vi.red.offset = %3d .length = %3d\n"
591 " vi.green.offset = %3d .length = %3d\n"
592 " vi.blue.offset = %3d .length = %3d\n",
593 vi.bits_per_pixel,
594 vi.red.offset, vi.red.length,
595 vi.green.offset, vi.green.length,
596 vi.blue.offset, vi.blue.length);
597
598 gr_framebuffer.width = vi.xres;
599 gr_framebuffer.height = vi.yres;
600 gr_framebuffer.row_bytes = fi.line_length;
601 gr_framebuffer.pixel_bytes = vi.bits_per_pixel / 8;
602 //gr_framebuffer.data = reinterpret_cast<uint8_t*>(bits);
603 if (vi.bits_per_pixel == 16) {
604 printf("setting GGL_PIXEL_FORMAT_RGB_565\n");
605 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGB_565;
Ziyan4fea38a2016-01-28 01:19:35 +0100606 } else if (vi.red.offset == 8 || vi.red.offset == 16) {
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100607 printf("setting GGL_PIXEL_FORMAT_BGRA_8888\n");
608 gr_framebuffer.format = GGL_PIXEL_FORMAT_BGRA_8888;
609 } else if (vi.red.offset == 0) {
610 printf("setting GGL_PIXEL_FORMAT_RGBA_8888\n");
611 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBA_8888;
612 } else if (vi.red.offset == 24) {
613 printf("setting GGL_PIXEL_FORMAT_RGBX_8888\n");
614 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBX_8888;
615 } else {
616 if (vi.red.length == 8) {
617 printf("No valid pixel format detected, trying GGL_PIXEL_FORMAT_RGBX_8888\n");
618 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBX_8888;
619 } else {
620 printf("No valid pixel format detected, trying GGL_PIXEL_FORMAT_RGB_565\n");
621 gr_framebuffer.format = GGL_PIXEL_FORMAT_RGB_565;
622 }
623 }
624
625 frame_size = fi.line_length * vi.yres;
626
627 gr_framebuffer.data = reinterpret_cast<uint8_t*>(calloc(frame_size, 1));
628 if (gr_framebuffer.data == NULL) {
629 perror("failed to calloc framebuffer");
630 close(fd);
631 return NULL;
632 }
633
634 gr_draw = &gr_framebuffer;
635 fb_fd = fd;
636
637 printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
638
639 overlay_blank(backend, true);
640 overlay_blank(backend, false);
641
642 if (!alloc_ion_mem(frame_size))
643 allocate_overlay(fb_fd, gr_framebuffer);
644
645 return gr_draw;
646}
647
648static void overlay_exit(minui_backend* backend __unused) {
649 free_overlay(fb_fd);
650 free_ion_mem();
651
652 close(fb_fd);
653 fb_fd = -1;
654
655 if (gr_draw) {
656 free(gr_draw->data);
657 free(gr_draw);
658 }
659 gr_draw = NULL;
660}
661#else // MSM_BSP
662static GRSurface* overlay_flip(minui_backend* backend __unused) {
663 return NULL;
664}
665
666static GRSurface* overlay_init(minui_backend* backend __unused) {
667 return NULL;
668}
669
670static void overlay_exit(minui_backend* backend __unused) {
671 return;
672}
673#endif // MSM_BSP