diff options
Diffstat (limited to '')
-rw-r--r-- | minuitwrp/graphics_overlay.cpp (renamed from minuitwrp/graphics_overlay.c) | 492 |
1 files changed, 341 insertions, 151 deletions
diff --git a/minuitwrp/graphics_overlay.c b/minuitwrp/graphics_overlay.cpp index 723ffa2d4..5445b6f62 100644 --- a/minuitwrp/graphics_overlay.c +++ b/minuitwrp/graphics_overlay.cpp @@ -1,40 +1,29 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (C) 2014 The Android Open Source Project * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * 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 * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * 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 <errno.h> + #include <fcntl.h> #include <stdio.h> +#include <sys/cdefs.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> @@ -47,15 +36,32 @@ #include <linux/msm_ion.h> #endif -#include <pixelflinger/pixelflinger.h> - #include "minui.h" +#include "graphics.h" +#include <pixelflinger/pixelflinger.h> #define MDP_V4_0 400 +#define MAX_DISPLAY_DIM 2048 -#ifdef MSM_BSP +static GRSurface* overlay_init(minui_backend*); +static GRSurface* overlay_flip(minui_backend*); +static void overlay_blank(minui_backend*, bool); +static void overlay_exit(minui_backend*); + +static GRSurface gr_framebuffer; +static GRSurface* gr_draw = NULL; +static int displayed_buffer; + +static fb_var_screeninfo vi; +static int fb_fd = -1; +static bool isMDP5 = false; +static int leftSplit = 0; +static int rightSplit = 0; #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) +static size_t frame_size = 0; + +#ifdef MSM_BSP typedef struct { unsigned char *mem_buf; int size; @@ -72,23 +78,31 @@ static memInfo mem_info; static int map_mdp_pixel_format() { - int format = MDP_RGB_565; -#if defined(RECOVERY_BGRA) - format = MDP_BGRA_8888; -#elif defined(RECOVERY_RGBA) - format = MDP_RGBA_8888; -#elif defined(RECOVERY_RGBX) - format = MDP_RGBA_8888; -#endif - return format; + if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGB_565) + return MDP_RGB_565; + else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_BGRA_8888) + return MDP_BGRA_8888; + else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGBA_8888) + return MDP_RGBA_8888; + else if (gr_framebuffer.format == GGL_PIXEL_FORMAT_RGBX_8888) + return MDP_RGBA_8888; + printf("No known pixel format for map_mdp_pixel_format, defaulting to MDP_RGB_565.\n"); + return MDP_RGB_565; } +#endif // MSM_BSP -static bool overlay_supported = false; -static bool isMDP5 = false; +static minui_backend my_backend = { + .init = overlay_init, + .flip = overlay_flip, + .blank = overlay_blank, + .exit = overlay_exit, +}; bool target_has_overlay(char *version) { + int ret; int mdp_version; + bool overlay_supported = false; if (strlen(version) >= 8) { if(!strncmp(version, "msmfb", strlen("msmfb"))) { @@ -104,22 +118,100 @@ bool target_has_overlay(char *version) isMDP5 = true; } } - if (overlay_supported) printf("Using qcomm overlay\n"); + return overlay_supported; } -bool isTargetMdp5() +minui_backend* open_overlay() { + fb_fix_screeninfo fi; + int fd; + + fd = open("/dev/graphics/fb0", O_RDWR); + if (fd < 0) { + perror("open_overlay cannot open fb0"); + return NULL; + } + + if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return NULL; + } + + if (target_has_overlay(fi.id)) { +#ifdef MSM_BSP + close(fd); + return &my_backend; +#else + printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id); +#endif + } + close(fd); + return NULL; +} + +static void overlay_blank(minui_backend* backend __unused, bool blank) { - if (isMDP5) - return true; +#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS) + int fd; + char brightness[4]; + snprintf(brightness, 4, "%03d", TW_MAX_BRIGHTNESS/2); + + fd = open(TW_BRIGHTNESS_PATH, O_RDWR); + if (fd < 0) { + perror("cannot open LCD backlight"); + return; + } + write(fd, blank ? "000" : brightness, 3); + close(fd); +#else + int ret; - return false; + ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); + if (ret < 0) + perror("ioctl(): blank"); +#endif } -int free_ion_mem(void) { - if (!overlay_supported) - return -EINVAL; +#ifdef MSM_BSP +void setDisplaySplit(void) { + char split[64] = {0}; + if (!isMDP5) + return; + FILE* fp = fopen("/sys/class/graphics/fb0/msm_fb_split", "r"); + if (fp) { + //Format "left right" space as delimiter + if(fread(split, sizeof(char), 64, fp)) { + leftSplit = atoi(split); + printf("Left Split=%d\n",leftSplit); + char *rght = strpbrk(split, " "); + if (rght) + rightSplit = atoi(rght + 1); + printf("Right Split=%d\n", rightSplit); + } + } else { + printf("Failed to open mdss_fb_split node\n"); + } + if (fp) + fclose(fp); +} + +int getLeftSplit(void) { + //Default even split for all displays with high res + int lSplit = vi.xres / 2; + + //Override if split published by driver + if (leftSplit) + lSplit = leftSplit; + + return lSplit; +} +int getRightSplit(void) { + return rightSplit; +} + +int free_ion_mem(void) { int ret = 0; if (mem_info.mem_buf) @@ -144,8 +236,6 @@ int free_ion_mem(void) { int alloc_ion_mem(unsigned int size) { - if (!overlay_supported) - return -EINVAL; int result; struct ion_fd_data fd_data; struct ion_allocation_data ionAllocData; @@ -195,13 +285,20 @@ int alloc_ion_mem(unsigned int size) return 0; } -int allocate_overlay(int fd, GGLSurface gr_fb[]) +bool isDisplaySplit(void) { + if (vi.xres > MAX_DISPLAY_DIM) + return true; + //check if right split is set by driver + if (getRightSplit()) + return true; + + return false; +} + +int allocate_overlay(int fd, GRSurface gr_fb) { int ret = 0; - if (!overlay_supported) - return -EINVAL; - if (!isDisplaySplit()) { // Check if overlay is already allocated if (MSMFB_NEW_REQUEST == overlayL_id) { @@ -210,13 +307,13 @@ int allocate_overlay(int fd, GGLSurface gr_fb[]) memset(&overlayL, 0 , sizeof (struct mdp_overlay)); /* Fill Overlay Data */ - overlayL.src.width = ALIGN(gr_fb[0].width, 32); - overlayL.src.height = gr_fb[0].height; + overlayL.src.width = ALIGN(gr_fb.width, 32); + overlayL.src.height = gr_fb.height; overlayL.src.format = map_mdp_pixel_format(); - overlayL.src_rect.w = gr_fb[0].width; - overlayL.src_rect.h = gr_fb[0].height; - overlayL.dst_rect.w = gr_fb[0].width; - overlayL.dst_rect.h = gr_fb[0].height; + overlayL.src_rect.w = gr_fb.width; + overlayL.src_rect.h = gr_fb.height; + overlayL.dst_rect.w = gr_fb.width; + overlayL.dst_rect.h = gr_fb.height; overlayL.alpha = 0xFF; overlayL.transp_mask = MDP_TRANSP_NOP; overlayL.id = MSMFB_NEW_REQUEST; @@ -228,13 +325,13 @@ int allocate_overlay(int fd, GGLSurface gr_fb[]) overlayL_id = overlayL.id; } } else { - float xres = getFbXres(); + float xres = vi.xres; int lSplit = getLeftSplit(); float lSplitRatio = lSplit / xres; - float lCropWidth = gr_fb[0].width * lSplitRatio; + float lCropWidth = gr_fb.width * lSplitRatio; int lWidth = lSplit; - int rWidth = gr_fb[0].width - lSplit; - int height = gr_fb[0].height; + int rWidth = gr_fb.width - lSplit; + int height = gr_fb.height; if (MSMFB_NEW_REQUEST == overlayL_id) { @@ -243,13 +340,13 @@ int allocate_overlay(int fd, GGLSurface gr_fb[]) memset(&overlayL, 0 , sizeof (struct mdp_overlay)); /* Fill OverlayL Data */ - overlayL.src.width = ALIGN(gr_fb[0].width, 32); - overlayL.src.height = gr_fb[0].height; + overlayL.src.width = ALIGN(gr_fb.width, 32); + overlayL.src.height = gr_fb.height; overlayL.src.format = map_mdp_pixel_format(); overlayL.src_rect.x = 0; overlayL.src_rect.y = 0; overlayL.src_rect.w = lCropWidth; - overlayL.src_rect.h = gr_fb[0].height; + overlayL.src_rect.h = gr_fb.height; overlayL.dst_rect.x = 0; overlayL.dst_rect.y = 0; overlayL.dst_rect.w = lWidth; @@ -270,13 +367,13 @@ int allocate_overlay(int fd, GGLSurface gr_fb[]) memset(&overlayR, 0 , sizeof (struct mdp_overlay)); /* Fill OverlayR Data */ - overlayR.src.width = ALIGN(gr_fb[0].width, 32); - overlayR.src.height = gr_fb[0].height; + overlayR.src.width = ALIGN(gr_fb.width, 32); + overlayR.src.height = gr_fb.height; overlayR.src.format = map_mdp_pixel_format(); overlayR.src_rect.x = lCropWidth; overlayR.src_rect.y = 0; - overlayR.src_rect.w = gr_fb[0].width - lCropWidth; - overlayR.src_rect.h = gr_fb[0].height; + overlayR.src_rect.w = gr_fb.width - lCropWidth; + overlayR.src_rect.h = gr_fb.height; overlayR.dst_rect.x = 0; overlayR.dst_rect.y = 0; overlayR.dst_rect.w = rWidth; @@ -297,64 +394,8 @@ int allocate_overlay(int fd, GGLSurface gr_fb[]) return 0; } -int free_overlay(int fd) -{ - if (!overlay_supported) - return -EINVAL; - - int ret = 0; - struct mdp_display_commit ext_commit; - - if (!isDisplaySplit()) { - if (overlayL_id != MSMFB_NEW_REQUEST) { - ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id); - if (ret) { - perror("Overlay Unset Failed"); - overlayL_id = MSMFB_NEW_REQUEST; - return ret; - } - } - } else { - - if (overlayL_id != MSMFB_NEW_REQUEST) { - ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id); - if (ret) { - perror("OverlayL Unset Failed"); - overlayL_id = MSMFB_NEW_REQUEST; - return ret; - } - } - - if (overlayR_id != MSMFB_NEW_REQUEST) { - ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id); - if (ret) { - perror("OverlayR Unset Failed"); - overlayR_id = MSMFB_NEW_REQUEST; - return ret; - } - } - } - memset(&ext_commit, 0, sizeof(struct mdp_display_commit)); - ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY; - ext_commit.wait_for_finish = 1; - ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit); - if (ret < 0) { - perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!"); - overlayL_id = MSMFB_NEW_REQUEST; - overlayR_id = MSMFB_NEW_REQUEST; - return ret; - } - overlayL_id = MSMFB_NEW_REQUEST; - overlayR_id = MSMFB_NEW_REQUEST; - - return 0; -} - -int overlay_display_frame(int fd, GGLubyte* data, size_t size) +int overlay_display_frame(int fd, void* data, size_t size) { - if (!overlay_supported) - return -EINVAL; - int ret = 0; struct msmfb_overlay_data ovdataL, ovdataR; struct mdp_display_commit ext_commit; @@ -376,6 +417,7 @@ int overlay_display_frame(int fd, GGLubyte* data, size_t size) ret = ioctl(fd, MSMFB_OVERLAY_PLAY, &ovdataL); if (ret < 0) { perror("overlay_display_frame failed, overlay play Failed\n"); + printf("%i, %i, %i, %i\n", ret, fb_fd, fd, errno); return ret; } } else { @@ -426,38 +468,186 @@ int overlay_display_frame(int fd, GGLubyte* data, size_t size) return ret; } -#else - -bool target_has_overlay(char *version) { - return false; +static GRSurface* overlay_flip(minui_backend* backend __unused) { +#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 + // Copy from the in-memory surface to the framebuffer. + overlay_display_frame(fb_fd, gr_draw->data, frame_size); + return gr_draw; } -bool isTargetMdp5() { - return false; -} +int free_overlay(int fd) +{ + int ret = 0; + struct mdp_display_commit ext_commit; -int free_ion_mem(void) { - return -EINVAL; -} + if (!isDisplaySplit()) { + if (overlayL_id != MSMFB_NEW_REQUEST) { + ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id); + if (ret) { + perror("Overlay Unset Failed"); + overlayL_id = MSMFB_NEW_REQUEST; + return ret; + } + } + } else { -int alloc_ion_mem(unsigned int size) -{ - return -EINVAL; + if (overlayL_id != MSMFB_NEW_REQUEST) { + ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayL_id); + if (ret) { + perror("OverlayL Unset Failed"); + } + } + + if (overlayR_id != MSMFB_NEW_REQUEST) { + ret = ioctl(fd, MSMFB_OVERLAY_UNSET, &overlayR_id); + if (ret) { + perror("OverlayR Unset Failed"); + overlayR_id = MSMFB_NEW_REQUEST; + return ret; + } + } + } + memset(&ext_commit, 0, sizeof(struct mdp_display_commit)); + ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY; + ext_commit.wait_for_finish = 1; + ret = ioctl(fd, MSMFB_DISPLAY_COMMIT, &ext_commit); + if (ret < 0) { + perror("ERROR: Clear MSMFB_DISPLAY_COMMIT failed!"); + overlayL_id = MSMFB_NEW_REQUEST; + overlayR_id = MSMFB_NEW_REQUEST; + return ret; + } + overlayL_id = MSMFB_NEW_REQUEST; + overlayR_id = MSMFB_NEW_REQUEST; + + return 0; } -int allocate_overlay(int fd, GGLSurface gr_fb[]) -{ - return -EINVAL; +static GRSurface* overlay_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); + + gr_framebuffer.width = vi.xres; + gr_framebuffer.height = vi.yres; + gr_framebuffer.row_bytes = fi.line_length; + gr_framebuffer.pixel_bytes = vi.bits_per_pixel / 8; + //gr_framebuffer.data = reinterpret_cast<uint8_t*>(bits); + if (vi.bits_per_pixel == 16) { + printf("setting GGL_PIXEL_FORMAT_RGB_565\n"); + gr_framebuffer.format = GGL_PIXEL_FORMAT_RGB_565; + } else if (vi.red.offset == 8) { + printf("setting GGL_PIXEL_FORMAT_BGRA_8888\n"); + gr_framebuffer.format = GGL_PIXEL_FORMAT_BGRA_8888; + } else if (vi.red.offset == 0) { + printf("setting GGL_PIXEL_FORMAT_RGBA_8888\n"); + gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBA_8888; + } else if (vi.red.offset == 24) { + printf("setting GGL_PIXEL_FORMAT_RGBX_8888\n"); + gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBX_8888; + } else { + if (vi.red.length == 8) { + printf("No valid pixel format detected, trying GGL_PIXEL_FORMAT_RGBX_8888\n"); + gr_framebuffer.format = GGL_PIXEL_FORMAT_RGBX_8888; + } else { + printf("No valid pixel format detected, trying GGL_PIXEL_FORMAT_RGB_565\n"); + gr_framebuffer.format = GGL_PIXEL_FORMAT_RGB_565; + } + } + + frame_size = fi.line_length * vi.yres; + + gr_framebuffer.data = reinterpret_cast<uint8_t*>(calloc(frame_size, 1)); + if (gr_framebuffer.data == NULL) { + perror("failed to calloc framebuffer"); + close(fd); + return NULL; + } + + gr_draw = &gr_framebuffer; + fb_fd = fd; + + printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); + + overlay_blank(backend, true); + overlay_blank(backend, false); + + if (!alloc_ion_mem(frame_size)) + allocate_overlay(fb_fd, gr_framebuffer); + + return gr_draw; } -int free_overlay(int fd) -{ - return -EINVAL; +static void overlay_exit(minui_backend* backend __unused) { + free_overlay(fb_fd); + free_ion_mem(); + + close(fb_fd); + fb_fd = -1; + + if (gr_draw) { + free(gr_draw->data); + free(gr_draw); + } + gr_draw = NULL; +} +#else // MSM_BSP +static GRSurface* overlay_flip(minui_backend* backend __unused) { + return NULL; } -int overlay_display_frame(int fd, GGLubyte* data, size_t size) -{ - return -EINVAL; +static GRSurface* overlay_init(minui_backend* backend __unused) { + return NULL; } -#endif //#ifdef MSM_BSP +static void overlay_exit(minui_backend* backend __unused) { + return; +} +#endif // MSM_BSP |