blob: d920c76c9754765a075674de45cc0a92274099ce [file] [log] [blame]
/*
* 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 <video_fb.h>
#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 = NULL;
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(MIDDLE_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;
}