st/egl: update fbdev backend
authorChia-I Wu <olv@lunarg.com>
Tue, 28 Jun 2011 01:22:01 +0000 (10:22 +0900)
committerChia-I Wu <olv@lunarg.com>
Tue, 28 Jun 2011 06:07:30 +0000 (15:07 +0900)
Considering fbdev as an in-kernel window system,

 - opening a device opens a connection
 - there is only one window: the framebuffer
 - fb_var_screeninfo decides window position, size, and even color format
 - there is no pixmap

Now EGL is built on top of this window system.  So we should have

 - the fd as the handle of the native display
 - reject all but one native window: NULL
 - no pixmap support

modeset support is still around, but it should be removed soon.

src/gallium/state_trackers/egl/fbdev/native_fbdev.c
src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.c
src/gallium/winsys/sw/fbdev/fbdev_sw_winsys.h

index 49e3728535dbd21f755dff414849b92be02d1691..6772d379f7355921be3127baf276cc2b04c7a0f9 100644 (file)
  *    Chia-I Wu <olv@lunarg.com>
  */
 
+/**
+ * Considering fbdev as an in-kernel window system,
+ *
+ *  - opening a device opens a connection
+ *  - there is only one window: the framebuffer
+ *  - fb_var_screeninfo decides window position, size, and even color format
+ *  - there is no pixmap
+ *
+ * Now EGL is built on top of this window system.  So we should have
+ *
+ *  - the fd as the handle of the native display
+ *  - reject all but one native window: NULL
+ *  - no pixmap support
+ */
+
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -48,13 +63,10 @@ struct fbdev_display {
    const struct native_event_handler *event_handler;
 
    struct fb_fix_screeninfo finfo;
-   struct fb_var_screeninfo vinfo;
-
+   struct fb_var_screeninfo config_vinfo;
    struct native_config config;
-   struct native_connector connector;
-   struct native_mode mode;
 
-   struct fbdev_surface *current_surface;
+   boolean assume_fixed_vinfo;
 };
 
 struct fbdev_surface {
@@ -66,7 +78,7 @@ struct fbdev_surface {
 
    unsigned int sequence_number;
 
-   boolean is_current;
+   struct fbdev_sw_drawable drawable;
 };
 
 static INLINE struct fbdev_display *
@@ -103,38 +115,70 @@ fbdev_surface_validate(struct native_surface *nsurf, uint attachment_mask,
    return TRUE;
 }
 
-static boolean
-fbdev_surface_flush_frontbuffer(struct native_surface *nsurf)
+static enum pipe_format
+vinfo_to_format(const struct fb_var_screeninfo *vinfo)
 {
-   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+   enum pipe_format format = PIPE_FORMAT_NONE;
 
-   if (!fbsurf->is_current)
-      return TRUE;
+   /* should also check channel offsets... */
+   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 resource_surface_present(fbsurf->rsurf,
-         NATIVE_ATTACHMENT_FRONT_LEFT, NULL);
+   return format;
 }
 
 static boolean
-fbdev_surface_swap_buffers(struct native_surface *nsurf)
+fbdev_surface_update_drawable(struct native_surface *nsurf,
+                              const struct fb_var_screeninfo *vinfo)
 {
    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);
+   unsigned x, y, width, height;
+
+   x = vinfo->xoffset;
+   y = vinfo->yoffset;
+   width = MIN2(vinfo->xres, fbsurf->width);
+   height = MIN2(vinfo->yres, fbsurf->height);
+
+   /* sanitize the values */
+   if (x + width > vinfo->xres_virtual) {
+      if (x > vinfo->xres_virtual)
+         width = 0;
+      else
+         width = vinfo->xres_virtual - x;
+   }
+   if (y + height > vinfo->yres_virtual) {
+      if (y > vinfo->yres_virtual)
+         height = 0;
+      else
+         height = vinfo->yres_virtual - y;
    }
 
-   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);
+   fbsurf->drawable.format = vinfo_to_format(vinfo);
+   fbsurf->drawable.x = vinfo->xoffset;
+   fbsurf->drawable.y = vinfo->yoffset;
+   fbsurf->drawable.width = vinfo->xres;
+   fbsurf->drawable.height = vinfo->yres;
 
-   return ret;
+   return (fbsurf->drawable.format != PIPE_FORMAT_NONE &&
+           fbsurf->drawable.width &&
+           fbsurf->drawable.height);
 }
 
 static boolean
