Mesa (master): egl_dri2: Use double buffering for window surfaces

Kristian Høgsberg krh at kemper.freedesktop.org
Fri Feb 11 04:52:17 UTC 2011


Module: Mesa
Branch: master
Commit: 87dde5b1cd596c4008695ff2db9469f88c09f925
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=87dde5b1cd596c4008695ff2db9469f88c09f925

Author: Benjamin Franzke <benjaminfranzke at googlemail.com>
Date:   Wed Feb  9 15:30:20 2011 +0100

egl_dri2: Use double buffering for window surfaces

---

 src/egl/drivers/dri2/egl_dri2.c         |   75 ++++++++++++++++++++++++-------
 src/egl/drivers/dri2/egl_dri2.h         |    5 +-
 src/egl/drivers/dri2/platform_drm.c     |    2 +-
 src/egl/drivers/dri2/platform_wayland.c |   35 +++++++++++---
 src/egl/drivers/dri2/platform_x11.c     |   33 ++++++++-----
 5 files changed, 110 insertions(+), 40 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 3e51077..2c4deaf 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -98,13 +98,16 @@ EGLint dri2_to_egl_attribute_map[] = {
 
 struct dri2_egl_config *
 dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
-		int depth, EGLint surface_type)
+		int depth, EGLint surface_type, const EGLint *attr_list)
 {
    struct dri2_egl_config *conf;
    struct dri2_egl_display *dri2_dpy;
    _EGLConfig base;
    unsigned int attrib, value, double_buffer;
    EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
+   _EGLConfig *matching_config;
+   EGLint num_configs = 0;
+   EGLint config_id;
    int i;
 
    dri2_dpy = disp->DriverData;
@@ -157,15 +160,9 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
       }
    }
 
-   /* In EGL, double buffer or not isn't a config attribute.  Pixmaps
-    * surfaces are always single buffered, pbuffer surfaces are always
-    * back buffers and windows can be either, selected by passing an
-    * attribute at window surface construction time.  To support this
-    * we ignore all double buffer configs and manipulate the buffer we
-    * return in the getBuffer callback to get the behaviour we want. */
-
-   if (double_buffer)
-      return NULL;
+   if (attr_list)
+      for (i = 0; attr_list[i] != EGL_NONE; i += 2)
+         _eglSetConfigKey(&base, attr_list[i], attr_list[i+1]);
 
    if (depth > 0 && depth != base.BufferSize)
       return NULL;
@@ -188,13 +185,48 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
       return NULL;
    }
 
-   conf = malloc(sizeof *conf);
-   if (conf != NULL) {
+   config_id = base.ConfigID;
+   base.ConfigID    = EGL_DONT_CARE;
+   base.SurfaceType = EGL_DONT_CARE;
+   num_configs = _eglFilterArray(disp->Configs, (void **) &matching_config, 1,
+                                 (_EGLArrayForEach) _eglMatchConfig, &base);
+
+   if (num_configs == 1) {
+      conf = (struct dri2_egl_config *) matching_config;
+
+      if (double_buffer && !conf->dri_double_config)
+         conf->dri_double_config = dri_config;
+      else if (!double_buffer && !conf->dri_single_config)
+         conf->dri_single_config = dri_config;
+      else
+         /* a similar config type is already added
+          * => attach it as new config
+          */
+         num_configs = 0;
+   }
+
+   if (num_configs == 0) {
+      conf = malloc(sizeof *conf);
+      if (conf == NULL)
+         return NULL;
+
       memcpy(&conf->base, &base, sizeof base);
-      conf->dri_config = dri_config;
+      if (double_buffer) {
+         conf->dri_double_config = dri_config;
+         conf->dri_single_config = NULL;
+      } else {
+         conf->dri_single_config = dri_config;
+         conf->dri_double_config = NULL;
+      }
+      conf->base.SurfaceType = 0;
+      conf->base.ConfigID = config_id;
+
       _eglLinkConfig(&conf->base);
    }
 
+   conf->base.SurfaceType |= surface_type & (!double_buffer ? EGL_PIXMAP_BIT:
+         (EGL_WINDOW_BIT | EGL_PBUFFER_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT));
+
    return conf;
 }
 
