From: Jonny Lamb <jonny.l...@collabora.co.uk> This is a rebase/squash/rewrite of a series Jonny had sent long ago. The major change is implementing this in terms of the drmDevice API. Both relevant piglits go from skip to pass on i965.
Signed-off-by: Adam Jackson <a...@redhat.com> --- src/egl/Makefile.sources | 2 + src/egl/drivers/dri2/egl_dri2.c | 64 +++++++++ src/egl/main/eglapi.c | 79 ++++++++++++ src/egl/main/eglapi.h | 4 + src/egl/main/egldevice.c | 280 ++++++++++++++++++++++++++++++++++++++++ src/egl/main/egldevice.h | 74 +++++++++++ src/egl/main/eglentrypoint.h | 10 ++ src/egl/main/eglglobals.c | 12 +- src/egl/main/eglglobals.h | 2 + src/egl/main/egltypedefs.h | 4 + 10 files changed, 529 insertions(+), 2 deletions(-) create mode 100644 src/egl/main/egldevice.c create mode 100644 src/egl/main/egldevice.h diff --git a/src/egl/Makefile.sources b/src/egl/Makefile.sources index e6fd3f114c..bd13bfc06a 100644 --- a/src/egl/Makefile.sources +++ b/src/egl/Makefile.sources @@ -11,6 +11,8 @@ LIBEGL_C_FILES := \ main/eglcurrent.c \ main/eglcurrent.h \ main/egldefines.h \ + main/egldevice.c \ + main/egldevice.h \ main/egldisplay.c \ main/egldisplay.h \ main/egldriver.c \ diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 91456b025d..717ab0f860 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -57,6 +57,7 @@ #include "egl_dri2.h" #include "loader/loader.h" +#include "egldevice.h" #include "util/u_atomic.h" /* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate @@ -2861,6 +2862,67 @@ dri2_interop_export_object(_EGLDisplay *dpy, _EGLContext *ctx, return dri2_dpy->interop->export_object(dri2_ctx->dri_context, in, out); } +#ifdef HAVE_LIBDRM +/* XXX kind of copypasta of drmCompareBusInfo */ +static int +dri2_bus_info_equal(drmDevicePtr a, drmDevicePtr b) +{ + if (a == NULL || b == NULL) + return 0; + + if (a->bustype != b->bustype) + return 0; + + if (a->bustype == DRM_BUS_PCI) + return !memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)); + + return 0; +} +#endif + +static EGLBoolean +dri2_query_device_from_display(_EGLDisplay *disp, _EGLDeviceInfo *info, + EGLAttrib *value) +{ + EGLBoolean ret = EGL_FALSE; +#ifdef HAVE_LIBDRM + struct dri2_egl_display *dri2_dpy = disp->DriverData; + drmDevicePtr dev; + int i; + + if (dri2_dpy->fd == -1) { + *value = (EGLAttrib) info; /* a dummy value is fine */ + return EGL_TRUE; + } + + if (drmGetDevice(dri2_dpy->fd, &dev) < 0) + return ret; + + /* loop over _EGLDisplayInfo to find a match */ + for (i = 0; i < info->num_drm_devices; i++) { + if (dri2_bus_info_equal(dev, info->drm_devices[i])) { + *value = (EGLAttrib) info->drm_devices[i]; + ret = EGL_TRUE; + break; + } + } + + drmFreeDevice(&dev); +#endif + return ret; +} + +static const char * +dri2_query_device_name(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = disp->DriverData; + + if (dri2_dpy->fd == -1) + return dri2_dpy->driver_name; + + return loader_get_device_name_for_fd(dri2_dpy->fd); +} + static void dri2_unload(_EGLDriver *drv) { @@ -2985,6 +3047,8 @@ _eglBuiltInDriverDRI2(const char *args) 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.API.QueryDeviceFromDisplay = dri2_query_device_from_display; + dri2_drv->base.API.QueryDeviceName = dri2_query_device_name; dri2_drv->base.Name = "DRI2"; dri2_drv->base.Unload = dri2_unload; diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index fc243a58e8..2f323e9fd4 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -93,6 +93,7 @@ #include "eglglobals.h" #include "eglcontext.h" +#include "egldevice.h" #include "egldisplay.h" #include "egltypedefs.h" #include "eglcurrent.h" @@ -156,6 +157,12 @@ #define _EGL_CHECK_SYNC(disp, s, ret, drv) \ _EGL_CHECK_OBJECT(disp, Sync, s, ret, drv) +#define _EGL_CHECK_DEVICE(dev, ret, devptr) \ + do { \ + devptr = _eglLookupDevice(dev); \ + if (!devptr) \ + RETURN_EGL_ERROR(NULL, EGL_BAD_DEVICE_EXT, ret); \ + } while (0) struct _egl_entrypoint { const char *name; @@ -2368,6 +2375,78 @@ _eglFunctionCompare(const void *key, const void *elem) return strcmp(procname, entrypoint->name); } +#ifdef HAVE_LIBDRM +#ifdef EGL_EXT_device_query +static EGLBoolean EGLAPIENTRY +eglQueryDeviceAttribEXT(EGLDeviceEXT device, + EGLint attribute, + EGLAttrib *value) +{ + _EGLDevice *dev; + EGLBoolean ret; + + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, EGL_FALSE); + + _EGL_CHECK_DEVICE(device, EGL_FALSE, dev); + + ret = _eglQueryDeviceAttribEXT(dev, attribute, value); + + RETURN_EGL_EVAL(NULL, ret); +} + +static const char * EGLAPIENTRY +eglQueryDeviceStringEXT(EGLDeviceEXT device, + EGLint name) +{ + _EGLDevice *dev; + const char *ret; + + _EGL_FUNC_START(NULL, EGL_OBJECT_THREAD_KHR, NULL, NULL); + + _EGL_CHECK_DEVICE(device, NULL, dev); + + ret = _eglQueryDeviceStringEXT(dev, name); + + RETURN_EGL_EVAL(NULL, ret); +} + +static EGLBoolean EGLAPIENTRY +eglQueryDisplayAttribEXT(EGLDisplay dpy, + EGLint attribute, + EGLAttrib *value) +{ + _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLDriver *drv; + EGLBoolean ret; + + _EGL_FUNC_START(disp, EGL_OBJECT_DISPLAY_KHR, NULL, EGL_FALSE); + + _EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv); + + if (!disp->Initialized) + RETURN_EGL_ERROR(disp, EGL_NOT_INITIALIZED, EGL_FALSE); + + ret = _eglQueryDisplayAttribEXT(drv, disp, attribute, value); + + RETURN_EGL_EVAL(disp, ret); +} +#endif + +#ifdef EGL_EXT_device_enumeration +static EGLBoolean EGLAPIENTRY +eglQueryDevicesEXT(EGLint max_devices, + EGLDeviceEXT *devices, + EGLint *num_devices) +{ + EGLBoolean ret; + + ret = _eglQueryDevicesEXT(max_devices, (_EGLDevice **) devices, num_devices); + + RETURN_EGL_EVAL(NULL, ret); +} +#endif +#endif /* HAVE_LIBDRM */ + __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname) { diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index 710c5d860a..e2f9651441 100644 --- a/src/egl/main/eglapi.h +++ b/src/egl/main/eglapi.h @@ -198,6 +198,10 @@ struct _egl_api int (*GLInteropExportObject)(_EGLDisplay *dpy, _EGLContext *ctx, struct mesa_glinterop_export_in *in, struct mesa_glinterop_export_out *out); + EGLBoolean (*QueryDeviceFromDisplay)(_EGLDisplay *disp, + _EGLDeviceInfo *info, + EGLAttrib *value); + const char *(*QueryDeviceName)(_EGLDisplay *disp); }; #ifdef __cplusplus diff --git a/src/egl/main/egldevice.c b/src/egl/main/egldevice.c new file mode 100644 index 0000000000..62c73cb236 --- /dev/null +++ b/src/egl/main/egldevice.c @@ -0,0 +1,280 @@ +/************************************************************************** + * + * Copyright 2015 Collabora + * Copyright 2016 Red Hat, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <assert.h> +#include <string.h> + +#include "eglcurrent.h" +#include "egldevice.h" +#include "egldriver.h" +#include "eglglobals.h" +#include "egllog.h" +#include "egltypedefs.h" + +#define MIN(x,y) (((x)<(y))?(x):(y)) + +static EGLBoolean +_eglFillDeviceList(_EGLDeviceInfo *info) +{ +#ifdef HAVE_LIBDRM + info->num_drm_devices = drmGetDevices(NULL, 0); + + if (info->num_drm_devices < 0) { + info->num_drm_devices = 0; + return EGL_FALSE; + } + + info->drm_devices = calloc(info->num_drm_devices, sizeof(drmDevicePtr)); + if (!info->drm_devices) { + info->num_drm_devices = 0; + return EGL_FALSE; + } + + if (drmGetDevices(info->drm_devices, info->num_drm_devices) < 0) { + free(info->drm_devices); + info->num_drm_devices = 0; + return EGL_FALSE; + } + + return EGL_TRUE; +#else + return EGL_FALSE; +#endif +} + +static _EGLDeviceInfo * +_eglEnsureDeviceInfo(void) +{ + _EGLDeviceInfo *info; + + mtx_lock(_eglGlobal.Mutex); + + info = _eglGlobal.DeviceInfo; + + if (!info) { + info = calloc(1, sizeof(_EGLDeviceInfo)); + if (!info) + goto out; + + /* update this string like in eglglobals.c to add support for a device + * extension */ + info->extensions = ""; + + if (!_eglFillDeviceList(info)) { + free(info); + info = NULL; + } + } + + _eglGlobal.DeviceInfo = info; + +out: + mtx_unlock(_eglGlobal.Mutex); + + return info; +} + +/** + * Lookup an existing device in the device list. + * Return NULL if the device pointer doesn't already exist in the device list. + */ +_EGLDevice * +_eglLookupDevice(EGLDeviceEXT device) +{ + _EGLDeviceInfo *info; + _EGLDevice *dev = NULL; + + info = _eglEnsureDeviceInfo(); + if (!info) + return NULL; + + mtx_lock(_eglGlobal.Mutex); + + /* special case for swrast */ + if (device == info) + dev = device; + +#ifdef HAVE_LIBDRM + for (int i = 0; !dev && i < info->num_drm_devices; i++) + if ((void *)info->drm_devices[i] == (void *)device) + dev = device; +#endif + + mtx_unlock(_eglGlobal.Mutex); + + return dev; +} + +/** + * Finish device management. + */ +void +_eglFiniDeviceInfo(void) +{ + _EGLDeviceInfo *info; + + /* atexit function is called with global mutex locked */ + + info = _eglGlobal.DeviceInfo; + + if (!info) + return; + +#ifdef HAVE_LIBDRM + drmFreeDevices(info->drm_devices, info->num_drm_devices); + free(info->drm_devices); +#endif + + free(info); + _eglGlobal.DeviceInfo = NULL; +} + +/** + * Get attribute about specific device + */ +EGLBoolean +_eglQueryDeviceAttribEXT(_EGLDevice *device, + EGLint attribute, + EGLAttrib *value) +{ + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceAttribEXT"); + + switch (attribute) { + default: + return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDeviceAttribEXT"); + } +} + +/** + * Get string about a specific device. + */ +const char * +_eglQueryDeviceStringEXT(_EGLDevice *device, EGLint name) +{ + _EGLDeviceInfo *info; + + info =_eglEnsureDeviceInfo(); + if (!info) { + _eglError(EGL_BAD_ALLOC, "eglQueryDeviceStringEXT"); + return NULL; + } + + switch (name) { + case EGL_EXTENSIONS: + return info->extensions; + + default: + _eglError(EGL_BAD_PARAMETER, "eglQueryDeviceStringEXT"); + return NULL; + }; +} + +static EGLBoolean +_eglQueryDeviceFromDisplay(_EGLDeviceInfo *info, + _EGLDriver *drv, + _EGLDisplay *disp, + EGLAttrib *value) +{ + if (drv->API.QueryDeviceFromDisplay) + return drv->API.QueryDeviceFromDisplay(disp, info, value); + + return EGL_FALSE; +} + +EGLBoolean +_eglQueryDisplayAttribEXT(_EGLDriver *drv, + _EGLDisplay *disp, + EGLint attribute, + EGLAttrib *value) +{ + _EGLDeviceInfo *info; + + info = _eglEnsureDeviceInfo(); + if (!info) + return _eglError(EGL_BAD_ALLOC, "eglQueryDisplayAttribEXT"); + + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglQueryDisplayAttribEXT"); + + switch (attribute) { + case EGL_DEVICE_EXT: + return _eglQueryDeviceFromDisplay(info, drv, disp, value); + default: + return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryDisplayAttribEXT"); + } +} + +/** + * Enumerate EGL devices. + */ +EGLBoolean +_eglQueryDevicesEXT(EGLint max_devices, + _EGLDevice **devices, + EGLint *num_devices) +{ + _EGLDeviceInfo *info; + EGLBoolean ret = EGL_TRUE; + int i = 0; + + /* max_devices can only be bad if devices is non-NULL. num_devices must + * always be present. */ + if ((devices && max_devices < 1) || !num_devices) + return _eglError(EGL_BAD_PARAMETER, "eglQueryDevicesEXT"); + + info = _eglEnsureDeviceInfo(); + if (!info) + return _eglError(EGL_BAD_ALLOC, "eglQueryDevicesEXT"); + + mtx_lock(_eglGlobal.Mutex); + + /* count devices */ +#ifdef HAVE_LIBDRM + i += info->num_drm_devices; +#endif + + /* bail early if devices is NULL */ + if (!devices) { + *num_devices = i; + goto out; + } + + /* create and fill devices array */ + *num_devices = MIN(i, max_devices); + + i = 0; +#ifdef HAVE_LIBDRM + for (; i < *num_devices && i < info->num_drm_devices; i++) + devices[i] = (void *)info->drm_devices[i]; +#endif + +out: + mtx_unlock(_eglGlobal.Mutex); + + return ret; +} diff --git a/src/egl/main/egldevice.h b/src/egl/main/egldevice.h new file mode 100644 index 0000000000..7159ef19c0 --- /dev/null +++ b/src/egl/main/egldevice.h @@ -0,0 +1,74 @@ +/************************************************************************** + * + * Copyright 2015 Collabora + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef EGLDEVICE_INCLUDED +#define EGLDEVICE_INCLUDED + +#ifdef HAVE_LIBDRM +#include <xf86drm.h> +#endif +#include "egltypedefs.h" + +typedef struct _egl_device_info { + const char *extensions; + +#ifdef HAVE_LIBDRM + drmDevicePtr *drm_devices; + int num_drm_devices; +#endif +} _EGLDeviceInfo; + + +extern void +_eglFiniDeviceInfo(void); + + +_EGLDevice * +_eglLookupDevice(EGLDeviceEXT device); + + +EGLBoolean +_eglQueryDeviceAttribEXT(_EGLDevice *device, EGLint attribute, + EGLAttrib *value); + + +const char * +_eglQueryDeviceStringEXT(_EGLDevice *device, EGLint name); + + +EGLBoolean +_eglQueryDevicesEXT(EGLint max_devices, _EGLDevice **devices, + EGLint *num_devices); + + +EGLBoolean +_eglQueryDisplayAttribEXT(_EGLDriver *drv, _EGLDisplay *disp, + EGLint attribute, EGLAttrib *value); + + +#endif /* EGLDEVICE_INCLUDED */ diff --git a/src/egl/main/eglentrypoint.h b/src/egl/main/eglentrypoint.h index e6318b9311..4b06357e59 100644 --- a/src/egl/main/eglentrypoint.h +++ b/src/egl/main/eglentrypoint.h @@ -56,6 +56,16 @@ EGL_ENTRYPOINT(eglPostSubBufferNV) EGL_ENTRYPOINT(eglQueryAPI) EGL_ENTRYPOINT(eglQueryContext) EGL_ENTRYPOINT(eglQueryDebugKHR) +#ifdef HAVE_LIBDRM +#ifdef EGL_EXT_device_query +EGL_ENTRYPOINT(eglQueryDeviceAttribEXT) +EGL_ENTRYPOINT(eglQueryDeviceStringEXT) +#ifdef EGL_EXT_device_enumeration +EGL_ENTRYPOINT(eglQueryDevicesEXT) +#endif +EGL_ENTRYPOINT(eglQueryDisplayAttribEXT) +#endif +#endif EGL_ENTRYPOINT(eglQueryString) EGL_ENTRYPOINT(eglQuerySurface) EGL_ENTRYPOINT(eglQueryWaylandBufferWL) diff --git a/src/egl/main/eglglobals.c b/src/egl/main/eglglobals.c index baf96bb1ec..2c18458f49 100644 --- a/src/egl/main/eglglobals.c +++ b/src/egl/main/eglglobals.c @@ -35,6 +35,7 @@ #include "c11/threads.h" #include "eglglobals.h" +#include "egldevice.h" #include "egldisplay.h" #include "egldriver.h" @@ -45,15 +46,22 @@ struct _egl_global _eglGlobal = { &_eglGlobalMutex, /* Mutex */ NULL, /* DisplayList */ - 2, /* NumAtExitCalls */ + NULL, /* DeviceInfo */ + 3, /* NumAtExitCalls */ { /* default AtExitCalls, called in reverse order */ _eglUnloadDrivers, /* always called last */ - _eglFiniDisplay + _eglFiniDisplay, + _eglFiniDeviceInfo }, /* ClientOnlyExtensionString */ "EGL_EXT_client_extensions" +#ifdef HAVE_LIBDRM + " EGL_EXT_device_base" + " EGL_EXT_device_query" + " EGL_EXT_device_enumeration" +#endif " EGL_EXT_platform_base" " EGL_KHR_client_get_all_proc_addresses" " EGL_KHR_debug", diff --git a/src/egl/main/eglglobals.h b/src/egl/main/eglglobals.h index c6ef59d482..7659070854 100644 --- a/src/egl/main/eglglobals.h +++ b/src/egl/main/eglglobals.h @@ -54,6 +54,8 @@ struct _egl_global /* the list of all displays */ _EGLDisplay *DisplayList; + void *DeviceInfo; + EGLint NumAtExitCalls; void (*AtExitCalls[10])(void); diff --git a/src/egl/main/egltypedefs.h b/src/egl/main/egltypedefs.h index 7facdb47f8..8ccb6f5fb5 100644 --- a/src/egl/main/egltypedefs.h +++ b/src/egl/main/egltypedefs.h @@ -49,6 +49,10 @@ typedef struct _egl_config _EGLConfig; typedef struct _egl_context _EGLContext; +typedef struct _egl_device _EGLDevice; /* note: opaque */ + +typedef struct _egl_device_info _EGLDeviceInfo; + typedef struct _egl_display _EGLDisplay; typedef struct _egl_driver _EGLDriver; -- 2.12.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev