1 /* 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 "graphics.h" 18 19 #include <stdint.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include <memory> 25 26 #include <android-base/properties.h> 27 28 #include "graphics_adf.h" 29 #include "graphics_drm.h" 30 #include "graphics_fbdev.h" 31 #include "minui/minui.h" 32 33 static GRFont* gr_font = nullptr; 34 static MinuiBackend* gr_backend = nullptr; 35 36 static int overscan_offset_x = 0; 37 static int overscan_offset_y = 0; 38 39 static uint32_t gr_current = ~0; 40 static constexpr uint32_t alpha_mask = 0xff000000; 41 42 // gr_draw is owned by backends. 43 static GRSurface* gr_draw = nullptr; 44 static GRRotation rotation = GRRotation::NONE; 45 static PixelFormat pixel_format = PixelFormat::UNKNOWN; 46 47 static bool outside(int x, int y) { 48 auto swapped = (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT); 49 return x < 0 || x >= (swapped ? gr_draw->height : gr_draw->width) || y < 0 || 50 y >= (swapped ? gr_draw->width : gr_draw->height); 51 } 52 53 const GRFont* gr_sys_font() { 54 return gr_font; 55 } 56 57 PixelFormat gr_pixel_format() { 58 return pixel_format; 59 } 60 61 int gr_measure(const GRFont* font, const char* s) { 62 if (font == nullptr) { 63 return -1; 64 } 65 66 return font->char_width * strlen(s); 67 } 68 69 int gr_font_size(const GRFont* font, int* x, int* y) { 70 if (font == nullptr) { 71 return -1; 72 } 73 74 *x = font->char_width; 75 *y = font->char_height; 76 return 0; 77 } 78 79 // Blends gr_current onto pix value, assumes alpha as most significant byte. 80 static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) { 81 if (alpha == 255) return gr_current; 82 if (alpha == 0) return pix; 83 uint32_t pix_r = pix & 0xff; 84 uint32_t pix_g = pix & 0xff00; 85 uint32_t pix_b = pix & 0xff0000; 86 uint32_t cur_r = gr_current & 0xff; 87 uint32_t cur_g = gr_current & 0xff00; 88 uint32_t cur_b = gr_current & 0xff0000; 89 90 uint32_t out_r = (pix_r * (255 - alpha) + cur_r * alpha) / 255; 91 uint32_t out_g = (pix_g * (255 - alpha) + cur_g * alpha) / 255; 92 uint32_t out_b = (pix_b * (255 - alpha) + cur_b * alpha) / 255; 93 94 return (out_r & 0xff) | (out_g & 0xff00) | (out_b & 0xff0000) | (gr_current & 0xff000000); 95 } 96 97 // Increments pixel pointer right, with current rotation. 98 static void incr_x(uint32_t** p, int row_pixels) { 99 if (rotation == GRRotation::LEFT) { 100 *p = *p - row_pixels; 101 } else if (rotation == GRRotation::RIGHT) { 102 *p = *p + row_pixels; 103 } else if (rotation == GRRotation::DOWN) { 104 *p = *p - 1; 105 } else { // GRRotation::NONE 106 *p = *p + 1; 107 } 108 } 109 110 // Increments pixel pointer down, with current rotation. 111 static void incr_y(uint32_t** p, int row_pixels) { 112 if (rotation == GRRotation::LEFT) { 113 *p = *p + 1; 114 } else if (rotation == GRRotation::RIGHT) { 115 *p = *p - 1; 116 } else if (rotation == GRRotation::DOWN) { 117 *p = *p - row_pixels; 118 } else { // GRRotation::NONE 119 *p = *p + row_pixels; 120 } 121 } 122 123 // Returns pixel pointer at given coordinates with rotation adjustment. 124 static uint32_t* PixelAt(GRSurface* surface, int x, int y, int row_pixels) { 125 switch (rotation) { 126 case GRRotation::NONE: 127 return reinterpret_cast<uint32_t*>(surface->data()) + y * row_pixels + x; 128 case GRRotation::RIGHT: 129 return reinterpret_cast<uint32_t*>(surface->data()) + x * row_pixels + (surface->width - y); 130 case GRRotation::DOWN: 131 return reinterpret_cast<uint32_t*>(surface->data()) + (surface->height - 1 - y) * row_pixels + 132 (surface->width - 1 - x); 133 case GRRotation::LEFT: 134 return reinterpret_cast<uint32_t*>(surface->data()) + (surface->height - 1 - x) * row_pixels + 135 y; 136 default: 137 printf("invalid rotation %d", static_cast<int>(rotation)); 138 } 139 return nullptr; 140 } 141 142 static void TextBlend(const uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, int dst_row_pixels, 143 int width, int height) { 144 uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24); 145 for (int j = 0; j < height; ++j) { 146 const uint8_t* sx = src_p; 147 uint32_t* px = dst_p; 148 for (int i = 0; i < width; ++i, incr_x(&px, dst_row_pixels)) { 149 uint8_t a = *sx++; 150 if (alpha_current < 255) a = (static_cast<uint32_t>(a) * alpha_current) / 255; 151 *px = pixel_blend(a, *px); 152 } 153 src_p += src_row_bytes; 154 incr_y(&dst_p, dst_row_pixels); 155 } 156 } 157 158 void gr_text(const GRFont* font, int x, int y, const char* s, bool bold) { 159 if (!font || !font->texture || (gr_current & alpha_mask) == 0) return; 160 161 if (font->texture->pixel_bytes != 1) { 162 printf("gr_text: font has wrong format\n"); 163 return; 164 } 165 166 bold = bold && (font->texture->height != font->char_height); 167 168 x += overscan_offset_x; 169 y += overscan_offset_y; 170 171 unsigned char ch; 172 while ((ch = *s++)) { 173 if (outside(x, y) || outside(x + font->char_width - 1, y + font->char_height - 1)) break; 174 175 if (ch < ' ' || ch > '~') { 176 ch = '?'; 177 } 178 179 int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes; 180 const uint8_t* src_p = font->texture->data() + ((ch - ' ') * font->char_width) + 181 (bold ? font->char_height * font->texture->row_bytes : 0); 182 uint32_t* dst_p = PixelAt(gr_draw, x, y, row_pixels); 183 184 TextBlend(src_p, font->texture->row_bytes, dst_p, row_pixels, font->char_width, 185 font->char_height); 186 187 x += font->char_width; 188 } 189 } 190 191 void gr_texticon(int x, int y, const GRSurface* icon) { 192 if (icon == nullptr) return; 193 194 if (icon->pixel_bytes != 1) { 195 printf("gr_texticon: source has wrong format\n"); 196 return; 197 } 198 199 x += overscan_offset_x; 200 y += overscan_offset_y; 201 202 if (outside(x, y) || outside(x + icon->width - 1, y + icon->height - 1)) return; 203 204 int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes; 205 const uint8_t* src_p = icon->data(); 206 uint32_t* dst_p = PixelAt(gr_draw, x, y, row_pixels); 207 TextBlend(src_p, icon->row_bytes, dst_p, row_pixels, icon->width, icon->height); 208 } 209 210 void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { 211 uint32_t r32 = r, g32 = g, b32 = b, a32 = a; 212 if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) { 213 gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32; 214 } else { 215 gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32; 216 } 217 } 218 219 void gr_clear() { 220 if ((gr_current & 0xff) == ((gr_current >> 8) & 0xff) && 221 (gr_current & 0xff) == ((gr_current >> 16) & 0xff) && 222 (gr_current & 0xff) == ((gr_current >> 24) & 0xff) && 223 gr_draw->row_bytes == gr_draw->width * gr_draw->pixel_bytes) { 224 memset(gr_draw->data(), gr_current & 0xff, gr_draw->height * gr_draw->row_bytes); 225 } else { 226 uint32_t* px = reinterpret_cast<uint32_t*>(gr_draw->data()); 227 int row_diff = gr_draw->row_bytes / gr_draw->pixel_bytes - gr_draw->width; 228 for (int y = 0; y < gr_draw->height; ++y) { 229 for (int x = 0; x < gr_draw->width; ++x) { 230 *px++ = gr_current; 231 } 232 px += row_diff; 233 } 234 } 235 } 236 237 void gr_fill(int x1, int y1, int x2, int y2) { 238 x1 += overscan_offset_x; 239 y1 += overscan_offset_y; 240 241 x2 += overscan_offset_x; 242 y2 += overscan_offset_y; 243 244 if (outside(x1, y1) || outside(x2 - 1, y2 - 1)) return; 245 246 int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes; 247 uint32_t* p = PixelAt(gr_draw, x1, y1, row_pixels); 248 uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24)); 249 if (alpha > 0) { 250 for (int y = y1; y < y2; ++y) { 251 uint32_t* px = p; 252 for (int x = x1; x < x2; ++x) { 253 *px = pixel_blend(alpha, *px); 254 incr_x(&px, row_pixels); 255 } 256 incr_y(&p, row_pixels); 257 } 258 } 259 } 260 261 void gr_blit(const GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) { 262 if (source == nullptr) return; 263 264 if (gr_draw->pixel_bytes != source->pixel_bytes) { 265 printf("gr_blit: source has wrong format\n"); 266 return; 267 } 268 269 dx += overscan_offset_x; 270 dy += overscan_offset_y; 271 272 if (outside(dx, dy) || outside(dx + w - 1, dy + h - 1)) return; 273 274 if (rotation != GRRotation::NONE) { 275 int src_row_pixels = source->row_bytes / source->pixel_bytes; 276 int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes; 277 const uint32_t* src_py = 278 reinterpret_cast<const uint32_t*>(source->data()) + sy * source->row_bytes / 4 + sx; 279 uint32_t* dst_py = PixelAt(gr_draw, dx, dy, row_pixels); 280 281 for (int y = 0; y < h; y += 1) { 282 const uint32_t* src_px = src_py; 283 uint32_t* dst_px = dst_py; 284 for (int x = 0; x < w; x += 1) { 285 *dst_px = *src_px++; 286 incr_x(&dst_px, row_pixels); 287 } 288 src_py += src_row_pixels; 289 incr_y(&dst_py, row_pixels); 290 } 291 } else { 292 const uint8_t* src_p = source->data() + sy * source->row_bytes + sx * source->pixel_bytes; 293 uint8_t* dst_p = gr_draw->data() + dy * gr_draw->row_bytes + dx * gr_draw->pixel_bytes; 294 295 for (int i = 0; i < h; ++i) { 296 memcpy(dst_p, src_p, w * source->pixel_bytes); 297 src_p += source->row_bytes; 298 dst_p += gr_draw->row_bytes; 299 } 300 } 301 } 302 303 unsigned int gr_get_width(const GRSurface* surface) { 304 if (surface == nullptr) { 305 return 0; 306 } 307 return surface->width; 308 } 309 310 unsigned int gr_get_height(const GRSurface* surface) { 311 if (surface == nullptr) { 312 return 0; 313 } 314 return surface->height; 315 } 316 317 int gr_init_font(const char* name, GRFont** dest) { 318 GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font))); 319 if (font == nullptr) { 320 return -1; 321 } 322 323 int res = res_create_alpha_surface(name, &(font->texture)); 324 if (res < 0) { 325 free(font); 326 return res; 327 } 328 329 // The font image should be a 96x2 array of character images. The 330 // columns are the printable ASCII characters 0x20 - 0x7f. The 331 // top row is regular text; the bottom row is bold. 332 font->char_width = font->texture->width / 96; 333 font->char_height = font->texture->height / 2; 334 335 *dest = font; 336 337 return 0; 338 } 339 340 void gr_flip() { 341 gr_draw = gr_backend->Flip(); 342 } 343 344 int gr_init() { 345 // pixel_format needs to be set before loading any resources or initializing backends. 346 std::string format = android::base::GetProperty("ro.minui.pixel_format", ""); 347 if (format == "ABGR_8888") { 348 pixel_format = PixelFormat::ABGR; 349 } else if (format == "RGBX_8888") { 350 pixel_format = PixelFormat::RGBX; 351 } else if (format == "BGRA_8888") { 352 pixel_format = PixelFormat::BGRA; 353 } else { 354 pixel_format = PixelFormat::UNKNOWN; 355 } 356 357 int ret = gr_init_font("font", &gr_font); 358 if (ret != 0) { 359 printf("Failed to init font: %d, continuing graphic backend initialization without font file\n", 360 ret); 361 } 362 363 auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() }; 364 gr_draw = backend->Init(); 365 366 if (!gr_draw) { 367 backend = std::make_unique<MinuiBackendDrm>(); 368 gr_draw = backend->Init(); 369 } 370 371 if (!gr_draw) { 372 backend = std::make_unique<MinuiBackendFbdev>(); 373 gr_draw = backend->Init(); 374 } 375 376 if (!gr_draw) { 377 return -1; 378 } 379 380 gr_backend = backend.release(); 381 382 int overscan_percent = android::base::GetIntProperty("ro.minui.overscan_percent", 0); 383 overscan_offset_x = gr_draw->width * overscan_percent / 100; 384 overscan_offset_y = gr_draw->height * overscan_percent / 100; 385 386 gr_flip(); 387 gr_flip(); 388 if (!gr_draw) { 389 printf("gr_init: gr_draw becomes nullptr after gr_flip\n"); 390 return -1; 391 } 392 393 std::string rotation_str = 394 android::base::GetProperty("ro.minui.default_rotation", "ROTATION_NONE"); 395 if (rotation_str == "ROTATION_RIGHT") { 396 gr_rotate(GRRotation::RIGHT); 397 } else if (rotation_str == "ROTATION_DOWN") { 398 gr_rotate(GRRotation::DOWN); 399 } else if (rotation_str == "ROTATION_LEFT") { 400 gr_rotate(GRRotation::LEFT); 401 } else { // "ROTATION_NONE" or unknown string 402 gr_rotate(GRRotation::NONE); 403 } 404 405 if (gr_draw->pixel_bytes != 4) { 406 printf("gr_init: Only 4-byte pixel formats supported\n"); 407 } 408 409 return 0; 410 } 411 412 void gr_exit() { 413 delete gr_backend; 414 gr_backend = nullptr; 415 416 delete gr_font; 417 gr_font = nullptr; 418 } 419 420 int gr_fb_width() { 421 return (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT) 422 ? gr_draw->height - 2 * overscan_offset_y 423 : gr_draw->width - 2 * overscan_offset_x; 424 } 425 426 int gr_fb_height() { 427 return (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT) 428 ? gr_draw->width - 2 * overscan_offset_x 429 : gr_draw->height - 2 * overscan_offset_y; 430 } 431 432 void gr_fb_blank(bool blank) { 433 gr_backend->Blank(blank); 434 } 435 436 void gr_rotate(GRRotation rot) { 437 rotation = rot; 438 } 439