Files
android_bootable_recovery/minuitwrp/graphics.cpp
bigbiff d58ba18272 AOSP10 TWRP Merge: fix conflicts and update libraries needed
This allows flame to boot TWRP. Still will need to work on
super partition for vendor and system access.

The plan will be to cherry-pick any updates to android-9.0
through gerrit.twrp.me to this branch as a WIP.
2020-03-23 11:18:29 -04:00

489 lines
14 KiB
C++
Executable File

/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <time.h>
#include <pixelflinger/pixelflinger.h>
#include "../gui/placement.h"
#include "minui.h"
#include "graphics.h"
// For std::min and std::max
#include <algorithm>
#include "truetype.hpp"
struct GRFont {
GRSurface* texture;
int cwidth;
int cheight;
};
static minui_backend* gr_backend = NULL;
static int overscan_percent = OVERSCAN_PERCENT;
static int overscan_offset_x = 0;
static int overscan_offset_y = 0;
static unsigned char gr_current_r = 255;
static unsigned char gr_current_g = 255;
static unsigned char gr_current_b = 255;
GRSurface* gr_draw = NULL;
static GGLContext *gr_context = 0;
GGLSurface gr_mem_surface;
static int gr_is_curr_clr_opaque = 0;
int gr_textEx_scaleW(int x, int y, const char *s, void* pFont, int max_width, int placement, int scale)
{
GGLContext *gl = gr_context;
void* vfont = pFont;
GRFont *font = (GRFont*) pFont;
int y_scale = 0, measured_width, measured_height, new_height;
if (!s || strlen(s) == 0 || !font)
return 0;
measured_height = twrpTruetype::gr_ttf_getMaxFontHeight(font);
if (scale) {
measured_width = twrpTruetype::gr_ttf_measureEx(s, vfont);
if (measured_width > max_width) {
// Adjust font size down until the text fits
void *new_font = twrpTruetype::gr_ttf_scaleFont(vfont, max_width, measured_width);
if (!new_font) {
printf("gr_textEx_scaleW new_font is NULL\n");
return 0;
}
measured_width = twrpTruetype::gr_ttf_measureEx(s, new_font);
// These next 2 lines adjust the y point based on the new font's height
new_height = twrpTruetype::gr_ttf_getMaxFontHeight(new_font);
y_scale = (measured_height - new_height) / 2;
vfont = new_font;
}
} else
measured_width = twrpTruetype::gr_ttf_measureEx(s, vfont);
int x_adj = measured_width;
if (measured_width > max_width)
x_adj = max_width;
if (placement != TOP_LEFT && placement != BOTTOM_LEFT && placement != TEXT_ONLY_RIGHT) {
if (placement == CENTER || placement == CENTER_X_ONLY)
x -= (x_adj / 2);
else
x -= x_adj;
}
if (placement != TOP_LEFT && placement != TOP_RIGHT) {
if (placement == CENTER || placement == TEXT_ONLY_RIGHT)
y -= (measured_height / 2);
else if (placement == BOTTOM_LEFT || placement == BOTTOM_RIGHT)
y -= measured_height;
}
return twrpTruetype::gr_ttf_textExWH(gl, x, y + y_scale, s, vfont, measured_width + x, -1, gr_draw);
}
void gr_clip(int x, int y, int w, int h)
{
GGLContext *gl = gr_context;
#if TW_ROTATION == 0
gl->scissor(gl, x, y, w, h);
#elif TW_ROTATION == 90
gl->scissor(gl, gr_draw->width - y - h, x, h, w);
#elif TW_ROTATION == 270
gl->scissor(gl, y, gr_draw->height - x - w, h, w);
#else
int t_disp = gr_draw->height - y - h;
int l_disp = gr_draw->width - x - w;
gl->scissor(gl, l_disp, t_disp, w, h);
#endif
gl->enable(gl, GGL_SCISSOR_TEST);
}
void gr_noclip()
{
GGLContext *gl = gr_context;
gl->scissor(gl, 0, 0,
gr_draw->width - 2 * overscan_offset_x,
gr_draw->height - 2 * overscan_offset_y);
gl->disable(gl, GGL_SCISSOR_TEST);
}
void gr_line(int x0, int y0, int x1, int y1, int width)
{
GGLContext *gl = gr_context;
int x0_disp, y0_disp, x1_disp, y1_disp;
x0_disp = ROTATION_X_DISP(x0, y0, gr_draw);
y0_disp = ROTATION_Y_DISP(x0, y0, gr_draw);
x1_disp = ROTATION_X_DISP(x1, y1, gr_draw);
y1_disp = ROTATION_Y_DISP(x1, y1, gr_draw);
if(gr_is_curr_clr_opaque)
gl->disable(gl, GGL_BLEND);
const int coords0[2] = { x0_disp << 4, y0_disp << 4 };
const int coords1[2] = { x1_disp << 4, y1_disp << 4 };
gl->linex(gl, coords0, coords1, width << 4);
if(gr_is_curr_clr_opaque)
gl->enable(gl, GGL_BLEND);
}
gr_surface gr_render_circle(int radius, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
int rx, ry;
GGLSurface *surface;
const int diameter = radius*2 + 1;
const int radius_check = radius*radius + radius*0.8;
const uint32_t px = (a << 24) | (b << 16) | (g << 8) | r;
uint32_t *data;
surface = (GGLSurface *)malloc(sizeof(GGLSurface));
memset(surface, 0, sizeof(GGLSurface));
data = (uint32_t *)malloc(diameter * diameter * 4);
memset(data, 0, diameter * diameter * 4);
surface->version = sizeof(surface);
surface->width = diameter;
surface->height = diameter;
surface->stride = diameter;
surface->data = (GGLubyte*)data;
#if defined(RECOVERY_BGRA)
surface->format = GGL_PIXEL_FORMAT_BGRA_8888;
#else
surface->format = GGL_PIXEL_FORMAT_RGBA_8888;
#endif
for(ry = -radius; ry <= radius; ++ry)
for(rx = -radius; rx <= radius; ++rx)
if(rx*rx+ry*ry <= radius_check)
*(data + diameter*(radius + ry) + (radius+rx)) = px;
return (gr_surface)surface;
}
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
GGLContext *gl = gr_context;
GGLint color[4];
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
color[0] = ((b << 8) | r) + 1;
color[1] = ((g << 8) | g) + 1;
color[2] = ((r << 8) | b) + 1;
color[3] = ((a << 8) | a) + 1;
#else
color[0] = ((r << 8) | r) + 1;
color[1] = ((g << 8) | g) + 1;
color[2] = ((b << 8) | b) + 1;
color[3] = ((a << 8) | a) + 1;
#endif
gl->color4xv(gl, color);
gr_is_curr_clr_opaque = (a == 255);
}
void gr_clear()
{
if (gr_draw->pixel_bytes == 2) {
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
return;
}
// This code only works on 32bpp devices
if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
} else {
unsigned char* px = gr_draw->data;
for (int y = 0; y < gr_draw->height; ++y) {
for (int x = 0; x < gr_draw->width; ++x) {
*px++ = gr_current_r;
*px++ = gr_current_g;
*px++ = gr_current_b;
px++;
}
px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
}
}
}
void gr_fill(int x, int y, int w, int h)
{
GGLContext *gl = gr_context;
int x0_disp, y0_disp, x1_disp, y1_disp;
int l_disp, r_disp, t_disp, b_disp;
if(gr_is_curr_clr_opaque)
gl->disable(gl, GGL_BLEND);
x0_disp = ROTATION_X_DISP(x, y, gr_draw);
y0_disp = ROTATION_Y_DISP(x, y, gr_draw);
x1_disp = ROTATION_X_DISP(x + w, y + h, gr_draw);
y1_disp = ROTATION_Y_DISP(x + w, y + h, gr_draw);
l_disp = std::min(x0_disp, x1_disp);
r_disp = std::max(x0_disp, x1_disp);
t_disp = std::min(y0_disp, y1_disp);
b_disp = std::max(y0_disp, y1_disp);
gl->recti(gl, l_disp, t_disp, r_disp, b_disp);
if(gr_is_curr_clr_opaque)
gl->enable(gl, GGL_BLEND);
}
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy)
{
if (gr_context == NULL) {
return;
}
GGLContext *gl = gr_context;
GGLSurface *surface = (GGLSurface*)source;
if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
gl->disable(gl, GGL_BLEND);
int dx0_disp, dy0_disp, dx1_disp, dy1_disp;
int l_disp, r_disp, t_disp, b_disp;
// Figuring out display coordinates works for TW_ROTATION == 0 too,
// and isn't as expensive as allocating and rotating another surface,
// so we do this anyway.
dx0_disp = ROTATION_X_DISP(dx, dy, gr_draw);
dy0_disp = ROTATION_Y_DISP(dx, dy, gr_draw);
dx1_disp = ROTATION_X_DISP(dx + w, dy + h, gr_draw);
dy1_disp = ROTATION_Y_DISP(dx + w, dy + h, gr_draw);
l_disp = std::min(dx0_disp, dx1_disp);
r_disp = std::max(dx0_disp, dx1_disp);
t_disp = std::min(dy0_disp, dy1_disp);
b_disp = std::max(dy0_disp, dy1_disp);
#if TW_ROTATION != 0
// Do not perform relatively expensive operation if not needed
GGLSurface surface_rotated;
surface_rotated.version = sizeof(surface_rotated);
// Skip the **(TW_ROTATION == 0)** || (TW_ROTATION == 180) check
// because we are under a TW_ROTATION != 0 conditional compilation statement
surface_rotated.width = (TW_ROTATION == 180) ? surface->width : surface->height;
surface_rotated.height = (TW_ROTATION == 180) ? surface->height : surface->width;
surface_rotated.stride = surface_rotated.width;
surface_rotated.format = surface->format;
surface_rotated.data = (GGLubyte*) malloc(surface_rotated.stride * surface_rotated.height * 4);
surface_ROTATION_transform((gr_surface) &surface_rotated, (const gr_surface) surface, 4);
gl->bindTexture(gl, &surface_rotated);
#else
gl->bindTexture(gl, surface);
#endif
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
gl->enable(gl, GGL_TEXTURE_2D);
gl->texCoord2i(gl, sx - l_disp, sy - t_disp);
gl->recti(gl, l_disp, t_disp, r_disp, b_disp);
gl->disable(gl, GGL_TEXTURE_2D);
#if TW_ROTATION != 0
free(surface_rotated.data);
#endif
if(surface->format == GGL_PIXEL_FORMAT_RGBX_8888)
gl->enable(gl, GGL_BLEND);
}
unsigned int gr_get_width(gr_surface surface) {
if (surface == NULL) {
return 0;
}
return ((GGLSurface*) surface)->width;
}
unsigned int gr_get_height(gr_surface surface) {
if (surface == NULL) {
return 0;
}
return ((GGLSurface*) surface)->height;
}
void gr_flip() {
gr_draw = gr_backend->flip(gr_backend);
// On double buffered back ends, when we flip, we need to tell
// pixel flinger to draw to the other buffer
gr_mem_surface.data = (GGLubyte*)gr_draw->data;
gr_context->colorBuffer(gr_context, &gr_mem_surface);
}
static void get_memory_surface(GGLSurface* ms) {
ms->version = sizeof(*ms);
ms->width = gr_draw->width;
ms->height = gr_draw->height;
ms->stride = gr_draw->row_bytes / gr_draw->pixel_bytes;
ms->data = (GGLubyte*)gr_draw->data;
ms->format = gr_draw->format;
}
int gr_init(void)
{
gr_draw = NULL;
#ifdef MSM_BSP
gr_backend = open_overlay();
if (gr_backend) {
gr_draw = gr_backend->init(gr_backend);
if (!gr_draw) {
gr_backend->exit(gr_backend);
} else
printf("Using overlay graphics.\n");
}
#endif
#ifdef HAS_ADF
if (!gr_backend || !gr_draw) {
gr_backend = open_adf();
if (gr_backend) {
gr_draw = gr_backend->init(gr_backend);
if (!gr_draw) {
gr_backend->exit(gr_backend);
} else
printf("Using adf graphics.\n");
}
}
#else
#ifdef MSM_BSP
printf("Skipping adf graphics because TW_TARGET_USES_QCOM_BSP := true\n");
#else
printf("Skipping adf graphics -- not present in build tree\n");
#endif
#endif
#ifdef HAS_DRM
if (!gr_backend || !gr_draw) {
gr_backend = open_drm();
gr_draw = gr_backend->init(gr_backend);
if (gr_draw)
printf("Using drm graphics.\n");
}
#else
printf("Skipping drm graphics -- not present in build tree\n");
#endif
if (!gr_backend || !gr_draw) {
gr_backend = open_fbdev();
gr_draw = gr_backend->init(gr_backend);
if (gr_draw == NULL) {
return -1;
} else
printf("Using fbdev graphics.\n");
}
overscan_offset_x = gr_draw->width * overscan_percent / 100;
overscan_offset_y = gr_draw->height * overscan_percent / 100;
// Set up pixelflinger
get_memory_surface(&gr_mem_surface);
gglInit(&gr_context);
GGLContext *gl = gr_context;
gl->colorBuffer(gl, &gr_mem_surface);
gl->activeTexture(gl, 0);
gl->enable(gl, GGL_BLEND);
gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
gr_flip();
gr_flip();
#ifdef TW_SCREEN_BLANK_ON_BOOT
printf("TW_SCREEN_BLANK_ON_BOOT := true\n");
gr_fb_blank(true);
gr_fb_blank(false);
#endif
return 0;
}
void gr_exit(void)
{
gr_backend->exit(gr_backend);
}
int gr_fb_width(void)
{
return (TW_ROTATION == 0 || TW_ROTATION == 180) ?
gr_draw->width - 2 * overscan_offset_x :
gr_draw->height - 2 * overscan_offset_y;
}
int gr_fb_height(void)
{
return (TW_ROTATION == 0 || TW_ROTATION == 180) ?
gr_draw->height - 2 * overscan_offset_y :
gr_draw->width - 2 * overscan_offset_x;
}
void gr_fb_blank(bool blank)
{
gr_backend->blank(gr_backend, blank);
}
int gr_get_surface(gr_surface* surface)
{
GGLSurface* ms = (GGLSurface*)malloc(sizeof(GGLSurface));
if (!ms) return -1;
// Allocate the data
get_memory_surface(ms);
ms->data = (GGLubyte*)malloc(ms->stride * ms->height * gr_draw->pixel_bytes);
// Now, copy the data
memcpy(ms->data, gr_mem_surface.data, gr_draw->width * gr_draw->height * gr_draw->pixel_bytes / 8);
*surface = (gr_surface*) ms;
return 0;
}
int gr_free_surface(gr_surface surface)
{
if (!surface)
return -1;
GGLSurface* ms = (GGLSurface*) surface;
free(ms->data);
free(ms);
return 0;
}
void gr_write_frame_to_file(int fd)
{
write(fd, gr_mem_surface.data, gr_draw->width * gr_draw->height * gr_draw->pixel_bytes / 8);
}