X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fdri2%2Fegl_dri2.c;h=8f50f0ce5737dbdd8d8cef1629a4892575ff251d;hb=d943ac432de1f46cea47bdbf5ffe5365e2aef386;hp=380bd7b095ea1ea38caf4ec123d8adffadf9d019;hpb=5f280d0c4416627810de73a6c68c422453d2b7d9;p=mesa.git diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 380bd7b095e..8f50f0ce573 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -27,6 +27,9 @@ #define WL_HIDE_DEPRECATED +#include +#include +#include #include #include #include @@ -35,7 +38,7 @@ #include #include #include -#ifdef HAVE_DRM_PLATFORM +#ifdef HAVE_LIBDRM #include #include #endif @@ -50,6 +53,23 @@ #endif #include "egl_dri2.h" +#include "util/u_atomic.h" + +/* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate + * some of the definitions here so that building Mesa won't bleeding-edge + * kernel headers. + */ +#ifndef DRM_FORMAT_R8 +#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ +#endif + +#ifndef DRM_FORMAT_RG88 +#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */ +#endif + +#ifndef DRM_FORMAT_GR88 +#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */ +#endif const __DRIuseInvalidateExtension use_invalidate = { .base = { __DRI_USE_INVALIDATE, 1 } @@ -107,6 +127,16 @@ EGLint dri2_to_egl_attribute_map[] = { 0, /* __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE */ }; +const __DRIconfig * +dri2_get_dri_config(struct dri2_egl_config *conf, EGLint surface_type, + EGLenum colorspace) +{ + const bool srgb = colorspace == EGL_GL_COLORSPACE_SRGB_KHR; + + return surface_type == EGL_WINDOW_BIT ? conf->dri_double_config[srgb] : + conf->dri_single_config[srgb]; +} + static EGLBoolean dri2_match_config(const _EGLConfig *conf, const _EGLConfig *criteria) { @@ -128,6 +158,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, struct dri2_egl_display *dri2_dpy; _EGLConfig base; unsigned int attrib, value, double_buffer; + bool srgb = false; EGLint key, bind_to_texture_rgb, bind_to_texture_rgba; unsigned int dri_masks[4] = { 0, 0, 0, 0 }; _EGLConfig *matching_config; @@ -137,7 +168,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, dri2_dpy = disp->DriverData; _eglInitConfig(&base, disp, id); - + i = 0; double_buffer = 0; bind_to_texture_rgb = 0; @@ -153,7 +184,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, else return NULL; _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value); - break; + break; case __DRI_ATTRIB_CONFIG_CAVEAT: if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) @@ -193,6 +224,21 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, dri_masks[3] = value; break; + case __DRI_ATTRIB_ACCUM_RED_SIZE: + case __DRI_ATTRIB_ACCUM_GREEN_SIZE: + case __DRI_ATTRIB_ACCUM_BLUE_SIZE: + case __DRI_ATTRIB_ACCUM_ALPHA_SIZE: + /* Don't expose visuals with the accumulation buffer. */ + if (value > 0) + return NULL; + break; + + case __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE: + srgb = value != 0; + if (!disp->Extensions.KHR_gl_colorspace && srgb) + return NULL; + break; + default: key = dri2_to_egl_attribute_map[attrib]; if (key != 0) @@ -238,27 +284,25 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, 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; + if (double_buffer && !conf->dri_double_config[srgb]) + conf->dri_double_config[srgb] = dri_config; + else if (!double_buffer && !conf->dri_single_config[srgb]) + conf->dri_single_config[srgb] = dri_config; else /* a similar config type is already added (unlikely) => discard */ return NULL; } else if (num_configs == 0) { - conf = malloc(sizeof *conf); + conf = calloc(1, sizeof *conf); if (conf == NULL) return NULL; + if (double_buffer) + conf->dri_double_config[srgb] = dri_config; + else + conf->dri_single_config[srgb] = dri_config; + memcpy(&conf->base, &base, sizeof base); - 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; @@ -304,14 +348,18 @@ const __DRIimageLookupExtension image_lookup_extension = { .lookupEGLImage = dri2_lookup_egl_image }; -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 dri3_driver_extensions[] = { + { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, + { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) }, + { NULL, 0, 0 } +}; + static struct dri2_extension_match dri2_driver_extensions[] = { { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) }, { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) }, @@ -345,22 +393,22 @@ dri2_bind_extensions(struct dri2_egl_display *dri2_dpy, void *field; for (i = 0; extensions[i]; i++) { - _eglLog(_EGL_DEBUG, "DRI2: found extension `%s'", extensions[i]->name); + _eglLog(_EGL_DEBUG, "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", + _eglLog(_EGL_INFO, "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", + _eglLog(_EGL_WARNING, "did not find extension %s version %d", matches[j].name, matches[j].version); ret = EGL_FALSE; } @@ -388,7 +436,7 @@ dri2_open_driver(_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) { + for (p = search_paths; p < end; p = next + 1) { int len; next = strchr(p, ':'); if (next == NULL) @@ -410,6 +458,15 @@ dri2_open_driver(_EGLDisplay *disp) /* not need continue to loop all paths once the driver is found */ if (dri2_dpy->driver != NULL) break; + +#ifdef ANDROID + snprintf(path, sizeof path, "%.*s/gallium_dri.so", len, p); + 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()); + else + break; +#endif } if (dri2_dpy->driver == NULL) { @@ -444,6 +501,25 @@ dri2_open_driver(_EGLDisplay *disp) return extensions; } +EGLBoolean +dri2_load_driver_dri3(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = disp->DriverData; + const __DRIextension **extensions; + + extensions = dri2_open_driver(disp); + if (!extensions) + return EGL_FALSE; + + if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions)) { + dlclose(dri2_dpy->driver); + return EGL_FALSE; + } + dri2_dpy->driver_extensions = extensions; + + return EGL_TRUE; +} + EGLBoolean dri2_load_driver(_EGLDisplay *disp) { @@ -469,9 +545,7 @@ dri2_load_driver_swrast(_EGLDisplay *disp) struct dri2_egl_display *dri2_dpy = disp->DriverData; const __DRIextension **extensions; - dri2_dpy->driver_name = "swrast"; extensions = dri2_open_driver(disp); - if (!extensions) return EGL_FALSE; @@ -484,13 +558,28 @@ dri2_load_driver_swrast(_EGLDisplay *disp) return EGL_TRUE; } +static unsigned +dri2_renderer_query_integer(struct dri2_egl_display *dri2_dpy, int param) +{ + const __DRI2rendererQueryExtension *rendererQuery = dri2_dpy->rendererQuery; + unsigned int value = 0; + + if (!rendererQuery || + rendererQuery->queryInteger(dri2_dpy->dri_screen, param, &value) == -1) + return 0; + + return value; +} + void dri2_setup_screen(_EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned int api_mask; - if (dri2_dpy->dri2) { + if (dri2_dpy->image_driver) { + api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen); + } else if (dri2_dpy->dri2) { api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen); } else { assert(dri2_dpy->swrast); @@ -510,19 +599,46 @@ dri2_setup_screen(_EGLDisplay *disp) if (api_mask & (1 << __DRI_API_GLES3)) disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR; - assert(dri2_dpy->dri2 || dri2_dpy->swrast); + assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast); disp->Extensions.KHR_surfaceless_context = EGL_TRUE; disp->Extensions.MESA_configless_context = EGL_TRUE; - if (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) { + if (dri2_renderer_query_integer(dri2_dpy, + __DRI2_RENDERER_HAS_FRAMEBUFFER_SRGB)) + disp->Extensions.KHR_gl_colorspace = EGL_TRUE; + + if (dri2_dpy->image_driver || + (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) || + (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) { disp->Extensions.KHR_create_context = EGL_TRUE; if (dri2_dpy->robustness) disp->Extensions.EXT_create_context_robustness = EGL_TRUE; } + if (dri2_dpy->fence) { + disp->Extensions.KHR_fence_sync = EGL_TRUE; + disp->Extensions.KHR_wait_sync = EGL_TRUE; + if (dri2_dpy->fence->get_fence_from_cl_event) + disp->Extensions.KHR_cl_event2 = EGL_TRUE; + } + if (dri2_dpy->image) { - disp->Extensions.MESA_drm_image = EGL_TRUE; + if (dri2_dpy->image->base.version >= 10 && + dri2_dpy->image->getCapabilities != NULL) { + int capabilities; + + capabilities = dri2_dpy->image->getCapabilities(dri2_dpy->dri_screen); + disp->Extensions.MESA_drm_image = (capabilities & __DRI_IMAGE_CAP_GLOBAL_NAMES) != 0; + + if (dri2_dpy->image->base.version >= 11) + disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE; + } else { + disp->Extensions.MESA_drm_image = EGL_TRUE; + if (dri2_dpy->image->base.version >= 11) + disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE; + } + disp->Extensions.KHR_image_base = EGL_TRUE; disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; if (dri2_dpy->image->base.version >= 5 && @@ -530,7 +646,10 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE; } -#ifdef HAVE_DRM_PLATFORM + if (dri2_renderer_query_integer(dri2_dpy, + __DRI2_RENDERER_HAS_TEXTURE_3D)) + disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE; +#ifdef HAVE_LIBDRM if (dri2_dpy->image->base.version >= 8 && dri2_dpy->image->createImageFromDmaBufs) { disp->Extensions.EXT_image_dma_buf_import = EGL_TRUE; @@ -539,15 +658,27 @@ dri2_setup_screen(_EGLDisplay *disp) } } +/* All platforms but DRM call this function to create the screen, query the + * dri extensions, setup the vtables and populate the driver_configs. + * DRM inherits all that information from its display - GBM. + */ EGLBoolean dri2_create_screen(_EGLDisplay *disp) { const __DRIextension **extensions; struct dri2_egl_display *dri2_dpy; + unsigned i; dri2_dpy = disp->DriverData; - if (dri2_dpy->dri2) { + if (dri2_dpy->image_driver) { + dri2_dpy->dri_screen = + dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd, + dri2_dpy->extensions, + dri2_dpy->driver_extensions, + &dri2_dpy->driver_configs, + disp); + } else if (dri2_dpy->dri2) { if (dri2_dpy->dri2->base.version >= 4) { dri2_dpy->dri_screen = dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd, @@ -582,27 +713,31 @@ dri2_create_screen(_EGLDisplay *disp) dri2_dpy->own_dri_screen = 1; extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen); - - if (dri2_dpy->dri2) { - unsigned i; + if (dri2_dpy->image_driver || dri2_dpy->dri2) { if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions)) goto cleanup_dri_screen; - - for (i = 0; extensions[i]; i++) { - if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) { - dri2_dpy->robustness = (__DRIrobustnessExtension *) extensions[i]; - } - if (strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0) { - dri2_dpy->config = (__DRI2configQueryExtension *) extensions[i]; - } - } } else { assert(dri2_dpy->swrast); if (!dri2_bind_extensions(dri2_dpy, swrast_core_extensions, extensions)) goto cleanup_dri_screen; } + for (i = 0; extensions[i]; i++) { + if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) { + dri2_dpy->robustness = (__DRIrobustnessExtension *) extensions[i]; + } + if (strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0) { + dri2_dpy->config = (__DRI2configQueryExtension *) extensions[i]; + } + if (strcmp(extensions[i]->name, __DRI2_FENCE) == 0) { + dri2_dpy->fence = (__DRI2fenceExtension *) extensions[i]; + } + if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { + dri2_dpy->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; + } + } + dri2_setup_screen(disp); return EGL_TRUE; @@ -624,6 +759,13 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) return EGL_FALSE; switch (disp->Platform) { +#ifdef HAVE_SURFACELESS_PLATFORM + case _EGL_PLATFORM_SURFACELESS: + if (disp->Options.TestOnly) + return EGL_TRUE; + return dri2_initialize_surfaceless(drv, disp); +#endif + #ifdef HAVE_X11_PLATFORM case _EGL_PLATFORM_X11: if (disp->Options.TestOnly) @@ -651,6 +793,7 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) #endif default: + _eglLog(_EGL_WARNING, "No EGL platform enabled."); return EGL_FALSE; } } @@ -662,17 +805,19 @@ static EGLBoolean dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + unsigned i; _eglReleaseDisplayResources(drv, disp); _eglCleanupDisplay(disp); if (dri2_dpy->own_dri_screen) dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); - if (dri2_dpy->fd) + if (dri2_dpy->fd >= 0) close(dri2_dpy->fd); if (dri2_dpy->driver) dlclose(dri2_dpy->driver); free(dri2_dpy->device_name); + free(dri2_dpy->driver_name); switch (disp->Platform) { #ifdef HAVE_X11_PLATFORM @@ -691,7 +836,12 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) #endif #ifdef HAVE_WAYLAND_PLATFORM case _EGL_PLATFORM_WAYLAND: - wl_drm_destroy(dri2_dpy->wl_drm); + if (dri2_dpy->wl_drm) + wl_drm_destroy(dri2_dpy->wl_drm); + if (dri2_dpy->wl_shm) + wl_shm_destroy(dri2_dpy->wl_shm); + wl_registry_destroy(dri2_dpy->wl_registry); + wl_event_queue_destroy(dri2_dpy->wl_queue); if (dri2_dpy->own_device) { wl_display_disconnect(dri2_dpy->wl_dpy); } @@ -701,6 +851,15 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) break; } + /* The drm platform does not create the screen/driver_configs but reuses + * the ones from the gbm device. As such the gbm itself is responsible + * for the cleanup. + */ + if (disp->Platform != _EGL_PLATFORM_DRM) { + for (i = 0; dri2_dpy->driver_configs[i]; i++) + free((__DRIconfig *) dri2_dpy->driver_configs[i]); + free(dri2_dpy->driver_configs); + } free(dri2_dpy); disp->DriverData = NULL; @@ -771,6 +930,55 @@ dri2_create_context_attribs_error(int dri_error) _eglError(egl_error, "dri2_create_context"); } +static bool +dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx, + struct dri2_egl_display *dri2_dpy, + uint32_t *ctx_attribs, + unsigned *num_attribs) +{ + int pos = 0; + + assert(*num_attribs >= 8); + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; + ctx_attribs[pos++] = dri2_ctx->base.ClientMajorVersion; + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MINOR_VERSION; + ctx_attribs[pos++] = dri2_ctx->base.ClientMinorVersion; + + if (dri2_ctx->base.Flags != 0) { + /* If the implementation doesn't support the __DRI2_ROBUSTNESS + * extension, don't even try to send it the robust-access flag. + * It may explode. Instead, generate the required EGL error here. + */ + if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0 + && !dri2_dpy->robustness) { + _eglError(EGL_BAD_MATCH, "eglCreateContext"); + return false; + } + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_FLAGS; + ctx_attribs[pos++] = dri2_ctx->base.Flags; + } + + if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) { + /* If the implementation doesn't support the __DRI2_ROBUSTNESS + * extension, don't even try to send it a reset strategy. It may + * explode. Instead, generate the required EGL error here. + */ + if (!dri2_dpy->robustness) { + _eglError(EGL_BAD_CONFIG, "eglCreateContext"); + return false; + } + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; + ctx_attribs[pos++] = __DRI_CTX_RESET_LOSE_CONTEXT; + } + + *num_attribs = pos; + + return true; +} + /** * Called via eglCreateContext(), drv->API.CreateContext(). */ @@ -811,8 +1019,9 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, api = __DRI_API_GLES3; break; default: - _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); - return NULL; + _eglError(EGL_BAD_PARAMETER, "eglCreateContext"); + free(dri2_ctx); + return NULL; } break; case EGL_OPENGL_API: @@ -838,10 +1047,10 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, * doubleBufferMode check in * src/mesa/main/context.c:check_compatible() */ - if (dri2_config->dri_double_config) - dri_config = dri2_config->dri_double_config; + if (dri2_config->dri_double_config[0]) + dri_config = dri2_config->dri_double_config[0]; else - dri_config = dri2_config->dri_single_config; + dri_config = dri2_config->dri_single_config[0]; /* EGL_WINDOW_BIT is set only when there is a dri_double_config. This * makes sure the back buffer will always be used. @@ -852,47 +1061,34 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, else dri_config = NULL; - if (dri2_dpy->dri2) { + if (dri2_dpy->image_driver) { + unsigned error; + unsigned num_attribs = 8; + uint32_t ctx_attribs[8]; + + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; + + dri2_ctx->dri_context = + dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen, + api, + dri_config, + shared, + num_attribs / 2, + ctx_attribs, + & error, + dri2_ctx); + dri2_create_context_attribs_error(error); + } else if (dri2_dpy->dri2) { if (dri2_dpy->dri2->base.version >= 3) { unsigned error; - unsigned num_attribs = 0; + unsigned num_attribs = 8; uint32_t ctx_attribs[8]; - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; - ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMajorVersion; - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; - ctx_attribs[num_attribs++] = dri2_ctx->base.ClientMinorVersion; - - if (dri2_ctx->base.Flags != 0) { - /* If the implementation doesn't support the __DRI2_ROBUSTNESS - * extension, don't even try to send it the robust-access flag. - * It may explode. Instead, generate the required EGL error here. - */ - if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0 - && !dri2_dpy->robustness) { - _eglError(EGL_BAD_MATCH, "eglCreateContext"); - goto cleanup; - } - - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_FLAGS; - ctx_attribs[num_attribs++] = dri2_ctx->base.Flags; - } - - if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) { - /* If the implementation doesn't support the __DRI2_ROBUSTNESS - * extension, don't even try to send it a reset strategy. It may - * explode. Instead, generate the required EGL error here. - */ - if (!dri2_dpy->robustness) { - _eglError(EGL_BAD_CONFIG, "eglCreateContext"); - goto cleanup; - } - - ctx_attribs[num_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; - ctx_attribs[num_attribs++] = __DRI_CTX_RESET_LOSE_CONTEXT; - } - - assert(num_attribs <= ARRAY_SIZE(ctx_attribs)); + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; dri2_ctx->dri_context = dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen, @@ -914,12 +1110,33 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, } } else { assert(dri2_dpy->swrast); - dri2_ctx->dri_context = - dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen, - api, - dri_config, - shared, - dri2_ctx); + if (dri2_dpy->swrast->base.version >= 3) { + unsigned error; + unsigned num_attribs = 8; + uint32_t ctx_attribs[8]; + + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; + + dri2_ctx->dri_context = + dri2_dpy->swrast->createContextAttribs(dri2_dpy->dri_screen, + api, + dri_config, + shared, + num_attribs / 2, + ctx_attribs, + & error, + dri2_ctx); + dri2_create_context_attribs_error(error); + } else { + dri2_ctx->dri_context = + dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen, + api, + dri_config, + shared, + dri2_ctx); + } } if (!dri2_ctx->dri_context) @@ -958,11 +1175,10 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, { 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); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); _EGLContext *old_ctx; _EGLSurface *old_dsurf, *old_rsurf; + _EGLSurface *tmp_dsurf, *tmp_rsurf; __DRIdrawable *ddraw, *rdraw; __DRIcontext *cctx; @@ -974,8 +1190,8 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, if (old_ctx && dri2_drv->glFlush) dri2_drv->glFlush(); - ddraw = (dri2_dsurf) ? dri2_dsurf->dri_drawable : NULL; - rdraw = (dri2_rsurf) ? dri2_rsurf->dri_drawable : NULL; + ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL; + rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL; cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL; if (old_ctx) { @@ -995,10 +1211,10 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, return EGL_TRUE; } else { /* undo the previous _eglBindContext */ - _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &dsurf, &rsurf); + _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf); assert(&dri2_ctx->base == ctx && - &dri2_dsurf->base == dsurf && - &dri2_rsurf->base == rsurf); + tmp_dsurf == dsurf && + tmp_rsurf == rsurf); _eglPutSurface(dsurf); _eglPutSurface(rsurf); @@ -1012,6 +1228,14 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, } } +__DRIdrawable * +dri2_surface_get_dri_drawable(_EGLSurface *surf) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + return dri2_surf->dri_drawable; +} + /* * Called from eglGetProcAddress() via drv->API.GetProcAddress(). */ @@ -1066,6 +1290,42 @@ dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, return dri2_dpy->vtbl->swap_interval(drv, dpy, surf, interval); } +/** + * Asks the client API to flush any rendering to the drawable so that we can + * do our swapbuffers. + */ +void +dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(draw); + + if (dri2_dpy->flush) { + if (dri2_dpy->flush->base.version >= 4) { + /* We know there's a current context because: + * + * "If surface is not bound to the calling thread’s current + * context, an EGL_BAD_SURFACE error is generated." + */ + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + + /* From the EGL 1.4 spec (page 52): + * + * "The contents of ancillary buffers are always undefined + * after calling eglSwapBuffers." + */ + dri2_dpy->flush->flush_with_flags(dri2_ctx->dri_context, + dri_drawable, + __DRI2_FLUSH_DRAWABLE | + __DRI2_FLUSH_INVALIDATE_ANCILLARY, + __DRI2_THROTTLE_SWAPBUFFER); + } else { + dri2_dpy->flush->flush(dri_drawable); + } + } +} + static EGLBoolean dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) { @@ -1118,7 +1378,8 @@ static EGLBoolean 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); + _EGLSurface *surf = ctx->DrawSurface; + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf); (void) drv; @@ -1126,7 +1387,7 @@ dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) * we need to copy fake to real here.*/ if (dri2_dpy->flush != NULL) - dri2_dpy->flush->flush(dri2_surf->dri_drawable); + dri2_dpy->flush->flush(dri_drawable); return EGL_TRUE; } @@ -1149,10 +1410,10 @@ 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; + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf); ctx = _eglGetCurrentContext(); dri2_ctx = dri2_egl_context(ctx); @@ -1160,7 +1421,7 @@ dri2_bind_tex_image(_EGLDriver *drv, if (!_eglBindTexImage(drv, disp, surf, buffer)) return EGL_FALSE; - switch (dri2_surf->base.TextureFormat) { + switch (surf->TextureFormat) { case EGL_TEXTURE_RGB: format = __DRI_TEXTURE_FORMAT_RGB; break; @@ -1168,20 +1429,22 @@ dri2_bind_tex_image(_EGLDriver *drv, format = __DRI_TEXTURE_FORMAT_RGBA; break; default: - assert(0); + assert(!"Unexpected texture format in dri2_bind_tex_image()"); + format = __DRI_TEXTURE_FORMAT_RGBA; } - switch (dri2_surf->base.TextureTarget) { + switch (surf->TextureTarget) { case EGL_TEXTURE_2D: target = GL_TEXTURE_2D; break; default: - assert(0); + target = GL_TEXTURE_2D; + assert(!"Unexpected texture target in dri2_bind_tex_image()"); } (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context, target, format, - dri2_surf->dri_drawable); + dri_drawable); return EGL_TRUE; } @@ -1191,10 +1454,10 @@ dri2_release_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 target; + __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf); ctx = _eglGetCurrentContext(); dri2_ctx = dri2_egl_context(ctx); @@ -1202,7 +1465,7 @@ dri2_release_tex_image(_EGLDriver *drv, if (!_eglReleaseTexImage(drv, disp, surf, buffer)) return EGL_FALSE; - switch (dri2_surf->base.TextureTarget) { + switch (surf->TextureTarget) { case EGL_TEXTURE_2D: target = GL_TEXTURE_2D; break; @@ -1214,7 +1477,7 @@ dri2_release_tex_image(_EGLDriver *drv, dri2_dpy->tex_buffer->releaseTexBuffer != NULL) { (*dri2_dpy->tex_buffer->releaseTexBuffer)(dri2_ctx->dri_context, target, - dri2_surf->dri_drawable); + dri_drawable); } return EGL_TRUE; @@ -1278,53 +1541,6 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, return dri2_create_image_from_dri(disp, dri_image); } -#ifdef HAVE_DRM_PLATFORM -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); - EGLint format, name, pitch, err; - _EGLImageAttribs attrs; - __DRIimage *dri_image; - - name = (EGLint) (uintptr_t) buffer; - - err = _eglParseImageAttribList(&attrs, disp, attr_list); - if (err != EGL_SUCCESS) - return NULL; - - if (attrs.Width <= 0 || attrs.Height <= 0 || - attrs.DRMBufferStrideMESA <= 0) { - _eglError(EGL_BAD_PARAMETER, - "bad width, height or stride"); - return NULL; - } - - switch (attrs.DRMBufferFormatMESA) { - case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: - format = __DRI_IMAGE_FORMAT_ARGB8888; - pitch = attrs.DRMBufferStrideMESA; - break; - default: - _eglError(EGL_BAD_PARAMETER, - "dri2_create_image_khr: unsupported pixmap depth"); - return NULL; - } - - dri_image = - dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, - attrs.Width, - attrs.Height, - format, - name, - pitch, - NULL); - - return dri2_create_image_from_dri(disp, dri_image); -} -#endif - #ifdef HAVE_WAYLAND_PLATFORM /* This structure describes how a wl_buffer maps to one or more @@ -1388,6 +1604,15 @@ dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, } #endif +static EGLBoolean +dri2_get_sync_values_chromium(_EGLDisplay *dpy, _EGLSurface *surf, + EGLuint64KHR *ust, EGLuint64KHR *msc, + EGLuint64KHR *sbc) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + return dri2_dpy->vtbl->get_sync_values(dpy, surf, ust, msc, sbc); +} + /** * Set the error code after a call to * dri2_egl_image::dri_image::createImageFromTexture. @@ -1413,6 +1638,10 @@ dri2_create_image_khr_texture_error(int dri_error) egl_error = EGL_BAD_PARAMETER; break; + case __DRI_IMAGE_ERROR_BAD_ACCESS: + egl_error = EGL_BAD_ACCESS; + break; + default: assert(0); egl_error = EGL_BAD_MATCH; @@ -1451,9 +1680,15 @@ dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, gl_target = GL_TEXTURE_2D; break; case EGL_GL_TEXTURE_3D_KHR: - depth = attrs.GLTextureZOffset; - gl_target = GL_TEXTURE_3D; - break; + if (disp->Extensions.KHR_gl_texture_3D_image) { + depth = attrs.GLTextureZOffset; + gl_target = GL_TEXTURE_3D; + break; + } + else { + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: @@ -1505,7 +1740,52 @@ dri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *dpy, return dri2_dpy->vtbl->create_wayland_buffer_from_image(drv, dpy, img); } -#ifdef HAVE_DRM_PLATFORM +#ifdef HAVE_LIBDRM +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); + EGLint format, name, pitch, err; + _EGLImageAttribs attrs; + __DRIimage *dri_image; + + name = (EGLint) (uintptr_t) buffer; + + err = _eglParseImageAttribList(&attrs, disp, attr_list); + if (err != EGL_SUCCESS) + return NULL; + + if (attrs.Width <= 0 || attrs.Height <= 0 || + attrs.DRMBufferStrideMESA <= 0) { + _eglError(EGL_BAD_PARAMETER, + "bad width, height or stride"); + return NULL; + } + + switch (attrs.DRMBufferFormatMESA) { + case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: + format = __DRI_IMAGE_FORMAT_ARGB8888; + pitch = attrs.DRMBufferStrideMESA; + break; + default: + _eglError(EGL_BAD_PARAMETER, + "dri2_create_image_khr: unsupported pixmap depth"); + return NULL; + } + + dri_image = + dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen, + attrs.Width, + attrs.Height, + format, + name, + pitch, + NULL); + + return dri2_create_image_from_dri(disp, dri_image); +} + static EGLBoolean dri2_check_dma_buf_attribs(const _EGLImageAttribs *attrs) { @@ -1558,6 +1838,9 @@ dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) unsigned i, plane_n; switch (attrs->DMABufFourCC.Value) { + case DRM_FORMAT_R8: + case DRM_FORMAT_RG88: + case DRM_FORMAT_GR88: case DRM_FORMAT_RGB332: case DRM_FORMAT_BGR233: case DRM_FORMAT_XRGB4444: @@ -1663,36 +1946,13 @@ dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) /** * The spec says: * - * "If eglCreateImageKHR is successful for a EGL_LINUX_DMA_BUF_EXT target, - * the EGL takes ownership of the file descriptor and is responsible for - * closing it, which it may do at any time while the EGLDisplay is - * initialized." + * "If eglCreateImageKHR is successful for a EGL_LINUX_DMA_BUF_EXT target, the + * EGL will take a reference to the dma_buf(s) which it will release at any + * time while the EGLDisplay is initialized. It is the responsibility of the + * application to close the dma_buf file descriptors." + * + * Therefore we must never close or otherwise modify the file descriptors. */ -static void -dri2_take_dma_buf_ownership(const int *fds, unsigned num_fds) -{ - int already_closed[num_fds]; - unsigned num_closed = 0; - unsigned i, j; - - for (i = 0; i < num_fds; ++i) { - /** - * The same file descriptor can be referenced multiple times in case more - * than one plane is found in the same buffer, just with a different - * offset. - */ - for (j = 0; j < num_closed; ++j) { - if (already_closed[j] == fds[i]) - break; - } - - if (j == num_closed) { - close(fds[i]); - already_closed[num_closed++] = fds[i]; - } - } -} - static _EGLImage * dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, EGLClientBuffer buffer, const EGLint *attr_list) @@ -1755,64 +2015,9 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, return EGL_NO_IMAGE_KHR; res = dri2_create_image_from_dri(disp, dri_image); - if (res) - dri2_take_dma_buf_ownership(fds, num_fds); return res; } -#endif - -_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_GL_TEXTURE_2D_KHR: - case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: - case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: - case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: - case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: - case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: - case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: - return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list); - case EGL_GL_RENDERBUFFER_KHR: - return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list); -#ifdef HAVE_DRM_PLATFORM - case EGL_DRM_BUFFER_MESA: - return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list); -#endif -#ifdef HAVE_WAYLAND_PLATFORM - case EGL_WAYLAND_BUFFER_WL: - return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list); -#endif -#ifdef HAVE_DRM_PLATFORM - case EGL_LINUX_DMA_BUF_EXT: - return dri2_create_image_dma_buf(disp, ctx, buffer, attr_list); -#endif - 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; -} - -#ifdef HAVE_DRM_PLATFORM static _EGLImage * dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, const EGLint *attr_list) @@ -1880,7 +2085,7 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA) dri_use |= __DRI_IMAGE_USE_CURSOR; - dri2_img->dri_image = + dri2_img->dri_image = dri2_dpy->image->createImage(dri2_dpy->dri_screen, attrs.Width, attrs.Height, format, dri_use, dri2_img); @@ -1923,7 +2128,113 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, return EGL_TRUE; } + +static EGLBoolean +dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp, + _EGLImage *img, + EGLint *fourcc, EGLint *nplanes, + EGLuint64KHR *modifiers) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(img); + + (void) drv; + + + if (nplanes) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_NUM_PLANES, nplanes); + if (fourcc) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_FOURCC, fourcc); + + if (modifiers) + *modifiers = 0; + + return EGL_TRUE; +} + +static EGLBoolean +dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, + int *fds, EGLint *strides, EGLint *offsets) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(img); + + (void) drv; + + /* rework later to provide multiple fds/strides/offsets */ + if (fds) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_FD, fds); + + if (strides) + dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_STRIDE, strides); + + if (offsets) + offsets[0] = 0; + + return EGL_TRUE; +} + +#endif + +_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_GL_TEXTURE_2D_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: + return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list); + case EGL_GL_TEXTURE_3D_KHR: + if (disp->Extensions.KHR_gl_texture_3D_image) { + return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list); + } + else { + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + case EGL_GL_RENDERBUFFER_KHR: + return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list); +#ifdef HAVE_LIBDRM + case EGL_DRM_BUFFER_MESA: + return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list); + case EGL_LINUX_DMA_BUF_EXT: + return dri2_create_image_dma_buf(disp, ctx, buffer, attr_list); #endif +#ifdef HAVE_WAYLAND_PLATFORM + case EGL_WAYLAND_BUFFER_WL: + return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list); +#endif + 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; +} #ifdef HAVE_WAYLAND_PLATFORM @@ -1991,7 +2302,7 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *wl_dpy) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - int ret, flags = 0; + int flags = 0; uint64_t cap; (void) drv; @@ -2002,8 +2313,8 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, wl_drm_callbacks.authenticate = (int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate; - ret = drmGetCap(dri2_dpy->fd, DRM_CAP_PRIME, &cap); - if (ret == 0 && cap == (DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT) && + if (drmGetCap(dri2_dpy->fd, DRM_CAP_PRIME, &cap) == 0 && + cap == (DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT) && dri2_dpy->image->base.version >= 7 && dri2_dpy->image->createImageFromFds != NULL) flags |= WAYLAND_DRM_PRIME; @@ -2072,6 +2383,135 @@ dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp, } #endif +static void +dri2_egl_ref_sync(struct dri2_egl_sync *sync) +{ + p_atomic_inc(&sync->refcount); +} + +static void +dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_sync *dri2_sync) +{ + if (p_atomic_dec_zero(&dri2_sync->refcount)) { + dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence); + free(dri2_sync); + } +} + +static _EGLSync * +dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, + EGLenum type, const EGLint *attrib_list, + const EGLAttrib *attrib_list64) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_sync *dri2_sync; + + dri2_sync = calloc(1, sizeof(struct dri2_egl_sync)); + if (!dri2_sync) { + _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR"); + return NULL; + } + + if (!_eglInitSync(&dri2_sync->base, dpy, type, attrib_list, + attrib_list64)) { + free(dri2_sync); + return NULL; + } + + switch (type) { + case EGL_SYNC_FENCE_KHR: + dri2_sync->fence = dri2_dpy->fence->create_fence(dri2_ctx->dri_context); + if (!dri2_sync->fence) { + /* Why did it fail? DRI doesn't return an error code, so we emit + * a generic EGL error that doesn't communicate user error. + */ + _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR"); + free(dri2_sync); + return NULL; + } + break; + + case EGL_SYNC_CL_EVENT_KHR: + dri2_sync->fence = dri2_dpy->fence->get_fence_from_cl_event( + dri2_dpy->dri_screen, + dri2_sync->base.CLEvent); + /* this can only happen if the cl_event passed in is invalid. */ + if (!dri2_sync->fence) { + _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR"); + free(dri2_sync); + return NULL; + } + + /* the initial status must be "signaled" if the cl_event is signaled */ + if (dri2_dpy->fence->client_wait_sync(dri2_ctx->dri_context, + dri2_sync->fence, 0, 0)) + dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR; + break; + } + + p_atomic_set(&dri2_sync->refcount, 1); + return &dri2_sync->base; +} + +static EGLBoolean +dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); + + dri2_egl_unref_sync(dri2_dpy, dri2_sync); + return EGL_TRUE; +} + +static EGLint +dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, + EGLint flags, EGLTime timeout) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); + unsigned wait_flags = 0; + EGLint ret = EGL_CONDITION_SATISFIED_KHR; + + /* The EGL_KHR_fence_sync spec states: + * + * "If no context is current for the bound API, + * the EGL_SYNC_FLUSH_COMMANDS_BIT_KHR bit is ignored. + */ + if (dri2_ctx && flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR) + wait_flags |= __DRI2_FENCE_FLAG_FLUSH_COMMANDS; + + /* the sync object should take a reference while waiting */ + dri2_egl_ref_sync(dri2_sync); + + if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL, + dri2_sync->fence, wait_flags, + timeout)) + dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR; + else + ret = EGL_TIMEOUT_EXPIRED_KHR; + + dri2_egl_unref_sync(dri2_dpy, dri2_sync); + return ret; +} + +static EGLint +dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); + + dri2_dpy->fence->server_wait_sync(dri2_ctx->dri_context, + dri2_sync->fence, 0); + return EGL_TRUE; +} + static void dri2_unload(_EGLDriver *drv) { @@ -2086,18 +2526,12 @@ static EGLBoolean dri2_load(_EGLDriver *drv) { struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); -#ifdef HAVE_SHARED_GLAPI #ifdef HAVE_ANDROID_PLATFORM const char *libname = "libglapi.so"; +#elif defined(__APPLE__) + const char *libname = "libglapi.0.dylib"; #else const char *libname = "libglapi.so.0"; -#endif -#else - /* - * Both libGL.so and libglapi.so are glapi providers. There is no way to - * tell which one to load. - */ - const char *libname = NULL; #endif void *handle; @@ -2172,15 +2606,22 @@ _eglBuiltInDriverDRI2(const char *args) dri2_drv->base.API.CreateImageKHR = dri2_create_image; dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr; dri2_drv->base.API.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image; -#ifdef HAVE_DRM_PLATFORM +#ifdef HAVE_LIBDRM dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa; dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa; + dri2_drv->base.API.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa; + dri2_drv->base.API.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa; #endif #ifdef HAVE_WAYLAND_PLATFORM dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl; dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl; dri2_drv->base.API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl; #endif + dri2_drv->base.API.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium; + dri2_drv->base.API.CreateSyncKHR = dri2_create_sync; + dri2_drv->base.API.ClientWaitSyncKHR = dri2_client_wait_sync; + dri2_drv->base.API.WaitSyncKHR = dri2_server_wait_sync; + dri2_drv->base.API.DestroySyncKHR = dri2_destroy_sync; dri2_drv->base.Name = "DRI2"; dri2_drv->base.Unload = dri2_unload;