198 lines
5.1 KiB
C
198 lines
5.1 KiB
C
/*
|
|
* 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;
|
|
|
|
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;
|
|
}
|