@@ -143,21 +187,43 @@ fbdev_surface_present(struct native_surface *nsurf,
                       boolean preserve,
                       uint swap_interval)
 {
-   boolean ret;
+   struct fbdev_surface *fbsurf = fbdev_surface(nsurf);
+   struct fbdev_display *fbdpy = fbsurf->fbdpy;
+   boolean ret = FALSE;
 
-   if (preserve || swap_interval)
+   if (swap_interval)
+      return FALSE;
+   if (natt != NATIVE_ATTACHMENT_BACK_LEFT)
       return FALSE;
 
-   switch (natt) {
-   case NATIVE_ATTACHMENT_FRONT_LEFT:
-      ret = fbdev_surface_flush_frontbuffer(nsurf);
-      break;
-   case NATIVE_ATTACHMENT_BACK_LEFT:
-      ret = fbdev_surface_swap_buffers(nsurf);
-      break;
-   default:
-      ret = FALSE;
-      break;
+   if (!fbdpy->assume_fixed_vinfo) {
+      struct fb_var_screeninfo vinfo;
+
+      memset(&vinfo, 0, sizeof(vinfo));
+      if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo))
+         return FALSE;
+
+      /* present the surface */
+      if (fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) {
+         ret = resource_surface_present(fbsurf->rsurf,
+               natt, (void *) &fbsurf->drawable);
+      }
+
+      fbsurf->width = vinfo.xres;
+      fbsurf->height = vinfo.yres;
+
+      if (resource_surface_set_size(fbsurf->rsurf,
+               fbsurf->width, fbsurf->height)) {
+         /* surface resized */
+         fbsurf->sequence_number++;
+         fbdpy->event_handler->invalid_surface(&fbdpy->base,
+               &fbsurf->base, fbsurf->sequence_number);
+      }
+   }
+   else {
+      /* the drawable never changes */
+      ret = resource_surface_present(fbsurf->rsurf,
+            natt, (void *) &fbsurf->drawable);
    }
 
    return ret;
@@ -179,26 +245,48 @@ fbdev_surface_destroy(struct native_surface *nsurf)
 }
 
 static struct native_surface *
-fbdev_display_create_scanout_surface(struct native_display *ndpy,
-                                   const struct native_config *nconf,
-                                   uint width, uint height)
+fbdev_display_create_window_surface(struct native_display *ndpy,
+                                    EGLNativeWindowType win,
+                                    const struct native_config *nconf)
 {
    struct fbdev_display *fbdpy = fbdev_display(ndpy);
    struct fbdev_surface *fbsurf;
+   struct fb_var_screeninfo vinfo;
+
+   /* there is only one native window: NULL */
+   if (win)
+      return NULL;
 
    fbsurf = CALLOC_STRUCT(fbdev_surface);
    if (!fbsurf)
       return NULL;
 
    fbsurf->fbdpy = fbdpy;
-   fbsurf->width = width;
-   fbsurf->height = height;
+
+   /* get current vinfo */
+   if (fbdpy->assume_fixed_vinfo) {
+      vinfo = fbdpy->config_vinfo;
+   }
+   else {
+      memset(&vinfo, 0, sizeof(vinfo));
+      if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &vinfo)) {
+         FREE(fbsurf);
+         return NULL;
+      }
+   }
+
+   fbsurf->width = vinfo.xres;
+   fbsurf->height = vinfo.yres;
+
+   if (!fbdev_surface_update_drawable(&fbsurf->base, &vinfo)) {
+      FREE(fbsurf);
+      return NULL;
+   }
 
    fbsurf->rsurf = resource_surface_create(fbdpy->base.screen,
          nconf->color_format,
          PIPE_BIND_RENDER_TARGET |
-         PIPE_BIND_DISPLAY_TARGET |
-         PIPE_BIND_SCANOUT);
+         PIPE_BIND_DISPLAY_TARGET);
    if (!fbsurf->rsurf) {
       FREE(fbsurf);
       return NULL;
@@ -214,42 +302,43 @@ fbdev_display_create_scanout_surface(struct native_display *ndpy,
    return &fbsurf->base;
 }
 
+static struct native_surface *
+fbdev_display_create_scanout_surface(struct native_display *ndpy,
+                                     const struct native_config *nconf,
+                                     uint width, uint height)
+{
+   return fbdev_display_create_window_surface(ndpy,
+         (EGLNativeWindowType) NULL, nconf);
+}
+
 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)
+                        const struct native_connector *nconn,
+                        int *num_modes)
 {
-   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   static struct native_mode mode;
    const struct native_mode **modes;
 
+   if (!mode.desc) {
+      struct fbdev_display *fbdpy = fbdev_display(ndpy);
+      mode.desc = "Current Mode";
+      mode.width = fbdpy->config_vinfo.xres;
+      mode.height = fbdpy->config_vinfo.yres;
+      mode.refresh_rate = 60 * 1000; /* dummy */
+   }
+
    modes = MALLOC(sizeof(*modes));
    if (modes) {
-      modes[0] = &fbdpy->mode;
+      modes[0] = &mode;
       if (num_modes)
          *num_modes = 1;
    }
@@ -261,12 +350,12 @@ 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);
+   static struct native_connector connector;
    const struct native_connector **connectors;
 
    connectors = MALLOC(sizeof(*connectors));
    if (connectors) {
-      connectors[0] = &fbdpy->connector;
+      connectors[0] = &connector;
       if (num_connectors)
          *num_connectors = 1;
    }
