st/egl: Add fbdev backend.
authorChia-I Wu <olv@lunarg.com>
Thu, 3 Jun 2010 11:52:15 +0000 (19:52 +0800)
committerChia-I Wu <olv@lunarg.com>
Fri, 11 Jun 2010 04:55:09 +0000 (12:55 +0800)
The backend is pure software.  It implements EGL_MESA_screen_surface
extension, and is kept simple by only exporting the current mode.

src/gallium/state_trackers/egl/Makefile
src/gallium/state_trackers/egl/fbdev/native_fbdev.c [new file with mode: 0644]
src/gallium/targets/Makefile.egl

index 8933890323adc81a4a21d316f92cdefa4bd969fb..a11dbf5395c0c8e8cfbc11b6559bc43dc20b8048 100644 (file)
@@ -31,9 +31,14 @@ kms_SOURCES = $(wildcard kms/*.c)
 kms_OBJECTS = $(kms_SOURCES:.c=.o)
 
 
-ALL_INCLUDES = $(common_INCLUDES) $(x11_INCLUDES) $(kms_INCLUDES)
-ALL_SOURCES = $(common_SOURCES) $(x11_SOURCES) $(kms_SOURCES)
-ALL_OBJECTS = $(common_OBJECTS) $(x11_OBJECTS) $(kms_OBJECTS)
+fbdev_INCLUDES = -I$(TOP)/src/gallium/winsys/sw -I$(TOP)/src/gallium/drivers
+fbdev_SOURCES = $(wildcard fbdev/*.c)
+fbdev_OBJECTS = $(fbdev_SOURCES:.c=.o)
+
+
+ALL_INCLUDES = $(common_INCLUDES) $(x11_INCLUDES) $(kms_INCLUDES) $(fbdev_INCLUDES)
+ALL_SOURCES = $(common_SOURCES) $(x11_SOURCES) $(kms_SOURCES) $(fbdev_SOURCES)
+ALL_OBJECTS = $(common_OBJECTS) $(x11_OBJECTS) $(kms_OBJECTS) $(fbdev_OBJECTS)
 
 ##### TARGETS #####
 
@@ -48,6 +53,9 @@ libeglx11.a: $(x11_OBJECTS) $(common_OBJECTS) Makefile
 libeglkms.a: $(kms_OBJECTS) $(common_OBJECTS) Makefile
        $(MKLIB) -o eglkms -static $(kms_OBJECTS) $(common_OBJECTS)
 
+libeglfbdev.a: $(fbdev_OBJECTS) $(common_OBJECTS) Makefile
+       $(MKLIB) -o eglfbdev -static $(fbdev_OBJECTS) $(common_OBJECTS)
+
 depend: 
        rm -f depend
        touch depend
@@ -73,4 +81,7 @@ $(x11_OBJECTS): %.o: %.c
 $(kms_OBJECTS): %.o: %.c
        $(CC) -c $(common_INCLUDES) $(kms_INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
 
+$(fbdev_OBJECTS): %.o: %.c
+       $(CC) -c $(common_INCLUDES) $(fbdev_INCLUDES) $(DEFINES) $(CFLAGS) $< -o $@
+
 sinclude depend
diff --git a/src/gallium/state_trackers/egl/fbdev/native_fbdev.c b/src/gallium/state_trackers/egl/fbdev/native_fbdev.c
new file mode 100644 (file)
index 0000000..d70b7c6
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/fb.h>
+
+#include "pipe/p_screen.h"
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "util/u_pointer.h"
+
+#include "common/native.h"
+#include "common/native_helper.h"
+#include "fbdev/fbdev_sw_winsys.h"
+
+struct fbdev_display {
+   struct native_display base;
+
+   int fd;
+   struct native_event_handler *event_handler;
+
+   struct fb_fix_screeninfo finfo;
+   struct fb_var_screeninfo vinfo;
+
+   struct native_config config;
+   struct native_connector connector;
+   struct native_mode mode;
+
+   struct fbdev_surface *current_surface;
+};
+
+struct fbdev_surface {
+   struct native_surface base;
+
+   struct fbdev_display *fbdpy;
+   struct resource_surface *rsurf;
+   int width, height;
+
+   unsigned int sequence_number;
+
+   boolean is_current;
+};
+
+static INLINE struct fbdev_display *
+fbdev_display(const struct native_display *ndpy)
+{
+   return (struct fbdev_display *) ndpy;
+}
+
+static INLINE struct fbdev_surface *
+fbdev_surface(const struct native_surface *nsurf)
+{
+   return (struct fbdev_surface *) nsurf;
+}
+
+static boolean
+fbdev_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+                     unsigned int *seq_num, struct pipe_resource **textures,
+                     int *width, int *height)
+{
+   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+   if (!resource_surface_add_resources(fbsurf->rsurf, attachment_mask))
+      return FALSE;
+   if (textures)
+      resource_surface_get_resources(fbsurf->rsurf, textures, attachment_mask);
+
+   if (seq_num)
+      *seq_num = fbsurf->sequence_number;
+   if (width)
+      *width = fbsurf->width;
+   if (height)
+      *height = fbsurf->height;
+
+   return TRUE;
+}
+
+static boolean
+fbdev_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+   if (!fbsurf->is_current)
+      return TRUE;
+
+   return resource_surface_present(fbsurf->rsurf,
+         NATIVE_ATTACHMENT_FRONT_LEFT, NULL);
+}
+
+static boolean
+fbdev_surface_swap_buffers(struct native_surface *nsurf)
+{
+   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+   struct fbdev_display *fbdpy = fbsurf->fbdpy;
+   boolean ret = TRUE;
+
+   if (fbsurf->is_current) {
+      ret = resource_surface_present(fbsurf->rsurf,
+            NATIVE_ATTACHMENT_BACK_LEFT, NULL);
+   }
+
+   resource_surface_swap_buffers(fbsurf->rsurf,
+         NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE);
+   /* the front/back textures are swapped */
+   fbsurf->sequence_number++;
+   fbdpy->event_handler->invalid_surface(&fbdpy->base,
+         &fbsurf->base, fbsurf->sequence_number);
+
+   return ret;
+}
+
+static void
+fbdev_surface_wait(struct native_surface *nsurf)
+{
+   /* no-op */
+}
+
+static void
+fbdev_surface_destroy(struct native_surface *nsurf)
+{
+   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+   resource_surface_destroy(fbsurf->rsurf);
+   FREE(fbsurf);
+}
+
+static struct native_surface *
+fbdev_display_create_scanout_surface(struct native_display *ndpy,
+                                   const struct native_config *nconf,
+                                   uint width, uint height)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   struct fbdev_surface *fbsurf;
+
+   fbsurf = CALLOC_STRUCT(fbdev_surface);
+   if (!fbsurf)
+      return NULL;
+
+   fbsurf->fbdpy = fbdpy;
+   fbsurf->width = width;
+   fbsurf->height = height;
+
+   fbsurf->rsurf = resource_surface_create(fbdpy->base.screen,
+         nconf->color_format,
+         PIPE_BIND_RENDER_TARGET |
+         PIPE_BIND_DISPLAY_TARGET |
+         PIPE_BIND_SCANOUT);
+   if (!fbsurf->rsurf) {
+      FREE(fbsurf);
+      return NULL;
+   }
+
+   resource_surface_set_size(fbsurf->rsurf, fbsurf->width, fbsurf->height);
+
+   fbsurf->base.destroy = fbdev_surface_destroy;
+   fbsurf->base.swap_buffers = fbdev_surface_swap_buffers;
+   fbsurf->base.flush_frontbuffer = fbdev_surface_flush_frontbuffer;
+   fbsurf->base.validate = fbdev_surface_validate;
+   fbsurf->base.wait = fbdev_surface_wait;
+
+   return &fbsurf->base;
+}
+
+static boolean
+fbdev_display_program(struct native_display *ndpy, int crtc_idx,
+                      struct native_surface *nsurf, uint x, uint y,
+                      const struct native_connector **nconns, int num_nconns,
+                      const struct native_mode *nmode)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+
+   if (x || y)
+      return FALSE;
+
+   if (fbdpy->current_surface) {
+      if (fbdpy->current_surface == fbsurf)
+         return TRUE;
+      fbdpy->current_surface->is_current = FALSE;
+   }
+
+   if (fbsurf)
+      fbsurf->is_current = TRUE;
+   fbdpy->current_surface = fbsurf;
+
+   return TRUE;
+}
+
+static const struct native_mode **
+fbdev_display_get_modes(struct native_display *ndpy,
+                      const struct native_connector *nconn,
+                      int *num_modes)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   const struct native_mode **modes;
+
+   modes = MALLOC(sizeof(*modes));
+   if (modes) {
+      modes[0] = &fbdpy->mode;
+      if (num_modes)
+         *num_modes = 1;
+   }
+
+   return modes;
+}
+
+static const struct native_connector **
+fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors,
+                           int *num_crtc)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   const struct native_connector **connectors;
+
+   connectors = MALLOC(sizeof(*connectors));
+   if (connectors) {
+      connectors[0] = &fbdpy->connector;
+      if (num_connectors)
+         *num_connectors = 1;
+   }
+
+   return connectors;
+}
+
+static struct native_display_modeset fbdev_display_modeset = {
+   .get_connectors = fbdev_display_get_connectors,
+   .get_modes = fbdev_display_get_modes,
+   .create_scanout_surface = fbdev_display_create_scanout_surface,
+   .program = fbdev_display_program
+};
+
+static const struct native_config **
+fbdev_display_get_configs(struct native_display *ndpy, int *num_configs)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   const struct native_config **configs;
+
+   configs = MALLOC(sizeof(*configs));
+   if (configs) {
+      configs[0] = &fbdpy->config;
+      if (num_configs)
+         *num_configs = 1;
+   }
+
+   return configs;
+}
+
+static int
+fbdev_display_get_param(struct native_display *ndpy,
+                      enum native_param_type param)
+{
+   int val;
+
+   switch (param) {
+   default:
+      val = 0;
+      break;
+   }
+
+   return val;
+}
+
+static void
+fbdev_display_destroy(struct native_display *ndpy)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+
+   fbdpy->base.screen->destroy(fbdpy->base.screen);
+   close(fbdpy->fd);
+   FREE(fbdpy);
+}
+
+static boolean
+fbdev_display_init_modes(struct native_display *ndpy)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   struct native_mode *nmode = &fbdpy->mode;
+
+   nmode->desc = "Current Mode";
+   nmode->width = fbdpy->vinfo.xres;
+   nmode->height = fbdpy->vinfo.yres;
+   nmode->refresh_rate = 60 * 1000; /* dummy */
+
+   return TRUE;
+}
+
+static boolean
+fbdev_display_init_connectors(struct native_display *ndpy)
+{
+   return TRUE;
+}
+
+static enum pipe_format
+vinfo_to_format(const struct fb_var_screeninfo *vinfo)
+{
+   enum pipe_format format = PIPE_FORMAT_NONE;
+
+   switch (vinfo->bits_per_pixel) {
+   case 32:
+      if (vinfo->red.length == 8 &&
+          vinfo->green.length == 8 &&
+          vinfo->blue.length == 8) {
+         format = (vinfo->transp.length == 8) ?
+            PIPE_FORMAT_B8G8R8A8_UNORM : PIPE_FORMAT_B8G8R8X8_UNORM;
+      }
+      break;
+   case 16:
+      if (vinfo->red.length == 5 &&
+          vinfo->green.length == 6 &&
+          vinfo->blue.length == 5 &&
+          vinfo->transp.length == 0)
+         format = PIPE_FORMAT_B5G6R5_UNORM;
+      break;
+   default:
+      break;
+   }
+
+   return format;
+}
+
+static boolean
+fbdev_display_init_configs(struct native_display *ndpy)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   struct native_config *nconf = &fbdpy->config;
+
+   nconf->color_format = vinfo_to_format(&fbdpy->vinfo);
+   if (nconf->color_format == PIPE_FORMAT_NONE)
+      return FALSE;
+
+   nconf->buffer_mask =
+      (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
+      (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+
+   nconf->scanout_bit = TRUE;
+
+   return TRUE;
+}
+
+static boolean
+fbdev_display_init(struct native_display *ndpy)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   struct sw_winsys *ws;
+
+   if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo))
+      return FALSE;
+
+   if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo))
+      return FALSE;
+
+   if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR ||
+       fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS)
+      return FALSE;
+
+   if (!fbdev_display_init_configs(&fbdpy->base) ||
+       !fbdev_display_init_connectors(&fbdpy->base) ||
+       !fbdev_display_init_modes(&fbdpy->base))
+      return FALSE;
+
+   ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format);
+   if (ws)
+      fbdpy->base.screen = native_create_sw_screen(ws);
+
+   if (fbdpy->base.screen) {
+      if (!fbdpy->base.screen->is_format_supported(fbdpy->base.screen,
+               fbdpy->config.color_format, PIPE_TEXTURE_2D, 0,
+               PIPE_BIND_RENDER_TARGET, 0)) {
+         fbdpy->base.screen->destroy(fbdpy->base.screen);
+         fbdpy->base.screen = NULL;
+      }
+   }
+
+   return (fbdpy->base.screen != NULL);
+}
+
+static struct native_display *
+fbdev_display_create(int fd, struct native_event_handler *event_handler)
+{
+   struct fbdev_display *fbdpy;
+
+   fbdpy = CALLOC_STRUCT(fbdev_display);
+   if (!fbdpy)
+      return NULL;
+
+   fbdpy->fd = fd;
+   fbdpy->event_handler = event_handler;
+
+   if (!fbdev_display_init(&fbdpy->base)) {
+      FREE(fbdpy);
+      return NULL;
+   }
+
+   fbdpy->base.destroy = fbdev_display_destroy;
+   fbdpy->base.get_param = fbdev_display_get_param;
+   fbdpy->base.get_configs = fbdev_display_get_configs;
+
+   fbdpy->base.modeset = &fbdev_display_modeset;
+
+   return &fbdpy->base;
+}
+
+struct native_probe *
+native_create_probe(EGLNativeDisplayType dpy)
+{
+   return NULL;
+}
+
+enum native_probe_result
+native_get_probe_result(struct native_probe *nprobe)
+{
+   return NATIVE_PROBE_UNKNOWN;
+}
+
+const char *
+native_get_name(void)
+{
+   return "FBDEV";
+}
+
+struct native_display *
+native_create_display(EGLNativeDisplayType dpy,
+                      struct native_event_handler *event_handler)
+{
+   struct native_display *ndpy;
+   int fd;
+
+   /* well, this makes fd 0 being ignored */
+   if (dpy == EGL_DEFAULT_DISPLAY) {
+      fd = open("/dev/fb0", O_RDWR);
+   }
+   else {
+      fd = dup((int) pointer_to_intptr((void *) dpy));
+   }
+   if (fd < 0)
+      return NULL;
+
+   ndpy = fbdev_display_create(fd, event_handler);
+   if (!ndpy)
+      close(fd);
+
+   return ndpy;
+}
index 4fa13e85ce4a04431b6f9ff36b353b8c47aafb3f..49ca039337eb4a54553c5c8fe8432561079bf4a3 100644 (file)
@@ -24,15 +24,26 @@ x11_ST = $(TOP)/src/gallium/state_trackers/egl/libeglx11.a \
 
 x11_LIBS = $(common_LIBS) -lX11 -lXext -lXfixes
 
