修改前java
修改後linux
修改相關文件
bootable\recovery\minui\Android.mk
bootable\recovery\minui\mt_graphic_rotate.cpp
bootable\recovery\minui\mt_graphic_rotate.h
bootable\recovery\minui\graphics_fbdev.cpp
bootable\recovery\minui\minui.handroid
LOCAL_SRC_FILES := \ events.cpp \ graphics.cpp \ graphics_adf.cpp \ graphics_drm.cpp \ graphics_fbdev.cpp \ resources.cpp \ #cczheng add LOCAL_SRC_FILES += mt_graphic_rotate.cpp
/* * Copyright (C) 2014 MediaTek Inc. * Modification based on code covered by the mentioned copyright * and/or permission notice(s). */ #include <stdbool.h> #include <stdlib.h> #include <unistd.h> #include <inttypes.h> #include <fcntl.h> #include <stdio.h> #include <sys/cdefs.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> #include <linux/fb.h> #include <linux/kd.h> #include "minui.h" #include "graphics.h" GRSurface __gr_canvas; GRSurface* gr_canvas = NULL; int rotate_index=-1; static void print_surface_info(GRSurface *s, const char *name) { printf("[graphics] %s > Height:%d, Width:%d, PixelBytes:%d, RowBytes:%d, Size:%d, Data: 0x%08" PRIxPTR "\n", name, s->height, s->width, s->pixel_bytes, s->row_bytes, s->height* s->row_bytes, (uintptr_t) s->data); } // Read configuration from MTK_LCM_PHYSICAL_ROTATION #ifndef MTK_LCM_PHYSICAL_ROTATION #define MTK_LCM_PHYSICAL_ROTATION "undefined" #endif static int rotate_config(GRSurface *gr_draw) { if (rotate_index<0) { if (gr_draw->pixel_bytes != 4) rotate_index=0; // support 4 bytes pixel only else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "90", 2)) rotate_index=1; else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "180", 3)) rotate_index=2; else if (0 == strncmp(MTK_LCM_PHYSICAL_ROTATION, "270", 3)) rotate_index=3; else rotate_index=0; printf("[graphics] rotate_config %d %s\n", rotate_index, MTK_LCM_PHYSICAL_ROTATION); } return rotate_index; } #define swap(x, y, type) {type z; z=x; x=y; y=z;} // Allocate and setup the canvas object void rotate_canvas_init(GRSurface *gr_draw) { gr_canvas = &__gr_canvas; memcpy(gr_canvas, gr_draw, sizeof(GRSurface)); // Swap canvas' height and width, if the rotate angle is 90" or 270" if (rotate_config(gr_draw)%2) { swap(gr_canvas->width, gr_canvas->height, int); gr_canvas->row_bytes = gr_canvas->width * gr_canvas->pixel_bytes; } gr_canvas->data = (unsigned char*) malloc(gr_canvas->height * gr_canvas->row_bytes); if (gr_canvas->data == NULL) { printf("[graphics] rotate_canvas_init() malloc gr_canvas->data failed\n"); gr_canvas = NULL; return; } memset(gr_canvas->data, 0, gr_canvas->height * gr_canvas->row_bytes); print_surface_info(gr_draw, "gr_draw"); print_surface_info(gr_canvas, "gr_canvas"); } // Cleanup the canvas void rotate_canvas_exit(void) { if (gr_canvas) { if (gr_canvas->data) free(gr_canvas->data); free(gr_canvas); } gr_canvas=NULL; } // Return the canvas object GRSurface *rotate_canvas_get(GRSurface *gr_draw) { // Initialize the canvas, if it was not exist. if (gr_canvas==NULL) rotate_canvas_init(gr_draw); return gr_canvas; } // Surface Rotate Routines static void rotate_surface_0(GRSurface *dst, GRSurface *src) { memcpy(dst->data, src->data, src->height*src->row_bytes); } static void rotate_surface_270(GRSurface *dst, GRSurface *src) { int v, w, h; unsigned int *src_pixel; unsigned int *dst_pixel; for (h=0, v=src->width-1; h<dst->height; h++, v--) { for (w=0; w<dst->width; w++) { dst_pixel = (unsigned int *)(dst->data + dst->row_bytes*h); src_pixel = (unsigned int *)(src->data + src->row_bytes*w); *(dst_pixel+w)=*(src_pixel+v); } } } static void rotate_surface_180(GRSurface *dst, GRSurface *src) { int v, w, k, h; unsigned int *src_pixel; unsigned int *dst_pixel; for (h=0, k=src->height-1; h<dst->height && k>=0 ; h++, k--) { dst_pixel = (unsigned int *)(dst->data + dst->row_bytes*h); src_pixel = (unsigned int *)(src->data + src->row_bytes*k); for (w=0, v=src->width-1; w<dst->width && v>=0; w++, v--) { *(dst_pixel+w)=*(src_pixel+v); } } } static void rotate_surface_90(GRSurface *dst, GRSurface *src) { int w, k, h; unsigned int *src_pixel; unsigned int *dst_pixel; for (h=0; h<dst->height; h++) { for (w=0, k=src->height-1; w<dst->width; w++, k--) { dst_pixel = (unsigned int *)(dst->data + dst->row_bytes*h); src_pixel = (unsigned int *)(src->data + src->row_bytes*k); *(dst_pixel+w)=*(src_pixel+h); } } } typedef void (*rotate_surface_t) (GRSurface *, GRSurface *); rotate_surface_t rotate_func[4]= { rotate_surface_0, rotate_surface_90, rotate_surface_180, rotate_surface_270 }; // rotate and copy src* surface to dst surface void rotate_surface(GRSurface *dst, GRSurface *src) { rotate_surface_t rotate; rotate=rotate_func[rotate_config(dst)]; rotate(dst, src); }
/* * Copyright (C) 2014 MediaTek Inc. * Modification based on code covered by the mentioned copyright * and/or permission notice(s). */ #ifndef MT_GRAPHICS_ROTATE_H_ #define MT_GRAPHICS_ROTATE_H_ #include "minui.h" void rotate_canvas_exit(void); void rotate_canvas_init(GRSurface *gr_draw); void rotate_surface(GRSurface *dst, GRSurface *src); GRSurface *rotate_canvas_get(GRSurface *gr_draw); #endif
/* * Copyright (C) 2014 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/cdefs.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> #include <linux/fb.h> #include <linux/kd.h> #include "minui.h" #include "graphics.h" #include "mt_graphic_rotate.h" static GRSurface* fbdev_init(minui_backend*); static GRSurface* fbdev_flip(minui_backend*); static void fbdev_blank(minui_backend*, bool); static void fbdev_exit(minui_backend*); static GRSurface gr_framebuffer[2]; static bool double_buffered; static GRSurface* gr_draw = NULL; static int displayed_buffer; static fb_var_screeninfo vi; static int fb_fd = -1; static minui_backend my_backend = { .init = fbdev_init, .flip = fbdev_flip, .blank = fbdev_blank, .exit = fbdev_exit, }; minui_backend* open_fbdev() { return &my_backend; } static void fbdev_blank(minui_backend* backend __unused, bool blank) { int ret; ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); if (ret < 0) perror("ioctl(): blank"); } static void set_displayed_framebuffer(unsigned n) { if (n > 1 || !double_buffered) return; vi.yres_virtual = gr_framebuffer[0].height * 2; vi.yoffset = n * gr_framebuffer[0].height; vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8; if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) { perror("active fb swap failed"); } displayed_buffer = n; } static GRSurface* fbdev_init(minui_backend* backend) { int fd = open("/dev/graphics/fb0", O_RDWR); if (fd == -1) { perror("cannot open fb0"); return NULL; } fb_fix_screeninfo fi; if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { perror("failed to get fb0 info"); close(fd); return NULL; } if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { perror("failed to get fb0 info"); close(fd); return NULL; } // We print this out for informational purposes only, but // throughout we assume that the framebuffer device uses an RGBX // pixel format. This is the case for every development device I // have access to. For some of those devices (eg, hammerhead aka // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a // different format (XBGR) but actually produces the correct // results on the display when you write RGBX. // // If you have a device that actually *needs* another pixel format // (ie, BGRX, or 565), patches welcome... printf("fb0 reports (possibly inaccurate):\n" " vi.bits_per_pixel = %d\n" " vi.red.offset = %3d .length = %3d\n" " vi.green.offset = %3d .length = %3d\n" " vi.blue.offset = %3d .length = %3d\n", vi.bits_per_pixel, vi.red.offset, vi.red.length, vi.green.offset, vi.green.length, vi.blue.offset, vi.blue.length); void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (bits == MAP_FAILED) { perror("failed to mmap framebuffer"); close(fd); return NULL; } memset(bits, 0, fi.smem_len); gr_framebuffer[0].width = vi.xres; gr_framebuffer[0].height = vi.yres; gr_framebuffer[0].row_bytes = fi.line_length; gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8; gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits); memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes); /* check if we can use double buffering */ printf("[graphics] vi.yres * fi.line_length = %d * %d * 2 = %d, fi.smem_len=%d\n", vi.yres, fi.line_length, vi.yres * fi.line_length * 2, fi.smem_len); if (vi.yres * fi.line_length * 2 <= fi.smem_len) { double_buffered = true; printf("[graphics] double buffered\n"); memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface)); gr_framebuffer[1].data = gr_framebuffer[0].data + gr_framebuffer[0].height * gr_framebuffer[0].row_bytes; gr_draw = gr_framebuffer+1; } else { double_buffered = false; printf("[graphics] without double buffer\n"); // Without double-buffering, we allocate RAM for a buffer to // draw in, and then "flipping" the buffer consists of a // memcpy from the buffer we allocated to the framebuffer. gr_draw = (GRSurface*) malloc(sizeof(GRSurface)); memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface)); gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes); if (!gr_draw->data) { perror("failed to allocate in-memory surface"); return NULL; } } memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); fb_fd = fd; set_displayed_framebuffer(0); printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); #if 0 // to avoid display blink due to display driver not disable backlight after kernel standardization, so that temp state between display suspend/resume is shown fbdev_blank(backend, true); fbdev_blank(backend, false); #endif return rotate_canvas_get(gr_draw); } static GRSurface* fbdev_flip(minui_backend* backend __unused) { rotate_surface(gr_draw, rotate_canvas_get(gr_draw)); if (double_buffered) { #if defined(RECOVERY_BGRA) // In case of BGRA, do some byte swapping unsigned int idx; unsigned char tmp; unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data; for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes); idx += 4) { tmp = ucfb_vaddr[idx]; ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2]; ucfb_vaddr[idx + 2] = tmp; } #endif // Change gr_draw to point to the buffer currently displayed, // then flip the driver so we're displaying the other buffer // instead. gr_draw = gr_framebuffer + displayed_buffer; set_displayed_framebuffer(1-displayed_buffer); } else { // Copy from the in-memory surface to the framebuffer. memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes); } return rotate_canvas_get(gr_draw); } static void fbdev_exit(minui_backend* backend __unused) { close(fb_fd); fb_fd = -1; rotate_canvas_exit(); if (!double_buffered && gr_draw) { free(gr_draw->data); free(gr_draw); } gr_draw = NULL; }
/* * 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. */ #ifndef _MINUI_H_ #define _MINUI_H_ #include <sys/types.h> #include <functional> // // Graphics. // struct GRSurface { int width; int height; int row_bytes; int pixel_bytes; unsigned char* data; }; int gr_init(); void gr_exit(); int gr_fb_width(); int gr_fb_height(); void gr_flip(); void gr_fb_blank(bool blank); void gr_clear(); // clear entire surface to current color void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void gr_fill(int x1, int y1, int x2, int y2); void gr_text(int x, int y, const char *s, bool bold); void gr_texticon(int x, int y, GRSurface* icon); int gr_measure(const char *s); void gr_font_size(int *x, int *y); void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy); unsigned int gr_get_width(GRSurface* surface); unsigned int gr_get_height(GRSurface* surface); // // Input events. // struct input_event; // TODO: move these over to std::function. typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); typedef int (*ev_set_key_callback)(int code, int value, void* data); int ev_init(ev_callback input_cb, void* data); void ev_exit(); int ev_add_fd(int fd, ev_callback cb, void* data); void ev_iterate_available_keys(std::function<void(int)> f); int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); // 'timeout' has the same semantics as poll(2). // 0 : don't block // < 0 : block forever // > 0 : block for 'timeout' milliseconds int ev_wait(int timeout); int ev_get_input(int fd, uint32_t epevents, input_event* ev); void ev_dispatch(); int ev_get_epollfd(); // // Resources // // res_create_*_surface() functions return 0 if no error, else // negative. // // A "display" surface is one that is intended to be drawn to the // screen with gr_blit(). An "alpha" surface is a grayscale image // interpreted as an alpha mask used to render text in the current // color (with gr_text() or gr_texticon()). // // All these functions load PNG images from "/res/images/${name}.png". // Load a single display surface from a PNG image. int res_create_display_surface(const char* name, GRSurface** pSurface); // Load an array of display surfaces from a single PNG image. The PNG // should have a 'Frames' text chunk whose value is the number of // frames this image represents. The pixel data itself is interlaced // by row. int res_create_multi_display_surface(const char* name, int* frames, GRSurface*** pSurface); // Load a single alpha surface from a grayscale PNG image. int res_create_alpha_surface(const char* name, GRSurface** pSurface); // Load part of a grayscale PNG image that is the first match for the // given locale. The image is expected to be a composite of multiple // translations of the same text, with special added rows that encode // the subimages' size and intended locale in the pixel data. See // development/tools/recovery_l10n for an app that will generate these // specialized images from Android resources. int res_create_localized_alpha_surface(const char* name, const char* locale, GRSurface** pSurface); // Free a surface allocated by any of the res_create_*_surface() // functions. void res_free_surface(GRSurface* surface); #endif
8.1 的修改步驟和 6.0 大致差很少,前三步都同樣,請參考上面的,因爲 8.1 中不須要 minui.h 文件,因此 mt_graphic_rotate.h 和 mt_graphic_rotate.cpp 中 須要註釋express
//#include "minui.h"
/* * Copyright (C) 2014 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 "graphics_fbdev.h" #include <fcntl.h> #include <linux/fb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> #include "minui/minui.h" //cczheng add for rotateCanvas #include "mt_graphic_rotate.h" MinuiBackendFbdev::MinuiBackendFbdev() : gr_draw(nullptr), fb_fd(-1) {} void MinuiBackendFbdev::Blank(bool blank) { int ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); if (ret < 0) perror("ioctl(): blank"); } void MinuiBackendFbdev::SetDisplayedFramebuffer(unsigned n) { if (n > 1 || !double_buffered) return; vi.yres_virtual = gr_framebuffer[0].height * 2; vi.yoffset = n * gr_framebuffer[0].height; vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8; if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) { perror("active fb swap failed"); } displayed_buffer = n; } GRSurface* MinuiBackendFbdev::Init() { int fd = open("/dev/graphics/fb0", O_RDWR); if (fd == -1) { perror("cannot open fb0"); return nullptr; } fb_fix_screeninfo fi; if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { perror("failed to get fb0 info"); close(fd); return nullptr; } if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { perror("failed to get fb0 info"); close(fd); return nullptr; } // We print this out for informational purposes only, but // throughout we assume that the framebuffer device uses an RGBX // pixel format. This is the case for every development device I // have access to. For some of those devices (eg, hammerhead aka // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a // different format (XBGR) but actually produces the correct // results on the display when you write RGBX. // // If you have a device that actually *needs* another pixel format // (ie, BGRX, or 565), patches welcome... printf( "fb0 reports (possibly inaccurate):\n" " vi.bits_per_pixel = %d\n" " vi.red.offset = %3d .length = %3d\n" " vi.green.offset = %3d .length = %3d\n" " vi.blue.offset = %3d .length = %3d\n", vi.bits_per_pixel, vi.red.offset, vi.red.length, vi.green.offset, vi.green.length, vi.blue.offset, vi.blue.length); void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (bits == MAP_FAILED) { perror("failed to mmap framebuffer"); close(fd); return nullptr; } memset(bits, 0, fi.smem_len); gr_framebuffer[0].width = vi.xres; gr_framebuffer[0].height = vi.yres; gr_framebuffer[0].row_bytes = fi.line_length; gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8; gr_framebuffer[0].data = static_cast<uint8_t*>(bits); memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes); /* check if we can use double buffering */ if (vi.yres * fi.line_length * 2 <= fi.smem_len) { double_buffered = true; memcpy(gr_framebuffer + 1, gr_framebuffer, sizeof(GRSurface)); gr_framebuffer[1].data = gr_framebuffer[0].data + gr_framebuffer[0].height * gr_framebuffer[0].row_bytes; gr_draw = gr_framebuffer + 1; } else { double_buffered = false; // Without double-buffering, we allocate RAM for a buffer to // draw in, and then "flipping" the buffer consists of a // memcpy from the buffer we allocated to the framebuffer. gr_draw = static_cast<GRSurface*>(malloc(sizeof(GRSurface))); memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface)); gr_draw->data = static_cast<unsigned char*>(malloc(gr_draw->height * gr_draw->row_bytes)); if (!gr_draw->data) { perror("failed to allocate in-memory surface"); return nullptr; } } memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); fb_fd = fd; SetDisplayedFramebuffer(0); printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); #if 0 Blank(true); Blank(false); #endif //return gr_draw; //cczheng add for rotateCanvas return rotate_canvas_get(gr_draw); } GRSurface* MinuiBackendFbdev::Flip() { //cczheng add for rotateCanvas rotate_surface(gr_draw, rotate_canvas_get(gr_draw)); if (double_buffered) { // Change gr_draw to point to the buffer currently displayed, // then flip the driver so we're displaying the other buffer // instead. gr_draw = gr_framebuffer + displayed_buffer; SetDisplayedFramebuffer(1 - displayed_buffer); } else { // Copy from the in-memory surface to the framebuffer. memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes); } //return gr_draw; //cczheng add for rotateCanvas return rotate_canvas_get(gr_draw); } MinuiBackendFbdev::~MinuiBackendFbdev() { close(fb_fd); fb_fd = -1; //cczheng add for rotateCanvas rotate_canvas_exit(); if (!double_buffered && gr_draw) { free(gr_draw->data); free(gr_draw); } gr_draw = nullptr; }
修改旋轉角度,在 mt_graphic_rotate.cpp 中的 rotate_config(GRSurface gr_draw)
旋轉90度就將 return rotate_index 直接改成 return 1,
依次類推轉 180度, 改成 return 2, 270 度改成 return 3.
注意旋轉方向爲順時針旋轉apache
我修改的狀況對應 return 3.canvas