From 87dde5b1cd596c4008695ff2db9469f88c09f925 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Wed, 9 Feb 2011 15:30:20 +0100 Subject: [PATCH] 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; -- 2.7.4