fbdev: initial implementation
authorJunghoon <jh13.son@samsung.com>
Fri, 12 Jun 2015 08:12:46 +0000 (17:12 +0900)
committerTaekyun Kim <tkq.kim@samsung.com>
Tue, 7 Jul 2015 06:56:50 +0000 (15:56 +0900)
    - use libinput & pixman renderer
    - just clear screen once

Change-Id: I1b2470734d220c51a7b816a6d38a0d3bdbc9f996

12 files changed:
fbdev/Makefile.am [new file with mode: 0644]
fbdev/autogen.sh [new file with mode: 0755]
fbdev/configure.ac [new file with mode: 0644]
fbdev/src/Makefile.am [new file with mode: 0644]
fbdev/src/fbdev-common.c [new file with mode: 0644]
fbdev/src/fbdev-internal.h [new file with mode: 0644]
fbdev/src/fbdev-output.c [new file with mode: 0644]
fbdev/src/pepper-fbdev.h [new file with mode: 0644]
fbdev/src/pepper-fbdev.pc.in [new file with mode: 0644]
samples/configure.ac
samples/src/Makefile.am
samples/src/fbdev-backend.c [new file with mode: 0644]

diff --git a/fbdev/Makefile.am b/fbdev/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/fbdev/autogen.sh b/fbdev/autogen.sh
new file mode 100755 (executable)
index 0000000..916169a
--- /dev/null
@@ -0,0 +1,9 @@
+#! /bin/sh
+
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+(
+  cd "$srcdir" &&
+  autoreconf --force -v --install
+) || exit
+test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/fbdev/configure.ac b/fbdev/configure.ac
new file mode 100644 (file)
index 0000000..247ffe3
--- /dev/null
@@ -0,0 +1,36 @@
+m4_define([pepper_fbdev_major], 0)
+m4_define([pepper_fbdev_minor], 0)
+m4_define([pepper_fbdev_micro], 0)
+
+m4_define([pepper_fbdev_version], [pepper_fbdev_major.pepper_fbdev_minor.pepper_fbdev_micro])
+
+AC_PREREQ([2.64])
+AC_INIT([pepper_fbdev], [pepper_fbdev_version], [tkq.kim@samsung.com])
+
+AC_SUBST([PEPPER_FBDEV_VERSION_MAJOR], [pepper_fbdev_major_version])
+AC_SUBST([PEPPER_FBDEV_VERSION_MINOR], [pepper_fbdev_minor_version])
+AC_SUBST([PEPPER_FBDEV_VERSION_MICRO], [pepper_fbdev_micro_version])
+AC_SUBST([PEPPER_FBDEV_VERSION], [pepper_fbdev_version])
+
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
+AM_SILENT_RULES([yes])
+
+AC_PROG_CC
+
+LT_PREREQ([2.2])
+LT_INIT([disable-static])
+
+PEPPER_FBDEV_MODULES="pepper pepper-render pepper-libinput pixman-1 wayland-server \
+                    pepper-desktop-shell"
+
+PKG_CHECK_MODULES(PEPPER_FBDEV, [$PEPPER_FBDEV_MODULES])
+AC_SUBST([PEPPER_FBDEV_REQUIRES], [$PEPPER_FBDEV_MODULES])
+
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+src/pepper-fbdev.pc
+])
+
+AC_OUTPUT
diff --git a/fbdev/src/Makefile.am b/fbdev/src/Makefile.am
new file mode 100644 (file)
index 0000000..c774ad5
--- /dev/null
@@ -0,0 +1,12 @@
+lib_LTLIBRARIES = libpepper-fbdev.la
+include_HEADERS = pepper-fbdev.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = pepper-fbdev.pc
+
+libpepper_fbdev_la_CFLAGS = $(PEPPER_FBDEV_CFLAGS) -Wall
+libpepper_fbdev_la_LIBADD = $(PEPPER_FBDEV_LIBS)
+
+libpepper_fbdev_la_SOURCES = fbdev-internal.h      \
+                             fbdev-common.c        \
+                             fbdev-output.c
diff --git a/fbdev/src/fbdev-common.c b/fbdev/src/fbdev-common.c
new file mode 100644 (file)
index 0000000..85a8344
--- /dev/null
@@ -0,0 +1,70 @@
+#include <libudev.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "fbdev-internal.h"
+
+PEPPER_API pepper_fbdev_t *
+pepper_fbdev_create(pepper_compositor_t *compositor, const char *device)
+{
+    pepper_fbdev_t *fbdev;
+
+    fbdev = (pepper_fbdev_t *)calloc(1, sizeof(pepper_fbdev_t));
+    if (!fbdev)
+    {
+        PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    fbdev->udev = udev_new();
+    if (!fbdev->udev)
+    {
+        PEPPER_ERROR("Failed to create udev context in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    fbdev->compositor = compositor;
+    fbdev->input = pepper_libinput_create(compositor, fbdev->udev);
+
+    if (!fbdev->input)
+    {
+        PEPPER_ERROR("Failed to create pepper_libinput in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    wl_list_init(&fbdev->output_list);
+
+    if (!pepper_fbdev_output_create(fbdev))
+    {
+        PEPPER_ERROR("Failed to connect fbdev output in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    return fbdev;
+
+error:
+    if (fbdev)
+        pepper_fbdev_destroy(fbdev);
+
+    return NULL;
+}
+
+PEPPER_API void
+pepper_fbdev_destroy(pepper_fbdev_t *fbdev)
+{
+    fbdev_output_t *output, *next;
+
+    if (!wl_list_empty(&fbdev->output_list))
+    {
+        wl_list_for_each_safe(output, next, &fbdev->output_list, link)
+            pepper_fbdev_output_destroy(output);
+    }
+
+    if (fbdev->input)
+        pepper_libinput_destroy(fbdev->input);
+
+    if (fbdev->udev)
+        udev_unref(fbdev->udev);
+
+    free(fbdev);
+}
diff --git a/fbdev/src/fbdev-internal.h b/fbdev/src/fbdev-internal.h
new file mode 100644 (file)
index 0000000..05de11a
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef FBDEV_INTERNAL_H
+#define FBDEV_INTERNAL_H
+
+#include <pixman.h>
+
+#include <pepper-libinput.h>
+#include <pepper-render.h>
+
+#include "pepper-fbdev.h"
+
+/* TODO: Error Logging. */
+#define PEPPER_ERROR(...)
+
+typedef struct fbdev_output     fbdev_output_t;
+
+struct pepper_fbdev
+{
+    pepper_compositor_t        *compositor;
+    pepper_libinput_t          *input;
+
+    struct wl_list              output_list;
+
+    uint32_t                    min_width, min_height;
+    uint32_t                    max_width, max_height;
+
+    struct udev                *udev;
+};
+
+struct fbdev_output
+{
+    pepper_fbdev_t             *fbdev;
+    pepper_output_t            *base;
+
+    struct wl_list              link;
+
+    int32_t                     subpixel;
+    uint32_t                    w, h;
+    uint32_t                    pixel_format;
+    uint32_t                    bits_per_pixel;
+
+    struct wl_signal            destroy_signal;
+    struct wl_signal            mode_change_signal;
+    struct wl_signal            frame_signal;
+
+    void                       *fb;
+    pixman_image_t             *fb_image;
+
+    pepper_renderer_t          *renderer;
+    /* TODO */
+};
+
+pepper_bool_t
+pepper_fbdev_output_create(pepper_fbdev_t *fbdev);
+
+void
+pepper_fbdev_output_destroy(fbdev_output_t *output);
+
+#endif /* FBDEV_INTERNAL_H */
diff --git a/fbdev/src/fbdev-output.c b/fbdev/src/fbdev-output.c
new file mode 100644 (file)
index 0000000..0cb0b62
--- /dev/null
@@ -0,0 +1,376 @@
+#include <fcntl.h>
+#include <libudev.h>
+#include <linux/fb.h>
+#include <pixman.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <pepper-pixman-renderer.h>
+#include <pepper-gl-renderer.h>
+
+#include "fbdev-internal.h"
+
+#define USE_PIXMAN  1   /* FIXME */
+
+static pepper_bool_t
+init_renderer(fbdev_output_t *output);
+
+static void
+fini_renderer(fbdev_output_t *output);
+
+void
+fbdev_output_destroy(void *o)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+
+    wl_list_remove(&output->link);
+    fini_renderer(output);
+
+    if (output->fb_image)
+        pixman_image_unref(output->fb_image);
+
+    if (output->fb)
+        munmap(output->fb, output->w * output->h * (output->bits_per_pixel / 8));
+
+    wl_signal_emit(&output->destroy_signal, NULL);
+    free(output);
+}
+
+static void
+fbdev_output_add_destroy_listener(void *o, struct wl_listener *listener)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+    wl_signal_add(&output->destroy_signal, listener);
+}
+
+static void
+fbdev_output_add_mode_change_listener(void *o, struct wl_listener *listener)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+    wl_signal_add(&output->mode_change_signal, listener);
+}
+
+static int32_t
+fbdev_output_get_subpixel_order(void *o)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+    return output->subpixel;
+}
+
+static const char *
+fbdev_output_get_maker_name(void *o)
+{
+    return "PePPer FBDEV";
+}
+
+static const char *
+fbdev_output_get_model_name(void *o)
+{
+    return "PePPer FBDEV";
+}
+
+static int
+fbdev_output_get_mode_count(void *o)
+{
+    return 1;
+}
+
+static void
+fbdev_output_get_mode(void *o, int index, pepper_output_mode_t *mode)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+
+     if (index != 0)
+        return;
+
+    mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+    mode->w = output->w;
+    mode->h = output->h;
+    mode->refresh = 60000;
+}
+
+static pepper_bool_t
+fbdev_output_set_mode(void *o, const pepper_output_mode_t *mode)
+{
+    return PEPPER_FALSE;
+}
+
+static void
+draw_pixman(fbdev_output_t *output)
+{
+    /* FIXME: copy shadow image to fb? */
+    pepper_renderer_repaint_output(output->renderer, output->base);
+}
+
+static void
+draw(fbdev_output_t *output)
+{
+    if (USE_PIXMAN)
+        draw_pixman(output);
+}
+
+static void
+fbdev_output_repaint(void *o)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+
+    draw(output);
+
+    /* TODO */
+}
+
+static void
+fbdev_output_add_frame_listener(void *o, struct wl_listener *listener)
+{
+    fbdev_output_t *output = (fbdev_output_t *)o;
+    wl_signal_add(&output->frame_signal, listener);
+}
+
+struct pepper_output_interface fbdev_output_interface =
+{
+    fbdev_output_destroy,
+    fbdev_output_add_destroy_listener,
+    fbdev_output_add_mode_change_listener,
+
+    fbdev_output_get_subpixel_order,
+    fbdev_output_get_maker_name,
+    fbdev_output_get_model_name,
+
+    fbdev_output_get_mode_count,
+    fbdev_output_get_mode,
+    fbdev_output_set_mode,
+
+    fbdev_output_repaint,
+    fbdev_output_add_frame_listener,
+};
+
+static int
+fbdev_open(const char *path, int flags)
+{
+    int fd;
+
+    fd = open(path, flags | O_CLOEXEC);
+    if (fd == -1)
+        PEPPER_ERROR("Failed to open file[%s] in %s\n", path, __FUNCTION__);
+
+    return fd;
+}
+
+static void
+fini_pixman_renderer(fbdev_output_t *output)
+{
+    if (output->renderer)
+        pepper_renderer_destroy(output->renderer);
+}
+
+static pepper_bool_t
+init_pixman_renderer(fbdev_output_t *output)
+{
+    output->renderer = pepper_pixman_renderer_create(output->fbdev->compositor);
+    if (!output->renderer)
+    {
+        PEPPER_ERROR("Failed to create pixman renderer in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    /* FIXME: use shadow image? */
+    pepper_pixman_renderer_set_target(output->renderer, output->fb_image);
+
+    return PEPPER_TRUE;
+
+error:
+
+    fini_pixman_renderer(output);
+
+    return PEPPER_FALSE;
+}
+
+static pepper_bool_t
+init_renderer(fbdev_output_t *output)
+{
+    if (USE_PIXMAN)
+        return init_pixman_renderer(output);
+    else
+        return PEPPER_FALSE;
+}
+
+static void
+fini_renderer(fbdev_output_t *output)
+{
+    if (USE_PIXMAN)
+        fini_pixman_renderer(output);
+}
+
+pepper_bool_t
+pepper_fbdev_output_create(pepper_fbdev_t *fbdev)
+{
+    fbdev_output_t             *output;
+
+    int                         fd;
+    struct fb_fix_screeninfo    fixed_info;
+    struct fb_var_screeninfo    var_info;
+
+    /* fbdev open */
+    fd = fbdev_open("/dev/fb0"/*FIXME*/, O_RDWR);
+    if (fd < 0)
+    {
+        PEPPER_ERROR("Failed to open fbdev in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    if (ioctl(fd, FBIOGET_FSCREENINFO, &fixed_info) < 0)
+    {
+        PEPPER_ERROR("Failed to get fixed screen info in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+#if 1   /* print out some of the fixed info */
+    {
+        printf("Framebuffer ID: %s\n", fixed_info.id);
+        printf("Framebuffer type: ");
+        switch (fixed_info.type)
+        {
+            case FB_TYPE_PACKED_PIXELS:
+                printf("packed pixels\n");
+                break;
+            case FB_TYPE_PLANES:
+                printf("planar (non-interleaved)\n");
+                break;
+            case FB_TYPE_INTERLEAVED_PLANES:
+                printf("planar (interleaved)\n");
+                break;
+            case FB_TYPE_TEXT:
+                printf("text (not a framebuffer)\n");
+                break;
+            case FB_TYPE_VGA_PLANES:
+                printf("planar (EGA/VGA)\n");
+                break;
+            default:
+                printf("?????\n");
+        }
+        printf("Bytes per scanline: %i\n", fixed_info.line_length);
+        printf("Visual type: ");
+        switch (fixed_info.visual)
+        {
+            case FB_VISUAL_TRUECOLOR:
+                printf("truecolor\n");
+                break;
+            case FB_VISUAL_PSEUDOCOLOR:
+                printf("pseudocolor\n");
+                break;
+            case FB_VISUAL_DIRECTCOLOR:
+                printf("directcolor\n");
+                break;
+            case FB_VISUAL_STATIC_PSEUDOCOLOR:
+                printf("fixed pseudocolor\n");
+                break;
+            default:
+                printf("?????\n");
+        }
+    }
+#endif
+
+    if (ioctl(fd, FBIOGET_VSCREENINFO, &var_info) < 0)
+    {
+        PEPPER_ERROR("Failed to get variable screen info in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+#if 1   /* print out some info */
+    {
+        printf("Bits per pixel:     %i\n", var_info.bits_per_pixel);
+        printf("Resolution:         %ix%i (virtual %ix%i)\n",
+               var_info.xres, var_info.yres,
+               var_info.xres_virtual, var_info.yres_virtual);
+        printf("Scrolling offset:   (%i,%i)\n",
+               var_info.xoffset, var_info.yoffset);
+        printf("Red channel:        %i bits at offset %i\n",
+               var_info.red.length, var_info.red.offset);
+        printf("Green channel:      %i bits at offset %i\n",
+               var_info.red.length, var_info.green.offset);
+        printf("Blue channel:       %i bits at offset %i\n",
+               var_info.red.length, var_info.blue.offset);
+    }
+#endif
+
+    output = (fbdev_output_t *)calloc(1, sizeof(fbdev_output_t));
+    if (!output)
+    {
+        PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    output->fbdev = fbdev;
+
+    output->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
+    output->w = var_info.xres;
+    output->h = var_info.yres;
+    output->pixel_format = PIXMAN_x8r8g8b8; /*FIXME*/
+    output->bits_per_pixel = var_info.bits_per_pixel;
+
+    wl_signal_init(&output->destroy_signal);
+    wl_signal_init(&output->mode_change_signal);
+    wl_signal_init(&output->frame_signal);
+
+    wl_list_insert(&fbdev->output_list, &output->link);
+
+    output->fb = mmap(NULL, output->w * output->h * (output->bits_per_pixel / 8),
+                      PROT_WRITE, MAP_SHARED, fd, 0);
+    if (!output->fb)
+    {
+        PEPPER_ERROR("Failed to mmap in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    output->fb_image = pixman_image_create_bits(output->pixel_format,
+                                                output->w, output->h, output->fb,
+                                                output->w * (output->bits_per_pixel / 8));
+    if (!output->fb_image)
+    {
+        PEPPER_ERROR("Failed to create pixman image in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    /* TODO : make shadow image? */
+
+    output->base = pepper_compositor_add_output(output->fbdev->compositor,
+                                                &fbdev_output_interface, output);
+    if (!output->base)
+    {
+        PEPPER_ERROR("Failed to add output to compositor in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    if (!init_renderer(output))
+    {
+        PEPPER_ERROR("Failed to initialize renderer in %s\n", __FUNCTION__);
+        goto error;
+    }
+
+    if (fd >=0)
+        close(fd);
+
+    return PEPPER_TRUE;
+
+error:
+
+    if (output)
+        pepper_fbdev_output_destroy(output);
+
+    if (fd >= 0)
+        close(fd);
+
+    return PEPPER_FALSE;
+}
+
+void
+pepper_fbdev_output_destroy(fbdev_output_t *output)
+{
+    fbdev_output_destroy(output);
+}
diff --git a/fbdev/src/pepper-fbdev.h b/fbdev/src/pepper-fbdev.h
new file mode 100644 (file)
index 0000000..0696881
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef PEPPER_FBDEV_H
+#define PEPPER_FBDEV_H
+
+#include <pepper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pepper_fbdev   pepper_fbdev_t;
+
+PEPPER_API pepper_fbdev_t *
+pepper_fbdev_create(pepper_compositor_t *compositor, const char *device/*FIXME*/);
+
+PEPPER_API void
+pepper_fbdev_destroy(pepper_fbdev_t *fbdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PEPPER_FBDEV_H */
diff --git a/fbdev/src/pepper-fbdev.pc.in b/fbdev/src/pepper-fbdev.pc.in
new file mode 100644 (file)
index 0000000..36e9d77
--- /dev/null
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+libexecdir=@libexecdir@
+pkglibexecdir=${libexecdir}/@PACKAGE@
+
+Name: Pepper FBDEV Backend Library
+Description: Pepper FBDEV backend library header and library files
+Version: @PEPPER_FBDEV_VERSION@
+
+Requires.private: @PEPPER_FBDEV_REQUIRES@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lpepper-fbdev
index 6ebe7ee..ca3bfa7 100644 (file)
@@ -27,6 +27,12 @@ PKG_CHECK_MODULES(DRM_BACKEND,
                    pepper-drm pepper-libinput
                    pepper-desktop-shell])
 
+# fbdev-backend
+PKG_CHECK_MODULES(FBDEV_BACKEND,
+                  [wayland-server pepper pepper-render
+                   pepper-fbdev pepper-libinput
+                   pepper-desktop-shell])
+
 # wayland-backend
 PKG_CHECK_MODULES(WAYLAND_BACKEND,
                   [wayland-server pepper pepper-render pepper-wayland pepper-desktop-shell])
index 3fe6e8e..17f67d0 100644 (file)
@@ -6,6 +6,12 @@ drm_backend_CFLAGS = $(DRM_BACKEND_CFLAGS)
 drm_backend_LDADD = $(DRM_BACKEND_LIBS)
 drm_backend_SOURCES = drm-backend.c
 
+# fbdev-backend
+noinst_PROGRAMS += fbdev-backend
+fbdev_backend_CFLAGS = $(FBDEV_BACKEND_CFLAGS)
+fbdev_backend_LDADD = $(FBDEV_BACKEND_LIBS)
+fbdev_backend_SOURCES = fbdev-backend.c
+
 # wayland-backend
 noinst_PROGRAMS += wayland-backend
 wayland_backend_CFLAGS = $(WAYLAND_BACKEND_CFLAGS)
diff --git a/samples/src/fbdev-backend.c b/samples/src/fbdev-backend.c
new file mode 100644 (file)
index 0000000..6f42438
--- /dev/null
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <pepper.h>
+#include <pepper-fbdev.h>
+#include <pepper-desktop-shell.h>
+
+/* TODO: */
+#define PEPPER_ASSERT(exp)
+#define PEPPER_ERROR(...)
+
+static int
+handle_sigint(int signal_number, void *data)
+{
+    struct wl_display *display = (struct wl_display *)data;
+    wl_display_terminate(display);
+
+    return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+    pepper_compositor_t    *compositor;
+    pepper_fbdev_t         *fbdev;
+    struct wl_display      *display;
+    struct wl_event_loop   *loop;
+    struct wl_event_source *sigint;
+
+    {   /* for gdb attach */
+        char cc;
+        int  ret;
+
+        ret = scanf("%c", &cc);
+        if (ret < 0)
+            return -1;
+    }
+
+    compositor = pepper_compositor_create("wayland-0");
+    PEPPER_ASSERT(compositor);
+
+    fbdev = pepper_fbdev_create(compositor, "");
+    PEPPER_ASSERT(fbdev);
+
+    if (!pepper_desktop_shell_init(compositor))
+        PEPPER_ASSERT(0);
+
+    display = pepper_compositor_get_display(compositor);
+    PEPPER_ASSERT(display);
+
+    loop = wl_display_get_event_loop(display);
+    sigint = wl_event_loop_add_signal(loop, SIGINT, handle_sigint, display);
+    PEPPER_ASSERT(sigint);
+
+    wl_display_run(display);
+
+    wl_event_source_remove(sigint);
+    pepper_fbdev_destroy(fbdev);
+    pepper_compositor_destroy(compositor);
+
+    return 0;
+}