@@ -491,8 +523,19 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
       return NULL;
    }
 
-   if (conf != NULL)
-      dri_config = dri2_config->dri_config;
+   if (conf != NULL) {
+      /* The config chosen here isn't necessarily
+       * used for surfaces later.
+       * A pixmap surface will use the single config.
+       * This opportunity depends on disabling the
+       * doubleBufferMode check in
+       * src/mesa/main/context.c:check_compatible()
+       */
+      if (dri2_config->dri_double_config)
+         dri_config = dri2_config->dri_double_config;
+      else
+         dri_config = dri2_config->dri_single_config;
+   }
    else
       dri_config = NULL;
 
@@ -507,7 +550,7 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
    } else if (api == __DRI_API_OPENGL) {
       dri2_ctx->dri_context =
 	 dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen,
-					  dri2_config->dri_config,
+					  dri_config,
 					  dri2_ctx_shared ? 
 					  dri2_ctx_shared->dri_context : NULL,
 					  dri2_ctx);
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 72e887c..1656a50 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -139,7 +139,8 @@ struct dri2_egl_buffer {
 struct dri2_egl_config
 {
    _EGLConfig         base;
-   const __DRIconfig *dri_config;
+   const __DRIconfig *dri_single_config;
+   const __DRIconfig *dri_double_config;
 };
 
 struct dri2_egl_image
@@ -163,7 +164,7 @@ dri2_create_screen(_EGLDisplay *disp);
 
 struct dri2_egl_config *
 dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
-		int depth, EGLint surface_type);
+		int depth, EGLint surface_type, const EGLint *attr_list);
 
 _EGLImage *
 dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c
index 431bfa0..42939a5 100644
--- a/src/egl/drivers/dri2/platform_drm.c
+++ b/src/egl/drivers/dri2/platform_drm.c
@@ -649,7 +649,7 @@ dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp)
       goto cleanup_driver;
 
    for (i = 0; dri2_dpy->driver_configs[i]; i++)
-      dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0, 0);
+      dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0, 0, NULL);
 
    disp->Extensions.MESA_drm_image = EGL_TRUE;
    disp->Extensions.KHR_image_base = EGL_TRUE;
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index 16e0888..9be9a81 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -94,7 +94,10 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
 
    dri2_surf->dri_drawable = 
       (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
-					    dri2_conf->dri_config, dri2_surf);
+					    type == EGL_WINDOW_BIT ?
+					    dri2_conf->dri_double_config : 
+					    dri2_conf->dri_single_config,
+					    dri2_surf);
    if (dri2_surf->dri_drawable == NULL) {
       _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
       goto cleanup_dri_drawable;
@@ -181,20 +184,34 @@ dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
 }
 
 static void
-dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
+dri2_process_back_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
 {
    struct dri2_egl_display *dri2_dpy =
       dri2_egl_display(dri2_surf->base.Resource.Display);
-   struct dri2_egl_buffer *dri2_buf;
 
-   /* allocate a back buffer for our double-buffered window*/
+   (void) format;
+
    switch (dri2_surf->type) {
    case DRI2_WINDOW_SURFACE:
-      dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT] = 
+      /* allocate a front buffer for our double-buffered window*/
+      dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT] = 
          dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
-               __DRI_BUFFER_BACK_LEFT, format,
+               __DRI_BUFFER_FRONT_LEFT, format,
                dri2_surf->base.Width, dri2_surf->base.Height);
       break;
