summaryrefslogtreecommitdiff
path: root/src/egl/drivers/dri2/egl_dri2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/drivers/dri2/egl_dri2.c')
-rw-r--r--src/egl/drivers/dri2/egl_dri2.c282
1 files changed, 205 insertions, 77 deletions
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 92378892e5..5d36c49b2c 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -58,15 +58,16 @@ struct dri2_egl_driver
struct dri2_egl_display
{
- xcb_connection_t *conn;
- int dri2_major;
- int dri2_minor;
- __DRIscreen *dri_screen;
- void *driver;
- __DRIcoreExtension *core;
- __DRIdri2Extension *dri2;
- __DRI2flushExtension *flush;
- int fd;
+ xcb_connection_t *conn;
+ int dri2_major;
+ int dri2_minor;
+ __DRIscreen *dri_screen;
+ void *driver;
+ __DRIcoreExtension *core;
+ __DRIdri2Extension *dri2;
+ __DRI2flushExtension *flush;
+ __DRItexBufferExtension *tex_buffer;
+ int fd;
__DRIdri2LoaderExtension loader_extension;
const __DRIextension *extensions[2];
@@ -86,7 +87,6 @@ struct dri2_egl_surface
__DRIbuffer buffers[5];
int buffer_count;
xcb_xfixes_region_t region;
- int have_back;
int have_fake_front;
int swap_interval;
};
@@ -107,7 +107,7 @@ EGLint dri2_to_egl_attribute_map[] = {
EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */
EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */
EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */
- 0, /* __DRI_ATTRIB_LUMINANCE_SIZE */
+ EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */
EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */
0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */
EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */
@@ -152,28 +152,22 @@ EGLint dri2_to_egl_attribute_map[] = {
};
static void
-dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id)
+dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
+ int depth, xcb_visualtype_t *visual)
{
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;
int i;
dri2_dpy = disp->DriverData;
- conf = malloc(sizeof *conf);
- if (conf == NULL)
- return;
-
- conf->dri_config = dri_config;
- _eglInitConfig(&conf->base, disp, id);
+ _eglInitConfig(&base, disp, id);
i = 0;
while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
switch (attrib) {
- case 0:
- break;
-
case __DRI_ATTRIB_RENDER_TYPE:
if (value & __DRI_ATTRIB_RGBA_BIT)
value = EGL_RGB_BUFFER;
@@ -181,7 +175,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id)
value = EGL_LUMINANCE_BUFFER;
else
/* not valid */;
- _eglSetConfigKey(&conf->base, EGL_COLOR_BUFFER_TYPE, value);
+ _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
break;
case __DRI_ATTRIB_CONFIG_CAVEAT:
@@ -191,7 +185,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id)
value = EGL_SLOW_CONFIG;
else
value = EGL_NONE;
- _eglSetConfigKey(&conf->base, EGL_CONFIG_CAVEAT, value);
+ _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
break;
case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
@@ -209,39 +203,57 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id)
default:
key = dri2_to_egl_attribute_map[attrib];
if (key != 0)
- _eglSetConfigKey(&conf->base, key, value);
+ _eglSetConfigKey(&base, key, value);
break;
}
}
- /* EGL_SWAP_BEHAVIOR_PRESERVED_BIT */
+ /* 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) {
- /* FIXME: Figure out how to get the visual ID and types */
- _eglSetConfigKey(&conf->base, EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
- _eglSetConfigKey(&conf->base, EGL_NATIVE_VISUAL_ID, 0x21);
- _eglSetConfigKey(&conf->base, EGL_NATIVE_VISUAL_TYPE,
- XCB_VISUAL_CLASS_TRUE_COLOR);
+ if (double_buffer)
+ return;
+
+ if (visual != NULL) {
+ if (depth != _eglGetConfigKey(&base, EGL_BUFFER_SIZE))
+ return;
+
+ _eglSetConfigKey(&base, EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT |
+ EGL_SWAP_BEHAVIOR_PRESERVED_BIT);
+
+ _eglSetConfigKey(&base, EGL_NATIVE_VISUAL_ID, visual->visual_id);
+ _eglSetConfigKey(&base, EGL_NATIVE_VISUAL_TYPE, visual->_class);
} else {
- _eglSetConfigKey(&conf->base,
- EGL_SURFACE_TYPE, EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
- _eglSetConfigKey(&conf->base,
- EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb);
- _eglSetConfigKey(&conf->base,
- EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
+ _eglSetConfigKey(&base, EGL_SURFACE_TYPE,
+ EGL_PIXMAP_BIT | EGL_PBUFFER_BIT);
}
+ _eglSetConfigKey(&base, EGL_NATIVE_RENDERABLE, EGL_TRUE);
+ _eglSetConfigKey(&base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb);
+ if (_eglGetConfigKey(&base, EGL_ALPHA_SIZE) > 0)
+ _eglSetConfigKey(&base,
+ EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba);
+
/* EGL_OPENGL_ES_BIT, EGL_OPENVG_BIT, EGL_OPENGL_ES2_BIT */
- _eglSetConfigKey(&conf->base, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
- _eglSetConfigKey(&conf->base, EGL_CONFORMANT, EGL_OPENGL_BIT);
+ _eglSetConfigKey(&base, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT);
+ _eglSetConfigKey(&base, EGL_CONFORMANT, EGL_OPENGL_BIT);
- if (!_eglValidateConfig(&conf->base, EGL_FALSE)) {
+ if (!_eglValidateConfig(&base, EGL_FALSE)) {
_eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
- free(conf);
return;
}
- _eglAddConfig(disp, &conf->base);
+ conf = malloc(sizeof *conf);
+ if (conf != NULL) {
+ memcpy(&conf->base, &base, sizeof base);
+ conf->dri_config = dri_config;
+ _eglAddConfig(disp, &conf->base);
+ }
}
/**
@@ -261,7 +273,6 @@ dri2_process_buffers(struct dri2_egl_surface *dri2_surf,
dri2_surf->buffer_count = count;
dri2_surf->have_fake_front = 0;
- dri2_surf->have_back = 0;
/* This assumes the DRI2 buffer attachment tokens matches the
* __DRIbuffer tokens. */
@@ -271,10 +282,14 @@ dri2_process_buffers(struct dri2_egl_surface *dri2_surf,
dri2_surf->buffers[i].pitch = buffers[i].pitch;
dri2_surf->buffers[i].cpp = buffers[i].cpp;
dri2_surf->buffers[i].flags = buffers[i].flags;
+
+ /* We only use the DRI drivers single buffer configs. This
+ * means that if we try to render to a window, DRI2 will give us
+ * the fake front buffer, which we'll use as a back buffer.
+ * Note that EGL doesn't require that several clients rendering
+ * to the same window must see the same aux buffers. */
if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT)
dri2_surf->have_fake_front = 1;
- if (dri2_surf->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT)
- dri2_surf->have_back = 1;
}
if (dri2_surf->region != XCB_NONE)
@@ -375,6 +390,57 @@ static const char dri_driver_format[] = "%.*s/%.*s_dri.so";
static const char dri_driver_path[] = DEFAULT_DRIVER_DIR;
+struct dri2_extension_match {
+ const char *name;
+ int version;
+ int offset;
+};
+
+static struct dri2_extension_match dri2_driver_extensions[] = {
+ { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
+ { __DRI_DRI2, 1, offsetof(struct dri2_egl_display, dri2) },
+ { NULL }
+};
+
+static struct dri2_extension_match dri2_core_extensions[] = {
+ { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
+ { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
+ { NULL }
+};
+
+static EGLBoolean
+dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
+ struct dri2_extension_match *matches,
+ const __DRIextension **extensions)
+{
+ int i, j, ret = EGL_TRUE;
+ void *field;
+
+ for (i = 0; extensions[i]; i++) {
+ _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name);
+ for (j = 0; matches[j].name; j++) {
+ if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
+ extensions[i]->version >= matches[j].version) {
+ field = ((char *) dri2_dpy + matches[j].offset);
+ *(const __DRIextension **) field = extensions[i];
+ _eglLog(_EGL_INFO, "DRI2: found extension %s version %d",
+ extensions[i]->name, extensions[i]->version);
+ }
+ }
+ }
+
+ for (j = 0; matches[j].name; j++) {
+ field = ((char *) dri2_dpy + matches[j].offset);
+ if (*(const __DRIextension **) field == NULL) {
+ _eglLog(_EGL_FATAL, "DRI2: did not find extension %s version %d",
+ matches[j].name, matches[j].version);
+ ret = EGL_FALSE;
+ }
+ }
+
+ return ret;
+}
+
/**
* Called via eglInitialize(), GLX_drv->API.Initialize().
*/
@@ -397,7 +463,9 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
xcb_generic_error_t *error;
drm_magic_t magic;
xcb_screen_iterator_t s;
- int i;
+ xcb_depth_iterator_t d;
+ xcb_visualtype_t *visuals;
+ int i, j, id;
dri2_dpy = malloc(sizeof *dri2_dpy);
if (!dri2_dpy)
@@ -497,24 +565,8 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
goto cleanup_driver;
}
- for (i = 0; extensions[i]; i++) {
- _eglLog(_EGL_DEBUG, "DRI2: found driver extension `%s'",
- extensions[i]->name);
- if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
- dri2_dpy->core = (__DRIcoreExtension *) extensions[i];
- if (strcmp(extensions[i]->name, __DRI_DRI2) == 0)
- dri2_dpy->dri2 = (__DRIdri2Extension *) extensions[i];
- }
-
- if (dri2_dpy->core == NULL) {
- _eglLog(_EGL_FATAL, "DRI2: driver has no core extension");
+ if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions))
goto cleanup_driver;
- }
-
- if (dri2_dpy->dri2 == NULL) {
- _eglLog(_EGL_FATAL, "DRI2: driver has no dri2 extension");
- goto cleanup_driver;
- }
snprintf(path, sizeof path, "%.*s",
xcb_dri2_connect_device_name_length (connect),
@@ -570,20 +622,30 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp,
}
extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
- for (i = 0; extensions[i]; i++) {
- _eglLog(_EGL_DEBUG, "DRI2: found core extension `%s'",
- extensions[i]->name);
- if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0))
- dri2_dpy->flush = (__DRI2flushExtension *) extensions[i];
- }
-
- if (dri2_dpy->flush == NULL) {
- _eglLog(_EGL_FATAL, "DRI2: driver doesn't support the flush extension");
+ if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions))
goto cleanup_dri_screen;
+
+ s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn));
+ d = xcb_screen_allowed_depths_iterator(s.data);
+ id = 1;
+ while (d.rem > 0) {
+ EGLBoolean class_added[6] = { 0, };
+
+ visuals = xcb_depth_visuals(d.data);
+ for (i = 0; i < xcb_depth_visuals_length(d.data); i++) {
+ if (class_added[visuals[i]._class])
+ continue;
+
+ class_added[visuals[i]._class] = EGL_TRUE;
+ for (j = 0; driver_configs[j]; j++)
+ dri2_add_config(disp, driver_configs[j],
+ id++, d.data->depth, &visuals[i]);
+
+ }
+
+ xcb_depth_next(&d);
}
- for (i = 0; driver_configs[i]; i++)
- dri2_add_config(disp, driver_configs[i], i + 1);
if (!disp->NumConfigs) {
_eglLog(_EGL_WARNING, "DRI2: failed to create any config");
goto cleanup_configs;
@@ -852,21 +914,22 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
#if 0
/* FIXME: Add support for dri swapbuffers, that'll give us swap
* interval and page flipping (at least for fullscreen windows) as
- * well as the page flip event. */
+ * well as the page flip event. Unless surface->SwapBehavior is
+ * EGL_BUFFER_PRESERVED. */
#if __DRI2_FLUSH_VERSION >= 2
if (pdraw->psc->f)
(*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable);
#endif
#endif
- if (!dri2_surf->have_back)
+ if (!dri2_surf->have_fake_front)
return EGL_TRUE;
cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn,
dri2_surf->drawable,
dri2_surf->region,
XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT,
- XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT);
+ XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT);
free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL));
return EGL_TRUE;
@@ -939,6 +1002,69 @@ dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
return EGL_TRUE;
}
+static EGLBoolean
+dri2_bind_tex_image(_EGLDriver *drv,
+ _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
+ struct dri2_egl_context *dri2_ctx;
+ _EGLContext *ctx;
+ GLint format, target;
+
+ ctx = _eglGetCurrentContext();
+ dri2_ctx = dri2_egl_context(ctx);
+
+ if (buffer != EGL_BACK_BUFFER) {
+ _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
+ return EGL_FALSE;
+ }
+
+ /* We allow binding pixmaps too... Not conformat, but we can do it
+ * for free and it's useful for X compositors. Supposedly there's
+ * a EGL_NOKIA_texture_from_pixmap extension that allows that, but
+ * I couldn't find it at this time. */
+ if ((dri2_surf->base.Type & (EGL_PBUFFER_BIT | EGL_PIXMAP_BIT)) == 0) {
+ _eglError(EGL_BAD_SURFACE, "eglBindTexImage");
+ return EGL_FALSE;
+ }
+
+ switch (dri2_surf->base.TextureFormat) {
+ case EGL_TEXTURE_RGB:
+ format = __DRI_TEXTURE_FORMAT_RGB;
+ break;
+ case EGL_TEXTURE_RGBA:
+ format = __DRI_TEXTURE_FORMAT_RGBA;
+ break;
+ default:
+ _eglError(EGL_BAD_MATCH, "eglBindTexImage");
+ return EGL_FALSE;
+ }
+
+ switch (dri2_surf->base.TextureTarget) {
+ case EGL_TEXTURE_2D:
+ target = GL_TEXTURE_2D;
+ break;
+ default:
+ _eglError(EGL_BAD_PARAMETER, "eglBindTexImage");
+ return EGL_FALSE;
+ }
+
+ (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
+ target, format,
+ dri2_surf->dri_drawable);
+
+ return dri2_surf->base.BoundToTexture = EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_release_tex_image(_EGLDriver *drv,
+ _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
+{
+ return EGL_TRUE;
+}
+
+
/**
* This is the main entrypoint into the driver, called by libEGL.
* Create a new _EGLDriver object and init its dispatch table.
@@ -966,6 +1092,8 @@ _eglMain(const char *args)
dri2_drv->base.API.WaitClient = dri2_wait_client;
dri2_drv->base.API.WaitNative = dri2_wait_native;
dri2_drv->base.API.CopyBuffers = dri2_copy_buffers;
+ dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
+ dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
dri2_drv->base.Name = "DRI2";
dri2_drv->base.Unload = dri2_unload;