@@ -274,7 +363,8 @@ fbdev_display_get_connectors(struct native_display *ndpy, int *num_connectors,
    return connectors;
 }
 
-static struct native_display_modeset fbdev_display_modeset = {
+/* remove modeset support one day! */
+static const 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,
@@ -304,8 +394,10 @@ fbdev_display_get_param(struct native_display *ndpy,
    int val;
 
    switch (param) {
-   case NATIVE_PARAM_USE_NATIVE_BUFFER:
    case NATIVE_PARAM_PRESERVE_BUFFER:
+      val = 1;
+      break;
+   case NATIVE_PARAM_USE_NATIVE_BUFFER:
    case NATIVE_PARAM_MAX_SWAP_INTERVAL:
    default:
       val = 0;
@@ -325,80 +417,13 @@ fbdev_display_destroy(struct native_display *ndpy)
    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_screen(struct native_display *ndpy)
 {
    struct fbdev_display *fbdpy = fbdev_display(ndpy);
    struct sw_winsys *ws;
 
-   ws = fbdev_create_sw_winsys(fbdpy->fd, fbdpy->config.color_format);
+   ws = fbdev_create_sw_winsys(fbdpy->fd);
    if (!ws)
       return FALSE;
 
@@ -420,6 +445,26 @@ fbdev_display_init_screen(struct native_display *ndpy)
    return TRUE;
 }
 
+static boolean
+fbdev_display_init_config(struct native_display *ndpy)
+{
+   struct fbdev_display *fbdpy = fbdev_display(ndpy);
+   struct native_config *nconf = &fbdpy->config;
+
+   if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->config_vinfo))
+      return FALSE;
+
+   nconf->color_format = vinfo_to_format(&fbdpy->config_vinfo);
+   if (nconf->color_format == PIPE_FORMAT_NONE)
+      return FALSE;
+
+   nconf->buffer_mask = (1 << NATIVE_ATTACHMENT_BACK_LEFT);
+
+   nconf->window_bit = TRUE;
+
+   return TRUE;
+}
+
 static struct native_display *
 fbdev_display_create(int fd, const struct native_event_handler *event_handler)
 {
@@ -435,23 +480,24 @@ fbdev_display_create(int fd, const struct native_event_handler *event_handler)
    if (ioctl(fbdpy->fd, FBIOGET_FSCREENINFO, &fbdpy->finfo))
       goto fail;
 
-   if (ioctl(fbdpy->fd, FBIOGET_VSCREENINFO, &fbdpy->vinfo))
-      goto fail;
-
    if (fbdpy->finfo.visual != FB_VISUAL_TRUECOLOR ||
        fbdpy->finfo.type != FB_TYPE_PACKED_PIXELS)
       goto fail;
 
-   if (!fbdev_display_init_configs(&fbdpy->base) ||
-       !fbdev_display_init_connectors(&fbdpy->base) ||
-       !fbdev_display_init_modes(&fbdpy->base))
+   if (!fbdev_display_init_config(&fbdpy->base))
       goto fail;
 
+   fbdpy->assume_fixed_vinfo = TRUE;
+
    fbdpy->base.init_screen = fbdev_display_init_screen;
    fbdpy->base.destroy = fbdev_display_destroy;
    fbdpy->base.get_param = fbdev_display_get_param;
    fbdpy->base.get_configs = fbdev_display_get_configs;
 
+   fbdpy->base.create_window_surface = fbdev_display_create_window_surface;
+
+   /* we'd like to remove modeset support one day */
+   fbdpy->config.scanout_bit = TRUE;
    fbdpy->base.modeset = &fbdev_display_modeset;
 
    return &fbdpy->base;
index f4f4cd7969b87e95605ff6dc69a0862f1705ac83..38d88f63aa2d5ee7fc5dca9aca010e9aedc8992d 100644 (file)
@@ -54,10 +54,8 @@ struct fbdev_sw_winsys
    struct sw_winsys base;
 
    int fd;
-   enum pipe_format format;
 
    struct fb_fix_screeninfo finfo;
-   void *fbmem;
    unsigned rows;
    unsigned stride;
 };
@@ -77,22 +75,53 @@ fbdev_sw_winsys(struct sw_winsys *ws)
 static void
 fbdev_displaytarget_display(struct sw_winsys *ws,
                             struct sw_displaytarget *dt,
-                            void *context_private)
+                            void *winsys_private)
 {
    struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
-   struct fbdev_sw_displaytarget *fbdt = fbdev_sw_displaytarget(dt);
-   unsigned rows, len, i;
+   struct fbdev_sw_displaytarget *src = fbdev_sw_displaytarget(dt);
+   const struct fbdev_sw_drawable *dst =
+      (const struct fbdev_sw_drawable *) winsys_private;
+   unsigned height, row_offset, row_len, i;
+   void *fbmem;
+
+   /* FIXME format conversion */
+   if (dst->format != src->format) {
+      assert(0);
+      return;
+   }
 
-   rows = MIN2(fbdt->height, fbdev->rows);
-   len = util_format_get_stride(fbdt->format, fbdt->width);
-   len = MIN2(len, fbdev->stride);
+   height = dst->height;
+   if (dst->y + dst->height > fbdev->rows) {
+      /* nothing to copy */
+      if (dst->y >= fbdev->rows)
+         return;
 
-   for (i = 0; i < rows; i++) {
-      void *dst = fbdev->fbmem + fbdev->stride * i;
-      void *src = fbdt->data + fbdt->stride * i;
+      height = fbdev->rows - dst->y;
+   }
+
+   row_offset = util_format_get_stride(dst->format, dst->x);
+   row_len = util_format_get_stride(dst->format, dst->width);
+   if (row_offset + row_len > fbdev->stride) {
+      /* nothing to copy */
+      if (row_offset >= fbdev->stride)
+         return;
 
-      memcpy(dst, src, len);
+      row_len = fbdev->stride - row_offset;
    }
+
+   fbmem = mmap(0, fbdev->finfo.smem_len,
+         PROT_WRITE, MAP_SHARED, fbdev->fd, 0);
+   if (fbmem == MAP_FAILED)
+      return;
+
+   for (i = 0; i < height; i++) {
+      char *from = (char *) src->data + src->stride * i;
+      char *to = (char *) fbmem + fbdev->stride * (dst->y + i) + row_offset;
+
+      memcpy(to, from, row_len);
+   }
+
+   munmap(fbmem, fbdev->finfo.smem_len);
 }
 
 static void
@@ -133,13 +162,9 @@ fbdev_displaytarget_create(struct sw_winsys *ws,
                            unsigned alignment,
                            unsigned *stride)
 {
-   struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
    struct fbdev_sw_displaytarget *fbdt;
    unsigned nblocksy, size, format_stride;
 
-   if (fbdev->format != format)
-      return NULL;
-
    fbdt = CALLOC_STRUCT(fbdev_sw_displaytarget);
    if (!fbdt)
       return NULL;
@@ -170,8 +195,7 @@ fbdev_is_displaytarget_format_supported(struct sw_winsys *ws,
                                         unsigned tex_usage,
                                         enum pipe_format format)
 {
-   struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
-   return (fbdev->format == format);
+   return TRUE;
 }
 
 static void
@@ -179,12 +203,11 @@ fbdev_destroy(struct sw_winsys *ws)
 {
    struct fbdev_sw_winsys *fbdev = fbdev_sw_winsys(ws);
 
-   munmap(fbdev->fbmem, fbdev->finfo.smem_len);
    FREE(fbdev);
 }
 
 struct sw_winsys *
-fbdev_create_sw_winsys(int fd, enum pipe_format format)
+fbdev_create_sw_winsys(int fd)
 {
    struct fbdev_sw_winsys *fbdev;
 
@@ -193,19 +216,11 @@ fbdev_create_sw_winsys(int fd, enum pipe_format format)
       return NULL;
 
    fbdev->fd = fd;
-   fbdev->format = format;
    if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->finfo)) {
       FREE(fbdev);
       return NULL;
    }
 
-   fbdev->fbmem = mmap(0, fbdev->finfo.smem_len,
-         PROT_WRITE, MAP_SHARED, fbdev->fd, 0);
-   if (fbdev->fbmem == MAP_FAILED) {
-      FREE(fbdev);
-      return NULL;
-   }
-
    fbdev->rows = fbdev->finfo.smem_len / fbdev->finfo.line_length;
    fbdev->stride = fbdev->finfo.line_length;
 
index d958ab9db3e6705b40995d46c5617a31b4cf975b..59d8a8f5cfe57abfc8350dbf353360f43fe480b2 100644 (file)
 struct sw_winsys;
 enum pipe_format;
 
+/* for pipe_screen::flush_frontbuffer */
+struct fbdev_sw_drawable {
+   enum pipe_format format;
+   unsigned x, y;
+   unsigned width, height;
+};
+
 struct sw_winsys *
-fbdev_create_sw_winsys(int fd, enum pipe_format format);
+fbdev_create_sw_winsys(int fd);
 
 #endif /* FBDEV_SW_WINSYS */