blob: 47325d01ef3e63de55c1de5a62ea858bf9053290 [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
299 gr_backend = open_overlay();
300 if (gr_backend) {
301 gr_draw = gr_backend->init(gr_backend);
302 if (!gr_draw) {
303 gr_backend->exit(gr_backend);
304 } else
305 printf("Using overlay graphics.\n");
306 }
307
308#ifdef HAS_ADF
309 if (!gr_draw) {
310 gr_backend = open_adf();
311 if (gr_backend) {
312 gr_draw = gr_backend->init(gr_backend);
313 if (!gr_draw) {
314 gr_backend->exit(gr_backend);
315 } else
316 printf("Using adf graphics.\n");
317 }
318 }
319#else
320#ifdef MSM_BSP
321 printf("Skipping adf graphics because TW_TARGET_USES_QCOM_BSP := true\n");
322#else
323 printf("Skipping adf graphics -- not present in build tree\n");
324#endif
325#endif
326
327#ifdef HAS_DRM
328 if (!gr_draw) {
329 gr_backend = open_drm();
330 gr_draw = gr_backend->init(gr_backend);
331 if (gr_draw)
332 printf("Using drm graphics.\n");
333 }
334#else
335 printf("Skipping drm graphics -- not present in build tree\n");
336#endif
337
338 if (!gr_draw) {
339 gr_backend = open_fbdev();
340 gr_draw = gr_backend->init(gr_backend);
341 if (gr_draw == NULL) {
342 return -1;
343 } else
344 printf("Using fbdev graphics.\n");
345 }
346
347 overscan_offset_x = gr_draw->width * overscan_percent / 100;
348 overscan_offset_y = gr_draw->height * overscan_percent / 100;
349
350 // Set up pixelflinger
351 get_memory_surface(&gr_mem_surface);
352 gglInit(&gr_context);
353 GGLContext *gl = gr_context;
354 gl->colorBuffer(gl, &gr_mem_surface);
355
356 gl->activeTexture(gl, 0);
357 gl->enable(gl, GGL_BLEND);
358 gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
359
360 gr_flip();
361 gr_flip();
362
363 return 0;
364}
365
366void gr_exit(void)
367{
368 gr_backend->exit(gr_backend);
369}
370
371int gr_fb_width(void)
372{
373 return gr_draw->width - 2*overscan_offset_x;
374}
375
376int gr_fb_height(void)
377{
378 return gr_draw->height - 2*overscan_offset_y;
379}
380
381void gr_fb_blank(bool blank)
382{
383 gr_backend->blank(gr_backend, blank);
384}
385
386int gr_get_surface(gr_surface* surface)
387{
388 GGLSurface* ms = (GGLSurface*)malloc(sizeof(GGLSurface));
389 if (!ms) return -1;
390
391 // Allocate the data
392 get_memory_surface(ms);
393 ms->data = (GGLubyte*)malloc(ms->stride * ms->height * gr_draw->pixel_bytes);
394
395 // Now, copy the data
396 memcpy(ms->data, gr_mem_surface.data, gr_draw->width * gr_draw->height * gr_draw->pixel_bytes / 8);
397
398 *surface = (gr_surface*) ms;
399 return 0;
400}
401
402int gr_free_surface(gr_surface surface)
403{
404 if (!surface)
405 return -1;
406
407 GGLSurface* ms = (GGLSurface*) surface;
408 free(ms->data);
409 free(ms);
410 return 0;
411}
412
413void gr_write_frame_to_file(int fd)
414{
415 write(fd, gr_mem_surface.data, gr_draw->width * gr_draw->height * gr_draw->pixel_bytes / 8);
416}