/* * 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 "minui.h" #include "graphics.h" #include "minui_log.h" #include "../osd/osd_hw.h" #include #define DOUBLE_BUFFER /* Graphic Device */ static GraphicDevice *gdev = NULL; static grsurface *fbdev_init(void); static grsurface *fbdev_flip(void); static void fbdev_blank(bool); static void fbdev_exit(void); extern int video_scale_bitmap(void); static grsurface gr_framebuffer[2]; static bool double_buffered; static int displayed_buffer; grsurface *gr_draw; static minui_backend my_backend = { .init = fbdev_init, .flip = fbdev_flip, .blank = fbdev_blank, .exit = fbdev_exit, }; static unsigned long env_strtoul(const char *name, int base) { unsigned long ret = 0; ret = getenv_ulong(name, base, 0); if (base == 16) ui_logd("%s: 0x%lx\n", name, ret); else if (base == 10) ui_logd("%s: %ld\n", name, ret); return ret; } minui_backend *open_fbdev(void) { return &my_backend; } static void fbdev_blank(bool blank) { int osd_index; osd_index = get_osd_layer(); if (osd_index >= 0) osd_enable_hw(osd_index, blank); } static void set_displayed_framebuffer(unsigned n) { int osd_index; if ( n > 1 || !double_buffered) return; osd_index = get_osd_layer(); if (double_buffered) { osd_pan_display_hw(osd_index, 0, n * gr_framebuffer[0].height); ui_logd("pan display:yoffset=%d\n", n * gr_framebuffer[0].height); } displayed_buffer = n; } static char *getenv_str(const char *name) { char *str = NULL; if (!name) { ui_loge("read env, name is NULL\n"); return NULL; } str = getenv(name); return str ? str : NULL; } static grsurface *fbdev_init(void) { u32 color_index, display_bpp; char buf[16] = {}; char *outputmode = NULL; char mode[64]; outputmode = getenv_str("outputmode"); if (!outputmode) return NULL; memset(mode, 0, sizeof(mode)); snprintf(mode, sizeof(mode), "vout output %s", outputmode); run_command(mode, 0); color_index = env_strtoul("display_color_index", 10); display_bpp = env_strtoul("display_bpp", 10); setenv("display_color_index", "32"); setenv("display_bpp", "32"); gdev = video_hw_init(RECT_MODE); if (gdev == NULL) { ui_loge("Initialize video device failed!\n"); return NULL; } gr_framebuffer[0].width = gdev->fb_width; gr_framebuffer[0].height = gdev->fb_height; gr_framebuffer[0].row_bytes = gdev->fb_width * gdev->gdfBytesPP; gr_framebuffer[0].pixel_bytes = gdev->gdfBytesPP; gr_framebuffer[0].data = (unsigned char *)(long long)(gdev->frameAdrs); memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes); #ifdef DOUBLE_BUFFER 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 = (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) { ui_loge("failed to allocate in-memory surface"); return NULL; } #endif memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); set_displayed_framebuffer(0); ui_logi("framebuffer: (%d x %d)\n", gr_draw->width, gr_draw->height); fbdev_blank(true); fbdev_blank(false); #ifdef CONFIG_OSD_SCALE_ENABLE video_scale_bitmap(); #endif sprintf(buf, "%d", color_index); setenv("display_color_index", buf); sprintf(buf, "%d", display_bpp); setenv("display_bpp", buf); return gr_draw; } static grsurface *fbdev_flip(void) { 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. ui_logd("fbdev_flip:gr_draw=0x%lx\n", (unsigned long)(unsigned char*)gr_draw->data); flush_cache((unsigned long)gr_draw->data, gr_draw->row_bytes * gr_draw->height); gr_draw = gr_framebuffer + displayed_buffer; set_displayed_framebuffer(1-displayed_buffer); } else { // Copy from the in-memory surface to the framebuffer. set_displayed_framebuffer(0); memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes); ui_logd("flip: \n"); } return gr_draw; } static void fbdev_exit(void) { if (!double_buffered && gr_draw) { free(gr_draw->data); free(gr_draw); } gr_draw = NULL; }