X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fegl%2Fdrivers%2Fdri2%2Fegl_dri2.c;h=8721e67afb32cf8588e787be9d37ff6bedbf7a46;hb=9d84a922b86e371e53b44baeb49cabfff28f2bc1;hp=e55bff6dbbfb8a505d057fcc81133a12e182ec3e;hpb=9365ff4b885730d76e535edc12445b6f1b72f667;p=mesa.git diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index e55bff6dbbf..8721e67afb3 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -25,8 +25,6 @@ * Kristian Høgsberg */ -#define WL_HIDE_DEPRECATED - #include #include #include @@ -42,54 +40,47 @@ #include #ifdef HAVE_LIBDRM #include -#include +#include "drm-uapi/drm_fourcc.h" #endif #include #include -#include "GL/mesa_glinterop.h" #include #include #ifdef HAVE_WAYLAND_PLATFORM +#include #include "wayland-drm.h" #include "wayland-drm-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" #endif #ifdef HAVE_X11_PLATFORM #include "X11/Xlibint.h" #endif +#include "egldefines.h" #include "egl_dri2.h" +#include "GL/mesa_glinterop.h" #include "loader/loader.h" #include "util/u_atomic.h" +#include "util/u_vector.h" +#include "mapi/glapi/glapi.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. +/* Additional definitions not yet in the drm_fourcc.h. */ -#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 */ +#ifndef DRM_FORMAT_P010 +#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cb:Cr plane 10 bits per channel */ #endif -#ifndef DRM_FORMAT_R16 -#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R 16 little endian */ +#ifndef DRM_FORMAT_P012 +#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cb:Cr plane 12 bits per channel */ #endif -#ifndef DRM_FORMAT_GR1616 -#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] R:G 16:16 little endian */ +#ifndef DRM_FORMAT_P016 +#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cb:Cr plane 16 bits per channel */ #endif -#ifndef DRM_FORMAT_MOD_INVALID -#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) -#endif +#define NUM_ATTRIBS 12 static void dri_set_background_context(void *loaderPrivate) @@ -100,6 +91,26 @@ dri_set_background_context(void *loaderPrivate) _eglBindContextToThread(ctx, t); } +static void +dri2_gl_flush() +{ + static void (*glFlush)(void); + static mtx_t glFlushMutex = _MTX_INITIALIZER_NP; + + mtx_lock(&glFlushMutex); + if (!glFlush) + glFlush = _glapi_get_proc_address("glFlush"); + mtx_unlock(&glFlushMutex); + + /* if glFlush is not available things are horribly broken */ + if (!glFlush) { + _eglLog(_EGL_WARNING, "DRI2: failed to find glFlush entry point"); + return; + } + + glFlush(); +} + static GLboolean dri_is_thread_safe(void *loaderPrivate) { @@ -276,7 +287,10 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, _eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT, _EGL_MAX_PBUFFER_HEIGHT); break; - + case __DRI_ATTRIB_MUTABLE_RENDER_BUFFER: + if (disp->Extensions.KHR_mutable_render_buffer) + surface_type |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR; + break; default: key = dri2_to_egl_attribute_map[attrib]; if (key != 0) @@ -342,7 +356,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, _eglLinkConfig(&conf->base); } else { - assert(0); + unreachable("duplicates should not be possible"); return NULL; } @@ -426,12 +440,22 @@ static const struct dri2_extension_match swrast_core_extensions[] = { { NULL, 0, 0 } }; +static const struct dri2_extension_match optional_driver_extensions[] = { + { __DRI_CONFIG_OPTIONS, 1, offsetof(struct dri2_egl_display, configOptions) }, + { NULL, 0, 0 } +}; + static const struct dri2_extension_match optional_core_extensions[] = { { __DRI2_ROBUSTNESS, 1, offsetof(struct dri2_egl_display, robustness) }, + { __DRI2_NO_ERROR, 1, offsetof(struct dri2_egl_display, no_error) }, { __DRI2_CONFIG_QUERY, 1, offsetof(struct dri2_egl_display, config) }, { __DRI2_FENCE, 1, offsetof(struct dri2_egl_display, fence) }, { __DRI2_RENDERER_QUERY, 1, offsetof(struct dri2_egl_display, rendererQuery) }, { __DRI2_INTEROP, 1, offsetof(struct dri2_egl_display, interop) }, + { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) }, + { __DRI2_FLUSH_CONTROL, 1, offsetof(struct dri2_egl_display, flush_control) }, + { __DRI2_BLOB, 1, offsetof(struct dri2_egl_display, blob) }, + { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1, offsetof(struct dri2_egl_display, mutable_render_buffer) }, { NULL, 0, 0 } }; @@ -479,79 +503,19 @@ static const __DRIextension ** dri2_open_driver(_EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - const __DRIextension **extensions = NULL; - char path[PATH_MAX], *search_paths, *next, *end; - char *get_extensions_name; - const __DRIextension **(*get_extensions)(void); - - search_paths = NULL; - if (geteuid() == getuid()) { - /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ - search_paths = getenv("LIBGL_DRIVERS_PATH"); - } - if (search_paths == NULL) - search_paths = DEFAULT_DRIVER_DIR; - - dri2_dpy->driver = NULL; - end = search_paths + strlen(search_paths); - for (char *p = search_paths; p < end; p = next + 1) { - int len; - next = strchr(p, ':'); - if (next == NULL) - next = end; - - len = next - p; -#if GLX_USE_TLS - snprintf(path, sizeof path, - "%.*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()); - } - /* not need continue to loop all paths once the driver is found */ - if (dri2_dpy->driver != NULL) - break; - } - - if (dri2_dpy->driver == NULL) { - _eglLog(_EGL_WARNING, - "DRI2: failed to open %s (search paths %s)", - dri2_dpy->driver_name, search_paths); - return NULL; - } - - _eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path); - - get_extensions_name = loader_get_extensions_name(dri2_dpy->driver_name); - if (get_extensions_name) { - get_extensions = dlsym(dri2_dpy->driver, get_extensions_name); - if (get_extensions) { - extensions = get_extensions(); - } else { - _eglLog(_EGL_DEBUG, "driver does not expose %s(): %s\n", - get_extensions_name, dlerror()); - } - free(get_extensions_name); - } + static const char *search_path_vars[] = { + "LIBGL_DRIVERS_PATH", + NULL, + }; - if (!extensions) - extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS); - if (extensions == NULL) { - _eglLog(_EGL_WARNING, - "DRI2: driver exports no extensions (%s)", dlerror()); - dlclose(dri2_dpy->driver); - } - - return extensions; + return loader_open_driver(dri2_dpy->driver_name, + &dri2_dpy->driver, + search_path_vars); } -EGLBoolean -dri2_load_driver_dri3(_EGLDisplay *disp) +static EGLBoolean +dri2_load_driver_common(_EGLDisplay *disp, + const struct dri2_extension_match *driver_extensions) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); const __DRIextension **extensions; @@ -560,51 +524,33 @@ dri2_load_driver_dri3(_EGLDisplay *disp) if (!extensions) return EGL_FALSE; - if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions, false)) { + if (!dri2_bind_extensions(dri2_dpy, driver_extensions, extensions, false)) { dlclose(dri2_dpy->driver); return EGL_FALSE; } dri2_dpy->driver_extensions = extensions; + dri2_bind_extensions(dri2_dpy, optional_driver_extensions, extensions, true); + return EGL_TRUE; } EGLBoolean dri2_load_driver(_EGLDisplay *disp) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - const __DRIextension **extensions; - - extensions = dri2_open_driver(disp); - if (!extensions) - return EGL_FALSE; - - if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions, false)) { - dlclose(dri2_dpy->driver); - return EGL_FALSE; - } - dri2_dpy->driver_extensions = extensions; + return dri2_load_driver_common(disp, dri2_driver_extensions); +} - return EGL_TRUE; +EGLBoolean +dri2_load_driver_dri3(_EGLDisplay *disp) +{ + return dri2_load_driver_common(disp, dri3_driver_extensions); } EGLBoolean dri2_load_driver_swrast(_EGLDisplay *disp) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - const __DRIextension **extensions; - - extensions = dri2_open_driver(disp); - if (!extensions) - return EGL_FALSE; - - if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions, false)) { - dlclose(dri2_dpy->driver); - return EGL_FALSE; - } - dri2_dpy->driver_extensions = extensions; - - return EGL_TRUE; + return dri2_load_driver_common(disp, swrast_driver_extensions); } static unsigned @@ -620,12 +566,44 @@ dri2_renderer_query_integer(struct dri2_egl_display *dri2_dpy, int param) return value; } +static const char * +dri2_query_driver_name(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->driver_name; +} + +static char * +dri2_query_driver_config(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + const __DRIconfigOptionsExtension *ext = dri2_dpy->configOptions; + + if (ext->base.version >= 2) + return ext->getXml(dri2_dpy->driver_name); + + return strdup(ext->xml); +} + + void dri2_setup_screen(_EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned int api_mask; + /* + * EGL 1.5 specification defines the default value to 1. Moreover, + * eglSwapInterval() is required to clamp requested value to the supported + * range. Since the default value is implicitly assumed to be supported, + * use it as both minimum and maximum for the platforms that do not allow + * changing the interval. Platforms, which allow it (e.g. x11, wayland) + * override these values already. + */ + dri2_dpy->min_swap_interval = 1; + dri2_dpy->max_swap_interval = 1; + dri2_dpy->default_swap_interval = 1; + if (dri2_dpy->image_driver) { api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen); } else if (dri2_dpy->dri2) { @@ -652,6 +630,17 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.KHR_no_config_context = EGL_TRUE; disp->Extensions.KHR_surfaceless_context = EGL_TRUE; + if (dri2_dpy->configOptions) { + disp->Extensions.MESA_query_driver = EGL_TRUE; + } + + /* Report back to EGL the bitmask of priorities supported */ + disp->Extensions.IMG_context_priority = + dri2_renderer_query_integer(dri2_dpy, + __DRI2_RENDERER_HAS_CONTEXT_PRIORITY); + + disp->Extensions.EXT_pixel_format_float = EGL_TRUE; + if (dri2_renderer_query_integer(dri2_dpy, __DRI2_RENDERER_HAS_FRAMEBUFFER_SRGB)) disp->Extensions.KHR_gl_colorspace = EGL_TRUE; @@ -665,12 +654,16 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.EXT_create_context_robustness = EGL_TRUE; } + if (dri2_dpy->no_error) + disp->Extensions.KHR_create_context_no_error = 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->fence->base.version >= 2) { + if (dri2_dpy->fence->base.version >= 2 && + dri2_dpy->fence->get_capabilities) { unsigned capabilities = dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen); disp->Extensions.ANDROID_native_fence_sync = @@ -678,6 +671,9 @@ dri2_setup_screen(_EGLDisplay *disp) } } + if (dri2_dpy->blob) + disp->Extensions.ANDROID_blob_cache = EGL_TRUE; + disp->Extensions.KHR_reusable_sync = EGL_TRUE; if (dri2_dpy->image) { @@ -702,10 +698,11 @@ dri2_setup_screen(_EGLDisplay *disp) dri2_dpy->image->createImageFromTexture) { disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE; + + if (dri2_renderer_query_integer(dri2_dpy, + __DRI2_RENDERER_HAS_TEXTURE_3D)) + disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE; } - 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) { @@ -719,6 +716,44 @@ dri2_setup_screen(_EGLDisplay *disp) } #endif } + + if (dri2_dpy->flush_control) + disp->Extensions.KHR_context_flush_control = EGL_TRUE; +} + +void +dri2_setup_swap_interval(_EGLDisplay *disp, int max_swap_interval) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; + + /* Allow driconf to override applications.*/ + if (dri2_dpy->config) + dri2_dpy->config->configQueryi(dri2_dpy->dri_screen, + "vblank_mode", &vblank_mode); + switch (vblank_mode) { + case DRI_CONF_VBLANK_NEVER: + dri2_dpy->min_swap_interval = 0; + dri2_dpy->max_swap_interval = 0; + dri2_dpy->default_swap_interval = 0; + break; + case DRI_CONF_VBLANK_ALWAYS_SYNC: + dri2_dpy->min_swap_interval = 1; + dri2_dpy->max_swap_interval = max_swap_interval; + dri2_dpy->default_swap_interval = 1; + break; + case DRI_CONF_VBLANK_DEF_INTERVAL_0: + dri2_dpy->min_swap_interval = 0; + dri2_dpy->max_swap_interval = max_swap_interval; + dri2_dpy->default_swap_interval = 0; + break; + default: + case DRI_CONF_VBLANK_DEF_INTERVAL_1: + dri2_dpy->min_swap_interval = 0; + dri2_dpy->max_swap_interval = max_swap_interval; + dri2_dpy->default_swap_interval = 1; + break; + } } /* All platforms but DRM call this function to create the screen and populate @@ -789,6 +824,15 @@ dri2_setup_extensions(_EGLDisplay *disp) if (!dri2_bind_extensions(dri2_dpy, mandatory_core_extensions, extensions, false)) return EGL_FALSE; +#ifdef HAVE_DRI3_MODIFIERS + dri2_dpy->multibuffers_available = + (dri2_dpy->dri3_major_version > 1 || (dri2_dpy->dri3_major_version == 1 && + dri2_dpy->dri3_minor_version >= 2)) && + (dri2_dpy->present_major_version > 1 || (dri2_dpy->present_major_version == 1 && + dri2_dpy->present_minor_version >= 2)) && + (dri2_dpy->image && dri2_dpy->image->base.version >= 15); +#endif + dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true); return EGL_TRUE; } @@ -822,56 +866,36 @@ dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) return EGL_TRUE; } - /* not until swrast_dri is supported */ - if (disp->Options.UseFallback) - return EGL_FALSE; - - /* Nothing to initialize for a test only display */ - if (disp->Options.TestOnly) - return EGL_TRUE; + loader_set_logger(_eglLog); switch (disp->Platform) { -#ifdef HAVE_SURFACELESS_PLATFORM case _EGL_PLATFORM_SURFACELESS: ret = dri2_initialize_surfaceless(drv, disp); break; -#endif -#ifdef HAVE_X11_PLATFORM case _EGL_PLATFORM_X11: ret = dri2_initialize_x11(drv, disp); break; -#endif -#ifdef HAVE_DRM_PLATFORM case _EGL_PLATFORM_DRM: ret = dri2_initialize_drm(drv, disp); break; -#endif -#ifdef HAVE_WAYLAND_PLATFORM case _EGL_PLATFORM_WAYLAND: ret = dri2_initialize_wayland(drv, disp); break; -#endif -#ifdef HAVE_ANDROID_PLATFORM case _EGL_PLATFORM_ANDROID: ret = dri2_initialize_android(drv, disp); break; -#endif default: - _eglLog(_EGL_WARNING, "No EGL platform enabled."); + unreachable("Callers ensure we cannot get here."); return EGL_FALSE; } - if (ret) { - dri2_dpy = dri2_egl_display(disp); - - if (!dri2_dpy) { - return EGL_FALSE; - } + if (!ret) + return EGL_FALSE; - dri2_dpy->ref_count++; - } + dri2_dpy = dri2_egl_display(disp); + dri2_dpy->ref_count++; - return ret; + return EGL_TRUE; } /** @@ -902,8 +926,11 @@ dri2_display_destroy(_EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - if (dri2_dpy->own_dri_screen) + if (dri2_dpy->own_dri_screen) { + if (dri2_dpy->vtbl && dri2_dpy->vtbl->close_screen_notify) + dri2_dpy->vtbl->close_screen_notify(disp); dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); + } if (dri2_dpy->fd >= 0) close(dri2_dpy->fd); if (dri2_dpy->driver) @@ -915,35 +942,17 @@ dri2_display_destroy(_EGLDisplay *disp) #endif switch (disp->Platform) { -#ifdef HAVE_X11_PLATFORM case _EGL_PLATFORM_X11: - if (dri2_dpy->own_device) { - xcb_disconnect(dri2_dpy->conn); - } + dri2_teardown_x11(dri2_dpy); break; -#endif -#ifdef HAVE_DRM_PLATFORM case _EGL_PLATFORM_DRM: - if (dri2_dpy->own_device) { - gbm_device_destroy(&dri2_dpy->gbm_dri->base); - } + dri2_teardown_drm(dri2_dpy); break; -#endif -#ifdef HAVE_WAYLAND_PLATFORM case _EGL_PLATFORM_WAYLAND: - 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); - wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper); - if (dri2_dpy->own_device) { - wl_display_disconnect(dri2_dpy->wl_dpy); - } + dri2_teardown_wayland(dri2_dpy); break; -#endif default: + /* TODO: add teardown for other platforms */ break; } @@ -960,6 +969,40 @@ dri2_display_destroy(_EGLDisplay *disp) disp->DriverData = NULL; } +__DRIbuffer * +dri2_egl_surface_alloc_local_buffer(struct dri2_egl_surface *dri2_surf, + unsigned int att, unsigned int format) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + if (att >= ARRAY_SIZE(dri2_surf->local_buffers)) + return NULL; + + if (!dri2_surf->local_buffers[att]) { + dri2_surf->local_buffers[att] = + dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format, + dri2_surf->base.Width, dri2_surf->base.Height); + } + + return dri2_surf->local_buffers[att]; +} + +void +dri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + for (int i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) { + if (dri2_surf->local_buffers[i]) { + dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen, + dri2_surf->local_buffers[i]); + dri2_surf->local_buffers[i] = NULL; + } + } +} + /** * Called via eglTerminate(), drv->API.Terminate(). * @@ -1033,7 +1076,7 @@ dri2_create_context_attribs_error(int dri_error) break; default: - assert(0); + assert(!"unknown dri_error code"); egl_error = EGL_BAD_MATCH; break; } @@ -1049,14 +1092,14 @@ dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx, { int pos = 0; - assert(*num_attribs >= 8); + assert(*num_attribs >= NUM_ATTRIBS); 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 (dri2_ctx->base.Flags != 0 || dri2_ctx->base.NoError) { /* 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. @@ -1068,7 +1111,8 @@ dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx, } ctx_attribs[pos++] = __DRI_CTX_ATTRIB_FLAGS; - ctx_attribs[pos++] = dri2_ctx->base.Flags; + ctx_attribs[pos++] = dri2_ctx->base.Flags | + (dri2_ctx->base.NoError ? __DRI_CTX_FLAG_NO_ERROR : 0); } if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) { @@ -1085,6 +1129,33 @@ dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx, ctx_attribs[pos++] = __DRI_CTX_RESET_LOSE_CONTEXT; } + if (dri2_ctx->base.ContextPriority != EGL_CONTEXT_PRIORITY_MEDIUM_IMG) { + unsigned val; + + switch (dri2_ctx->base.ContextPriority) { + case EGL_CONTEXT_PRIORITY_HIGH_IMG: + val = __DRI_CTX_PRIORITY_HIGH; + break; + case EGL_CONTEXT_PRIORITY_MEDIUM_IMG: + val = __DRI_CTX_PRIORITY_MEDIUM; + break; + case EGL_CONTEXT_PRIORITY_LOW_IMG: + val = __DRI_CTX_PRIORITY_LOW; + break; + default: + _eglError(EGL_BAD_CONFIG, "eglCreateContext"); + return false; + } + + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_PRIORITY; + ctx_attribs[pos++] = val; + } + + if (dri2_ctx->base.ReleaseBehavior == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR) { + ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR; + ctx_attribs[pos++] = __DRI_CTX_RELEASE_BEHAVIOR_NONE; + } + *num_attribs = pos; return true; @@ -1105,6 +1176,9 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, struct dri2_egl_config *dri2_config = dri2_egl_config(conf); const __DRIconfig *dri_config; int api; + unsigned error; + unsigned num_attribs = NUM_ATTRIBS; + uint32_t ctx_attribs[NUM_ATTRIBS]; (void) drv; @@ -1131,6 +1205,17 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, goto cleanup; } + /* The EGL_KHR_create_context_no_error spec says: + * + * "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR + * used to create does not match the value of + * EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created." + */ + if (share_list && share_list->NoError != dri2_ctx->base.NoError) { + _eglError(EGL_BAD_MATCH, "eglCreateContext"); + goto cleanup; + } + switch (dri2_ctx->base.ClientAPI) { case EGL_OPENGL_ES_API: switch (dri2_ctx->base.ClientMajorVersion) { @@ -1176,25 +1261,15 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, dri_config = dri2_config->dri_config[1][0]; else dri_config = dri2_config->dri_config[0][0]; - - /* EGL_WINDOW_BIT is set only when there is a double-buffered dri_config. - * This makes sure the back buffer will always be used. - */ - if (conf->SurfaceType & EGL_WINDOW_BIT) - dri2_ctx->base.WindowRenderBuffer = EGL_BACK_BUFFER; } else dri_config = NULL; - 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; + if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs, + &num_attribs)) + goto cleanup; + if (dri2_dpy->image_driver) { dri2_ctx->dri_context = dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen, api, @@ -1207,14 +1282,6 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, dri2_create_context_attribs_error(error); } else if (dri2_dpy->dri2) { if (dri2_dpy->dri2->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->dri2->createContextAttribs(dri2_dpy->dri_screen, api, @@ -1236,14 +1303,6 @@ dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, } else { assert(dri2_dpy->swrast); 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, @@ -1291,15 +1350,76 @@ dri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) return EGL_TRUE; } +EGLBoolean +dri2_init_surface(_EGLSurface *surf, _EGLDisplay *disp, EGLint type, + _EGLConfig *conf, const EGLint *attrib_list, EGLBoolean enable_out_fence) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + dri2_surf->out_fence_fd = -1; + dri2_surf->enable_out_fence = false; + if (dri2_dpy->fence && dri2_dpy->fence->base.version >= 2 && + dri2_dpy->fence->get_capabilities && + (dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen) & + __DRI_FENCE_CAP_NATIVE_FD)) { + dri2_surf->enable_out_fence = enable_out_fence; + } + + return _eglInitSurface(surf, disp, type, conf, attrib_list); +} + +static void +dri2_surface_set_out_fence_fd( _EGLSurface *surf, int fence_fd) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + if (dri2_surf->out_fence_fd >= 0) + close(dri2_surf->out_fence_fd); + + dri2_surf->out_fence_fd = fence_fd; +} + +void +dri2_fini_surface(_EGLSurface *surf) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + dri2_surface_set_out_fence_fd(surf, -1); + dri2_surf->enable_out_fence = false; +} + static EGLBoolean -dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) +dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); if (!_eglPutSurface(surf)) return EGL_TRUE; - return dri2_dpy->vtbl->destroy_surface(drv, dpy, surf); + return dri2_dpy->vtbl->destroy_surface(drv, disp, surf); +} + +static void +dri2_surf_update_fence_fd(_EGLContext *ctx, + _EGLDisplay *disp, _EGLSurface *surf) +{ + __DRIcontext *dri_ctx = dri2_egl_context(ctx)->dri_context; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + int fence_fd = -1; + void *fence; + + if (!dri2_surf->enable_out_fence) + return; + + fence = dri2_dpy->fence->create_fence_fd(dri_ctx, -1); + if (fence) { + fence_fd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen, + fence); + dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, fence); + } + dri2_surface_set_out_fence_fd(surf, fence_fd); } /** @@ -1309,9 +1429,10 @@ 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_context *dri2_ctx = dri2_egl_context(ctx); + _EGLDisplay *old_disp = NULL; + struct dri2_egl_display *old_dri2_dpy = NULL; _EGLContext *old_ctx; _EGLSurface *old_dsurf, *old_rsurf; _EGLSurface *tmp_dsurf, *tmp_rsurf; @@ -1328,9 +1449,14 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, return EGL_FALSE; } + if (old_ctx) { + old_disp = old_ctx->Resource.Display; + old_dri2_dpy = dri2_egl_display(old_disp); + } + /* flush before context switch */ if (old_ctx) - dri2_drv->glFlush(); + dri2_gl_flush(); ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL; rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL; @@ -1338,31 +1464,33 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, if (old_ctx) { __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context; + + if (old_dsurf) + dri2_surf_update_fence_fd(old_ctx, disp, old_dsurf); + + /* Disable shared buffer mode */ + if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) && + old_dri2_dpy->vtbl->set_shared_buffer_mode) { + old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false); + } + dri2_dpy->core->unbindContext(old_cctx); } unbind = (cctx == NULL && ddraw == NULL && rdraw == NULL); - if (unbind || dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { - dri2_destroy_surface(drv, disp, old_dsurf); - dri2_destroy_surface(drv, disp, old_rsurf); - - if (!unbind) - dri2_dpy->ref_count++; - if (old_ctx) { - EGLDisplay old_disp = _eglGetDisplayHandle(old_ctx->Resource.Display); - dri2_destroy_context(drv, disp, old_ctx); - dri2_display_release(old_disp); - } - - return EGL_TRUE; - } else { + if (!unbind && !dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { /* undo the previous _eglBindContext */ _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf); assert(&dri2_ctx->base == ctx && tmp_dsurf == dsurf && tmp_rsurf == rsurf); + if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) && + old_dri2_dpy->vtbl->set_shared_buffer_mode) { + old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true); + } + _eglPutSurface(dsurf); _eglPutSurface(rsurf); _eglPutContext(ctx); @@ -1377,6 +1505,31 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, */ return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); } + + dri2_destroy_surface(drv, disp, old_dsurf); + dri2_destroy_surface(drv, disp, old_rsurf); + + if (!unbind) + dri2_dpy->ref_count++; + + if (old_ctx) { + dri2_destroy_context(drv, disp, old_ctx); + dri2_display_release(old_disp); + } + + if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) && + dri2_dpy->vtbl->set_shared_buffer_mode) { + /* Always update the shared buffer mode. This is obviously needed when + * the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When + * EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the + * case where external non-EGL API may have changed window's shared + * buffer mode since we last saw it. + */ + bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER); + dri2_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode); + } + + return EGL_TRUE; } __DRIdrawable * @@ -1393,45 +1546,45 @@ dri2_surface_get_dri_drawable(_EGLSurface *surf) static _EGLProc dri2_get_proc_address(_EGLDriver *drv, const char *procname) { - struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); - - return dri2_drv->get_proc_address(procname); + return _glapi_get_proc_address(procname); } static _EGLSurface* -dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy, +dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, void *native_window, const EGLint *attrib_list) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->create_window_surface(drv, dpy, conf, native_window, + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->create_window_surface(drv, disp, conf, native_window, attrib_list); } static _EGLSurface* -dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy, +dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, void *native_pixmap, const EGLint *attrib_list) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->create_pixmap_surface(drv, dpy, conf, native_pixmap, + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->create_pixmap_surface(drv, disp, conf, native_pixmap, attrib_list); } static _EGLSurface* -dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy, +dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf, const EGLint *attrib_list) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->create_pbuffer_surface(drv, dpy, conf, attrib_list); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->create_pbuffer_surface(drv, disp, conf, attrib_list); } static EGLBoolean -dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, +dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint interval) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->swap_interval(drv, dpy, surf, interval); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + if (!dri2_dpy->vtbl->swap_interval) + return EGL_TRUE; + return dri2_dpy->vtbl->swap_interval(drv, disp, surf, interval); } /** @@ -1471,59 +1624,67 @@ dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw) } static EGLBoolean -dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) +dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->swap_buffers(drv, dpy, surf); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + _EGLContext *ctx = _eglGetCurrentContext(); + + if (ctx && surf) + dri2_surf_update_fence_fd(ctx, disp, surf); + return dri2_dpy->vtbl->swap_buffers(drv, disp, surf); } static EGLBoolean -dri2_swap_buffers_with_damage(_EGLDriver *drv, _EGLDisplay *dpy, +dri2_swap_buffers_with_damage(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, const EGLint *rects, EGLint n_rects) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->swap_buffers_with_damage(drv, dpy, surf, + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + _EGLContext *ctx = _eglGetCurrentContext(); + + if (ctx && surf) + dri2_surf_update_fence_fd(ctx, disp, surf); + return dri2_dpy->vtbl->swap_buffers_with_damage(drv, disp, surf, rects, n_rects); } static EGLBoolean -dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, +dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint numRects, const EGLint *rects) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->swap_buffers_region(drv, dpy, surf, numRects, rects); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->swap_buffers_region(drv, disp, surf, numRects, rects); } static EGLBoolean -dri2_set_damage_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, +dri2_set_damage_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint *rects, EGLint n_rects) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->set_damage_region(drv, dpy, surf, rects, n_rects); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->set_damage_region(drv, disp, surf, rects, n_rects); } static EGLBoolean -dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, +dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint x, EGLint y, EGLint width, EGLint height) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->post_sub_buffer(drv, dpy, surf, x, y, width, height); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->post_sub_buffer(drv, disp, surf, x, y, width, height); } static EGLBoolean -dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, +dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->copy_buffers(drv, dpy, surf, native_pixmap_target); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->copy_buffers(drv, disp, surf, native_pixmap_target); } static EGLint -dri2_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) +dri2_query_buffer_age(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->query_buffer_age(drv, dpy, surf); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->query_buffer_age(drv, disp, surf); } static EGLBoolean @@ -1622,7 +1783,7 @@ dri2_release_tex_image(_EGLDriver *drv, target = GL_TEXTURE_2D; break; default: - assert(0); + assert(!"missing texture target"); } if (dri2_dpy->tex_buffer->base.version >= 3 && @@ -1635,12 +1796,12 @@ dri2_release_tex_image(_EGLDriver *drv, } static _EGLImage* -dri2_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx, +dri2_create_image(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->create_image(drv, dpy, ctx, target, buffer, + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->create_image(drv, disp, ctx, target, buffer, attr_list); } @@ -1667,6 +1828,29 @@ dri2_create_image_from_dri(_EGLDisplay *disp, __DRIimage *dri_image) return &dri2_img->base; } +/** + * Translate a DRI Image extension error code into an EGL error code. + */ +static EGLint +egl_error_from_dri_image_error(int dri_error) +{ + switch (dri_error) { + case __DRI_IMAGE_ERROR_SUCCESS: + return EGL_SUCCESS; + case __DRI_IMAGE_ERROR_BAD_ALLOC: + return EGL_BAD_ALLOC; + case __DRI_IMAGE_ERROR_BAD_MATCH: + return EGL_BAD_MATCH; + case __DRI_IMAGE_ERROR_BAD_PARAMETER: + return EGL_BAD_PARAMETER; + case __DRI_IMAGE_ERROR_BAD_ACCESS: + return EGL_BAD_ACCESS; + default: + assert(!"unknown dri_error code"); + return EGL_BAD_ALLOC; + } +} + static _EGLImage * dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, EGLClientBuffer buffer, @@ -1682,9 +1866,32 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, return EGL_NO_IMAGE_KHR; } - dri_image = - dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context, - renderbuffer, NULL); + if (!disp->Extensions.KHR_gl_renderbuffer_image) { + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + if (dri2_dpy->image->base.version >= 17 && + dri2_dpy->image->createImageFromRenderbuffer2) { + unsigned error = ~0; + + dri_image = dri2_dpy->image->createImageFromRenderbuffer2( + dri2_ctx->dri_context, renderbuffer, NULL, &error); + + assert(!!dri_image == (error == __DRI_IMAGE_ERROR_SUCCESS)); + + if (!dri_image) { + _eglError(egl_error_from_dri_image_error(error), "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + } else { + dri_image = dri2_dpy->image->createImageFromRenderbuffer( + dri2_ctx->dri_context, renderbuffer, NULL); + if (!dri_image) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + } return dri2_create_image_from_dri(disp, dri_image); } @@ -1719,7 +1926,6 @@ dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, const struct wl_drm_components_descriptor *f; __DRIimage *dri_image; _EGLImageAttribs attrs; - EGLint err; int32_t plane; buffer = wayland_drm_buffer_get(dri2_dpy->wl_server_drm, @@ -1727,13 +1933,10 @@ dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, if (!buffer) return NULL; - err = _eglParseImageAttribList(&attrs, disp, attr_list); - plane = attrs.PlaneWL; - if (err != EGL_SUCCESS) { - _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer"); + if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return NULL; - } + plane = attrs.PlaneWL; f = buffer->driver_format; if (plane < 0 || plane >= f->nplanes) { _eglError(EGL_BAD_PARAMETER, @@ -1742,7 +1945,8 @@ dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, } dri_image = dri2_dpy->image->fromPlanar(buffer->driver_buffer, plane, NULL); - + if (dri_image == NULL && plane == 0) + dri_image = dri2_dpy->image->dupImage(buffer->driver_buffer, NULL); if (dri_image == NULL) { _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer"); return NULL; @@ -1753,12 +1957,12 @@ dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, #endif static EGLBoolean -dri2_get_sync_values_chromium(_EGLDisplay *dpy, _EGLSurface *surf, +dri2_get_sync_values_chromium(_EGLDisplay *disp, _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); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->get_sync_values(disp, surf, ust, msc, sbc); } /** @@ -1768,35 +1972,10 @@ dri2_get_sync_values_chromium(_EGLDisplay *dpy, _EGLSurface *surf, static void dri2_create_image_khr_texture_error(int dri_error) { - EGLint egl_error; - - switch (dri_error) { - case __DRI_IMAGE_ERROR_SUCCESS: - return; + EGLint egl_error = egl_error_from_dri_image_error(dri_error); - case __DRI_IMAGE_ERROR_BAD_ALLOC: - egl_error = EGL_BAD_ALLOC; - break; - - case __DRI_IMAGE_ERROR_BAD_MATCH: - egl_error = EGL_BAD_MATCH; - break; - - case __DRI_IMAGE_ERROR_BAD_PARAMETER: - 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; - break; - } - - _eglError(egl_error, "dri2_create_image_khr_texture"); + if (egl_error != EGL_SUCCESS) + _eglError(egl_error, "dri2_create_image_khr_texture"); } static _EGLImage * @@ -1819,35 +1998,43 @@ dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, return EGL_NO_IMAGE_KHR; } - if (_eglParseImageAttribList(&attrs, disp, attr_list) != EGL_SUCCESS) + if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return EGL_NO_IMAGE_KHR; switch (target) { case EGL_GL_TEXTURE_2D_KHR: + if (!disp->Extensions.KHR_gl_texture_2D_image) { + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } depth = 0; gl_target = GL_TEXTURE_2D; break; case EGL_GL_TEXTURE_3D_KHR: - if (disp->Extensions.KHR_gl_texture_3D_image) { - depth = attrs.GLTextureZOffset; - gl_target = GL_TEXTURE_3D; - break; - } - else { + if (!disp->Extensions.KHR_gl_texture_3D_image) { _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); return EGL_NO_IMAGE_KHR; } + + depth = attrs.GLTextureZOffset; + gl_target = GL_TEXTURE_3D; + break; 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: + if (!disp->Extensions.KHR_gl_texture_cubemap_image) { + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + depth = target - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR; gl_target = GL_TEXTURE_CUBE_MAP; break; default: - _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + unreachable("Unexpected target in dri2_create_image_khr_texture()"); return EGL_NO_IMAGE_KHR; } @@ -1877,21 +2064,21 @@ dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, } static EGLBoolean -dri2_query_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf, +dri2_query_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf, EGLint attribute, EGLint *value) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); if (!dri2_dpy->vtbl->query_surface) - return _eglQuerySurface(drv, dpy, surf, attribute, value); - return dri2_dpy->vtbl->query_surface(drv, dpy, surf, attribute, value); + return _eglQuerySurface(drv, disp, surf, attribute, value); + return dri2_dpy->vtbl->query_surface(drv, disp, surf, attribute, value); } static struct wl_buffer* -dri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *dpy, +dri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); - return dri2_dpy->vtbl->create_wayland_buffer_from_image(drv, dpy, img); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + return dri2_dpy->vtbl->create_wayland_buffer_from_image(drv, disp, img); } #ifdef HAVE_LIBDRM @@ -1900,14 +2087,13 @@ 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; + EGLint format, name, pitch; _EGLImageAttribs attrs; __DRIimage *dri_image; name = (EGLint) (uintptr_t) buffer; - err = _eglParseImageAttribList(&attrs, disp, attr_list); - if (err != EGL_SUCCESS) + if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return NULL; if (attrs.Width <= 0 || attrs.Height <= 0 || @@ -2006,13 +2192,13 @@ dri2_check_dma_buf_attribs(const _EGLImageAttribs *attrs) return EGL_TRUE; } -/* Returns the total number of file descriptors. Zero indicates an error. */ +/* Returns the total number of planes for the format or zero if it isn't a + * valid fourcc format. + */ static unsigned -dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) +dri2_num_fourcc_format_planes(EGLint format) { - unsigned plane_n; - - switch (attrs->DMABufFourCC.Value) { + switch (format) { case DRM_FORMAT_R8: case DRM_FORMAT_RG88: case DRM_FORMAT_GR88: @@ -2060,14 +2246,18 @@ dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) case DRM_FORMAT_YVYU: case DRM_FORMAT_UYVY: case DRM_FORMAT_VYUY: - plane_n = 1; - break; + case DRM_FORMAT_AYUV: + return 1; + case DRM_FORMAT_NV12: case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: - plane_n = 2; - break; + case DRM_FORMAT_P010: + case DRM_FORMAT_P012: + case DRM_FORMAT_P016: + return 2; + case DRM_FORMAT_YUV410: case DRM_FORMAT_YVU410: case DRM_FORMAT_YUV411: @@ -2078,12 +2268,40 @@ dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) case DRM_FORMAT_YVU422: case DRM_FORMAT_YUV444: case DRM_FORMAT_YVU444: - plane_n = 3; - break; + return 3; + default: - _eglError(EGL_BAD_ATTRIBUTE, "invalid format"); return 0; } +} + +/* Returns the total number of file descriptors. Zero indicates an error. */ +static unsigned +dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) +{ + unsigned plane_n = dri2_num_fourcc_format_planes(attrs->DMABufFourCC.Value); + if (plane_n == 0) { + _eglError(EGL_BAD_MATCH, "unknown drm fourcc format"); + return 0; + } + + for (unsigned i = plane_n; i < DMA_BUF_MAX_PLANES; i++) { + /** + * The modifiers extension spec says: + * + * "Modifiers may modify any attribute of a buffer import, including + * but not limited to adding extra planes to a format which + * otherwise does not have those planes. As an example, a modifier + * may add a plane for an external compression buffer to a + * single-plane format. The exact meaning and effect of any + * modifier is canonically defined by drm_fourcc.h, not as part of + * this extension." + */ + if (attrs->DMABufPlaneModifiersLo[i].IsPresent && + attrs->DMABufPlaneModifiersHi[i].IsPresent) { + plane_n = i + 1; + } + } /** * The spec says: @@ -2111,25 +2329,7 @@ dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) for (unsigned i = plane_n; i < DMA_BUF_MAX_PLANES; ++i) { if (attrs->DMABufPlaneFds[i].IsPresent || attrs->DMABufPlaneOffsets[i].IsPresent || - attrs->DMABufPlanePitches[i].IsPresent || - attrs->DMABufPlaneModifiersLo[i].IsPresent || - attrs->DMABufPlaneModifiersHi[i].IsPresent) { - - /** - * The modifiers extension spec says: - * - * "Modifiers may modify any attribute of a buffer import, including - * but not limited to adding extra planes to a format which - * otherwise does not have those planes. As an example, a modifier - * may add a plane for an external compression buffer to a - * single-plane format. The exact meaning and effect of any - * modifier is canonically defined by drm_fourcc.h, not as part of - * this extension." - */ - if (attrs->DMABufPlaneModifiersLo[i].IsPresent && - attrs->DMABufPlaneModifiersHi[i].IsPresent) - continue; - + attrs->DMABufPlanePitches[i].IsPresent) { _eglError(EGL_BAD_ATTRIBUTE, "too many plane attributes"); return 0; } @@ -2154,6 +2354,18 @@ dri2_query_dma_buf_formats(_EGLDriver *drv, _EGLDisplay *disp, formats, count)) return EGL_FALSE; + if (max > 0) { + /* Assert that all of the formats returned are actually fourcc formats. + * Some day, if we want the internal interface function to be able to + * return the fake fourcc formats defined in dri_interface.h, we'll have + * to do something more clever here to pair the list down to just real + * fourcc formats so that we don't leak the fake internal ones. + */ + for (int i = 0; i < *count; i++) { + assert(dri2_num_fourcc_format_planes(formats[i]) > 0); + } + } + return EGL_TRUE; } @@ -2164,6 +2376,9 @@ dri2_query_dma_buf_modifiers(_EGLDriver *drv, _EGLDisplay *disp, EGLint format, { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + if (dri2_num_fourcc_format_planes(format) == 0) + return _eglError(EGL_BAD_PARAMETER, "invalid fourcc format"); + if (max < 0) return _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats"); @@ -2199,7 +2414,6 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); _EGLImage *res; - EGLint err; _EGLImageAttribs attrs; __DRIimage *dri_image; unsigned num_fds; @@ -2221,11 +2435,8 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, return NULL; } - err = _eglParseImageAttribList(&attrs, disp, attr_list); - if (err != EGL_SUCCESS) { - _eglError(err, "bad attribute"); + if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return NULL; - } if (!dri2_check_dma_buf_attribs(&attrs)) return NULL; @@ -2244,11 +2455,9 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, * will be present in attrs.DMABufPlaneModifiersLo[0] and * attrs.DMABufPlaneModifiersHi[0] */ if (attrs.DMABufPlaneModifiersLo[0].IsPresent) { - modifier = (uint64_t) attrs.DMABufPlaneModifiersHi[0].Value << 32; - modifier |= (uint64_t) (attrs.DMABufPlaneModifiersLo[0].Value & 0xffffffff); + modifier = combine_u32_into_u64(attrs.DMABufPlaneModifiersHi[0].Value, + attrs.DMABufPlaneModifiersLo[0].Value); has_modifier = true; - } else { - modifier = DRM_FORMAT_MOD_INVALID; } if (has_modifier) { @@ -2298,7 +2507,6 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImageAttribs attrs; unsigned int dri_use, valid_mask; int format; - EGLint err = EGL_SUCCESS; (void) drv; @@ -2307,11 +2515,8 @@ dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, return EGL_NO_IMAGE_KHR; } - err = _eglParseImageAttribList(&attrs, disp, attr_list); - if (err != EGL_SUCCESS) { - _eglError(EGL_BAD_PARAMETER, __func__); + if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return EGL_NO_IMAGE_KHR; - } if (attrs.Width <= 0 || attrs.Height <= 0) { _eglError(EGL_BAD_PARAMETER, __func__); @@ -2389,6 +2594,28 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, return EGL_TRUE; } +/** + * Checks if we can support EGL_MESA_image_dma_buf_export on this image. + + * The spec provides a boolean return for the driver to reject exporting for + * basically any reason, but doesn't specify any particular error cases. For + * now, we just fail if we don't have a DRM fourcc for the format. + */ +static bool +dri2_can_export_dma_buf_image(_EGLDisplay *disp, _EGLImage *img) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(img); + EGLint fourcc; + + if (!dri2_dpy->image->queryImage(dri2_img->dri_image, + __DRI_IMAGE_ATTRIB_FOURCC, &fourcc)) { + return false; + } + + return true; +} + static EGLBoolean dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, @@ -2400,6 +2627,8 @@ dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp, (void) drv; + if (!dri2_can_export_dma_buf_image(disp, img)) + return EGL_FALSE; if (nplanes) dri2_dpy->image->queryImage(dri2_img->dri_image, @@ -2423,6 +2652,9 @@ dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *im (void) drv; + if (!dri2_can_export_dma_buf_image(disp, img)) + return EGL_FALSE; + /* rework later to provide multiple fds/strides/offsets */ if (fds) dri2_dpy->image->queryImage(dri2_img->dri_image, @@ -2462,15 +2694,8 @@ dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp, 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; - } + 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_LIBDRM @@ -2558,17 +2783,17 @@ dri2_wl_release_buffer(void *user_data, struct wl_drm_buffer *buffer) dri2_dpy->image->destroyImage(buffer->driver_buffer); } -static struct wayland_drm_callbacks wl_drm_callbacks = { - .authenticate = NULL, - .reference_buffer = dri2_wl_reference_buffer, - .release_buffer = dri2_wl_release_buffer -}; - static EGLBoolean dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *wl_dpy) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + const struct wayland_drm_callbacks wl_drm_callbacks = { + .authenticate = (int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate, + .reference_buffer = dri2_wl_reference_buffer, + .release_buffer = dri2_wl_release_buffer, + .is_format_supported = dri2_wl_is_format_supported + }; int flags = 0; uint64_t cap; @@ -2577,9 +2802,6 @@ dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp, if (dri2_dpy->wl_server_drm) return EGL_FALSE; - wl_drm_callbacks.authenticate = - (int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate; - 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 && @@ -2681,11 +2903,11 @@ dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy, } static _EGLSync * -dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, +dri2_create_sync(_EGLDriver *drv, _EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list) { _EGLContext *ctx = _eglGetCurrentContext(); - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); struct dri2_egl_sync *dri2_sync; EGLint ret; @@ -2697,7 +2919,7 @@ dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, return NULL; } - if (!_eglInitSync(&dri2_sync->base, dpy, type, attrib_list)) { + if (!_eglInitSync(&dri2_sync->base, disp, type, attrib_list)) { free(dri2_sync); return NULL; } @@ -2782,9 +3004,9 @@ dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy, } static EGLBoolean -dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); EGLint ret = EGL_TRUE; EGLint err; @@ -2811,9 +3033,9 @@ dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) } static EGLint -dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); assert(sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID); @@ -2835,21 +3057,27 @@ dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) return dup(sync->SyncFd); } +static void +dri2_set_blob_cache_funcs(_EGLDriver *drv, _EGLDisplay *disp, + EGLSetBlobFuncANDROID set, + EGLGetBlobFuncANDROID get) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + dri2_dpy->blob->set_cache_funcs(dri2_dpy->dri_screen, + disp->BlobCacheSet, + disp->BlobCacheGet); +} + static EGLint -dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, +dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync, EGLint flags, EGLTime timeout) { _EGLContext *ctx = _eglGetCurrentContext(); - struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); unsigned wait_flags = 0; - /* timespecs for cnd_timedwait */ - struct timespec current; - xtime expire; - EGLint ret = EGL_CONDITION_SATISFIED_KHR; /* The EGL_KHR_fence_sync spec states: @@ -2879,7 +3107,7 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, if (dri2_ctx && dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR && (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)) { /* flush context if EGL_SYNC_FLUSH_COMMANDS_BIT_KHR is set */ - dri2_drv->glFlush(); + dri2_gl_flush(); } /* if timeout is EGL_FOREVER_KHR, it should wait without any timeout.*/ @@ -2890,19 +3118,25 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, } else { /* if reusable sync has not been yet signaled */ if (dri2_sync->base.SyncStatus != EGL_SIGNALED_KHR) { + /* timespecs for cnd_timedwait */ + struct timespec current; + struct timespec expire; + + /* We override the clock to monotonic when creating the condition + * variable. */ clock_gettime(CLOCK_MONOTONIC, ¤t); /* calculating when to expire */ - expire.nsec = timeout % 1000000000L; - expire.sec = timeout / 1000000000L; + expire.tv_nsec = timeout % 1000000000L; + expire.tv_sec = timeout / 1000000000L; - expire.nsec += current.tv_nsec; - expire.sec += current.tv_sec; + expire.tv_nsec += current.tv_nsec; + expire.tv_sec += current.tv_sec; /* expire.nsec now is a number between 0 and 1999999998 */ - if (expire.nsec > 999999999L) { - expire.sec++; - expire.nsec -= 1000000000L; + if (expire.tv_nsec > 999999999L) { + expire.tv_sec++; + expire.tv_nsec -= 1000000000L; } mtx_lock(&dri2_sync->mutex); @@ -2927,7 +3161,7 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, } static EGLBoolean -dri2_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, +dri2_signal_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync, EGLenum mode) { struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); @@ -2953,10 +3187,10 @@ dri2_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync, } static EGLint -dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) +dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync) { _EGLContext *ctx = _eglGetCurrentContext(); - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync); @@ -2966,10 +3200,10 @@ dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync) } static int -dri2_interop_query_device_info(_EGLDisplay *dpy, _EGLContext *ctx, +dri2_interop_query_device_info(_EGLDisplay *disp, _EGLContext *ctx, struct mesa_glinterop_device_info *out) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); if (!dri2_dpy->interop) @@ -2979,11 +3213,11 @@ dri2_interop_query_device_info(_EGLDisplay *dpy, _EGLContext *ctx, } static int -dri2_interop_export_object(_EGLDisplay *dpy, _EGLContext *ctx, +dri2_interop_export_object(_EGLDisplay *disp, _EGLContext *ctx, struct mesa_glinterop_export_in *in, struct mesa_glinterop_export_out *out) { - struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); if (!dri2_dpy->interop) @@ -2992,136 +3226,62 @@ dri2_interop_export_object(_EGLDisplay *dpy, _EGLContext *ctx, return dri2_dpy->interop->export_object(dri2_ctx->dri_context, in, out); } -static void -dri2_unload(_EGLDriver *drv) -{ - struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); - - dlclose(dri2_drv->handle); - free(dri2_drv); -} - -static EGLBoolean -dri2_load(_EGLDriver *drv) -{ - struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); -#ifdef HAVE_ANDROID_PLATFORM - const char *libname = "libglapi.so"; -#elif defined(__APPLE__) - const char *libname = "libglapi.0.dylib"; -#elif defined(__CYGWIN__) - const char *libname = "cygglapi-0.dll"; -#else - const char *libname = "libglapi.so.0"; -#endif - void *handle; - - /* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */ - handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL); - if (!handle) { - _eglLog(_EGL_WARNING, "DRI2: failed to open glapi provider"); - goto no_handle; - } - - dri2_drv->get_proc_address = (_EGLProc (*)(const char *)) - dlsym(handle, "_glapi_get_proc_address"); - - /* if glapi is not available, loading DRI drivers will fail */ - if (!dri2_drv->get_proc_address) { - _eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address"); - goto no_symbol; - } - - dri2_drv->glFlush = (void (*)(void)) - dri2_drv->get_proc_address("glFlush"); - - /* if glFlush is not available things are horribly broken */ - if (!dri2_drv->glFlush) { - _eglLog(_EGL_WARNING, "DRI2: failed to find glFlush entry point"); - goto no_symbol; - } - - dri2_drv->handle = handle; - return EGL_TRUE; - -no_symbol: - dlclose(handle); -no_handle: - return EGL_FALSE; -} - /** * This is the main entrypoint into the driver, called by libEGL. - * Create a new _EGLDriver object and init its dispatch table. + * Gets an _EGLDriver object and init its dispatch table. */ -_EGLDriver * -_eglBuiltInDriverDRI2(const char *args) -{ - struct dri2_egl_driver *dri2_drv; - - (void) args; - - dri2_drv = calloc(1, sizeof *dri2_drv); - if (!dri2_drv) - return NULL; - - if (!dri2_load(&dri2_drv->base)) { - free(dri2_drv); - return NULL; - } - - _eglInitDriverFallbacks(&dri2_drv->base); - dri2_drv->base.API.Initialize = dri2_initialize; - dri2_drv->base.API.Terminate = dri2_terminate; - dri2_drv->base.API.CreateContext = dri2_create_context; - dri2_drv->base.API.DestroyContext = dri2_destroy_context; - dri2_drv->base.API.MakeCurrent = dri2_make_current; - dri2_drv->base.API.CreateWindowSurface = dri2_create_window_surface; - dri2_drv->base.API.CreatePixmapSurface = dri2_create_pixmap_surface; - dri2_drv->base.API.CreatePbufferSurface = dri2_create_pbuffer_surface; - dri2_drv->base.API.DestroySurface = dri2_destroy_surface; - dri2_drv->base.API.GetProcAddress = dri2_get_proc_address; - dri2_drv->base.API.WaitClient = dri2_wait_client; - dri2_drv->base.API.WaitNative = dri2_wait_native; - dri2_drv->base.API.BindTexImage = dri2_bind_tex_image; - dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image; - dri2_drv->base.API.SwapInterval = dri2_swap_interval; - dri2_drv->base.API.SwapBuffers = dri2_swap_buffers; - dri2_drv->base.API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage; - dri2_drv->base.API.SwapBuffersRegionNOK = dri2_swap_buffers_region; - dri2_drv->base.API.SetDamageRegion = dri2_set_damage_region; - dri2_drv->base.API.PostSubBufferNV = dri2_post_sub_buffer; - dri2_drv->base.API.CopyBuffers = dri2_copy_buffers, - dri2_drv->base.API.QueryBufferAge = dri2_query_buffer_age; - 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; - dri2_drv->base.API.QuerySurface = dri2_query_surface; +void +_eglInitDriver(_EGLDriver *dri2_drv) +{ + dri2_drv->API.Initialize = dri2_initialize; + dri2_drv->API.Terminate = dri2_terminate; + dri2_drv->API.CreateContext = dri2_create_context; + dri2_drv->API.DestroyContext = dri2_destroy_context; + dri2_drv->API.MakeCurrent = dri2_make_current; + dri2_drv->API.CreateWindowSurface = dri2_create_window_surface; + dri2_drv->API.CreatePixmapSurface = dri2_create_pixmap_surface; + dri2_drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface; + dri2_drv->API.DestroySurface = dri2_destroy_surface; + dri2_drv->API.GetProcAddress = dri2_get_proc_address; + dri2_drv->API.WaitClient = dri2_wait_client; + dri2_drv->API.WaitNative = dri2_wait_native; + dri2_drv->API.BindTexImage = dri2_bind_tex_image; + dri2_drv->API.ReleaseTexImage = dri2_release_tex_image; + dri2_drv->API.SwapInterval = dri2_swap_interval; + dri2_drv->API.SwapBuffers = dri2_swap_buffers; + dri2_drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage; + dri2_drv->API.SwapBuffersRegionNOK = dri2_swap_buffers_region; + dri2_drv->API.SetDamageRegion = dri2_set_damage_region; + dri2_drv->API.PostSubBufferNV = dri2_post_sub_buffer; + dri2_drv->API.CopyBuffers = dri2_copy_buffers, + dri2_drv->API.QueryBufferAge = dri2_query_buffer_age; + dri2_drv->API.CreateImageKHR = dri2_create_image; + dri2_drv->API.DestroyImageKHR = dri2_destroy_image_khr; + dri2_drv->API.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image; + dri2_drv->API.QuerySurface = dri2_query_surface; + dri2_drv->API.QueryDriverName = dri2_query_driver_name; + dri2_drv->API.QueryDriverConfig = dri2_query_driver_config; #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; - dri2_drv->base.API.QueryDmaBufFormatsEXT = dri2_query_dma_buf_formats; - dri2_drv->base.API.QueryDmaBufModifiersEXT = dri2_query_dma_buf_modifiers; + dri2_drv->API.CreateDRMImageMESA = dri2_create_drm_image_mesa; + dri2_drv->API.ExportDRMImageMESA = dri2_export_drm_image_mesa; + dri2_drv->API.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa; + dri2_drv->API.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa; + dri2_drv->API.QueryDmaBufFormatsEXT = dri2_query_dma_buf_formats; + dri2_drv->API.QueryDmaBufModifiersEXT = dri2_query_dma_buf_modifiers; #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; + dri2_drv->API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl; + dri2_drv->API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl; + dri2_drv->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.SignalSyncKHR = dri2_signal_sync; - dri2_drv->base.API.WaitSyncKHR = dri2_server_wait_sync; - dri2_drv->base.API.DestroySyncKHR = dri2_destroy_sync; - dri2_drv->base.API.GLInteropQueryDeviceInfo = dri2_interop_query_device_info; - dri2_drv->base.API.GLInteropExportObject = dri2_interop_export_object; - dri2_drv->base.API.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd; - - dri2_drv->base.Name = "DRI2"; - dri2_drv->base.Unload = dri2_unload; - - return &dri2_drv->base; + dri2_drv->API.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium; + dri2_drv->API.CreateSyncKHR = dri2_create_sync; + dri2_drv->API.ClientWaitSyncKHR = dri2_client_wait_sync; + dri2_drv->API.SignalSyncKHR = dri2_signal_sync; + dri2_drv->API.WaitSyncKHR = dri2_server_wait_sync; + dri2_drv->API.DestroySyncKHR = dri2_destroy_sync; + dri2_drv->API.GLInteropQueryDeviceInfo = dri2_interop_query_device_info; + dri2_drv->API.GLInteropExportObject = dri2_interop_export_object; + dri2_drv->API.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd; + dri2_drv->API.SetBlobCacheFuncsANDROID = dri2_set_blob_cache_funcs; }