blob: 5cc560e2fd39ab357eebf4ad15877458631421b6 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001/*
2 * Copyright (C) 2007 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 <unistd.h>
20
Ethan Yonker4ee5ad72014-02-18 18:41:17 -060021#include <errno.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040022#include <fcntl.h>
23#include <stdio.h>
Ethan Yonkerc798c9c2015-10-09 11:15:26 -050024#include <string.h>
Dees_Troy51a0e822012-09-05 15:24:24 -040025
26#include <sys/ioctl.h>
27#include <sys/mman.h>
28#include <sys/types.h>
29
30#include <linux/fb.h>
31#include <linux/kd.h>
32
33#include <pixelflinger/pixelflinger.h>
34
35#include "minui.h"
36
Dees_Troy51a0e822012-09-05 15:24:24 -040037#ifdef RECOVERY_BGRA
38#define PIXEL_FORMAT GGL_PIXEL_FORMAT_BGRA_8888
39#define PIXEL_SIZE 4
40#endif
Kra1o577568592015-10-14 18:09:54 +020041#ifdef RECOVERY_RGBA
42#define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGBA_8888
43#define PIXEL_SIZE 4
44#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040045#ifdef RECOVERY_RGBX
46#define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGBX_8888
47#define PIXEL_SIZE 4
48#endif
49#ifndef PIXEL_FORMAT
50#define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGB_565
51#define PIXEL_SIZE 2
52#endif
53
Hiemanshu Sharmaacf6a9b2012-11-21 11:28:36 -060054#define NUM_BUFFERS 2
Ethan Yonker4ee5ad72014-02-18 18:41:17 -060055#define MAX_DISPLAY_DIM 2048
Hiemanshu Sharmaacf6a9b2012-11-21 11:28:36 -060056
Dees_Troy51a0e822012-09-05 15:24:24 -040057// #define PRINT_SCREENINFO 1 // Enables printing of screen info to log
58
59typedef struct {
Vojtech Bocek76ee9032014-09-07 15:01:56 +020060 int type;
Dees_Troy51a0e822012-09-05 15:24:24 -040061 GGLSurface texture;
62 unsigned offset[97];
63 unsigned cheight;
64 unsigned ascent;
65} GRFont;
66
67static GRFont *gr_font = 0;
68static GGLContext *gr_context = 0;
69static GGLSurface gr_font_texture;
Hiemanshu Sharmaacf6a9b2012-11-21 11:28:36 -060070static GGLSurface gr_framebuffer[NUM_BUFFERS];
Vojtech Bocek03fd6c52014-03-13 18:46:34 +010071GGLSurface gr_mem_surface;
Dees_Troy51a0e822012-09-05 15:24:24 -040072static unsigned gr_active_fb = 0;
Hiemanshu Sharma94f6c882012-11-21 11:25:22 -060073static unsigned double_buffering = 0;
Vojtech Bocek1a4744a2014-02-06 19:52:28 +010074static int gr_is_curr_clr_opaque = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040075
76static int gr_fb_fd = -1;
77static int gr_vt_fd = -1;
78
Vojtech Bocek03fd6c52014-03-13 18:46:34 +010079struct fb_var_screeninfo vi;
Dees_Troy51a0e822012-09-05 15:24:24 -040080static struct fb_fix_screeninfo fi;
81
Ethan Yonker4ee5ad72014-02-18 18:41:17 -060082static bool has_overlay = false;
83static int leftSplit = 0;
84static int rightSplit = 0;
85
86bool target_has_overlay(char *version);
87int free_ion_mem(void);
88int alloc_ion_mem(unsigned int size);
89int allocate_overlay(int fd, GGLSurface gr_fb[]);
90int free_overlay(int fd);
91int overlay_display_frame(int fd, GGLubyte* data, size_t size);
92
Dees_Troy51a0e822012-09-05 15:24:24 -040093#ifdef PRINT_SCREENINFO
94static void print_fb_var_screeninfo()
95{
Dees_Troy2673cec2013-04-02 20:22:16 +000096 printf("vi.xres: %d\n", vi.xres);
97 printf("vi.yres: %d\n", vi.yres);
98 printf("vi.xres_virtual: %d\n", vi.xres_virtual);
99 printf("vi.yres_virtual: %d\n", vi.yres_virtual);
100 printf("vi.xoffset: %d\n", vi.xoffset);
101 printf("vi.yoffset: %d\n", vi.yoffset);
102 printf("vi.bits_per_pixel: %d\n", vi.bits_per_pixel);
103 printf("vi.grayscale: %d\n", vi.grayscale);
Dees_Troy51a0e822012-09-05 15:24:24 -0400104}
105#endif
106
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600107#ifdef MSM_BSP
108int getLeftSplit(void) {
109 //Default even split for all displays with high res
110 int lSplit = vi.xres / 2;
111
112 //Override if split published by driver
113 if (leftSplit)
114 lSplit = leftSplit;
115
116 return lSplit;
117}
118
119int getRightSplit(void) {
120 return rightSplit;
121}
122
123
124void setDisplaySplit(void) {
125 char split[64] = {0};
126 FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r");
127 if (fp) {
128 //Format "left right" space as delimiter
129 if(fread(split, sizeof(char), 64, fp)) {
130 leftSplit = atoi(split);
131 printf("Left Split=%d\n",leftSplit);
132 char *rght = strpbrk(split, " ");
133 if (rght)
134 rightSplit = atoi(rght + 1);
135 printf("Right Split=%d\n", rightSplit);
136 }
137 } else {
138 printf("Failed to open mdss_fb_split node\n");
139 }
140 if (fp)
141 fclose(fp);
142}
143
144bool isDisplaySplit(void) {
145 if (vi.xres > MAX_DISPLAY_DIM)
146 return true;
147 //check if right split is set by driver
148 if (getRightSplit())
149 return true;
150
151 return false;
152}
153
154int getFbXres(void) {
155 return vi.xres;
156}
157
158int getFbYres (void) {
159 return vi.yres;
160}
161#endif // MSM_BSP
162
Dees_Troy51a0e822012-09-05 15:24:24 -0400163static int get_framebuffer(GGLSurface *fb)
164{
Ethan Yonker4f6a9762015-03-09 13:58:54 -0500165 int fd, index = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400166 void *bits;
167
168 fd = open("/dev/graphics/fb0", O_RDWR);
jenkins79699132015-05-08 06:04:44 -0400169
170 while (fd < 0 && index < 30) {
Ethan Yonker4f6a9762015-03-09 13:58:54 -0500171 usleep(1000);
172 fd = open("/dev/graphics/fb0", O_RDWR);
173 index++;
174 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400175 if (fd < 0) {
Ethan Yonker4f6a9762015-03-09 13:58:54 -0500176 perror("cannot open fb0\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400177 return -1;
178 }
179
180 if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
181 perror("failed to get fb0 info");
182 close(fd);
183 return -1;
184 }
185
186 fprintf(stderr, "Pixel format: %dx%d @ %dbpp\n", vi.xres, vi.yres, vi.bits_per_pixel);
187
188 vi.bits_per_pixel = PIXEL_SIZE * 8;
189 if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_BGRA_8888) {
190 fprintf(stderr, "Pixel format: BGRA_8888\n");
191 if (PIXEL_SIZE != 4) fprintf(stderr, "E: Pixel Size mismatch!\n");
192 vi.red.offset = 8;
193 vi.red.length = 8;
194 vi.green.offset = 16;
195 vi.green.length = 8;
196 vi.blue.offset = 24;
197 vi.blue.length = 8;
198 vi.transp.offset = 0;
199 vi.transp.length = 8;
Kra1o577568592015-10-14 18:09:54 +0200200 } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGBA_8888) {
201 fprintf(stderr, "Pixel format: RGBA_8888\n");
202 if (PIXEL_SIZE != 4) fprintf(stderr, "E: Pixel Size mismatch!\n");
203 vi.red.offset = 0;
204 vi.red.length = 8;
205 vi.green.offset = 8;
206 vi.green.length = 8;
207 vi.blue.offset = 16;
208 vi.blue.length = 8;
209 vi.transp.offset = 24;
210 vi.transp.length = 8;
Dees_Troy51a0e822012-09-05 15:24:24 -0400211 } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGBX_8888) {
212 fprintf(stderr, "Pixel format: RGBX_8888\n");
213 if (PIXEL_SIZE != 4) fprintf(stderr, "E: Pixel Size mismatch!\n");
214 vi.red.offset = 24;
215 vi.red.length = 8;
216 vi.green.offset = 16;
217 vi.green.length = 8;
218 vi.blue.offset = 8;
219 vi.blue.length = 8;
220 vi.transp.offset = 0;
221 vi.transp.length = 8;
222 } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGB_565) {
223#ifdef RECOVERY_RGB_565
224 fprintf(stderr, "Pixel format: RGB_565\n");
225 vi.blue.offset = 0;
226 vi.green.offset = 5;
227 vi.red.offset = 11;
228#else
229 fprintf(stderr, "Pixel format: BGR_565\n");
230 vi.blue.offset = 11;
231 vi.green.offset = 5;
232 vi.red.offset = 0;
233#endif
234 if (PIXEL_SIZE != 2) fprintf(stderr, "E: Pixel Size mismatch!\n");
235 vi.blue.length = 5;
236 vi.green.length = 6;
237 vi.red.length = 5;
238 vi.blue.msb_right = 0;
239 vi.green.msb_right = 0;
240 vi.red.msb_right = 0;
241 vi.transp.offset = 0;
242 vi.transp.length = 0;
243 }
244 else
245 {
246 perror("unknown pixel format");
247 close(fd);
248 return -1;
249 }
250
251 vi.vmode = FB_VMODE_NONINTERLACED;
252 vi.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
253
254 if (ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
255 perror("failed to put fb0 info");
256 close(fd);
257 return -1;
258 }
259
260 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
261 perror("failed to get fb0 info");
262 close(fd);
263 return -1;
264 }
265
Dees Troyb0425382014-04-03 00:10:03 +0000266#ifdef MSM_BSP
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600267 has_overlay = target_has_overlay(fi.id);
268
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600269 if (isTargetMdp5())
270 setDisplaySplit();
Dees Troyb0425382014-04-03 00:10:03 +0000271#else
272 has_overlay = false;
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600273#endif
274
275 if (!has_overlay) {
276 printf("Not using qualcomm overlay, '%s'\n", fi.id);
277 bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
278 if (bits == MAP_FAILED) {
279 perror("failed to mmap framebuffer");
280 close(fd);
281 return -1;
282 }
283 } else {
284 printf("Using qualcomm overlay\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400285 }
286
287#ifdef RECOVERY_GRAPHICS_USE_LINELENGTH
288 vi.xres_virtual = fi.line_length / PIXEL_SIZE;
289#endif
290
291 fb->version = sizeof(*fb);
292 fb->width = vi.xres;
293 fb->height = vi.yres;
294#ifdef BOARD_HAS_JANKY_BACKBUFFER
Dees_Troy2673cec2013-04-02 20:22:16 +0000295 printf("setting JANKY BACKBUFFER\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400296 fb->stride = fi.line_length/2;
297#else
298 fb->stride = vi.xres_virtual;
299#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400300 fb->format = PIXEL_FORMAT;
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600301 if (!has_overlay) {
302 fb->data = bits;
303 memset(fb->data, 0, vi.yres * fb->stride * PIXEL_SIZE);
304 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400305
306 fb++;
307
Kra1o5c9556cc2015-06-24 12:19:09 +0200308#ifndef TW_DISABLE_DOUBLE_BUFFERING
Hiemanshu Sharma94f6c882012-11-21 11:25:22 -0600309 /* check if we can use double buffering */
310 if (vi.yres * fi.line_length * 2 > fi.smem_len)
Kra1o5c9556cc2015-06-24 12:19:09 +0200311#else
312 printf("TW_DISABLE_DOUBLE_BUFFERING := true\n");
313#endif
Hiemanshu Sharma94f6c882012-11-21 11:25:22 -0600314 return fd;
315
316 double_buffering = 1;
317
Dees_Troy51a0e822012-09-05 15:24:24 -0400318 fb->version = sizeof(*fb);
319 fb->width = vi.xres;
320 fb->height = vi.yres;
321#ifdef BOARD_HAS_JANKY_BACKBUFFER
322 fb->stride = fi.line_length/2;
Ethan Yonkerbcc502c2014-11-10 11:22:10 -0600323 fb->data = (GGLubyte*) (((unsigned long) bits) + vi.yres * fi.line_length);
Dees_Troy51a0e822012-09-05 15:24:24 -0400324#else
325 fb->stride = vi.xres_virtual;
Ethan Yonkerbcc502c2014-11-10 11:22:10 -0600326 fb->data = (GGLubyte*) (((unsigned long) bits) + vi.yres * fb->stride * PIXEL_SIZE);
Dees_Troy51a0e822012-09-05 15:24:24 -0400327#endif
328 fb->format = PIXEL_FORMAT;
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600329 if (!has_overlay) {
330 memset(fb->data, 0, vi.yres * fb->stride * PIXEL_SIZE);
331 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400332
333#ifdef PRINT_SCREENINFO
334 print_fb_var_screeninfo();
335#endif
336
337 return fd;
338}
339
340static void get_memory_surface(GGLSurface* ms) {
341 ms->version = sizeof(*ms);
342 ms->width = vi.xres;
343 ms->height = vi.yres;
344 ms->stride = vi.xres_virtual;
345 ms->data = malloc(vi.xres_virtual * vi.yres * PIXEL_SIZE);
346 ms->format = PIXEL_FORMAT;
347}
348
349static void set_active_framebuffer(unsigned n)
350{
Hiemanshu Sharma94f6c882012-11-21 11:25:22 -0600351 if (n > 1 || !double_buffering) return;
Hiemanshu Sharmaacf6a9b2012-11-21 11:28:36 -0600352 vi.yres_virtual = vi.yres * NUM_BUFFERS;
Dees_Troy51a0e822012-09-05 15:24:24 -0400353 vi.yoffset = n * vi.yres;
354// vi.bits_per_pixel = PIXEL_SIZE * 8;
355 if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
356 perror("active fb swap failed");
357 }
358}
359
360void gr_flip(void)
361{
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600362 if (-EINVAL == overlay_display_frame(gr_fb_fd, gr_mem_surface.data,
363 (fi.line_length * vi.yres))) {
364 GGLContext *gl = gr_context;
Dees_Troy51a0e822012-09-05 15:24:24 -0400365
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600366 /* swap front and back buffers */
367 if (double_buffering)
368 gr_active_fb = (gr_active_fb + 1) & 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400369
370#ifdef BOARD_HAS_FLIPPED_SCREEN
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600371 /* flip buffer 180 degrees for devices with physicaly inverted screens */
372 unsigned int i;
373 unsigned int j;
Bogdan Seniucd1372f72015-01-23 08:22:39 -0800374 for (i = 0; i < vi.yres; i++) {
375 for (j = 0; j < vi.xres; j++) {
376 memcpy(gr_framebuffer[gr_active_fb].data + (i * vi.xres_virtual + j) * PIXEL_SIZE,
377 gr_mem_surface.data + ((vi.yres - i - 1) * vi.xres_virtual + vi.xres - j - 1) * PIXEL_SIZE, PIXEL_SIZE);
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600378 }
379 }
Bogdan Seniucd1372f72015-01-23 08:22:39 -0800380#else
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600381 /* copy data from the in-memory surface to the buffer we're about
382 * to make active. */
383 memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data,
384 vi.xres_virtual * vi.yres * PIXEL_SIZE);
Bogdan Seniucd1372f72015-01-23 08:22:39 -0800385#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400386
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600387 /* inform the display driver */
388 set_active_framebuffer(gr_active_fb);
389 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400390}
391
392void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
393{
394 GGLContext *gl = gr_context;
395 GGLint color[4];
396 color[0] = ((r << 8) | r) + 1;
397 color[1] = ((g << 8) | g) + 1;
398 color[2] = ((b << 8) | b) + 1;
399 color[3] = ((a << 8) | a) + 1;
400 gl->color4xv(gl, color);
Vojtech Bocek1a4744a2014-02-06 19:52:28 +0100401
402 gr_is_curr_clr_opaque = (a == 255);
Dees_Troy51a0e822012-09-05 15:24:24 -0400403}
404
405int gr_measureEx(const char *s, void* font)
406{
407 GRFont* fnt = (GRFont*) font;
Dees_Troy51a0e822012-09-05 15:24:24 -0400408
Ethan Yonker88037f42015-10-04 22:09:08 -0500409 if (!fnt)
410 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400411
Ethan Yonker88037f42015-10-04 22:09:08 -0500412 return gr_ttf_measureEx(s, font);
Dees_Troy51a0e822012-09-05 15:24:24 -0400413}
414
Dees Troy31218ec2014-02-25 20:35:56 +0000415int gr_maxExW(const char *s, void* font, int max_width)
416{
417 GRFont* fnt = (GRFont*) font;
Dees Troy31218ec2014-02-25 20:35:56 +0000418
Ethan Yonker88037f42015-10-04 22:09:08 -0500419 if (!fnt)
420 return 0;
Dees Troy31218ec2014-02-25 20:35:56 +0000421
Ethan Yonker88037f42015-10-04 22:09:08 -0500422 return gr_ttf_maxExW(s, font, max_width);
Dees Troy31218ec2014-02-25 20:35:56 +0000423}
424
Dees_Troy51a0e822012-09-05 15:24:24 -0400425int gr_textEx(int x, int y, const char *s, void* pFont)
426{
427 GGLContext *gl = gr_context;
428 GRFont *font = (GRFont*) pFont;
Dees_Troy51a0e822012-09-05 15:24:24 -0400429
Ethan Yonker88037f42015-10-04 22:09:08 -0500430 if (!font)
431 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400432
Ethan Yonker88037f42015-10-04 22:09:08 -0500433 return gr_ttf_textExWH(gl, x, y, s, pFont, -1, -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400434}
435
436int gr_textExW(int x, int y, const char *s, void* pFont, int max_width)
437{
438 GGLContext *gl = gr_context;
439 GRFont *font = (GRFont*) pFont;
Dees_Troy51a0e822012-09-05 15:24:24 -0400440
Ethan Yonker88037f42015-10-04 22:09:08 -0500441 if (!font)
442 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400443
Ethan Yonker88037f42015-10-04 22:09:08 -0500444 return gr_ttf_textExWH(gl, x, y, s, pFont, max_width, -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400445}
446
447int gr_textExWH(int x, int y, const char *s, void* pFont, int max_width, int max_height)
448{
449 GGLContext *gl = gr_context;
450 GRFont *font = (GRFont*) pFont;
Dees_Troy51a0e822012-09-05 15:24:24 -0400451
Ethan Yonker88037f42015-10-04 22:09:08 -0500452 if (!font)
453 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400454
Ethan Yonker88037f42015-10-04 22:09:08 -0500455 return gr_ttf_textExWH(gl, x, y, s, pFont, max_width, max_height);
Dees_Troy51a0e822012-09-05 15:24:24 -0400456}
457
that9876ac32015-02-15 21:40:59 +0100458void gr_clip(int x, int y, int w, int h)
459{
460 GGLContext *gl = gr_context;
461 gl->scissor(gl, x, y, w, h);
462 gl->enable(gl, GGL_SCISSOR_TEST);
463}
464
465void gr_noclip()
466{
467 GGLContext *gl = gr_context;
468 gl->scissor(gl, 0, 0, gr_fb_width(), gr_fb_height());
469 gl->disable(gl, GGL_SCISSOR_TEST);
470}
471
Dees_Troy51a0e822012-09-05 15:24:24 -0400472void gr_fill(int x, int y, int w, int h)
473{
474 GGLContext *gl = gr_context;
Vojtech Bocek1a4744a2014-02-06 19:52:28 +0100475
476 if(gr_is_curr_clr_opaque)
477 gl->disable(gl, GGL_BLEND);
478
Dees_Troy51a0e822012-09-05 15:24:24 -0400479 gl->recti(gl, x, y, x + w, y + h);
Vojtech Bocek1a4744a2014-02-06 19:52:28 +0100480
481 if(gr_is_curr_clr_opaque)
482 gl->enable(gl, GGL_BLEND);
Dees_Troy51a0e822012-09-05 15:24:24 -0400483}
484
Vojtech Bocekdb378b62015-03-05 20:02:57 +0100485void gr_line(int x0, int y0, int x1, int y1, int width)
486{
487 GGLContext *gl = gr_context;
488
489 if(gr_is_curr_clr_opaque)
490 gl->disable(gl, GGL_BLEND);
491
492 const int coords0[2] = { x0 << 4, y0 << 4 };
493 const int coords1[2] = { x1 << 4, y1 << 4 };
494 gl->linex(gl, coords0, coords1, width << 4);
495
496 if(gr_is_curr_clr_opaque)
497 gl->enable(gl, GGL_BLEND);
498}
499
500gr_surface gr_render_circle(int radius, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
501{
502 int rx, ry;
503 GGLSurface *surface;
504 const int diameter = radius*2 + 1;
505 const int radius_check = radius*radius + radius*0.8;
506 const uint32_t px = (a << 24) | (b << 16) | (g << 8) | r;
507 uint32_t *data;
508
509 surface = malloc(sizeof(GGLSurface));
510 memset(surface, 0, sizeof(GGLSurface));
511
512 data = malloc(diameter * diameter * 4);
513 memset(data, 0, diameter * diameter * 4);
514
515 surface->version = sizeof(surface);
516 surface->width = diameter;
517 surface->height = diameter;
518 surface->stride = diameter;
519 surface->data = (GGLubyte*)data;
520 surface->format = GGL_PIXEL_FORMAT_RGBA_8888;
521
522 for(ry = -radius; ry <= radius; ++ry)
523 for(rx = -radius; rx <= radius; ++rx)
524 if(rx*rx+ry*ry <= radius_check)
525 *(data + diameter*(radius + ry) + (radius+rx)) = px;
526
527 return surface;
528}
529
Dees_Troy51a0e822012-09-05 15:24:24 -0400530void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
Dees Troyf171e102014-11-06 22:19:58 +0100531 if (gr_context == NULL) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400532 return;
533 }
534
535 GGLContext *gl = gr_context;
Vojtech Bocek6c694b62014-02-06 20:36:25 +0100536 GGLSurface *surface = (GGLSurface*)source;
537
538 if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
539 gl->disable(gl, GGL_BLEND);
540
541 gl->bindTexture(gl, surface);
Dees_Troy51a0e822012-09-05 15:24:24 -0400542 gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
543 gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
544 gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
545 gl->enable(gl, GGL_TEXTURE_2D);
546 gl->texCoord2i(gl, sx - dx, sy - dy);
547 gl->recti(gl, dx, dy, dx + w, dy + h);
Vojtech Bocek3041c882015-03-06 00:28:21 +0100548 gl->disable(gl, GGL_TEXTURE_2D);
Vojtech Bocek6c694b62014-02-06 20:36:25 +0100549
550 if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
Dees Troyf171e102014-11-06 22:19:58 +0100551 gl->enable(gl, GGL_BLEND);
Dees_Troy51a0e822012-09-05 15:24:24 -0400552}
553
554unsigned int gr_get_width(gr_surface surface) {
555 if (surface == NULL) {
556 return 0;
557 }
558 return ((GGLSurface*) surface)->width;
559}
560
561unsigned int gr_get_height(gr_surface surface) {
562 if (surface == NULL) {
563 return 0;
564 }
565 return ((GGLSurface*) surface)->height;
566}
567
Vojtech Bocek76ee9032014-09-07 15:01:56 +0200568int gr_getMaxFontHeight(void *font)
Dees_Troy51a0e822012-09-05 15:24:24 -0400569{
570 GRFont *fnt = (GRFont*) font;
571
Ethan Yonker88037f42015-10-04 22:09:08 -0500572 if (!fnt)
573 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400574
Ethan Yonker88037f42015-10-04 22:09:08 -0500575 return gr_ttf_getMaxFontHeight(font);
Dees_Troy51a0e822012-09-05 15:24:24 -0400576}
577
578int gr_init(void)
579{
580 gglInit(&gr_context);
581 GGLContext *gl = gr_context;
582
Dees_Troy51a0e822012-09-05 15:24:24 -0400583 gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC);
584 if (gr_vt_fd < 0) {
585 // This is non-fatal; post-Cupcake kernels don't have tty0.
586 } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {
587 // However, if we do open tty0, we expect the ioctl to work.
588 perror("failed KDSETMODE to KD_GRAPHICS on tty0");
589 gr_exit();
590 return -1;
591 }
592
593 gr_fb_fd = get_framebuffer(gr_framebuffer);
594 if (gr_fb_fd < 0) {
595 perror("Unable to get framebuffer.\n");
596 gr_exit();
597 return -1;
598 }
599
600 get_memory_surface(&gr_mem_surface);
601
602 fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
603 gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
604
605 /* start with 0 as front (displayed) and 1 as back (drawing) */
606 gr_active_fb = 0;
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600607 if (!has_overlay)
608 set_active_framebuffer(0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400609 gl->colorBuffer(gl, &gr_mem_surface);
610
611 gl->activeTexture(gl, 0);
612 gl->enable(gl, GGL_BLEND);
613 gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
614
xNUTxcd56f8c2014-07-23 01:30:20 +0200615#ifdef TW_SCREEN_BLANK_ON_BOOT
616 printf("TW_SCREEN_BLANK_ON_BOOT := true\n");
617 gr_fb_blank(true);
618 gr_fb_blank(false);
619#endif
Dees_Troy51a0e822012-09-05 15:24:24 -0400620
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600621 if (!alloc_ion_mem(fi.line_length * vi.yres))
622 allocate_overlay(gr_fb_fd, gr_framebuffer);
623
Dees_Troy51a0e822012-09-05 15:24:24 -0400624 return 0;
625}
626
627void gr_exit(void)
628{
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600629 free_overlay(gr_fb_fd);
630 free_ion_mem();
631
Dees_Troy51a0e822012-09-05 15:24:24 -0400632 close(gr_fb_fd);
633 gr_fb_fd = -1;
634
635 free(gr_mem_surface.data);
636
637 ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
638 close(gr_vt_fd);
639 gr_vt_fd = -1;
640}
641
642int gr_fb_width(void)
643{
644 return gr_framebuffer[0].width;
645}
646
647int gr_fb_height(void)
648{
649 return gr_framebuffer[0].height;
650}
651
652gr_pixel *gr_fb_data(void)
653{
654 return (unsigned short *) gr_mem_surface.data;
655}
656
Dees_Troy70237dc2013-02-28 21:31:48 +0000657int gr_fb_blank(int blank)
Dees_Troy51a0e822012-09-05 15:24:24 -0400658{
659 int ret;
Dees Troy05d18c92014-08-04 18:17:07 +0000660 //if (blank)
661 //free_overlay(gr_fb_fd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400662
663 ret = ioctl(gr_fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
664 if (ret < 0)
665 perror("ioctl(): blank");
Ethan Yonker4ee5ad72014-02-18 18:41:17 -0600666
Dees Troy05d18c92014-08-04 18:17:07 +0000667 //if (!blank)
668 //allocate_overlay(gr_fb_fd, gr_framebuffer);
669 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400670}
671
672int gr_get_surface(gr_surface* surface)
673{
674 GGLSurface* ms = malloc(sizeof(GGLSurface));
675 if (!ms) return -1;
676
677 // Allocate the data
678 get_memory_surface(ms);
679
680 // Now, copy the data
681 memcpy(ms->data, gr_mem_surface.data, vi.xres * vi.yres * vi.bits_per_pixel / 8);
682
683 *surface = (gr_surface*) ms;
684 return 0;
685}
686
687int gr_free_surface(gr_surface surface)
688{
689 if (!surface)
690 return -1;
691
692 GGLSurface* ms = (GGLSurface*) surface;
693 free(ms->data);
694 free(ms);
695 return 0;
696}
697
698void gr_write_frame_to_file(int fd)
699{
700 write(fd, gr_mem_surface.data, vi.xres * vi.yres * vi.bits_per_pixel / 8);
701}