egl_dri2: Use double buffering for window surfaces
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 @@
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 @@
}
}
- /* 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 @@
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 @@
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 @@
} 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_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 @@
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 @@
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_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 @@
}
static void
+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);
+
+ (void) format;
+
+ switch (dri2_surf->type) {
+ case DRI2_WINDOW_SURFACE:
+ /* 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_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;
- /* allocate a back buffer for our double-buffered window*/
switch (dri2_surf->type) {
- case DRI2_WINDOW_SURFACE:
- dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT] =
- dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
- __DRI_BUFFER_BACK_LEFT, format,
- dri2_surf->base.Width, dri2_surf->base.Height);
- break;
case DRI2_PIXMAP_SURFACE:
dri2_buf = malloc(sizeof *dri2_buf);
if (!dri2_buf)
@@ -264,6 +281,8 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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 @@
#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;