summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Trumtrar <s.trumtrar@pengutronix.de>2014-10-08 12:27:24 +0200
committerSteffen Trumtrar <s.trumtrar@pengutronix.de>2014-10-10 15:58:58 +0200
commit174986af4c7c7254f7b9e9e9eb2948321e9e7dcf (patch)
tree2171b42a728bb484152e79b553313c74f85d7ccc
parentcd76e0932f6352bc1050681a90571424fa2adf96 (diff)
downloadkmsfbwrap-174986af4c7c7254f7b9e9e9eb2948321e9e7dcf.tar.gz
kmsfbwrap-174986af4c7c7254f7b9e9e9eb2948321e9e7dcf.tar.xz
add png splash image support
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
-rw-r--r--Makefile.am7
-rw-r--r--configure.ac1
-rw-r--r--src/kmsfb-manage.c72
-rw-r--r--src/kmsfb.h10
-rw-r--r--src/png.c154
5 files changed, 242 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 78f8275..8e1d1db 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,7 +10,8 @@ AM_CPPFLAGS = \
-I${top_srcdir}/src/kmsfbwrap \
-I${top_srcdir}/src \
$(DRM_CFLAGS) \
- $(FUSE_CFLAGS)
+ $(FUSE_CFLAGS) \
+ $(LIBPNG_CFLAGS)
AM_CFLAGS = ${my_CFLAGS} \
-fvisibility=hidden \
@@ -36,11 +37,13 @@ SED_PROCESS = \
bin_PROGRAMS = kmsfb-manage
kmsfb_manage_SOURCES = \
+ src/png.c \
src/kmsfb-manage.c \
src/bgi.c
kmsfb_manage_LDADD = \
$(FUSE_LIBS) \
- $(DRM_LIBS)
+ $(DRM_LIBS) \
+ $(LIBPNG_LIBS)
noinst_HEADERS = src/kmsfb.h
diff --git a/configure.ac b/configure.ac
index 6e2ffd4..9ac00da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,6 +41,7 @@ AC_SUBST([my_CFLAGS])
PKG_CHECK_MODULES(DRM, libdrm)
PKG_CHECK_MODULES(FUSE, fuse)
+PKG_CHECK_MODULES(LIBPNG, libpng)
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_FILES([
diff --git a/src/kmsfb-manage.c b/src/kmsfb-manage.c
index 2f0182a..49d90e2 100644
--- a/src/kmsfb-manage.c
+++ b/src/kmsfb-manage.c
@@ -125,6 +125,13 @@ static int kms_data_val_set(struct kms_data *kd, const char *key, const char *va
kd->triplebuf = 1;
else if (!strcmp(key, "fill"))
kd->fill = 1;
+ else if (!strcmp(key, "file")) {
+ if (strlen(value) > MAX_FILENAME) {
+ pr_err("Filename '%s' is to long.\n", value);
+ return -EINVAL;
+ }
+ strcpy(kd->file, value);
+ }
else if (!strcmp(key, "vsync"))
kd->vsync = strtoul(value, NULL, 0);
else if (!strcmp(key, "xpos"))
@@ -1030,6 +1037,67 @@ struct cmd {
int (*fn)(int fd, int argc, char **argv);
};
+static void *convert_rgb2fb(unsigned char *rgb, unsigned int count, int bpp)
+{
+ void *result;
+ uint32_t *fbbuf;
+ int i;
+
+ switch (bpp) {
+ case 32:
+ fbbuf = (uint32_t *)malloc(count * sizeof(*fbbuf));
+
+ for (i = 0; i < count; i++) {
+ fbbuf[i] = ((rgb[i*3] << 16) & 0xff0000) |
+ ((rgb[i*3+1] << 8) & 0xff00) |
+ ((rgb[i*3+2]) & 0xff);
+ }
+ result = (void *)fbbuf;
+ break;
+ default:
+ fprintf(stderr, "Unsupported video mode! You've got: %dbpp\n", bpp);
+ return NULL;
+ }
+
+ return result;
+}
+
+static int fb_splash(struct kms_fb *fb, char *filename)
+{
+ unsigned char *alpha;
+ unsigned char *line;
+ unsigned char *fbbuf;
+ struct splash img;
+ int y;
+ int cpp;
+ int ret;
+
+ memset(&img, 0, sizeof(struct splash));
+
+ ret = png_load(filename, &img, &alpha);
+ if (ret)
+ return -EINVAL;
+
+ fbbuf = convert_rgb2fb(img.rgb, img.width * img.height, fb->bpp);
+ if (!fbbuf)
+ return -ENOMEM;
+
+ cpp = fb->bpp / 8;
+
+ if (img.width < fb->xres || img.height < fb->yres) {
+ line = fb->fb;
+ for (y = 0; y < img.height; y++) {
+ memcpy(line, fbbuf, img.width * cpp);
+ line += fb->pitch;
+ fbbuf += img.width * cpp;
+ }
+ } else {
+ memcpy(fb->fb, fbbuf, img.width * img.height * cpp);
+ }
+
+ return 0;
+}
+
static int fb_create(struct drm_resource *res, int fd, const char *cmd)
{
int ret;
@@ -1066,6 +1134,9 @@ static int fb_create(struct drm_resource *res, int fd, const char *cmd)
if (ret)
return ret;
+ if (strlen(kd.file) > 0)
+ fb_splash(fb, kd.file);
+
if (kd.fill) {
int x, y;
uint32_t *pix;
@@ -1105,6 +1176,7 @@ static void usage(const char *prgname)
" pitch [optional]: line pitch in bytes\n"
" 3d [optional]: create a framebuffer suitable for 3D rendering\n"
" fill [optional]: fill framebuffer with debug pattern\n"
+ " file [optional]: load file into framebuffer\n"
" vsync [optional]: vsync mode:\n"
" 0 - (default) don't wait for vsync when panning, but honor WAITFORVSYNC\n"
" 1 - never wait for vsync\n"
diff --git a/src/kmsfb.h b/src/kmsfb.h
index b9d1c8a..21bdd21 100644
--- a/src/kmsfb.h
+++ b/src/kmsfb.h
@@ -22,6 +22,7 @@ static inline void *zalloc(size_t size)
#define MAX_KMS_FBS 8
#define MAX_KMS_WINDOWS 8
+#define MAX_FILENAME 256
struct kms_window {
uint32_t crtc_id;
@@ -87,10 +88,19 @@ struct kms_data {
int triplebuf;
int fill;
+ char file[MAX_FILENAME];
int vsync;
int alpha;
};
+struct splash {
+ int width, height;
+ unsigned char *rgb;
+ unsigned char *alpha;
+};
+
+int png_load(char *name, struct splash *splash, unsigned char **alpha);
+
int bgi_init(struct kms_fb *fb);
#endif /* __KMSFB_H */
diff --git a/src/png.c b/src/png.c
new file mode 100644
index 0000000..0a89c15
--- /dev/null
+++ b/src/png.c
@@ -0,0 +1,154 @@
+/*
+ * Code based on:
+ *
+ * fbv -- simple image viewer for the linux framebuffer
+ * Copyright (C) 2000, 2001, 2003 Mateusz Golicz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <png.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "kmsfb.h"
+
+#define PNG_BYTES_TO_CHECK 4
+
+int png_load(char *name, struct splash *image, unsigned char **alpha)
+{
+ int bit_depth, color_type, interlace_type;
+ int number_passes,pass, trans = 0;
+ png_uint_32 width, height;
+ unsigned char *fbptr;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned int i;
+ unsigned char *rp;
+ png_bytep rptr[2];
+ FILE *fh;
+ int ret;
+ char id[4];
+
+ fh = fopen(name,"rb");
+ if (fh == -1)
+ return -ENOENT;
+
+ fread(&id, 1, 4, fh);
+
+ if (!(id[1] == 'P' && id[2]=='N' && id[3]=='G'))
+ return -EINVAL;
+
+ rewind(fh);
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL)
+ return -EINVAL;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ fclose(fh);
+
+ return -EINVAL;
+ }
+
+ rp=0;
+ if (setjmp(png_ptr->jmpbuf)) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ if(rp)
+ free(rp);
+
+ fclose(fh);
+
+ return -EINVAL;
+ }
+
+ png_init_io(png_ptr,fh);
+
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL);
+
+ image->rgb = (unsigned char*) malloc(width * height * 3);
+ image->width = width;
+ image->height = height;
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_expand(png_ptr);
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY || color_type== PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ trans = 1;
+ png_set_tRNS_to_alpha(png_ptr);
+ }
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+ number_passes = png_set_interlace_handling(png_ptr);
+ png_read_update_info(png_ptr,info_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans) {
+ unsigned char * alpha_buffer = (unsigned char*) malloc(width * height);
+ unsigned char * aptr;
+
+ rp = (unsigned char*) malloc(width * 4);
+ rptr[0] = (png_bytep) rp;
+
+ *alpha = alpha_buffer;
+
+ for (pass = 0; pass < number_passes; pass++) {
+ fbptr = image->rgb;
+ aptr = alpha_buffer;
+
+ for(i=0; i<height; i++) {
+ unsigned int n;
+ unsigned char *trp = rp;
+
+ png_read_rows(png_ptr, rptr, NULL, 1);
+
+ for(n = 0; n < width; n++, fbptr += 3, trp += 4) {
+ memcpy(fbptr, trp, 3);
+ *(aptr++) = trp[3];
+ }
+ }
+ }
+ free(rp);
+ } else {
+ for (pass = 0; pass < number_passes; pass++) {
+ fbptr = image->rgb;
+ for(i=0; i<height; i++, fbptr += width*3) {
+ rptr[0] = (png_bytep) fbptr;
+ png_read_rows(png_ptr, rptr, NULL, 1);
+ }
+ }
+ }
+
+ png_read_end(png_ptr, info_ptr);
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ fclose(fh);
+
+ return 0;
+}