1 Star 0 Fork 0

yoctoproject/psplash

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
psplash-fb.c 14.60 KB
一键复制 编辑 原始数据 按行查看 历史
Andrei Gherzan 提交于 2019-12-17 10:22 . Double buffering support
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
/*
* pslash - a lightweight framebuffer splashscreen for embedded devices.
*
* Copyright (c) 2006 Matthew Allum <[email protected]>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#include <endian.h>
#include "psplash.h"
static void
psplash_wait_for_vsync(PSplashFB *fb)
{
int err = ioctl(fb->fd, FBIO_WAITFORVSYNC, 0);
if (err != 0)
fprintf(stderr, "Error, FB vsync ioctl [%d]\n", err);
}
void
psplash_fb_flip(PSplashFB *fb, int sync)
{
char *tmp;
if (fb->double_buffering) {
/* Carry out the flip after a vsync */
psplash_wait_for_vsync(fb);
/* Switch the current activate area in fb */
if (fb->fb_var.yoffset == 0 ) {
fb->fb_var.yoffset = fb->real_height;
} else {
fb->fb_var.yoffset = 0;
}
if (ioctl(fb->fd, FBIOPAN_DISPLAY, &fb->fb_var) == -1 ) {
fprintf(stderr, "psplash_fb_flip: FBIOPAN_DISPLAY failed\n");
}
/* Switch the front and back data pointers */
tmp = fb->fdata;
fb->fdata = fb->bdata;
fb->bdata = tmp;
/* Sync new front to new back when requested */
if (sync) {
memcpy(fb->bdata, fb->fdata, fb->stride * fb->real_height);
}
}
}
void
psplash_fb_destroy (PSplashFB *fb)
{
if (fb->fd >= 0)
close (fb->fd);
free(fb);
}
static int
attempt_to_change_pixel_format (PSplashFB *fb,
struct fb_var_screeninfo *fb_var)
{
/* By default the framebuffer driver may have set an oversized
* yres_virtual to support VT scrolling via the panning interface.
*
* We don't try and maintain this since it's more likely that we
* will fail to increase the bpp if the driver's pre allocated
* framebuffer isn't large enough.
*/
fb_var->yres_virtual = fb_var->yres;
/* First try setting an 8,8,8,0 pixel format so we don't have to do
* any conversions while drawing. */
fb_var->bits_per_pixel = 32;
fb_var->red.offset = 0;
fb_var->red.length = 8;
fb_var->green.offset = 8;
fb_var->green.length = 8;
fb_var->blue.offset = 16;
fb_var->blue.length = 8;
fb_var->transp.offset = 0;
fb_var->transp.length = 0;
if (ioctl (fb->fd, FBIOPUT_VSCREENINFO, fb_var) == 0)
{
fprintf(stdout, "Switched to a 32 bpp 8,8,8 frame buffer\n");
return 1;
}
else
{
fprintf(stderr,
"Error, failed to switch to a 32 bpp 8,8,8 frame buffer\n");
}
/* Otherwise try a 16bpp 5,6,5 format */
fb_var->bits_per_pixel = 16;
fb_var->red.offset = 11;
fb_var->red.length = 5;
fb_var->green.offset = 5;
fb_var->green.length = 6;
fb_var->blue.offset = 0;
fb_var->blue.length = 5;
fb_var->transp.offset = 0;
fb_var->transp.length = 0;
if (ioctl (fb->fd, FBIOPUT_VSCREENINFO, fb_var) == 0)
{
fprintf(stdout, "Switched to a 16 bpp 5,6,5 frame buffer\n");
return 1;
}
else
{
fprintf(stderr,
"Error, failed to switch to a 16 bpp 5,6,5 frame buffer\n");
}
return 0;
}
PSplashFB*
psplash_fb_new (int angle, int fbdev_id)
{
struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix;
int off;
char fbdev[9] = "/dev/fb0";
PSplashFB *fb = NULL;
if (fbdev_id > 0 && fbdev_id < 10)
{
// Conversion from integer to ascii.
fbdev[7] = fbdev_id + 48;
}
if ((fb = malloc (sizeof(PSplashFB))) == NULL)
{
perror ("Error no memory");
goto fail;
}
memset (fb, 0, sizeof(PSplashFB));
fb->fd = -1;
if ((fb->fd = open (fbdev, O_RDWR)) < 0)
{
fprintf(stderr,
"Error opening %s\n",
fbdev);
goto fail;
}
if (ioctl (fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1)
{
perror ("Error getting variable framebuffer info");
goto fail;
}
if (fb_var.bits_per_pixel < 16)
{
fprintf(stderr,
"Error, no support currently for %i bpp frame buffers\n"
"Trying to change pixel format...\n",
fb_var.bits_per_pixel);
if (!attempt_to_change_pixel_format (fb, &fb_var))
goto fail;
}
if (ioctl (fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1)
{
perror ("Error getting variable framebuffer info (2)");
goto fail;
}
/* NB: It looks like the fbdev concept of fixed vs variable screen info is
* broken. The line_length is part of the fixed info but it can be changed
* if you set a new pixel format. */
if (ioctl (fb->fd, FBIOGET_FSCREENINFO, &fb_fix) == -1)
{
perror ("Error getting fixed framebuffer info");
goto fail;
}
/* Setup double virtual resolution for double buffering */
if (ioctl(fb->fd, FBIOPAN_DISPLAY, &fb_var) == -1) {
fprintf(stderr, "FBIOPAN_DISPLAY not supported, double buffering disabled");
} else {
if (fb_var.yres_virtual == fb_var.yres * 2) {
DBG("Virtual resolution already double");
fb->double_buffering = 1;
} else {
fb_var.yres_virtual = fb_var.yres * 2;
if (ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb_var) == -1) {
fprintf(stderr, "FBIOPUT_VSCREENINFO failed, double buffering disabled");
} else {
if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb_fix) == -1) {
perror(" Error getting the fixed framebuffer info");
goto fail;
} else {
DBG("Virtual resolution set to double");
fb->double_buffering = 1;
}
}
}
}
fb->real_width = fb->width = fb_var.xres;
fb->real_height = fb->height = fb_var.yres;
fb->bpp = fb_var.bits_per_pixel;
fb->stride = fb_fix.line_length;
fb->type = fb_fix.type;
fb->visual = fb_fix.visual;
fb->red_offset = fb_var.red.offset;
fb->red_length = fb_var.red.length;
fb->green_offset = fb_var.green.offset;
fb->green_length = fb_var.green.length;
fb->blue_offset = fb_var.blue.offset;
fb->blue_length = fb_var.blue.length;
if (fb->red_offset == 11 && fb->red_length == 5 &&
fb->green_offset == 5 && fb->green_length == 6 &&
fb->blue_offset == 0 && fb->blue_length == 5) {
fb->rgbmode = RGB565;
} else if (fb->red_offset == 0 && fb->red_length == 5 &&
fb->green_offset == 5 && fb->green_length == 6 &&
fb->blue_offset == 11 && fb->blue_length == 5) {
fb->rgbmode = BGR565;
} else if (fb->red_offset == 16 && fb->red_length == 8 &&
fb->green_offset == 8 && fb->green_length == 8 &&
fb->blue_offset == 0 && fb->blue_length == 8) {
fb->rgbmode = RGB888;
} else if (fb->red_offset == 0 && fb->red_length == 8 &&
fb->green_offset == 8 && fb->green_length == 8 &&
fb->blue_offset == 16 && fb->blue_length == 8) {
fb->rgbmode = BGR888;
} else {
fb->rgbmode = GENERIC;
}
DBG("width: %i, height: %i, bpp: %i, stride: %i",
fb->width, fb->height, fb->bpp, fb->stride);
fb->base = (char *) mmap ((caddr_t) NULL,
fb_fix.smem_len,
PROT_READ|PROT_WRITE,
MAP_SHARED,
fb->fd, 0);
if (fb->base == (char *)-1)
{
perror("Error cannot mmap framebuffer ");
goto fail;
}
off = (unsigned long) fb_fix.smem_start % (unsigned long) getpagesize();
fb->data = fb->base + off;
if (fb->double_buffering) {
/* fb_var is needed when flipping the buffers */
memcpy(&fb->fb_var, &fb_var, sizeof(struct fb_var_screeninfo));
if (fb->fb_var.yoffset == 0) {
printf("to back\n");
fb->fdata = fb->data;
fb->bdata = fb->data + fb->stride * fb->height;
} else {
printf("to front\n");
fb->fdata = fb->data + fb->stride * fb->height;
fb->bdata = fb->data;
}
} else {
fb->fdata = fb->data;
fb->bdata = fb->data;
}
#if 0
/* FIXME: No support for 8pp as yet */
if (visual == FB_VISUAL_PSEUDOCOLOR
|| visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
{
static struct fb_cmap cmap;
cmap.start = 0;
cmap.len = 16;
cmap.red = saved_red;
cmap.green = saved_green;
cmap.blue = saved_blue;
cmap.transp = NULL;
ioctl (fb, FBIOGETCMAP, &cmap);
}
if (!status)
atexit (bogl_done);
status = 2;
#endif
fb->angle = angle;
switch (fb->angle)
{
case 270:
case 90:
fb->width = fb->real_height;
fb->height = fb->real_width;
break;
case 180:
case 0:
default:
break;
}
return fb;
fail:
if (fb)
psplash_fb_destroy (fb);
return NULL;
}
#define OFFSET(fb,x,y) (((y) * (fb)->stride) + ((x) * ((fb)->bpp >> 3)))
static inline void
psplash_fb_plot_pixel (PSplashFB *fb,
int x,
int y,
uint8 red,
uint8 green,
uint8 blue)
{
/* Always write to back data (bdata) which points to the right data with or
* without double buffering support */
int off;
if (x < 0 || x > fb->width-1 || y < 0 || y > fb->height-1)
return;
switch (fb->angle)
{
case 270:
off = OFFSET (fb, fb->height - y - 1, x);
break;
case 180:
off = OFFSET (fb, fb->width - x - 1, fb->height - y - 1);
break;
case 90:
off = OFFSET (fb, y, fb->width - x - 1);
break;
case 0:
default:
off = OFFSET (fb, x, y);
break;
}
if (fb->rgbmode == RGB565 || fb->rgbmode == RGB888) {
switch (fb->bpp)
{
case 24:
#if __BYTE_ORDER == __BIG_ENDIAN
*(fb->bdata + off + 0) = red;
*(fb->bdata + off + 1) = green;
*(fb->bdata + off + 2) = blue;
#else
*(fb->bdata + off + 0) = blue;
*(fb->bdata + off + 1) = green;
*(fb->bdata + off + 2) = red;
#endif
break;
case 32:
*(volatile uint32_t *) (fb->bdata + off)
= (red << 16) | (green << 8) | (blue);
break;
case 16:
*(volatile uint16_t *) (fb->bdata + off)
= ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
break;
default:
/* depth not supported yet */
break;
}
} else if (fb->rgbmode == BGR565 || fb->rgbmode == BGR888) {
switch (fb->bpp)
{
case 24:
#if __BYTE_ORDER == __BIG_ENDIAN
*(fb->bdata + off + 0) = blue;
*(fb->bdata + off + 1) = green;
*(fb->bdata + off + 2) = red;
#else
*(fb->bdata + off + 0) = red;
*(fb->bdata + off + 1) = green;
*(fb->bdata + off + 2) = blue;
#endif
break;
case 32:
*(volatile uint32_t *) (fb->bdata + off)
= (blue << 16) | (green << 8) | (red);
break;
case 16:
*(volatile uint16_t *) (fb->bdata + off)
= ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3);
break;
default:
/* depth not supported yet */
break;
}
} else {
switch (fb->bpp)
{
case 32:
*(volatile uint32_t *) (fb->bdata + off)
= ((red >> (8 - fb->red_length)) << fb->red_offset)
| ((green >> (8 - fb->green_length)) << fb->green_offset)
| ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
break;
case 16:
*(volatile uint16_t *) (fb->bdata + off)
= ((red >> (8 - fb->red_length)) << fb->red_offset)
| ((green >> (8 - fb->green_length)) << fb->green_offset)
| ((blue >> (8 - fb->blue_length)) << fb->blue_offset);
break;
default:
/* depth not supported yet */
break;
}
}
}
void
psplash_fb_draw_rect (PSplashFB *fb,
int x,
int y,
int width,
int height,
uint8 red,
uint8 green,
uint8 blue)
{
int dx, dy;
for (dy=0; dy < height; dy++)
for (dx=0; dx < width; dx++)
psplash_fb_plot_pixel (fb, x+dx, y+dy, red, green, blue);
}
void
psplash_fb_draw_image (PSplashFB *fb,
int x,
int y,
int img_width,
int img_height,
int img_bytes_per_pixel,
int img_rowstride,
uint8 *rle_data)
{
uint8 *p = rle_data;
int dx = 0, dy = 0, total_len;
unsigned int len;
total_len = img_rowstride * img_height;
/* FIXME: Optimise, check for over runs ... */
while ((p - rle_data) < total_len)
{
len = *(p++);
if (len & 128)
{
len -= 128;
if (len == 0) break;
do
{
if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2));
if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
}
while (--len);
p += img_bytes_per_pixel;
}
else
{
if (len == 0) break;
do
{
if ((img_bytes_per_pixel < 4 || *(p+3)) && dx < img_width)
psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2));
if (++dx * img_bytes_per_pixel >= img_rowstride) { dx=0; dy++; }
p += img_bytes_per_pixel;
}
while (--len && (p - rle_data) < total_len);
}
}
}
/* Font rendering code based on BOGL by Ben Pfaff */
static int
psplash_font_glyph (const PSplashFont *font, wchar_t wc, u_int32_t **bitmap)
{
int mask = font->index_mask;
int i;
for (;;)
{
for (i = font->offset[wc & mask]; font->index[i]; i += 2)
{
if ((wchar_t)(font->index[i] & ~mask) == (wc & ~mask))
{
if (bitmap != NULL)
*bitmap = &font->content[font->index[i+1]];
return font->index[i] & mask;
}
}
}
return 0;
}
void
psplash_fb_text_size (int *width,
int *height,
const PSplashFont *font,
const char *text)
{
char *c = (char*)text;
wchar_t wc;
int k, n, w, h, mw;
n = strlen (text);
mw = h = w = 0;
mbtowc (0, 0, 0);
for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
{
if (*c == '\n')
{
if (w > mw)
mw = w;
w = 0;
h += font->height;
continue;
}
w += psplash_font_glyph (font, wc, NULL);
}
*width = (w > mw) ? w : mw;
*height = (h == 0) ? font->height : h;
}
void
psplash_fb_draw_text (PSplashFB *fb,
int x,
int y,
uint8 red,
uint8 green,
uint8 blue,
const PSplashFont *font,
const char *text)
{
int h, w, k, n, cx, cy, dx, dy;
char *c = (char*)text;
wchar_t wc;
n = strlen (text);
h = font->height;
dx = dy = 0;
mbtowc (0, 0, 0);
for (; (k = mbtowc (&wc, c, n)) > 0; c += k, n -= k)
{
u_int32_t *glyph = NULL;
if (*c == '\n')
{
dy += h;
dx = 0;
continue;
}
w = psplash_font_glyph (font, wc, &glyph);
if (glyph == NULL)
continue;
for (cy = 0; cy < h; cy++)
{
u_int32_t g = *glyph++;
for (cx = 0; cx < w; cx++)
{
if (g & 0x80000000)
psplash_fb_plot_pixel (fb, x+dx+cx, y+dy+cy,
red, green, blue);
g <<= 1;
}
}
dx += w;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/yoctoproject/psplash.git
[email protected]:yoctoproject/psplash.git
yoctoproject
psplash
psplash
master

搜索帮助