egl_dri2: Use double buffering for window surfaces
authorBenjamin Franzke <benjaminfranzke@googlemail.com>
Wed, 9 Feb 2011 14:30:20 +0000 (15:30 +0100)
committerKristian Høgsberg <krh@bitplanet.net>
Fri, 11 Feb 2011 04:07:01 +0000 (23:07 -0500)
src/egl/drivers/dri2/egl_dri2.c
src/egl/drivers/dri2/egl_dri2.h
src/egl/drivers/dri2/platform_drm.c
src/egl/drivers/dri2/platform_wayland.c
src/egl/drivers/dri2/platform_x11.c

index 3e5107756a5b8e8ecd1b9452f4fd90e38bb17de2..2c4deaf7c06d6641a46b2ee57f3e04d87cc33687 100644 (file)
@@ -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);
index 72e887c95b052c96263f5d0cf32fd5c6906c48c9..1656a50c0131e971e30637c4d344bcfde19fd44c 100644 (file)
@@ -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,
index 431bfa0fcc69ea0aa0be4c32852b9182ccfdefe3..42939a57a2aa79507e7bcc54b55036c8f3b43363 100644 (file)
@@ -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;
index 16e088827ed7f4c28d3ae8d8c897a4f556601d50..9be9a8190382e4473dbf628da6d0fdab607846d3 100644 (file)
@@ -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;
index 3b2f06e74807ac0652586dac699d48b366d81d05..e360266d803e4e883d3b4666572db97ed61b8010 100644 (file)
@@ -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;