diff options
Diffstat (limited to 'src/egl/drivers/dri2/egl_dri2.c')
-rw-r--r-- | src/egl/drivers/dri2/egl_dri2.c | 282 |
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; |