X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fegl%2Fdrivers%2Fdri2%2Fegl_dri2.c;h=f2b532d92c86424b05bff5f065445e44c3d7b6b9;hb=713c8734f45b51b3758ecc95b96cf7b5aecacec8;hp=08e7e0106e8f50caa27fe0b1436999ab9007aee6;hpb=c3c1a7e1d9357a6ba5b8092b3b0b9c873737e53d;p=mesa.git diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 08e7e0106e8..f2b532d92c8 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -40,9 +40,14 @@ #include #include #include +#include +#include + +#ifdef HAVE_LIBUDEV +#include +#endif #include -#include "eglconfigutil.h" #include "eglconfig.h" #include "eglcontext.h" #include "egldisplay.h" @@ -50,10 +55,15 @@ #include "eglcurrent.h" #include "egllog.h" #include "eglsurface.h" +#include "eglimage.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) struct dri2_egl_driver { _EGLDriver base; + + void (*glFlush)(void); }; struct dri2_egl_display @@ -62,15 +72,20 @@ struct dri2_egl_display int dri2_major; int dri2_minor; __DRIscreen *dri_screen; + const __DRIconfig **driver_configs; void *driver; __DRIcoreExtension *core; __DRIdri2Extension *dri2; __DRI2flushExtension *flush; __DRItexBufferExtension *tex_buffer; + __DRIimageExtension *image; int fd; + char *device_name; + char *driver_name; + __DRIdri2LoaderExtension loader_extension; - const __DRIextension *extensions[2]; + const __DRIextension *extensions[3]; }; struct dri2_egl_context @@ -93,12 +108,23 @@ struct dri2_egl_surface struct dri2_egl_config { - _EGLConfig base; + _EGLConfig base; const __DRIconfig *dri_config; }; +struct dri2_egl_image +{ + _EGLImage base; + __DRIimage *dri_image; +}; + /* standard typecasts */ _EGL_DRIVER_STANDARD_TYPECASTS(dri2_egl) +_EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj) + +static const __DRIuseInvalidateExtension use_invalidate = { + { __DRI_USE_INVALIDATE, 1 } +}; EGLint dri2_to_egl_attribute_map[] = { 0, @@ -107,7 +133,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 */ @@ -148,33 +174,30 @@ EGLint dri2_to_egl_attribute_map[] = { 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */ 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */ 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */ - 0, /* __DRI_ATTRIB_YINVERTED */ + EGL_Y_INVERTED_NOK, /* __DRI_ATTRIB_YINVERTED */ }; -static void +static struct dri2_egl_config * dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, - int depth, xcb_visualtype_t *visual) + int depth, EGLint surface_type) { 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; + double_buffer = 0; + bind_to_texture_rgb = 0; + bind_to_texture_rgba = 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; @@ -182,7 +205,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: @@ -192,7 +215,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: @@ -210,7 +233,7 @@ 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; } } @@ -222,44 +245,37 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, * 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) { - free(conf); - return; - } + if (double_buffer) + return NULL; - /* EGL_SWAP_BEHAVIOR_PRESERVED_BIT */ + if (depth > 0 && depth != base.BufferSize) + return NULL; - if (visual != NULL) { - if (depth != _eglGetConfigKey(&conf->base, EGL_BUFFER_SIZE)) { - free(conf); - return; - } + base.NativeRenderable = EGL_TRUE; - _eglSetConfigKey(&conf->base, EGL_SURFACE_TYPE, - EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT); - _eglSetConfigKey(&conf->base, EGL_NATIVE_VISUAL_ID, visual->visual_id); - _eglSetConfigKey(&conf->base, EGL_NATIVE_VISUAL_TYPE, visual->_class); - } else { - _eglSetConfigKey(&conf->base, EGL_SURFACE_TYPE, - EGL_PIXMAP_BIT | EGL_PBUFFER_BIT); + base.SurfaceType = surface_type; + if (surface_type & (EGL_PIXMAP_BIT | EGL_PBUFFER_BIT)) { + base.BindToTextureRGB = bind_to_texture_rgb; + if (base.AlphaSize > 0) + base.BindToTextureRGBA = bind_to_texture_rgba; } - _eglSetConfigKey(&conf->base, EGL_BIND_TO_TEXTURE_RGB, bind_to_texture_rgb); - if (_eglGetConfigKey(&conf->base, EGL_ALPHA_SIZE) > 0) - _eglSetConfigKey(&conf->base, - EGL_BIND_TO_TEXTURE_RGBA, bind_to_texture_rgba); + base.RenderableType = disp->ClientAPIsMask; + base.Conformant = disp->ClientAPIsMask; - /* 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); - - if (!_eglValidateConfig(&conf->base, EGL_FALSE)) { + if (!_eglValidateConfig(&base, EGL_FALSE)) { _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id); - free(conf); - return; + return NULL; } - _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); + } + + return conf; } /** @@ -275,7 +291,7 @@ dri2_process_buffers(struct dri2_egl_surface *dri2_surf, struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); xcb_rectangle_t rectangle; - int i; + unsigned i; dri2_surf->buffer_count = count; dri2_surf->have_fake_front = 0; @@ -322,6 +338,8 @@ dri2_get_buffers(__DRIdrawable * driDrawable, xcb_dri2_get_buffers_reply_t *reply; xcb_dri2_get_buffers_cookie_t cookie; + (void) driDrawable; + cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn, dri2_surf->drawable, count, count, attachments); @@ -343,15 +361,44 @@ dri2_get_buffers(__DRIdrawable * driDrawable, static void dri2_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) { + (void) driDrawable; + /* FIXME: Does EGL support front buffer rendering at all? */ #if 0 struct dri2_egl_surface *dri2_surf = loaderPrivate; dri2WaitGL(dri2_surf); +#else + (void) loaderPrivate; #endif } +static __DRIimage * +dri2_lookup_egl_image(__DRIscreen *screen, void *image, void *data) +{ + _EGLDisplay *disp = data; + struct dri2_egl_image *dri2_img; + _EGLImage *img; + + (void) screen; + + img = _eglLookupImage(image, disp); + if (img == NULL) { + _eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image"); + return NULL; + } + + dri2_img = dri2_egl_image(image); + + return dri2_img->dri_image; +} + +static const __DRIimageLookupExtension image_lookup_extension = { + { __DRI_IMAGE_LOOKUP, 1 }, + dri2_lookup_egl_image +}; + static __DRIbuffer * dri2_get_buffers_with_format(__DRIdrawable * driDrawable, int *width, int *height, @@ -366,6 +413,8 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, xcb_dri2_get_buffers_with_format_cookie_t cookie; xcb_dri2_attach_format_t *format_attachments; + (void) driDrawable; + format_attachments = (xcb_dri2_attach_format_t *) attachments; cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn, dri2_surf->drawable, @@ -388,12 +437,6 @@ dri2_get_buffers_with_format(__DRIdrawable * driDrawable, return dri2_surf->buffers; } -#ifdef GLX_USE_TLS -static const char dri_driver_format[] = "%.*s/tls/%.*s_dri.so"; -#else -static const char dri_driver_format[] = "%.*s/%.*s_dri.so"; -#endif - static const char dri_driver_path[] = DEFAULT_DRIVER_DIR; struct dri2_extension_match { @@ -405,13 +448,14 @@ struct dri2_extension_match { 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 } + { NULL, 0, 0 } }; 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 } + { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) }, + { NULL, 0, 0 } }; static EGLBoolean @@ -447,45 +491,32 @@ dri2_bind_extensions(struct dri2_egl_display *dri2_dpy, return ret; } -/** - * Called via eglInitialize(), GLX_drv->API.Initialize(). - */ +static char * +dri2_strndup(const char *s, int length) +{ + char *d; + + d = malloc(length + 1); + if (d == NULL) + return NULL; + + memcpy(d, s, length); + d[length] = '\0'; + + return d; +} + static EGLBoolean -dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, - EGLint *major, EGLint *minor) +dri2_connect(struct dri2_egl_display *dri2_dpy) { - const __DRIextension **extensions; - const __DRIconfig **driver_configs; - struct dri2_egl_display *dri2_dpy; - char path[PATH_MAX], *search_paths, *p, *next, *end; xcb_xfixes_query_version_reply_t *xfixes_query; xcb_xfixes_query_version_cookie_t xfixes_query_cookie; xcb_dri2_query_version_reply_t *dri2_query; xcb_dri2_query_version_cookie_t dri2_query_cookie; xcb_dri2_connect_reply_t *connect; xcb_dri2_connect_cookie_t connect_cookie; - xcb_dri2_authenticate_reply_t *authenticate; - xcb_dri2_authenticate_cookie_t authenticate_cookie; xcb_generic_error_t *error; - drm_magic_t magic; xcb_screen_iterator_t s; - xcb_depth_iterator_t d; - xcb_visualtype_t *visuals; - int i, j, id; - - dri2_dpy = malloc(sizeof *dri2_dpy); - if (!dri2_dpy) - return _eglError(EGL_BAD_ALLOC, "eglInitialize"); - - disp->DriverData = (void *) dri2_dpy; - if (disp->NativeDisplay != NULL) - dri2_dpy->conn = XGetXCBConnection(disp->NativeDisplay); - else - dri2_dpy->conn = xcb_connect(0, 0); - if (!dri2_dpy->conn) { - _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed"); - goto cleanup_dpy; - } xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id); xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri2_id); @@ -510,7 +541,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, error != NULL || xfixes_query->major_version < 2) { _eglLog(_EGL_FATAL, "DRI2: failed to query xfixes version"); free(error); - goto cleanup_conn; + return EGL_FALSE; } free(xfixes_query); @@ -519,7 +550,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, if (dri2_query == NULL || error != NULL) { _eglLog(_EGL_FATAL, "DRI2: failed to query version"); free(error); - goto cleanup_conn; + return EGL_FALSE; } dri2_dpy->dri2_major = dri2_query->major_version; dri2_dpy->dri2_minor = dri2_query->minor_version; @@ -529,9 +560,117 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, if (connect == NULL || connect->driver_name_length + connect->device_name_length == 0) { _eglLog(_EGL_FATAL, "DRI2: failed to authenticate"); - goto cleanup_connect; + return EGL_FALSE; + } + + dri2_dpy->device_name = + dri2_strndup(xcb_dri2_connect_device_name (connect), + xcb_dri2_connect_device_name_length (connect)); + + dri2_dpy->driver_name = + dri2_strndup(xcb_dri2_connect_driver_name (connect), + xcb_dri2_connect_driver_name_length (connect)); + + if (dri2_dpy->device_name == NULL || dri2_dpy->driver_name == NULL) { + free(dri2_dpy->device_name); + free(dri2_dpy->driver_name); + free(connect); + return EGL_FALSE; + } + free(connect); + + return EGL_TRUE; +} + +static EGLBoolean +dri2_authenticate(struct dri2_egl_display *dri2_dpy) +{ + xcb_dri2_authenticate_reply_t *authenticate; + xcb_dri2_authenticate_cookie_t authenticate_cookie; + xcb_screen_iterator_t s; + drm_magic_t magic; + + if (drmGetMagic(dri2_dpy->fd, &magic)) { + _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic"); + return EGL_FALSE; + } + + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); + authenticate_cookie = + xcb_dri2_authenticate_unchecked(dri2_dpy->conn, s.data->root, magic); + authenticate = + xcb_dri2_authenticate_reply(dri2_dpy->conn, authenticate_cookie, NULL); + if (authenticate == NULL || !authenticate->authenticated) { + _eglLog(_EGL_FATAL, "DRI2: failed to authenticate"); + free(authenticate); + return EGL_FALSE; + } + + free(authenticate); + + return EGL_TRUE; +} + +static EGLBoolean +dri2_add_configs_for_visuals(struct dri2_egl_display *dri2_dpy, + _EGLDisplay *disp) +{ + xcb_screen_iterator_t s; + xcb_depth_iterator_t d; + xcb_visualtype_t *visuals; + int i, j, id; + struct dri2_egl_config *conf; + EGLint surface_type; + + s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); + d = xcb_screen_allowed_depths_iterator(s.data); + id = 1; + + surface_type = + EGL_WINDOW_BIT | + EGL_PIXMAP_BIT | + EGL_PBUFFER_BIT | + EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + + 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; 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); + } + } + + xcb_depth_next(&d); + } + + if (!_eglGetArraySize(disp->Configs)) { + _eglLog(_EGL_WARNING, "DRI2: failed to create any config"); + return EGL_FALSE; } + return EGL_TRUE; +} + +static EGLBoolean +dri2_load_driver(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = disp->DriverData; + const __DRIextension **extensions; + char path[PATH_MAX], *search_paths, *p, *next, *end; + search_paths = NULL; if (geteuid() == getuid()) { /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ @@ -543,63 +682,143 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, dri2_dpy->driver = NULL; end = search_paths + strlen(search_paths); for (p = search_paths; p < end && dri2_dpy->driver == NULL; p = next + 1) { + int len; next = strchr(p, ':'); if (next == NULL) next = end; + len = next - p; +#if GLX_USE_TLS snprintf(path, sizeof path, - dri_driver_format, - (int) (next - p), p, - xcb_dri2_connect_driver_name_length (connect), - xcb_dri2_connect_driver_name (connect)); - + "%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name); dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); +#endif + if (dri2_dpy->driver == NULL) { + snprintf(path, sizeof path, + "%.*s/%s_dri.so", len, p, dri2_dpy->driver_name); + dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL); + if (dri2_dpy->driver == NULL) + _eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror()); + } } if (dri2_dpy->driver == NULL) { - _eglLog(_EGL_FATAL, + _eglLog(_EGL_WARNING, "DRI2: failed to open any driver (search paths %s)", search_paths); - goto cleanup_connect; + return EGL_FALSE; } _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path); extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS); if (extensions == NULL) { - _eglLog(_EGL_FATAL, + _eglLog(_EGL_WARNING, "DRI2: driver exports no extensions (%s)", dlerror()); - goto cleanup_driver; + dlclose(dri2_dpy->driver); + return EGL_FALSE; } - if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) - goto cleanup_driver; + if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions)) { + dlclose(dri2_dpy->driver); + return EGL_FALSE; + } - snprintf(path, sizeof path, "%.*s", - xcb_dri2_connect_device_name_length (connect), - xcb_dri2_connect_device_name (connect)); - dri2_dpy->fd = open (path, O_RDWR); - if (dri2_dpy->fd == -1) { - _eglLog(_EGL_FATAL, - "DRI2: could not open %s (%s)", path, strerror(errno)); - goto cleanup_driver; + return EGL_TRUE; +} + +static EGLBoolean +dri2_create_screen(_EGLDisplay *disp) +{ + const __DRIextension **extensions; + struct dri2_egl_display *dri2_dpy; + unsigned int api_mask; + + dri2_dpy = disp->DriverData; + dri2_dpy->dri_screen = + dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions, + &dri2_dpy->driver_configs, disp); + + if (dri2_dpy->dri_screen == NULL) { + _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen"); + return EGL_FALSE; } - if (drmGetMagic(dri2_dpy->fd, &magic)) { - _eglLog(_EGL_FATAL, "DRI2: failed to get drm magic"); - goto cleanup_fd; + extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen); + if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions)) + goto cleanup_dri_screen; + + if (dri2_dpy->dri2->base.version >= 2) + api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen); + else + api_mask = __DRI_API_OPENGL; + + disp->ClientAPIsMask = 0; + if (api_mask & (1 <<__DRI_API_OPENGL)) + disp->ClientAPIsMask |= EGL_OPENGL_BIT; + if (api_mask & (1 <<__DRI_API_GLES)) + disp->ClientAPIsMask |= EGL_OPENGL_ES_BIT; + if (api_mask & (1 << __DRI_API_GLES2)) + disp->ClientAPIsMask |= EGL_OPENGL_ES2_BIT; + + if (dri2_dpy->dri2->base.version >= 2) { + disp->Extensions.KHR_surfaceless_gles1 = EGL_TRUE; + disp->Extensions.KHR_surfaceless_gles2 = EGL_TRUE; + disp->Extensions.KHR_surfaceless_opengl = EGL_TRUE; } - authenticate_cookie = xcb_dri2_authenticate_unchecked (dri2_dpy->conn, - s.data->root, magic); - authenticate = xcb_dri2_authenticate_reply (dri2_dpy->conn, - authenticate_cookie, NULL); - if (authenticate == NULL || !authenticate->authenticated) { - _eglLog(_EGL_FATAL, "DRI2: failed to authenticate"); - free(authenticate); - goto cleanup_fd; + return EGL_TRUE; + + cleanup_dri_screen: + dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); + + return EGL_FALSE; +} + +static EGLBoolean +dri2_initialize_x11(_EGLDriver *drv, _EGLDisplay *disp, + EGLint *major, EGLint *minor) +{ + struct dri2_egl_display *dri2_dpy; + + (void) drv; + + dri2_dpy = malloc(sizeof *dri2_dpy); + if (!dri2_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + disp->DriverData = (void *) dri2_dpy; + if (disp->PlatformDisplay == NULL) { + dri2_dpy->conn = xcb_connect(0, 0); + } else { + dri2_dpy->conn = XGetXCBConnection((Display *) disp->PlatformDisplay); + } + + if (xcb_connection_has_error(dri2_dpy->conn)) { + _eglLog(_EGL_WARNING, "DRI2: xcb_connect failed"); + goto cleanup_dpy; + } + + if (dri2_dpy->conn) { + if (!dri2_connect(dri2_dpy)) + goto cleanup_conn; + } + + if (!dri2_load_driver(disp)) + goto cleanup_conn; + + dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR); + if (dri2_dpy->fd == -1) { + _eglLog(_EGL_WARNING, + "DRI2: could not open %s (%s)", dri2_dpy->device_name, + strerror(errno)); + goto cleanup_driver; + } + + if (dri2_dpy->conn) { + if (!dri2_authenticate(dri2_dpy)) + goto cleanup_fd; } - free(authenticate); if (dri2_dpy->dri2_minor >= 1) { dri2_dpy->loader_extension.base.name = __DRI_DRI2_LOADER; dri2_dpy->loader_extension.base.version = 3; @@ -616,67 +835,40 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, } dri2_dpy->extensions[0] = &dri2_dpy->loader_extension.base; - dri2_dpy->extensions[1] = NULL; - - dri2_dpy->dri_screen = - dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd, dri2_dpy->extensions, - &driver_configs, dri2_dpy); + dri2_dpy->extensions[1] = &image_lookup_extension.base; + dri2_dpy->extensions[2] = NULL; - if (dri2_dpy->dri_screen == NULL) { - _eglLog(_EGL_FATAL, "DRI2: failed to create dri screen"); + if (!dri2_create_screen(disp)) goto cleanup_fd; - } - - extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen); - 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); - } - - if (!disp->NumConfigs) { - _eglLog(_EGL_WARNING, "DRI2: failed to create any config"); - goto cleanup_configs; + if (dri2_dpy->conn) { + if (!dri2_add_configs_for_visuals(dri2_dpy, disp)) + goto cleanup_configs; } - disp->ClientAPIsMask = EGL_OPENGL_BIT; + disp->Extensions.MESA_drm_image = EGL_TRUE; + disp->Extensions.KHR_image_base = EGL_TRUE; + disp->Extensions.KHR_image_pixmap = EGL_TRUE; + disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; + disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; + disp->Extensions.NOK_swap_region = EGL_TRUE; + disp->Extensions.NOK_texture_from_pixmap = EGL_TRUE; /* we're supporting EGL 1.4 */ *major = 1; *minor = 4; - free (connect); + return EGL_TRUE; cleanup_configs: _eglCleanupDisplay(disp); - cleanup_dri_screen: dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); cleanup_fd: close(dri2_dpy->fd); cleanup_driver: dlclose(dri2_dpy->driver); - cleanup_connect: - free(connect); cleanup_conn: - if (disp->NativeDisplay == NULL) + if (disp->PlatformDisplay == NULL) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); @@ -684,6 +876,178 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, return EGL_FALSE; } +#ifdef HAVE_LIBUDEV + +struct dri2_driver_map { + int vendor_id; + const char *driver; + const int *chip_ids; + int num_chips_ids; +}; + +const int i915_chip_ids[] = { + 0x3577, /* PCI_CHIP_I830_M */ + 0x2562, /* PCI_CHIP_845_G */ + 0x3582, /* PCI_CHIP_I855_GM */ + 0x2572, /* PCI_CHIP_I865_G */ + 0x2582, /* PCI_CHIP_I915_G */ + 0x258a, /* PCI_CHIP_E7221_G */ + 0x2592, /* PCI_CHIP_I915_GM */ + 0x2772, /* PCI_CHIP_I945_G */ + 0x27a2, /* PCI_CHIP_I945_GM */ + 0x27ae, /* PCI_CHIP_I945_GME */ + 0x29b2, /* PCI_CHIP_Q35_G */ + 0x29c2, /* PCI_CHIP_G33_G */ + 0x29d2, /* PCI_CHIP_Q33_G */ + 0xa011, /* Pineview */ +}; + +const int i965_chip_ids[] = { + 0x29a2, /* PCI_CHIP_I965_G */ + 0x2992, /* PCI_CHIP_I965_Q */ + 0x2982, /* PCI_CHIP_I965_G_1 */ + 0x2972, /* PCI_CHIP_I946_GZ */ + 0x2a02, /* PCI_CHIP_I965_GM */ + 0x2a12, /* PCI_CHIP_I965_GME */ + 0x2a42, /* PCI_CHIP_GM45_GM */ + 0x2e02, /* PCI_CHIP_IGD_E_G */ + 0x2e12, /* PCI_CHIP_Q45_G */ + 0x2e22, /* PCI_CHIP_G45_G */ + 0x2e32, /* PCI_CHIP_G41_G */ +}; + +const struct dri2_driver_map driver_map[] = { + { 0x8086, "i915", i915_chip_ids, ARRAY_SIZE(i915_chip_ids) }, + { 0x8086, "i965", i965_chip_ids, ARRAY_SIZE(i965_chip_ids) }, +}; + +static char * +dri2_get_driver_for_fd(int fd) +{ + struct udev *udev; + struct udev_device *device, *parent; + struct stat buf; + const char *pci_id; + char *driver = NULL; + int vendor_id, chip_id, i, j; + + udev = udev_new(); + if (fstat(fd, &buf) < 0) { + _eglLog(_EGL_WARNING, "EGL-DRI2: failed to stat fd %d", fd); + goto out; + } + + device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev); + if (device == NULL) { + _eglLog(_EGL_WARNING, + "EGL-DRI2: could not create udev device for fd %d", fd); + goto out; + } + + parent = udev_device_get_parent(device); + if (parent == NULL) { + _eglLog(_EGL_WARNING, "DRI2: could not get parent device"); + goto out; + } + + pci_id = udev_device_get_property_value(parent, "PCI_ID"); + if (pci_id == NULL || sscanf(pci_id, "%x:%x", &vendor_id, &chip_id) != 2) { + _eglLog(_EGL_WARNING, "EGL-DRI2: malformed or no PCI ID"); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(driver_map); i++) { + if (vendor_id != driver_map[i].vendor_id) + continue; + for (j = 0; j < driver_map[i].num_chips_ids; j++) + if (driver_map[i].chip_ids[j] == chip_id) { + driver = strdup(driver_map[i].driver); + _eglLog(_EGL_DEBUG, "pci id for %d: %04x:%04x, driver %s", + fd, vendor_id, chip_id, driver); + goto out; + } + } + + out: + udev_device_unref(device); + udev_unref(udev); + + return driver; +} + +static EGLBoolean +dri2_initialize_drm(_EGLDriver *drv, _EGLDisplay *disp, + EGLint *major, EGLint *minor) +{ + struct dri2_egl_display *dri2_dpy; + int i; + + dri2_dpy = malloc(sizeof *dri2_dpy); + if (!dri2_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + disp->DriverData = (void *) dri2_dpy; + dri2_dpy->fd = (int) disp->PlatformDisplay; + + dri2_dpy->driver_name = dri2_get_driver_for_fd(dri2_dpy->fd); + if (dri2_dpy->driver_name == NULL) + return _eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name"); + + if (!dri2_load_driver(disp)) + goto cleanup_driver_name; + + dri2_dpy->extensions[0] = &image_lookup_extension.base; + dri2_dpy->extensions[1] = &use_invalidate.base; + dri2_dpy->extensions[2] = NULL; + + if (!dri2_create_screen(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); + + disp->Extensions.MESA_drm_image = EGL_TRUE; + disp->Extensions.KHR_image_base = EGL_TRUE; + disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; + disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; + + /* we're supporting EGL 1.4 */ + *major = 1; + *minor = 4; + + return EGL_TRUE; + + cleanup_driver: + dlclose(dri2_dpy->driver); + cleanup_driver_name: + free(dri2_dpy->driver_name); + + return EGL_FALSE; +} + +#endif + +/** + * Called via eglInitialize(), GLX_drv->API.Initialize(). + */ +static EGLBoolean +dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp, + EGLint *major, EGLint *minor) +{ + switch (disp->Platform) { + case _EGL_PLATFORM_X11: + return dri2_initialize_x11(drv, disp, major, minor); + +#ifdef HAVE_LIBUDEV + case _EGL_PLATFORM_DRM: + return dri2_initialize_drm(drv, disp, major, minor); +#endif + + default: + return EGL_FALSE; + } +} + /** * Called via eglTerminate(), drv->API.Terminate(). */ @@ -698,7 +1062,7 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); close(dri2_dpy->fd); dlclose(dri2_dpy->driver); - if (disp->NativeDisplay == NULL) + if (disp->PlatformDisplay == NULL) xcb_disconnect(dri2_dpy->conn); free(dri2_dpy); disp->DriverData = NULL; @@ -718,6 +1082,10 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list); struct dri2_egl_config *dri2_config = dri2_egl_config(conf); + const __DRIconfig *dri_config; + int api; + + (void) drv; dri2_ctx = malloc(sizeof *dri2_ctx); if (!dri2_ctx) { @@ -728,12 +1096,51 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list)) goto cleanup; - dri2_ctx->dri_context = - dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen, - dri2_config->dri_config, - dri2_ctx_shared ? - dri2_ctx_shared->dri_context : NULL, - dri2_ctx); + switch (dri2_ctx->base.ClientAPI) { + case EGL_OPENGL_ES_API: + switch (dri2_ctx->base.ClientVersion) { + case 1: + api = __DRI_API_GLES; + break; + case 2: + api = __DRI_API_GLES2; + break; + default: + _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); + return NULL; + } + break; + case EGL_OPENGL_API: + api = __DRI_API_OPENGL; + break; + default: + _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); + return NULL; + } + + if (conf != NULL) + dri_config = dri2_config->dri_config; + else + dri_config = NULL; + + if (dri2_dpy->dri2->base.version >= 2) { + dri2_ctx->dri_context = + dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen, + api, + dri_config, + dri2_ctx_shared ? + dri2_ctx_shared->dri_context : NULL, + dri2_ctx); + } else if (api == __DRI_API_OPENGL) { + dri2_ctx->dri_context = + dri2_dpy->dri2->createNewContext(dri2_dpy->dri_screen, + dri2_config->dri_config, + dri2_ctx_shared ? + dri2_ctx_shared->dri_context : NULL, + dri2_ctx); + } else { + /* fail */ + } if (!dri2_ctx->dri_context) goto cleanup; @@ -751,6 +1158,8 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + (void) drv; + if (_eglIsSurfaceBound(surf)) return EGL_TRUE; @@ -773,6 +1182,7 @@ static EGLBoolean dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, _EGLSurface *rsurf, _EGLContext *ctx) { + struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_dsurf = dri2_egl_surface(dsurf); struct dri2_egl_surface *dri2_rsurf = dri2_egl_surface(rsurf); @@ -784,6 +1194,10 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, if (!_eglBindContext(&ctx, &dsurf, &rsurf)) return EGL_FALSE; + /* flush before context switch */ + if (ctx && dri2_drv->glFlush) + dri2_drv->glFlush(); + ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL; rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL; cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL; @@ -821,6 +1235,8 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, xcb_screen_iterator_t s; xcb_generic_error_t *error; + (void) drv; + dri2_surf = malloc(sizeof *dri2_surf); if (!dri2_surf) { _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); @@ -834,8 +1250,7 @@ dri2_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, if (type == EGL_PBUFFER_BIT) { dri2_surf->drawable = xcb_generate_id(dri2_dpy->conn); s = xcb_setup_roots_iterator(xcb_get_setup(dri2_dpy->conn)); - xcb_create_pixmap(dri2_dpy->conn, - _eglGetConfigKey(conf, EGL_BUFFER_SIZE), + xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize, dri2_surf->drawable, s.data->root, dri2_surf->base.Width, dri2_surf->base.Height); } else { @@ -909,18 +1324,28 @@ dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, } static EGLBoolean -dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +dri2_copy_region(_EGLDriver *drv, _EGLDisplay *disp, + _EGLSurface *draw, xcb_xfixes_region_t region) { + struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + _EGLContext *ctx; xcb_dri2_copy_region_cookie_t cookie; + if (dri2_drv->glFlush) { + ctx = _eglGetCurrentContext(); + if (ctx && ctx->DrawSurface == &dri2_surf->base) + dri2_drv->glFlush(); + } + (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); #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); @@ -932,7 +1357,7 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) cookie = xcb_dri2_copy_region_unchecked(dri2_dpy->conn, dri2_surf->drawable, - dri2_surf->region, + region, XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT, XCB_DRI2_ATTACHMENT_BUFFER_FAKE_FRONT_LEFT); free(xcb_dri2_copy_region_reply(dri2_dpy->conn, cookie, NULL)); @@ -940,12 +1365,52 @@ dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) return EGL_TRUE; } +static EGLBoolean +dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + + return dri2_copy_region(drv, disp, draw, dri2_surf->region); +} + +static EGLBoolean +dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw, + EGLint numRects, const EGLint *rects) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + EGLBoolean ret; + xcb_xfixes_region_t region; + xcb_rectangle_t rectangles[16]; + int i; + + if (numRects > (int)ARRAY_SIZE(rectangles)) + return dri2_copy_region(drv, disp, draw, dri2_surf->region); + + /* FIXME: Invert y here? */ + for (i = 0; i < numRects; i++) { + rectangles[i].x = rects[i * 4]; + rectangles[i].y = rects[i * 4 + 1]; + rectangles[i].width = rects[i * 4 + 2]; + rectangles[i].height = rects[i * 4 + 3]; + } + + region = xcb_generate_id(dri2_dpy->conn); + xcb_xfixes_create_region(dri2_dpy->conn, region, numRects, rectangles); + ret = dri2_copy_region(drv, disp, draw, region); + xcb_xfixes_destroy_region(dri2_dpy->conn, region); + + return ret; +} + /* * Called from eglGetProcAddress() via drv->API.GetProcAddress(). */ static _EGLProc dri2_get_proc_address(_EGLDriver *drv, const char *procname) { + (void) drv; + /* FIXME: Do we need to support lookup of EGL symbols too? */ return (_EGLProc) _glapi_get_proc_address(procname); @@ -957,6 +1422,8 @@ dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(ctx->DrawSurface); + (void) drv; + /* FIXME: If EGL allows frontbuffer rendering for window surfaces, * we need to copy fake to real here.*/ @@ -968,6 +1435,9 @@ dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) static EGLBoolean dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine) { + (void) drv; + (void) disp; + if (engine != EGL_CORE_NATIVE_ENGINE) return _eglError(EGL_BAD_PARAMETER, "eglWaitNative"); /* glXWaitX(); */ @@ -990,6 +1460,8 @@ dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); xcb_gcontext_t gc; + (void) drv; + (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); gc = xcb_generate_id(dri2_dpy->conn); @@ -1020,19 +1492,8 @@ dri2_bind_tex_image(_EGLDriver *drv, 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"); + if (!_eglBindTexImage(drv, disp, surf, buffer)) return EGL_FALSE; - } switch (dri2_surf->base.TextureFormat) { case EGL_TEXTURE_RGB: @@ -1042,8 +1503,7 @@ dri2_bind_tex_image(_EGLDriver *drv, format = __DRI_TEXTURE_FORMAT_RGBA; break; default: - _eglError(EGL_BAD_MATCH, "eglBindTexImage"); - return EGL_FALSE; + assert(0); } switch (dri2_surf->base.TextureTarget) { @@ -1051,24 +1511,403 @@ dri2_bind_tex_image(_EGLDriver *drv, target = GL_TEXTURE_2D; break; default: - _eglError(EGL_BAD_PARAMETER, "eglBindTexImage"); - return EGL_FALSE; + assert(0); } (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context, target, format, dri2_surf->dri_drawable); - return dri2_surf->base.BoundToTexture = EGL_TRUE; + return EGL_TRUE; } static EGLBoolean dri2_release_tex_image(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer) { + (void) drv; + (void) disp; + (void) surf; + (void) buffer; + return EGL_TRUE; } +static _EGLImage * +dri2_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img; + unsigned int attachments[1]; + xcb_drawable_t drawable; + xcb_dri2_get_buffers_cookie_t buffers_cookie; + xcb_dri2_get_buffers_reply_t *buffers_reply; + xcb_dri2_dri2_buffer_t *buffers; + xcb_get_geometry_cookie_t geometry_cookie; + xcb_get_geometry_reply_t *geometry_reply; + xcb_generic_error_t *error; + int stride, format; + + (void) ctx; + + drawable = (xcb_drawable_t) buffer; + xcb_dri2_create_drawable (dri2_dpy->conn, drawable); + attachments[0] = XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT; + buffers_cookie = + xcb_dri2_get_buffers_unchecked (dri2_dpy->conn, + drawable, 1, 1, attachments); + geometry_cookie = xcb_get_geometry (dri2_dpy->conn, drawable); + buffers_reply = xcb_dri2_get_buffers_reply (dri2_dpy->conn, + buffers_cookie, NULL); + buffers = xcb_dri2_get_buffers_buffers (buffers_reply); + if (buffers == NULL) { + return NULL; + } + + geometry_reply = xcb_get_geometry_reply (dri2_dpy->conn, + geometry_cookie, &error); + if (geometry_reply == NULL || error != NULL) { + _eglError(EGL_BAD_ALLOC, "xcb_get_geometry"); + free(error); + free(buffers_reply); + } + + switch (geometry_reply->depth) { + case 16: + format = __DRI_IMAGE_FORMAT_RGB565; + break; + case 24: + format = __DRI_IMAGE_FORMAT_XRGB8888; + break; + case 32: + format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + default: + _eglError(EGL_BAD_PARAMETER, + "dri2_create_image_khr: unsupported pixmap depth"); + free(buffers_reply); + free(geometry_reply); + return NULL; + } + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + free(buffers_reply); + free(geometry_reply); + _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + if (!_eglInitImage(&dri2_img->base, disp)) { + free(buffers_reply); + free(geometry_reply); + return EGL_NO_IMAGE_KHR; + } + + stride = buffers[0].pitch / buffers[0].cpp; + dri2_img->dri_image = + dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, + buffers_reply->width, + buffers_reply->height, + format, + buffers[0].name, + stride, + dri2_img); + + free(buffers_reply); + free(geometry_reply); + + return &dri2_img->base; +} + +static _EGLImage * +dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer buffer, + const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_image *dri2_img; + GLuint renderbuffer = (GLuint) buffer; + + if (renderbuffer == 0) { + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + if (!_eglInitImage(&dri2_img->base, disp)) + return EGL_NO_IMAGE_KHR; + + dri2_img->dri_image = + dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context, + renderbuffer, + dri2_img); + + return &dri2_img->base; +} + +static _EGLImage * +dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img; + EGLint width, height, format, name, stride, pitch, i, err; + + (void) ctx; + + name = (EGLint) buffer; + + err = EGL_SUCCESS; + width = 0; + height = 0; + format = 0; + stride = 0; + + for (i = 0; attr_list[i] != EGL_NONE; i++) { + EGLint attr = attr_list[i++]; + EGLint val = attr_list[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_STRIDE_MESA: + stride = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr); + return NULL; + } + } + + if (width <= 0 || height <= 0 || stride <= 0) { + _eglError(EGL_BAD_PARAMETER, + "bad width, height or stride"); + return NULL; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = __DRI_IMAGE_FORMAT_ARGB8888; + pitch = stride; + break; + default: + _eglError(EGL_BAD_PARAMETER, + "dri2_create_image_khr: unsupported pixmap depth"); + return NULL; + } + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm"); + return NULL; + } + + if (!_eglInitImage(&dri2_img->base, disp)) { + free(dri2_img); + return NULL; + } + + dri2_img->dri_image = + dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, + width, + height, + format, + name, + pitch, + dri2_img); + if (dri2_img->dri_image == NULL) { + free(dri2_img); + _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm"); + return NULL; + } + + return &dri2_img->base; +} + +static _EGLImage * +dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, + _EGLContext *ctx, EGLenum target, + EGLClientBuffer buffer, const EGLint *attr_list) +{ + (void) drv; + + switch (target) { + case EGL_NATIVE_PIXMAP_KHR: + return dri2_create_image_khr_pixmap(disp, ctx, buffer, attr_list); + case EGL_GL_RENDERBUFFER_KHR: + return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list); + case EGL_DRM_BUFFER_MESA: + return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list); + default: + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } +} + +static EGLBoolean +dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(image); + + (void) drv; + + dri2_dpy->image->destroyImage(dri2_img->dri_image); + free(dri2_img); + + return EGL_TRUE; +} + +static _EGLImage * +dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, + const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img; + int width, height, format, i; + unsigned int use, dri_use, valid_mask; + EGLint err = EGL_SUCCESS; + + (void) drv; + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + if (!attr_list) { + err = EGL_BAD_PARAMETER; + goto cleanup_img; + } + + if (!_eglInitImage(&dri2_img->base, disp)) { + err = EGL_BAD_PARAMETER; + goto cleanup_img; + } + + width = 0; + height = 0; + format = 0; + use = 0; + for (i = 0; attr_list[i] != EGL_NONE; i++) { + EGLint attr = attr_list[i++]; + EGLint val = attr_list[i]; + + switch (attr) { + case EGL_WIDTH: + width = val; + break; + case EGL_HEIGHT: + height = val; + break; + case EGL_DRM_BUFFER_FORMAT_MESA: + format = val; + break; + case EGL_DRM_BUFFER_USE_MESA: + use = val; + break; + default: + err = EGL_BAD_ATTRIBUTE; + break; + } + + if (err != EGL_SUCCESS) { + _eglLog(_EGL_WARNING, "bad image attribute 0x%04x", attr); + goto cleanup_img; + } + } + + if (width <= 0 || height <= 0) { + _eglLog(_EGL_WARNING, "bad width or height (%dx%d)", width, height); + goto cleanup_img; + } + + switch (format) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = __DRI_IMAGE_FORMAT_ARGB8888; + break; + default: + _eglLog(_EGL_WARNING, "bad image format value 0x%04x", format); + goto cleanup_img; + } + + valid_mask = + EGL_DRM_BUFFER_USE_SCANOUT_MESA | + EGL_DRM_BUFFER_USE_SHARE_MESA; + if (use & ~valid_mask) { + _eglLog(_EGL_WARNING, "bad image use bit 0x%04x", use & ~valid_mask); + goto cleanup_img; + } + + dri_use = 0; + if (use & EGL_DRM_BUFFER_USE_SHARE_MESA) + dri_use |= __DRI_IMAGE_USE_SHARE; + if (use & EGL_DRM_BUFFER_USE_SCANOUT_MESA) + dri_use |= __DRI_IMAGE_USE_SCANOUT; + + dri2_img->dri_image = + dri2_dpy->image->createImage(dri2_dpy->dri_screen, + width, height, format, dri_use, dri2_img); + if (dri2_img->dri_image == NULL) { + err = EGL_BAD_ALLOC; + goto cleanup_img; + } + + return &dri2_img->base; + + cleanup_img: + free(dri2_img); + _eglError(err, "dri2_create_drm_image_mesa"); + + return EGL_NO_IMAGE_KHR; +} + +static EGLBoolean +dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, + EGLint *name, EGLint *handle, EGLint *stride) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(img); + + (void) drv; + + if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_NAME, name)) { + _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa"); + return EGL_FALSE; + } + + if (handle) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_HANDLE, handle); + + if (stride) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_STRIDE, stride); + + return EGL_TRUE; +} /** * This is the main entrypoint into the driver, called by libEGL. @@ -1079,10 +1918,13 @@ _eglMain(const char *args) { struct dri2_egl_driver *dri2_drv; + (void) args; + dri2_drv = malloc(sizeof *dri2_drv); if (!dri2_drv) return NULL; + memset(dri2_drv, 0, sizeof *dri2_drv); _eglInitDriverFallbacks(&dri2_drv->base); dri2_drv->base.API.Initialize = dri2_initialize; dri2_drv->base.API.Terminate = dri2_terminate; @@ -1099,9 +1941,17 @@ _eglMain(const char *args) 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.API.CreateImageKHR = dri2_create_image_khr; + dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr; + dri2_drv->base.API.SwapBuffersRegionNOK = dri2_swap_buffers_region; + dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa; + dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa; dri2_drv->base.Name = "DRI2"; dri2_drv->base.Unload = dri2_unload; + dri2_drv->glFlush = + (void (*)(void)) dri2_get_proc_address(&dri2_drv->base, "glFlush"); + return &dri2_drv->base; }