+   default:
+      break;
+   }
+}
+
+static void
+dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
+{
+   struct dri2_egl_display *dri2_dpy =
+      dri2_egl_display(dri2_surf->base.Resource.Display);
+   struct dri2_egl_buffer *dri2_buf;
+
+   switch (dri2_surf->type) {
    case DRI2_PIXMAP_SURFACE:
       dri2_buf = malloc(sizeof *dri2_buf);
       if (!dri2_buf)
@@ -264,6 +281,8 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable,
 
          if (attachments[i] == __DRI_BUFFER_FRONT_LEFT)
             dri2_process_front_buffer(dri2_surf, attachments[i+1]);
+         else if (attachments[i] == __DRI_BUFFER_BACK_LEFT)
+            dri2_process_back_buffer(dri2_surf, attachments[i+1]);
       }
 
       memcpy(&dri2_surf->buffers[dri2_surf->buffer_count],
@@ -396,7 +415,7 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
       if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT])
 	 dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] =
 	    wayland_create_buffer(dri2_surf,
-		  dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]);
+		  dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]);
 
       wl_surface_attach(dri2_surf->wl_win->surface,
 	    dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT],
@@ -584,7 +603,7 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
 
    for (i = 0; dri2_dpy->driver_configs[i]; i++)
       dri2_add_config(disp, dri2_dpy->driver_configs[i], i + 1, 0,
-		      EGL_WINDOW_BIT | EGL_PIXMAP_BIT);
+		      EGL_WINDOW_BIT | EGL_PIXMAP_BIT, NULL);
 
 
    disp->Extensions.MESA_drm_image = EGL_TRUE;
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
index 3b2f06e..e360266 100644
--- a/src/egl/drivers/dri2/platform_x11.c
+++ b/src/egl/drivers/dri2/platform_x11.c
@@ -79,7 +79,10 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
 
    dri2_surf->dri_drawable = 
       (*dri2_dpy->dri2->createNewDrawable) (dri2_dpy->dri_screen,
-					    dri2_conf->dri_config, dri2_surf);
+					    type == EGL_WINDOW_BIT ?
+					    dri2_conf->dri_double_config : 
+					    dri2_conf->dri_single_config,
+					    dri2_surf);
    if (dri2_surf->dri_drawable == NULL) {
       _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
       goto cleanup_pixmap;
@@ -428,8 +431,12 @@ dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
    xcb_depth_iterator_t d;
    xcb_visualtype_t *visuals;
    int i, j, id;
-   struct dri2_egl_config *conf;
    EGLint surface_type;
+   EGLint config_attrs[] = {
+	   EGL_NATIVE_VISUAL_ID,   0,
+	   EGL_NATIVE_VISUAL_TYPE, 0,
+	   EGL_NONE
+   };
 
    s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
    d = xcb_screen_allowed_depths_iterator(s.data);
@@ -451,14 +458,11 @@ dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy,
 
 	 class_added[visuals[i]._class] = EGL_TRUE;
 	 for (j = 0; dri2_dpy->driver_configs[j]; j++) {
-	    conf = dri2_add_config(disp, dri2_dpy->driver_configs[j],
-				   id++, d.data->depth, surface_type);
-	    if (conf == NULL)
-	       continue;
-	    _eglSetConfigKey(&conf->base,
-			     EGL_NATIVE_VISUAL_ID, visuals[i].visual_id);
-	    _eglSetConfigKey(&conf->base,
-			     EGL_NATIVE_VISUAL_TYPE, visuals[i]._class);
+            config_attrs[1] = visuals[i].visual_id;
+            config_attrs[3] = visuals[i]._class;
+
+	    dri2_add_config(disp, dri2_dpy->driver_configs[j], id++,
+			    d.data->depth, surface_type, config_attrs);
 	 }
       }
 
@@ -481,6 +485,7 @@ dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
    _EGLContext *ctx;
+   enum xcb_dri2_attachment_t render_attachment;
    xcb_dri2_copy_region_cookie_t cookie;
 
    if (dri2_drv->glFlush) {
@@ -502,14 +507,16 @@ dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp,
 #endif
 #endif
 
-   if (!dri2_surf->have_fake_front)
-      return EGL_TRUE;
+   if (dri2_surf->have_fake_front)
+      render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT;
+   else
+      render_attachment = XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT;
 
    cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
 					   dri2_surf->drawable,
 					   region,
 					   XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
-					   XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT);
+					   render_attachment);
    free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
 
    return EGL_TRUE;




More information about the mesa-commit mailing list