blob: 3dc88d9db2e82c419111c2cf9a993e98a30aad6f [file] [log] [blame]
Ethan Yonkerfbb43532015-12-28 21:54:50 +01001/*
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 <string.h>
20#include <unistd.h>
21
22#include <fcntl.h>
23#include <stdio.h>
24
25#include <sys/ioctl.h>
26#include <sys/mman.h>
27#include <sys/types.h>
28
29#include <linux/fb.h>
30#include <linux/kd.h>
31
32#include <time.h>
33
34#include <pixelflinger/pixelflinger.h>
35#include "../gui/placement.h"
36#include "minui.h"
37#include "graphics.h"
38
39struct GRFont {
40 GRSurface* texture;
41 int cwidth;
42 int cheight;
43};
44
45static GRFont* gr_font = NULL;
46static minui_backend* gr_backend = NULL;
47
48static int overscan_percent = OVERSCAN_PERCENT;
49static int overscan_offset_x = 0;
50static int overscan_offset_y = 0;
51
52static unsigned char gr_current_r = 255;
53static unsigned char gr_current_g = 255;
54static unsigned char gr_current_b = 255;
55static unsigned char gr_current_a = 255;
56static unsigned char rgb_555[2];
57static unsigned char gr_current_r5 = 31;
58static unsigned char gr_current_g5 = 63;
59static unsigned char gr_current_b5 = 31;
60
61GRSurface* gr_draw = NULL;
62
63static GGLContext *gr_context = 0;
64GGLSurface gr_mem_surface;
65static int gr_is_curr_clr_opaque = 0;
66
67static bool outside(int x, int y)
68{
69 return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
70}
71
72int gr_textEx_scaleW(int x, int y, const char *s, void* pFont, int max_width, int placement, int scale)
73{
74 GGLContext *gl = gr_context;
75 void* vfont = pFont;
76 GRFont *font = (GRFont*) pFont;
77 unsigned off;
78 unsigned cwidth;
79 int y_scale = 0, measured_width, measured_height, ret, new_height;
80
81 if (!s || strlen(s) == 0 || !font)
82 return 0;
83
84 measured_height = gr_ttf_getMaxFontHeight(font);
85
86 if (scale) {
87 measured_width = gr_ttf_measureEx(s, vfont);
88 if (measured_width > max_width) {
89 // Adjust font size down until the text fits
90 void *new_font = gr_ttf_scaleFont(vfont, max_width, measured_width);
91 if (!new_font) {
92 printf("gr_textEx_scaleW new_font is NULL\n");
93 return 0;
94 }
95 measured_width = gr_ttf_measureEx(s, new_font);
96 // These next 2 lines adjust the y point based on the new font's height
97 new_height = gr_ttf_getMaxFontHeight(new_font);
98 y_scale = (measured_height - new_height) / 2;
99 vfont = new_font;
100 }
101 } else
102 measured_width = gr_ttf_measureEx(s, vfont);
103
104 int x_adj = measured_width;
105 if (measured_width > max_width)
106 x_adj = max_width;
107
108 if (placement != TOP_LEFT && placement != BOTTOM_LEFT && placement != TEXT_ONLY_RIGHT) {
109 if (placement == CENTER || placement == CENTER_X_ONLY)
110 x -= (x_adj / 2);
111 else
112 x -= x_adj;
113 }
114
115 if (placement != TOP_LEFT && placement != TOP_RIGHT) {
116 if (placement == CENTER || placement == TEXT_ONLY_RIGHT)
117 y -= (measured_height / 2);
118 else if (placement == BOTTOM_LEFT || placement == BOTTOM_RIGHT)
119 y -= measured_height;
120 }
121 return gr_ttf_textExWH(gl, x, y + y_scale, s, vfont, measured_width + x, -1);
122}
123
124void gr_clip(int x, int y, int w, int h)
125{
126 GGLContext *gl = gr_context;
127 gl->scissor(gl, x, y, w, h);
128 gl->enable(gl, GGL_SCISSOR_TEST);
129}
130
131void gr_noclip()
132{
133 GGLContext *gl = gr_context;
134 gl->scissor(gl, 0, 0, gr_fb_width(), gr_fb_height());
135 gl->disable(gl, GGL_SCISSOR_TEST);
136}
137
138void gr_line(int x0, int y0, int x1, int y1, int width)
139{
140 GGLContext *gl = gr_context;
141
142 if(gr_is_curr_clr_opaque)
143 gl->disable(gl, GGL_BLEND);
144
145 const int coords0[2] = { x0 << 4, y0 << 4 };
146 const int coords1[2] = { x1 << 4, y1 << 4 };
147 gl->linex(gl, coords0, coords1, width << 4);
148
149 if(gr_is_curr_clr_opaque)
150 gl->enable(gl, GGL_BLEND);
151}
152
153gr_surface gr_render_circle(int radius, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
154{
155 int rx, ry;
156 GGLSurface *surface;
157 const int diameter = radius*2 + 1;
158 const int radius_check = radius*radius + radius*0.8;
159 const uint32_t px = (a << 24) | (b << 16) | (g << 8) | r;
160 uint32_t *data;
161
162 surface = (GGLSurface *)malloc(sizeof(GGLSurface));
163 memset(surface, 0, sizeof(GGLSurface));
164
165 data = (uint32_t *)malloc(diameter * diameter * 4);
166 memset(data, 0, diameter * diameter * 4);
167
168 surface->version = sizeof(surface);
169 surface->width = diameter;
170 surface->height = diameter;
171 surface->stride = diameter;
172 surface->data = (GGLubyte*)data;
173 surface->format = GGL_PIXEL_FORMAT_RGBA_8888;
174
175 for(ry = -radius; ry <= radius; ++ry)
176 for(rx = -radius; rx <= radius; ++rx)
177 if(rx*rx+ry*ry <= radius_check)
178 *(data + diameter*(radius + ry) + (radius+rx)) = px;
179
180 return (gr_surface)surface;
181}
182
183void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
184{
185 GGLContext *gl = gr_context;
186 GGLint color[4];
187#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
188 color[0] = ((b << 8) | r) + 1;
189 color[1] = ((g << 8) | g) + 1;
190 color[2] = ((r << 8) | b) + 1;
191 color[3] = ((a << 8) | a) + 1;
192#else
193 color[0] = ((r << 8) | r) + 1;
194 color[1] = ((g << 8) | g) + 1;
195 color[2] = ((b << 8) | b) + 1;
196 color[3] = ((a << 8) | a) + 1;
197#endif
198 gl->color4xv(gl, color);
199
200 gr_is_curr_clr_opaque = (a == 255);
201}
202
203void gr_clear()
204{
205 if (gr_draw->pixel_bytes == 2) {
206 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
207 return;
208 }
209
210 // This code only works on 32bpp devices
211 if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
212 memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
213 } else {
214 unsigned char* px = gr_draw->data;
215 for (int y = 0; y < gr_draw->height; ++y) {
216 for (int x = 0; x < gr_draw->width; ++x) {
217 *px++ = gr_current_r;
218 *px++ = gr_current_g;
219 *px++ = gr_current_b;
220 px++;
221 }
222 px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
223 }
224 }
225}
226
227void gr_fill(int x, int y, int w, int h)
228{
229 GGLContext *gl = gr_context;
230
231 if(gr_is_curr_clr_opaque)
232 gl->disable(gl, GGL_BLEND);
233
234 gl->recti(gl, x, y, x + w, y + h);
235
236 if(gr_is_curr_clr_opaque)
237 gl->enable(gl, GGL_BLEND);
238}
239
240void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
241 if (gr_context == NULL) {
242 return;
243 }
244
245 GGLContext *gl = gr_context;
246 GGLSurface *surface = (GGLSurface*)source;
247
248 if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
249 gl->disable(gl, GGL_BLEND);
250
251 gl->bindTexture(gl, surface);
252 gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
253 gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
254 gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
255 gl->enable(gl, GGL_TEXTURE_2D);
256 gl->texCoord2i(gl, sx - dx, sy - dy);
257 gl->recti(gl, dx, dy, dx + w, dy + h);
258 gl->disable(gl, GGL_TEXTURE_2D);
259
260 if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
261 gl->enable(gl, GGL_BLEND);
262}
263
264unsigned int gr_get_width(gr_surface surface) {
265 if (surface == NULL) {
266 return 0;
267 }
268 return ((GGLSurface*) surface)->width;
269}
270
271unsigned int gr_get_height(gr_surface surface) {
272 if (surface == NULL) {
273 return 0;
274 }
275 return ((GGLSurface*) surface)->height;
276}
277
278void gr_flip() {
279 gr_draw = gr_backend->flip(gr_backend);
280 // On double buffered back ends, when we flip, we need to tell
281 // pixel flinger to draw to the other buffer
282 gr_mem_surface.data = (GGLubyte*)gr_draw->data;
283 gr_context->colorBuffer(gr_context, &gr_mem_surface);
284}
285
286static void get_memory_surface(GGLSurface* ms) {
287 ms->version = sizeof(*ms);
288 ms->width = gr_draw->width;
289 ms->height = gr_draw->height;
290 ms->stride = gr_draw->row_bytes / gr_draw->pixel_bytes;
291 ms->data = (GGLubyte*)gr_draw->data;
292 ms->format = gr_draw->format;
293}
294
295int gr_init(void)
296{
297 gr_draw = NULL;
298
Ethan Yonkerb386f712017-01-20 14:30:28 -0600299#ifdef MSM_BSP
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100300 gr_backend = open_overlay();
301 if (gr_backend) {
302 gr_draw = gr_backend->init(gr_backend);
303 if (!gr_draw) {
304 gr_backend->exit(gr_backend);
305 } else
306 printf("Using overlay graphics.\n");
307 }
Ethan Yonkerb386f712017-01-20 14:30:28 -0600308#endif
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100309
310#ifdef HAS_ADF
Ethan Yonkerb386f712017-01-20 14:30:28 -0600311 if (!gr_backend || !gr_draw) {
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100312 gr_backend = open_adf();
313 if (gr_backend) {
314 gr_draw = gr_backend->init(gr_backend);
315 if (!gr_draw) {
316 gr_backend->exit(gr_backend);
317 } else
318 printf("Using adf graphics.\n");
319 }
320 }
321#else
322#ifdef MSM_BSP
323 printf("Skipping adf graphics because TW_TARGET_USES_QCOM_BSP := true\n");
324#else
325 printf("Skipping adf graphics -- not present in build tree\n");
326#endif
327#endif
328
329#ifdef HAS_DRM
Ethan Yonkerb386f712017-01-20 14:30:28 -0600330 if (!gr_backend || !gr_draw) {
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100331 gr_backend = open_drm();
332 gr_draw = gr_backend->init(gr_backend);
333 if (gr_draw)
334 printf("Using drm graphics.\n");
335 }
336#else
337 printf("Skipping drm graphics -- not present in build tree\n");
338#endif
339
Ethan Yonkerb386f712017-01-20 14:30:28 -0600340 if (!gr_backend || !gr_draw) {
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100341 gr_backend = open_fbdev();
342 gr_draw = gr_backend->init(gr_backend);
343 if (gr_draw == NULL) {
344 return -1;
345 } else
346 printf("Using fbdev graphics.\n");
347 }
348
349 overscan_offset_x = gr_draw->width * overscan_percent / 100;
350 overscan_offset_y = gr_draw->height * overscan_percent / 100;
351
352 // Set up pixelflinger
353 get_memory_surface(&gr_mem_surface);
354 gglInit(&gr_context);
355 GGLContext *gl = gr_context;
356 gl->colorBuffer(gl, &gr_mem_surface);
357
358 gl->activeTexture(gl, 0);
359 gl->enable(gl, GGL_BLEND);
360 gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
361
362 gr_flip();
363 gr_flip();
364
¨Paul80bd1652016-04-26 16:49:58 +0100365#ifdef TW_SCREEN_BLANK_ON_BOOT
366 printf("TW_SCREEN_BLANK_ON_BOOT := true\n");
367 gr_fb_blank(true);
368 gr_fb_blank(false);
369#endif
370
Ethan Yonkerfbb43532015-12-28 21:54:50 +0100371 return 0;
372}
373
374void gr_exit(void)
375{
376 gr_backend->exit(gr_backend);
377}
378
379int gr_fb_width(void)
380{
381 return gr_draw->width - 2*overscan_offset_x;
382}
383
384int gr_fb_height(void)
385{
386 return gr_draw->height - 2*overscan_offset_y;
387}
388
389void gr_fb_blank(bool blank)
390{
391 gr_backend->blank(gr_backend, blank);
392}
393
394int gr_get_surface(gr_surface* surface)
395{
396 GGLSurface* ms = (GGLSurface*)malloc(sizeof(GGLSurface));
397 if (!ms) return -1;
398
399 // Allocate the data
400 get_memory_surface(ms);
401 ms->data = (GGLubyte*)malloc(ms->stride * ms->height * gr_draw->pixel_bytes);
402
403 // Now, copy the data
404 memcpy(ms->data, gr_mem_surface.data, gr_draw->width * gr_draw->height * gr_draw->pixel_bytes / 8);
405
406 *surface = (gr_surface*) ms;
407 return 0;
408}
409
410int gr_free_surface(gr_surface surface)
411{
412 if (!surface)
413 return -1;
414
415 GGLSurface* ms = (GGLSurface*) surface;
416 free(ms->data);
417 free(ms);
418 return 0;
419}
420
421void gr_write_frame_to_file(int fd)
422{
423 write(fd, gr_mem_surface.data, gr_draw->width * gr_draw->height * gr_draw->pixel_bytes / 8);
424}