#include "wayland-drm-client-protocol.h"
#endif
+#ifdef HAVE_X11_PLATFORM
+#include "X11/Xlibint.h"
+#endif
+
#include "egl_dri2.h"
#include "loader/loader.h"
#include "util/u_atomic.h"
#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] R:G 16:16 little endian */
#endif
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
+#endif
+
static void
dri_set_background_context(void *loaderPrivate)
{
_eglBindContextToThread(ctx, t);
}
+static GLboolean
+dri_is_thread_safe(void *loaderPrivate)
+{
+ struct dri2_egl_surface *dri2_surf = loaderPrivate;
+ _EGLDisplay *display = dri2_surf->base.Resource.Display;
+
+#ifdef HAVE_X11_PLATFORM
+ Display *xdpy = (Display*)display->PlatformDisplay;
+
+ /* Check Xlib is running in thread safe mode when running on EGL/X11-xlib
+ * platform
+ *
+ * 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'.
+ * It wll be NULL if XInitThreads wasn't called.
+ */
+ if (display->Platform == _EGL_PLATFORM_X11 && xdpy && !xdpy->lock_fns)
+ return false;
+#endif
+
+#ifdef HAVE_WAYLAND_PLATFORM
+ if (display->Platform == _EGL_PLATFORM_WAYLAND)
+ return true;
+#endif
+
+ return true;
+}
+
const __DRIbackgroundCallableExtension background_callable_extension = {
- .base = { __DRI_BACKGROUND_CALLABLE, 1 },
+ .base = { __DRI_BACKGROUND_CALLABLE, 2 },
.setBackgroundContext = dri_set_background_context,
+ .isThreadSafe = dri_is_thread_safe,
};
const __DRIuseInvalidateExtension use_invalidate = {
.base = { __DRI_USE_INVALIDATE, 1 }
};
-static const EGLint dri2_to_egl_attribute_map[] = {
+static const EGLint dri2_to_egl_attribute_map[__DRI_ATTRIB_MAX] = {
[__DRI_ATTRIB_BUFFER_SIZE ] = EGL_BUFFER_SIZE,
[__DRI_ATTRIB_LEVEL] = EGL_LEVEL,
[__DRI_ATTRIB_RED_SIZE] = EGL_RED_SIZE,
}
}
-/* 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.
+/* All platforms but DRM call this function to create the screen and populate
+ * the driver_configs. DRM inherits that information from its display - GBM.
*/
EGLBoolean
dri2_create_screen(_EGLDisplay *disp)
{
- const __DRIextension **extensions;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
if (dri2_dpy->image_driver) {
}
dri2_dpy->own_dri_screen = 1;
+ return EGL_TRUE;
+}
+
+EGLBoolean
+dri2_setup_extensions(_EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ const struct dri2_extension_match *mandatory_core_extensions;
+ const __DRIextension **extensions;
extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
- if (dri2_dpy->image_driver || dri2_dpy->dri2) {
- if (!dri2_bind_extensions(dri2_dpy, dri2_core_extensions, extensions, false))
- goto cleanup_dri_screen;
- } else {
- assert(dri2_dpy->swrast);
- if (!dri2_bind_extensions(dri2_dpy, swrast_core_extensions, extensions, false))
- goto cleanup_dri_screen;
- }
+ if (dri2_dpy->image_driver || dri2_dpy->dri2)
+ mandatory_core_extensions = dri2_core_extensions;
+ else
+ mandatory_core_extensions = swrast_core_extensions;
- dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);
- dri2_setup_screen(disp);
+ if (!dri2_bind_extensions(dri2_dpy, mandatory_core_extensions, extensions, false))
+ return EGL_FALSE;
+ dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);
return EGL_TRUE;
-
- cleanup_dri_screen:
- dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
-
- return EGL_FALSE;
}
/**
dri2_display_release(_EGLDisplay *disp)
{
struct dri2_egl_display *dri2_dpy;
- unsigned i;
if (!disp)
return;
return;
_eglCleanupDisplay(disp);
+ dri2_display_destroy(disp);
+}
+
+void
+dri2_display_destroy(_EGLDisplay *disp)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ unsigned i;
if (dri2_dpy->own_dri_screen)
dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
#ifdef HAVE_DRM_PLATFORM
case _EGL_PLATFORM_DRM:
if (dri2_dpy->own_device) {
- gbm_device_destroy(&dri2_dpy->gbm_dri->base.base);
+ gbm_device_destroy(&dri2_dpy->gbm_dri->base);
}
break;
#endif
* the ones from the gbm device. As such the gbm itself is responsible
* for the cleanup.
*/
- if (disp->Platform != _EGL_PLATFORM_DRM) {
+ if (disp->Platform != _EGL_PLATFORM_DRM && dri2_dpy->driver_configs) {
for (i = 0; dri2_dpy->driver_configs[i]; i++)
free((__DRIconfig *) dri2_dpy->driver_configs[i]);
free(dri2_dpy->driver_configs);
}
}
+ /**
+ * If <target> is EGL_LINUX_DMA_BUF_EXT, both or neither of the following
+ * attribute values may be given.
+ *
+ * This is referring to EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT and
+ * EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, and the same for other planes.
+ */
+ for (i = 0; i < DMA_BUF_MAX_PLANES; ++i) {
+ if (attrs->DMABufPlaneModifiersLo[i].IsPresent !=
+ attrs->DMABufPlaneModifiersHi[i].IsPresent) {
+ _eglError(EGL_BAD_PARAMETER, "modifier attribute lo or hi missing");
+ return EGL_FALSE;
+ }
+ }
+
+ /* Although the EGL_EXT_image_dma_buf_import_modifiers spec doesn't
+ * mandate it, we only accept the same modifier across all planes. */
+ for (i = 1; i < DMA_BUF_MAX_PLANES; ++i) {
+ if (attrs->DMABufPlaneFds[i].IsPresent) {
+ if ((attrs->DMABufPlaneModifiersLo[0].IsPresent !=
+ attrs->DMABufPlaneModifiersLo[i].IsPresent) ||
+ (attrs->DMABufPlaneModifiersLo[0].Value !=
+ attrs->DMABufPlaneModifiersLo[i].Value) ||
+ (attrs->DMABufPlaneModifiersHi[0].Value !=
+ attrs->DMABufPlaneModifiersHi[i].Value)) {
+ _eglError(EGL_BAD_PARAMETER, "modifier attributes not equal");
+ return EGL_FALSE;
+ }
+ }
+ }
+
return EGL_TRUE;
}
* "If <target> is EGL_LINUX_DMA_BUF_EXT, and the EGL_LINUX_DRM_FOURCC_EXT
* attribute indicates a single-plane format, EGL_BAD_ATTRIBUTE is
* generated if any of the EGL_DMA_BUF_PLANE1_* or EGL_DMA_BUF_PLANE2_*
- * attributes are specified."
+ * or EGL_DMA_BUF_PLANE3_* attributes are specified."
*/
- for (i = plane_n; i < 3; ++i) {
+ for (i = plane_n; i < DMA_BUF_MAX_PLANES; ++i) {
if (attrs->DMABufPlaneFds[i].IsPresent ||
attrs->DMABufPlaneOffsets[i].IsPresent ||
- attrs->DMABufPlanePitches[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;
+
_eglError(EGL_BAD_ATTRIBUTE, "too many plane attributes");
return 0;
}
return plane_n;
}
+static EGLBoolean
+dri2_query_dma_buf_formats(_EGLDriver *drv, _EGLDisplay *disp,
+ EGLint max, EGLint *formats, EGLint *count)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ if (max < 0 || (max > 0 && formats == NULL)) {
+ _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats");
+ return EGL_FALSE;
+ }
+
+ if (dri2_dpy->image->base.version < 15 ||
+ dri2_dpy->image->queryDmaBufFormats == NULL)
+ return EGL_FALSE;
+
+ if (!dri2_dpy->image->queryDmaBufFormats(dri2_dpy->dri_screen, max,
+ formats, count))
+ return EGL_FALSE;
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+dri2_query_dma_buf_modifiers(_EGLDriver *drv, _EGLDisplay *disp, EGLint format,
+ EGLint max, EGLuint64KHR *modifiers,
+ EGLBoolean *external_only, EGLint *count)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+ if (max < 0) {
+ _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats");
+ return EGL_FALSE;
+ }
+
+ if (max > 0 && modifiers == NULL) {
+ _eglError(EGL_BAD_PARAMETER, "invalid modifiers array");
+ return EGL_FALSE;
+ }
+
+ if (dri2_dpy->image->base.version < 15 ||
+ dri2_dpy->image->queryDmaBufModifiers == NULL)
+ return EGL_FALSE;
+
+ if (dri2_dpy->image->queryDmaBufModifiers(dri2_dpy->dri_screen, format,
+ max, modifiers,
+ (unsigned int *) external_only,
+ count) == false) {
+ _eglError(EGL_BAD_PARAMETER, "invalid format");
+ return EGL_FALSE;
+ }
+
+ return EGL_TRUE;
+}
+
/**
* The spec says:
*
__DRIimage *dri_image;
unsigned num_fds;
unsigned i;
- int fds[3];
- int pitches[3];
- int offsets[3];
+ int fds[DMA_BUF_MAX_PLANES];
+ int pitches[DMA_BUF_MAX_PLANES];
+ int offsets[DMA_BUF_MAX_PLANES];
+ uint64_t modifier;
+ bool has_modifier = false;
unsigned error;
/**
offsets[i] = attrs.DMABufPlaneOffsets[i].Value;
}
- dri_image =
- dri2_dpy->image->createImageFromDmaBufs(dri2_dpy->dri_screen,
- attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
- fds, num_fds, pitches, offsets,
- attrs.DMABufYuvColorSpaceHint.Value,
- attrs.DMABufSampleRangeHint.Value,
- attrs.DMABufChromaHorizontalSiting.Value,
- attrs.DMABufChromaVerticalSiting.Value,
- &error,
- NULL);
+ /* dri2_check_dma_buf_attribs ensures that the modifier, if available,
+ * will be present in attrs.DMABufPlaneModifiersLo[0] and
+ * attrs.DMABufPlaneModifiersHi[0] */
+ if (attrs.DMABufPlaneModifiersLo[0].IsPresent) {
+ modifier =
+ ((uint64_t) attrs.DMABufPlaneModifiersHi[0].Value << 32) |
+ attrs.DMABufPlaneModifiersLo[0].Value;
+ has_modifier = true;
+ } else {
+ modifier = DRM_FORMAT_MOD_INVALID;
+ }
+
+ if (has_modifier) {
+ if (dri2_dpy->image->base.version < 15 ||
+ dri2_dpy->image->createImageFromDmaBufs2 == NULL) {
+ _eglError(EGL_BAD_MATCH, "unsupported dma_buf format modifier");
+ return EGL_NO_IMAGE_KHR;
+ }
+ dri_image =
+ dri2_dpy->image->createImageFromDmaBufs2(dri2_dpy->dri_screen,
+ attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
+ modifier, fds, num_fds, pitches, offsets,
+ attrs.DMABufYuvColorSpaceHint.Value,
+ attrs.DMABufSampleRangeHint.Value,
+ attrs.DMABufChromaHorizontalSiting.Value,
+ attrs.DMABufChromaVerticalSiting.Value,
+ &error,
+ NULL);
+ }
+ else {
+ dri_image =
+ dri2_dpy->image->createImageFromDmaBufs(dri2_dpy->dri_screen,
+ attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
+ fds, num_fds, pitches, offsets,
+ attrs.DMABufYuvColorSpaceHint.Value,
+ attrs.DMABufSampleRangeHint.Value,
+ attrs.DMABufChromaHorizontalSiting.Value,
+ attrs.DMABufChromaVerticalSiting.Value,
+ &error,
+ NULL);
+ }
dri2_create_image_khr_texture_error(error);
if (!dri_image)
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;
#endif
#ifdef HAVE_WAYLAND_PLATFORM
dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;