egl_dri2: Use double buffering for window surfaces

This commit is contained in:
Benjamin Franzke 2011-02-09 15:30:20 +01:00 committed by Kristian Høgsberg
parent 71fa227029
commit 87dde5b1cd
5 changed files with 112 additions and 42 deletions

View 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);

View 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,

View 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;

View 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;
@ -180,6 +183,27 @@ dri2_wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
egl_pixmap->name = 0;
}
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)
{
@ -187,14 +211,7 @@ dri2_process_front_buffer(struct dri2_egl_surface *dri2_surf, unsigned format)
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 @@ 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;

View 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;