+kms_ST = $(TOP)/src/gallium/state_trackers/egl/libeglkms.a
+kms_LIBS = $(common_LIBS)
+
+fbdev_ST = \
+       $(TOP)/src/gallium/state_trackers/egl/libeglfbdev.a \
+       $(TOP)/src/gallium/winsys/sw/fbdev/libfbdev.a \
+       $(TOP)/src/gallium/drivers/softpipe/libsoftpipe.a \
+       $(TOP)/src/gallium/drivers/identity/libidentity.a \
+       $(TOP)/src/gallium/drivers/trace/libtrace.a \
+       $(TOP)/src/gallium/drivers/rbug/librbug.a
+fbdev_LIBS = $(common_LIBS)
+
 ifeq ($(MESA_LLVM),1)
 x11_ST += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a
 x11_LIBS += $(LLVM_LIBS)
+fbdev_ST += $(TOP)/src/gallium/drivers/llvmpipe/libllvmpipe.a
+fbdev_LIBS += $(LLVM_LIBS)
 LDFLAGS += $(LLVM_LDFLAGS)
 endif
 
-kms_ST = $(TOP)/src/gallium/state_trackers/egl/libeglkms.a
-kms_LIBS = $(common_LIBS)
-
 ### Include directories
 INCLUDES = \
        -I$(TOP)/include \
@@ -75,6 +86,9 @@ egl_x11_$(EGL_DRIVER_NAME).so: $(EGL_DRIVER_OBJECTS) $(x11_ST) $(EGL_DRIVER_PIPE
 egl_kms_$(EGL_DRIVER_NAME).so: $(EGL_DRIVER_OBJECTS) $(kms_ST) $(EGL_DRIVER_PIPES) $(GALLIUM_AUXILIARIES) Makefile
        $(call mklib-egl,kms)
 
+egl_fbdev_$(EGL_DRIVER_NAME).so: $(EGL_DRIVER_OBJECTS) $(fbdev_ST) $(EGL_DRIVER_PIPES) $(GALLIUM_AUXILIARIES) Makefile
+       $(call mklib-egl,fbdev)
+
 clean:
        -rm -f $(EGL_DRIVER_OBJECTS)
        -rm -f $(EGL_DISPLAY_DRIVERS)