blob: 082d385d94c89cc3ab6749cfdd795d9cc1acbcea [file] [log] [blame]
Ethan Yonkera59da092015-10-13 19:35:05 -05001/*
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>
Ethan Yonker8373cfe2017-09-08 06:50:54 -050037#else
38#define MSMFB_NEW_REQUEST 0
Ethan Yonkera59da092015-10-13 19:35:05 -050039#endif
40
Andreas Schneider9c820952017-11-02 17:56:56 +010041#include "graphics_overlay.h"
42
Ethan Yonker8373cfe2017-09-08 06:50:54 -050043#include "minui/minui.h"
Ethan Yonkera59da092015-10-13 19:35:05 -050044
45#define MDP_V4_0 400
46#define MAX_DISPLAY_DIM 2048
Ethan Yonkera59da092015-10-13 19:35:05 -050047#define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1))
48
Ethan Yonker8373cfe2017-09-08 06:50:54 -050049MinuiBackendOverlay::MinuiBackendOverlay() :
50 gr_draw(nullptr),
51 fb_fd(-1),
52 isMDP5(false),
53 leftSplit(0),
54 rightSplit(0),
55 frame_size(0),
56 overlayL_id(MSMFB_NEW_REQUEST),
57 overlayR_id(MSMFB_NEW_REQUEST) {}
Ethan Yonkera59da092015-10-13 19:35:05 -050058
59#ifdef MSM_BSP
Ethan Yonker8373cfe2017-09-08 06:50:54 -050060int MinuiBackendOverlay::map_mdp_pixel_format()
Ethan Yonkera59da092015-10-13 19:35:05 -050061{
62 int format = MDP_RGB_565;
63#if defined(RECOVERY_BGRA)
64 format = MDP_BGRA_8888;
Kra1o577568592015-10-14 18:09:54 +020065#elif defined(RECOVERY_RGBA)
66 format = MDP_RGBA_8888;
Ethan Yonkera59da092015-10-13 19:35:05 -050067#elif defined(RECOVERY_RGBX)
68 format = MDP_RGBA_8888;
69#endif
70 return format;
71}
Andreas Schneider06c62192017-11-02 17:57:37 +010072
73static memInfo mem_info;
74
Ethan Yonkera59da092015-10-13 19:35:05 -050075#endif // MSM_BSP
76
Ethan Yonker8373cfe2017-09-08 06:50:54 -050077bool MinuiBackendOverlay::target_has_overlay()
Ethan Yonkera59da092015-10-13 19:35:05 -050078{
79 int ret;
80 int mdp_version;
81 bool overlay_supported = false;
Ethan Yonkera59da092015-10-13 19:35:05 -050082 fb_fix_screeninfo fi;
83 int fd;
84
85 fd = open("/dev/graphics/fb0", O_RDWR);
86 if (fd < 0) {
87 perror("open_overlay cannot open fb0");
Ethan Yonker8373cfe2017-09-08 06:50:54 -050088 return false;
Ethan Yonkera59da092015-10-13 19:35:05 -050089 }
90
91 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
92 perror("failed to get fb0 info");
93 close(fd);
Ethan Yonker8373cfe2017-09-08 06:50:54 -050094 return false;
Ethan Yonkera59da092015-10-13 19:35:05 -050095 }
96 close(fd);
Ethan Yonker8373cfe2017-09-08 06:50:54 -050097
98 if (strlen(fi.id) >= 8) {
99 if(!strncmp(fi.id, "msmfb", strlen("msmfb"))) {
100 char str_ver[4];
101 memcpy(str_ver, fi.id + strlen("msmfb"), 3);
102 str_ver[3] = '\0';
103 mdp_version = atoi(str_ver);
104 if (mdp_version >= MDP_V4_0) {
105 overlay_supported = true;
106 }
107 } else if (!strncmp(fi.id, "mdssfb", strlen("mdssfb"))) {
108 overlay_supported = true;
109 isMDP5 = true;
110 }
111 }
112#ifndef MSM_BSP
113 if (overlay_supported)
114 printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id);
115#endif
116 return overlay_supported;
Ethan Yonkera59da092015-10-13 19:35:05 -0500117}
118
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500119void MinuiBackendOverlay::Blank(bool blank)
Ethan Yonkera59da092015-10-13 19:35:05 -0500120{
121#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
122 int fd;
123 char brightness[4];
124 snprintf(brightness, 4, "%03d", TW_MAX_BRIGHTNESS/2);
125
126 fd = open(TW_BRIGHTNESS_PATH, O_RDWR);
127 if (fd < 0) {
128 perror("cannot open LCD backlight");
129 return;
130 }
131 write(fd, blank ? "000" : brightness, 3);
132 close(fd);
133#else
134 int ret;
135
136 ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
137 if (ret < 0)
138 perror("ioctl(): blank");
139#endif
140}
141
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500142void MinuiBackendOverlay::SetDisplayedFramebuffer(unsigned n)
Ethan Yonkera59da092015-10-13 19:35:05 -0500143{
144 if (n > 1 || !double_buffered) return;
145
146 vi.yres_virtual = gr_framebuffer[0].height * 2;
147 vi.yoffset = n * gr_framebuffer[0].height;
148 vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
149 if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
150 perror("active fb swap failed");
151 }
152 displayed_buffer = n;
153}
154
155#ifdef MSM_BSP
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500156void MinuiBackendOverlay::setDisplaySplit(void) {
Ethan Yonkera59da092015-10-13 19:35:05 -0500157 char split[64] = {0};
158 if (!isMDP5)
159 return;
160 FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
161 if (fp) {
162 //Format "left right" space as delimiter
163 if(fread(split, sizeof(char), 64, fp)) {
164 leftSplit = atoi(split);
165 printf("Left Split=%d\n",leftSplit);
166 char *rght = strpbrk(split, " ");
167 if (rght)
168 rightSplit = atoi(rght + 1);
169 printf("Right Split=%d\n", rightSplit);
170 }
171 } else {
172 printf("Failed to open mdss_fb_split node\n");
173 }
174 if (fp)
175 fclose(fp);
176}
177
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500178int MinuiBackendOverlay::getLeftSplit(void) {
Ethan Yonkera59da092015-10-13 19:35:05 -0500179 //Default even split for all displays with high res
180 int lSplit = vi.xres / 2;
181
182 //Override if split published by driver
183 if (leftSplit)
184 lSplit = leftSplit;
185
186 return lSplit;
187}
188
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500189int MinuiBackendOverlay::getRightSplit(void) {
Ethan Yonkera59da092015-10-13 19:35:05 -0500190 return rightSplit;
191}
192
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500193int MinuiBackendOverlay::free_ion_mem(void) {
Ethan Yonkera59da092015-10-13 19:35:05 -0500194 int ret = 0;
195
196 if (mem_info.mem_buf)
197 munmap(mem_info.mem_buf, mem_info.size);
198
199 if (mem_info.ion_fd >= 0) {
200 ret = ioctl(mem_info.ion_fd, ION_IOC_FREE, &mem_info.handle_data);
201 if (ret < 0)
202 perror("free_mem failed ");
203 }
204
205 if (mem_info.mem_fd >= 0)
206 close(mem_info.mem_fd);
207 if (mem_info.ion_fd >= 0)
208 close(mem_info.ion_fd);
209
210 memset(&mem_info, 0, sizeof(mem_info));
211 mem_info.mem_fd = -1;
212 mem_info.ion_fd = -1;
213 return 0;
214}
215
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500216int MinuiBackendOverlay::alloc_ion_mem(unsigned int size)
Ethan Yonkera59da092015-10-13 19:35:05 -0500217{
218 int result;
219 struct ion_fd_data fd_data;
220 struct ion_allocation_data ionAllocData;
221
222 mem_info.ion_fd = open("/dev/ion", O_RDWR|O_DSYNC);
223 if (mem_info.ion_fd < 0) {
224 perror("ERROR: Can't open ion ");
225 return -errno;
226 }
227
228 ionAllocData.flags = 0;
229 ionAllocData.len = size;
230 ionAllocData.align = sysconf(_SC_PAGESIZE);
231#ifdef NEW_ION_HEAP
232 ionAllocData.heap_id_mask =
233#else
234 ionAllocData.heap_mask =
235#endif
236 ION_HEAP(ION_IOMMU_HEAP_ID) |
237 ION_HEAP(ION_SYSTEM_CONTIG_HEAP_ID);
238
239 result = ioctl(mem_info.ion_fd, ION_IOC_ALLOC, &ionAllocData);
240 if(result){
241 perror("ION_IOC_ALLOC Failed ");
242 close(mem_info.ion_fd);
243 return result;
244 }
245
246 fd_data.handle = ionAllocData.handle;
247 mem_info.handle_data.handle = ionAllocData.handle;
248 result = ioctl(mem_info.ion_fd, ION_IOC_MAP, &fd_data);
249 if (result) {
250 perror("ION_IOC_MAP Failed ");
251 free_ion_mem();
252 return result;
253 }
254 mem_info.mem_buf = (unsigned char *)mmap(NULL, size, PROT_READ |
255 PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
256 mem_info.mem_fd = fd_data.fd;
257
258 if (!mem_info.mem_buf) {
259 perror("ERROR: mem_buf MAP_FAILED ");
260 free_ion_mem();
261 return -ENOMEM;
262 }
263
264 return 0;
265}
266
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500267bool MinuiBackendOverlay::isDisplaySplit(void) {
Ethan Yonkera59da092015-10-13 19:35:05 -0500268 if (vi.xres > MAX_DISPLAY_DIM)
269 return true;
270 //check if right split is set by driver
271 if (getRightSplit())
272 return true;
273
274 return false;
275}
276
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500277int MinuiBackendOverlay::allocate_overlay(int fd, GRSurface gr_fb[])
Ethan Yonkera59da092015-10-13 19:35:05 -0500278{
279 int ret = 0;
280
281 if (!isDisplaySplit()) {
282 // Check if overlay is already allocated
283 if (MSMFB_NEW_REQUEST == overlayL_id) {
284 struct mdp_overlay overlayL;
285
286 memset(&overlayL, 0 , sizeof (struct mdp_overlay));
287
288 /* Fill Overlay Data */
289 overlayL.src.width = ALIGN(gr_fb[0].width, 32);
290 overlayL.src.height = gr_fb[0].height;
291 overlayL.src.format = map_mdp_pixel_format();
292 overlayL.src_rect.w = gr_fb[0].width;
293 overlayL.src_rect.h = gr_fb[0].height;
294 overlayL.dst_rect.w = gr_fb[0].width;
295 overlayL.dst_rect.h = gr_fb[0].height;
296 overlayL.alpha = 0xFF;
297 overlayL.transp_mask = MDP_TRANSP_NOP;
298 overlayL.id = MSMFB_NEW_REQUEST;
299 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
300 if (ret < 0) {
301 perror("Overlay Set Failed");
302 return ret;
303 }
304 overlayL_id = overlayL.id;
305 }
306 } else {
307 float xres = vi.xres;
308 int lSplit = getLeftSplit();
309 float lSplitRatio = lSplit / xres;
310 float lCropWidth = gr_fb[0].width * lSplitRatio;
311 int lWidth = lSplit;
312 int rWidth = gr_fb[0].width - lSplit;
313 int height = gr_fb[0].height;
314
315 if (MSMFB_NEW_REQUEST == overlayL_id) {
316
317 struct mdp_overlay overlayL;
318
319 memset(&overlayL, 0 , sizeof (struct mdp_overlay));
320
321 /* Fill OverlayL Data */
322 overlayL.src.width = ALIGN(gr_fb[0].width, 32);
323 overlayL.src.height = gr_fb[0].height;
324 overlayL.src.format = map_mdp_pixel_format();
325 overlayL.src_rect.x = 0;
326 overlayL.src_rect.y = 0;
327 overlayL.src_rect.w = lCropWidth;
328 overlayL.src_rect.h = gr_fb[0].height;
329 overlayL.dst_rect.x = 0;
330 overlayL.dst_rect.y = 0;
331 overlayL.dst_rect.w = lWidth;
332 overlayL.dst_rect.h = height;
333 overlayL.alpha = 0xFF;
334 overlayL.transp_mask = MDP_TRANSP_NOP;
335 overlayL.id = MSMFB_NEW_REQUEST;
336 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayL);
337 if (ret < 0) {
338 perror("OverlayL Set Failed");
339 return ret;
340 }
341 overlayL_id = overlayL.id;
342 }
343 if (MSMFB_NEW_REQUEST == overlayR_id) {
344 struct mdp_overlay overlayR;
345
346 memset(&overlayR, 0 , sizeof (struct mdp_overlay));
347
348 /* Fill OverlayR Data */
349 overlayR.src.width = ALIGN(gr_fb[0].width, 32);
350 overlayR.src.height = gr_fb[0].height;
351 overlayR.src.format = map_mdp_pixel_format();
352 overlayR.src_rect.x = lCropWidth;
353 overlayR.src_rect.y = 0;
354 overlayR.src_rect.w = gr_fb[0].width - lCropWidth;
355 overlayR.src_rect.h = gr_fb[0].height;
356 overlayR.dst_rect.x = 0;
357 overlayR.dst_rect.y = 0;
358 overlayR.dst_rect.w = rWidth;
359 overlayR.dst_rect.h = height;
360 overlayR.alpha = 0xFF;
361 overlayR.flags = MDSS_MDP_RIGHT_MIXER;
362 overlayR.transp_mask = MDP_TRANSP_NOP;
363 overlayR.id = MSMFB_NEW_REQUEST;
364 ret = ioctl(fd, MSMFB_OVERLAY_SET, &overlayR);
365 if (ret < 0) {
366 perror("OverlayR Set Failed");
367 return ret;
368 }
369 overlayR_id = overlayR.id;
370 }
371
372 }
373 return 0;
374}
375
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500376int MinuiBackendOverlay::overlay_display_frame(int fd, void* data, size_t size)
Ethan Yonkera59da092015-10-13 19:35:05 -0500377{
378 int ret = 0;
379 struct msmfb_overlay_data ovdataL, ovdataR;
380 struct mdp_display_commit ext_commit;
381
382 if (!isDisplaySplit()) {
383 if (overlayL_id == MSMFB_NEW_REQUEST) {
384 perror("display_frame failed, no overlay\n");
385 return -EINVAL;
386 }
387
388 memcpy(mem_info.mem_buf, data, size);
389
390 memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
391
392 ovdataL.id = overlayL_id;
393 ovdataL.data.flags = 0;
394 ovdataL.data.offset = 0;
395 ovdataL.data.memory_id = mem_info.mem_fd;
396 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
397 if (ret < 0) {
398 perror("overlay_display_frame failed, overlay play Failed\n");
399 return ret;
400 }
401 } else {
402
403 if (overlayL_id == MSMFB_NEW_REQUEST) {
404 perror("display_frame failed, no overlayL \n");
405 return -EINVAL;
406 }
407
408 memcpy(mem_info.mem_buf, data, size);
409
410 memset(&ovdataL, 0, sizeof(struct msmfb_overlay_data));
411
412 ovdataL.id = overlayL_id;
413 ovdataL.data.flags = 0;
414 ovdataL.data.offset = 0;
415 ovdataL.data.memory_id = mem_info.mem_fd;
416 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL);
417 if (ret < 0) {
418 perror("overlay_display_frame failed, overlayL play Failed\n");
419 return ret;
420 }
421
422 if (overlayR_id == MSMFB_NEW_REQUEST) {
423 perror("display_frame failed, no overlayR \n");
424 return -EINVAL;
425 }
426 memset(&ovdataR, 0, sizeof(struct msmfb_overlay_data));
427
428 ovdataR.id = overlayR_id;
429 ovdataR.data.flags = 0;
430 ovdataR.data.offset = 0;
431 ovdataR.data.memory_id = mem_info.mem_fd;
432 ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataR);
433 if (ret < 0) {
434 perror("overlay_display_frame failed, overlayR play Failed\n");
435 return ret;
436 }
437 }
438 memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
439 ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
440 ext_commit.wait_for_finish = 1;
441 ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
442 if (ret < 0) {
443 perror("overlay_display_frame failed, overlay commit Failed\n!");
444 }
445
446 return ret;
447}
448
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500449GRSurface* MinuiBackendOverlay::Flip() {
Ethan Yonkera59da092015-10-13 19:35:05 -0500450 if (double_buffered) {
451#if defined(RECOVERY_BGRA)
452 // In case of BGRA, do some byte swapping
453 unsigned int idx;
454 unsigned char tmp;
455 unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data;
456 for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes);
457 idx += 4) {
458 tmp = ucfb_vaddr[idx];
459 ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2];
460 ucfb_vaddr[idx + 2] = tmp;
461 }
462#endif
463 // Change gr_draw to point to the buffer currently displayed,
464 // then flip the driver so we're displaying the other buffer
465 // instead.
466 gr_draw = gr_framebuffer + displayed_buffer;
Andreas Schneider06c62192017-11-02 17:57:37 +0100467 SetDisplayedFramebuffer(1-displayed_buffer);
Ethan Yonkera59da092015-10-13 19:35:05 -0500468 overlay_display_frame(fb_fd, gr_draw->data, frame_size);
469 } else {
470 // Copy from the in-memory surface to the framebuffer.
471 overlay_display_frame(fb_fd, gr_draw->data, frame_size);
472 }
473 return gr_draw;
474}
475
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500476int MinuiBackendOverlay::free_overlay(int fd)
Ethan Yonkera59da092015-10-13 19:35:05 -0500477{
478 int ret = 0;
479 struct mdp_display_commit ext_commit;
480
481 if (!isDisplaySplit()) {
482 if (overlayL_id != MSMFB_NEW_REQUEST) {
483 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
484 if (ret) {
485 perror("Overlay Unset Failed");
486 overlayL_id = MSMFB_NEW_REQUEST;
487 return ret;
488 }
489 }
490 } else {
491
492 if (overlayL_id != MSMFB_NEW_REQUEST) {
493 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id);
494 if (ret) {
495 perror("OverlayL Unset Failed");
496 overlayL_id = MSMFB_NEW_REQUEST;
497 return ret;
498 }
499 }
500
501 if (overlayR_id != MSMFB_NEW_REQUEST) {
502 ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id);
503 if (ret) {
504 perror("OverlayR Unset Failed");
505 overlayR_id = MSMFB_NEW_REQUEST;
506 return ret;
507 }
508 }
509 }
510 memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
511 ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
512 ext_commit.wait_for_finish = 1;
513 ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit);
514 if (ret < 0) {
515 perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!");
516 overlayL_id = MSMFB_NEW_REQUEST;
517 overlayR_id = MSMFB_NEW_REQUEST;
518 return ret;
519 }
520 overlayL_id = MSMFB_NEW_REQUEST;
521 overlayR_id = MSMFB_NEW_REQUEST;
522
523 return 0;
524}
525
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500526GRSurface* MinuiBackendOverlay::Init() {
527 if (!target_has_overlay())
528 return NULL;
529
Ethan Yonkera59da092015-10-13 19:35:05 -0500530 int fd = open("/dev/graphics/fb0", O_RDWR);
531 if (fd == -1) {
532 perror("cannot open fb0");
533 return NULL;
534 }
535
536 fb_fix_screeninfo fi;
537 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
538 perror("failed to get fb0 info");
539 close(fd);
540 return NULL;
541 }
542
543 if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
544 perror("failed to get fb0 info");
545 close(fd);
546 return NULL;
547 }
548
549 // We print this out for informational purposes only, but
550 // throughout we assume that the framebuffer device uses an RGBX
551 // pixel format. This is the case for every development device I
552 // have access to. For some of those devices (eg, hammerhead aka
553 // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
554 // different format (XBGR) but actually produces the correct
555 // results on the display when you write RGBX.
556 //
557 // If you have a device that actually *needs* another pixel format
558 // (ie, BGRX, or 565), patches welcome...
559
560 printf("fb0 reports (possibly inaccurate):\n"
561 " vi.bits_per_pixel = %d\n"
562 " vi.red.offset = %3d .length = %3d\n"
563 " vi.green.offset = %3d .length = %3d\n"
564 " vi.blue.offset = %3d .length = %3d\n",
565 vi.bits_per_pixel,
566 vi.red.offset, vi.red.length,
567 vi.green.offset, vi.green.length,
568 vi.blue.offset, vi.blue.length);
569
570 void* bits = malloc(vi.xres_virtual * vi.yres * (vi.bits_per_pixel / 8));
571 if (bits == NULL) {
572 perror("failed to malloc framebuffer");
573 close(fd);
574 return NULL;
575 }
576
577 memset(bits, 0, fi.smem_len);
578
579 gr_framebuffer[0].width = vi.xres;
580 gr_framebuffer[0].height = vi.yres;
581 gr_framebuffer[0].row_bytes = fi.line_length;
582 gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
583 gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits);
584 memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
585
586 /* check if we can use double buffering */
587 if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
588 double_buffered = true;
589 printf("double buffered.\n");
590 memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface));
591 gr_framebuffer[1].data = gr_framebuffer[0].data +
592 gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
593
594 gr_draw = gr_framebuffer+1;
595
596 } else {
597 double_buffered = false;
598 printf("single buffered.\n");
599 // Without double-buffering, we allocate RAM for a buffer to
600 // draw in, and then "flipping" the buffer consists of a
601 // memcpy from the buffer we allocated to the framebuffer.
602
603 gr_draw = (GRSurface*) malloc(sizeof(GRSurface));
604 if (gr_draw == NULL) {
605 printf("Failed to malloc gr_draw for single buffering.\n");
606 return NULL;
607 } else {
608 memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
609 gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes);
610 if (!gr_draw->data) {
611 perror("failed to allocate in-memory surface");
612 return NULL;
613 }
614 }
615 }
616
617 memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
618 fb_fd = fd;
Andreas Schneider06c62192017-11-02 17:57:37 +0100619 SetDisplayedFramebuffer(0);
Ethan Yonkera59da092015-10-13 19:35:05 -0500620
621 frame_size = fi.line_length * vi.yres;
622
623 printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
624
Andreas Schneider06c62192017-11-02 17:57:37 +0100625 Blank(true);
626 Blank(false);
Ethan Yonkera59da092015-10-13 19:35:05 -0500627
628 if (!alloc_ion_mem(fi.line_length * vi.yres))
629 allocate_overlay(fb_fd, gr_framebuffer);
630
631 return gr_draw;
632}
633
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500634MinuiBackendOverlay::~MinuiBackendOverlay() {
Ethan Yonkera59da092015-10-13 19:35:05 -0500635 free_overlay(fb_fd);
636 free_ion_mem();
637
638 close(fb_fd);
639 fb_fd = -1;
640
641 if (!double_buffered && gr_draw) {
642 free(gr_draw->data);
643 free(gr_draw);
644 }
645 gr_draw = NULL;
646 if (gr_framebuffer[0].data) {
647 free(gr_framebuffer[0].data);
648 gr_framebuffer[0].data = NULL;
649 }
650}
651#else // MSM_BSP
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500652
653GRSurface* MinuiBackendOverlay::Flip() {
Ethan Yonkera59da092015-10-13 19:35:05 -0500654 return NULL;
655}
656
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500657GRSurface* MinuiBackendOverlay::Init() {
658 target_has_overlay(); // Don't care about return value, just for logging
Ethan Yonkera59da092015-10-13 19:35:05 -0500659 return NULL;
660}
661
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500662MinuiBackendOverlay::~MinuiBackendOverlay() {
Ethan Yonkera59da092015-10-13 19:35:05 -0500663 return;
664}
665#endif // MSM_BSP