#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"
/* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate
#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
#endif
+#ifndef DRM_FORMAT_R16
+#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R 16 little endian */
+#endif
+
+#ifndef DRM_FORMAT_GR1616
+#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)
+{
+ _EGLContext *ctx = _eglGetCurrentContext();
+ _EGLThreadInfo *t = _eglGetCurrentThread();
+
+ _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, 2 },
+
+ .setBackgroundContext = dri_set_background_context,
+ .isThreadSafe = dri_is_thread_safe,
+};
+
const __DRIuseInvalidateExtension use_invalidate = {
.base = { __DRI_USE_INVALIDATE, 1 }
};
-EGLint dri2_to_egl_attribute_map[] = {
- 0,
- EGL_BUFFER_SIZE, /* __DRI_ATTRIB_BUFFER_SIZE */
- EGL_LEVEL, /* __DRI_ATTRIB_LEVEL */
- EGL_RED_SIZE, /* __DRI_ATTRIB_RED_SIZE */
- EGL_GREEN_SIZE, /* __DRI_ATTRIB_GREEN_SIZE */
- EGL_BLUE_SIZE, /* __DRI_ATTRIB_BLUE_SIZE */
- EGL_LUMINANCE_SIZE, /* __DRI_ATTRIB_LUMINANCE_SIZE */
- EGL_ALPHA_SIZE, /* __DRI_ATTRIB_ALPHA_SIZE */
- 0, /* __DRI_ATTRIB_ALPHA_MASK_SIZE */
- EGL_DEPTH_SIZE, /* __DRI_ATTRIB_DEPTH_SIZE */
- EGL_STENCIL_SIZE, /* __DRI_ATTRIB_STENCIL_SIZE */
- 0, /* __DRI_ATTRIB_ACCUM_RED_SIZE */
- 0, /* __DRI_ATTRIB_ACCUM_GREEN_SIZE */
- 0, /* __DRI_ATTRIB_ACCUM_BLUE_SIZE */
- 0, /* __DRI_ATTRIB_ACCUM_ALPHA_SIZE */
- EGL_SAMPLE_BUFFERS, /* __DRI_ATTRIB_SAMPLE_BUFFERS */
- EGL_SAMPLES, /* __DRI_ATTRIB_SAMPLES */
- 0, /* __DRI_ATTRIB_RENDER_TYPE, */
- 0, /* __DRI_ATTRIB_CONFIG_CAVEAT */
- 0, /* __DRI_ATTRIB_CONFORMANT */
- 0, /* __DRI_ATTRIB_DOUBLE_BUFFER */
- 0, /* __DRI_ATTRIB_STEREO */
- 0, /* __DRI_ATTRIB_AUX_BUFFERS */
- 0, /* __DRI_ATTRIB_TRANSPARENT_TYPE */
- 0, /* __DRI_ATTRIB_TRANSPARENT_INDEX_VALUE */
- 0, /* __DRI_ATTRIB_TRANSPARENT_RED_VALUE */
- 0, /* __DRI_ATTRIB_TRANSPARENT_GREEN_VALUE */
- 0, /* __DRI_ATTRIB_TRANSPARENT_BLUE_VALUE */
- 0, /* __DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE */
- 0, /* __DRI_ATTRIB_FLOAT_MODE (deprecated) */
- 0, /* __DRI_ATTRIB_RED_MASK */
- 0, /* __DRI_ATTRIB_GREEN_MASK */
- 0, /* __DRI_ATTRIB_BLUE_MASK */
- 0, /* __DRI_ATTRIB_ALPHA_MASK */
- EGL_MAX_PBUFFER_WIDTH, /* __DRI_ATTRIB_MAX_PBUFFER_WIDTH */
- EGL_MAX_PBUFFER_HEIGHT, /* __DRI_ATTRIB_MAX_PBUFFER_HEIGHT */
- EGL_MAX_PBUFFER_PIXELS, /* __DRI_ATTRIB_MAX_PBUFFER_PIXELS */
- 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH */
- 0, /* __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT */
- 0, /* __DRI_ATTRIB_VISUAL_SELECT_GROUP */
- 0, /* __DRI_ATTRIB_SWAP_METHOD */
- EGL_MAX_SWAP_INTERVAL, /* __DRI_ATTRIB_MAX_SWAP_INTERVAL */
- EGL_MIN_SWAP_INTERVAL, /* __DRI_ATTRIB_MIN_SWAP_INTERVAL */
- 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGB */
- 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA */
- 0, /* __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE */
- 0, /* __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS */
- EGL_Y_INVERTED_NOK, /* __DRI_ATTRIB_YINVERTED */
- 0, /* __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE */
+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,
+ [__DRI_ATTRIB_GREEN_SIZE] = EGL_GREEN_SIZE,
+ [__DRI_ATTRIB_BLUE_SIZE] = EGL_BLUE_SIZE,
+ [__DRI_ATTRIB_LUMINANCE_SIZE] = EGL_LUMINANCE_SIZE,
+ [__DRI_ATTRIB_ALPHA_SIZE] = EGL_ALPHA_SIZE,
+ [__DRI_ATTRIB_DEPTH_SIZE] = EGL_DEPTH_SIZE,
+ [__DRI_ATTRIB_STENCIL_SIZE] = EGL_STENCIL_SIZE,
+ [__DRI_ATTRIB_SAMPLE_BUFFERS] = EGL_SAMPLE_BUFFERS,
+ [__DRI_ATTRIB_SAMPLES] = EGL_SAMPLES,
+ [__DRI_ATTRIB_MAX_PBUFFER_WIDTH] = EGL_MAX_PBUFFER_WIDTH,
+ [__DRI_ATTRIB_MAX_PBUFFER_HEIGHT] = EGL_MAX_PBUFFER_HEIGHT,
+ [__DRI_ATTRIB_MAX_PBUFFER_PIXELS] = EGL_MAX_PBUFFER_PIXELS,
+ [__DRI_ATTRIB_MAX_SWAP_INTERVAL] = EGL_MAX_SWAP_INTERVAL,
+ [__DRI_ATTRIB_MIN_SWAP_INTERVAL] = EGL_MIN_SWAP_INTERVAL,
+ [__DRI_ATTRIB_YINVERTED] = EGL_Y_INVERTED_NOK,
};
const __DRIconfig *
return NULL;
break;
+ case __DRI_ATTRIB_MAX_PBUFFER_WIDTH:
+ _eglSetConfigKey(&base, EGL_MAX_PBUFFER_WIDTH,
+ _EGL_MAX_PBUFFER_WIDTH);
+ break;
+ case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT:
+ _eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT,
+ _EGL_MAX_PBUFFER_HEIGHT);
+ break;
+
default:
key = dri2_to_egl_attribute_map[attrib];
if (key != 0)
int offset;
};
-static struct dri2_extension_match dri3_driver_extensions[] = {
+static const struct dri2_extension_match dri3_driver_extensions[] = {
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
{ __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },
{ NULL, 0, 0 }
};
-static struct dri2_extension_match dri2_driver_extensions[] = {
+static const struct dri2_extension_match dri2_driver_extensions[] = {
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
{ __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },
{ NULL, 0, 0 }
};
-static struct dri2_extension_match dri2_core_extensions[] = {
+static const struct dri2_extension_match dri2_core_extensions[] = {
{ __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
{ __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
{ __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
{ NULL, 0, 0 }
};
-static struct dri2_extension_match swrast_driver_extensions[] = {
+static const struct dri2_extension_match swrast_driver_extensions[] = {
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
{ __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) },
{ NULL, 0, 0 }
};
-static struct dri2_extension_match swrast_core_extensions[] = {
+static const struct dri2_extension_match swrast_core_extensions[] = {
{ __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
{ NULL, 0, 0 }
};
-static struct dri2_extension_match optional_core_extensions[] = {
+static const struct dri2_extension_match optional_core_extensions[] = {
{ __DRI2_ROBUSTNESS, 1, offsetof(struct dri2_egl_display, robustness) },
{ __DRI2_CONFIG_QUERY, 1, offsetof(struct dri2_egl_display, config) },
{ __DRI2_FENCE, 1, offsetof(struct dri2_egl_display, fence) },
static EGLBoolean
dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
- struct dri2_extension_match *matches,
+ const struct dri2_extension_match *matches,
const __DRIextension **extensions,
bool optional)
{
*(const __DRIextension **) field = extensions[i];
_eglLog(_EGL_INFO, "found extension %s version %d",
extensions[i]->name, extensions[i]->version);
+ break;
}
}
}
_eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
- if (asprintf(&get_extensions_name, "%s_%s",
- __DRI_DRIVER_GET_EXTENSIONS, dri2_dpy->driver_name) != -1) {
+ 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();
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) {
+ unsigned capabilities =
+ dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen);
+ disp->Extensions.ANDROID_native_fence_sync =
+ (capabilities & __DRI_FENCE_CAP_NATIVE_FD) != 0;
+ }
}
disp->Extensions.KHR_reusable_sync = EGL_TRUE;
}
}
-/* 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
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);
}
* 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 (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
goto cleanup;
+ /* The EGL_EXT_create_context_robustness spec says:
+ *
+ * "Add to the eglCreateContext context creation errors: [...]
+ *
+ * * If the reset notification behavior of <share_context> and the
+ * newly created context are different then an EGL_BAD_MATCH error is
+ * generated."
+ */
+ if (share_list && share_list->ResetNotificationStrategy !=
+ dri2_ctx->base.ResetNotificationStrategy) {
+ _eglError(EGL_BAD_MATCH, "eglCreateContext");
+ goto cleanup;
+ }
+
switch (dri2_ctx->base.ClientAPI) {
case EGL_OPENGL_ES_API:
switch (dri2_ctx->base.ClientMajorVersion) {
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
_EGLContext *old_ctx;
- _EGLDisplay *old_disp = NULL;
_EGLSurface *old_dsurf, *old_rsurf;
_EGLSurface *tmp_dsurf, *tmp_rsurf;
__DRIdrawable *ddraw, *rdraw;
__DRIcontext *cctx;
+ EGLBoolean unbind;
if (!dri2_dpy)
return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent");
return EGL_FALSE;
}
+ /* flush before context switch */
+ if (old_ctx)
+ dri2_drv->glFlush();
+
ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL;
rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL;
cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
if (old_ctx) {
__DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
-
- /* flush before context switch */
- dri2_drv->glFlush();
dri2_dpy->core->unbindContext(old_cctx);
-
- /* Keep track of the old dpy as we'll need it for resource cleanup */
- old_disp = old_ctx->Resource.Display;
}
- /* Bind if at least one of the primitives is valid ... */
- if (cctx || ddraw || rdraw) {
- if (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);
-
- _eglPutSurface(dsurf);
- _eglPutSurface(rsurf);
- _eglPutContext(ctx);
+ unbind = (cctx == NULL && ddraw == NULL && rdraw == NULL);
- _eglPutSurface(old_dsurf);
- _eglPutSurface(old_rsurf);
- _eglPutContext(old_ctx);
+ if (unbind || dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
+ dri2_destroy_surface(drv, disp, old_dsurf);
+ dri2_destroy_surface(drv, disp, old_rsurf);
- /* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but
- * setting the error to EGL_BAD_MATCH is surely better than leaving it
- * as EGL_SUCCESS.
- */
- return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
+ 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);
}
- /* ... and refcount the dpy when successful. */
- dri2_dpy->ref_count++;
+ return EGL_TRUE;
+ } else {
+ /* 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);
+
+ _eglPutSurface(dsurf);
+ _eglPutSurface(rsurf);
+ _eglPutContext(ctx);
+
+ _eglPutSurface(old_dsurf);
+ _eglPutSurface(old_rsurf);
+ _eglPutContext(old_ctx);
+
+ /* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but
+ * setting the error to EGL_BAD_MATCH is surely better than leaving it
+ * as EGL_SUCCESS.
+ */
+ return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
}
-
- dri2_destroy_surface(drv, disp, old_dsurf);
- dri2_destroy_surface(drv, disp, old_rsurf);
- dri2_destroy_context(drv, disp, old_ctx);
- dri2_display_release(old_disp);
-
- return EGL_TRUE;
}
__DRIdrawable *
assert(!"Unexpected texture target in dri2_bind_tex_image()");
}
- (*dri2_dpy->tex_buffer->setTexBuffer2)(dri2_ctx->dri_context,
- target, format,
- dri_drawable);
+ dri2_dpy->tex_buffer->setTexBuffer2(dri2_ctx->dri_context,
+ target, format,
+ dri_drawable);
return EGL_TRUE;
}
if (dri2_dpy->tex_buffer->base.version >= 3 &&
dri2_dpy->tex_buffer->releaseTexBuffer != NULL) {
- (*dri2_dpy->tex_buffer->releaseTexBuffer)(dri2_ctx->dri_context,
- target,
- dri_drawable);
+ dri2_dpy->tex_buffer->releaseTexBuffer(dri2_ctx->dri_context,
+ target, dri_drawable);
}
return EGL_TRUE;
}
}
+ /**
+ * 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;
}
case DRM_FORMAT_R8:
case DRM_FORMAT_RG88:
case DRM_FORMAT_GR88:
+ case DRM_FORMAT_R16:
+ case DRM_FORMAT_GR1616:
case DRM_FORMAT_RGB332:
case DRM_FORMAT_BGR233:
case DRM_FORMAT_XRGB4444:
* "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)
struct dri2_egl_sync *dri2_sync)
{
if (p_atomic_dec_zero(&dri2_sync->refcount)) {
- if (dri2_sync->base.Type == EGL_SYNC_REUSABLE_KHR)
+ switch (dri2_sync->base.Type) {
+ case EGL_SYNC_REUSABLE_KHR:
cnd_destroy(&dri2_sync->cond);
+ break;
+ case EGL_SYNC_NATIVE_FENCE_ANDROID:
+ if (dri2_sync->base.SyncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
+ close(dri2_sync->base.SyncFd);
+ break;
+ default:
+ break;
+ }
if (dri2_sync->fence)
dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence);
/* initial status of reusable sync must be "unsignaled" */
dri2_sync->base.SyncStatus = EGL_UNSIGNALED_KHR;
break;
+
+ case EGL_SYNC_NATIVE_FENCE_ANDROID:
+ if (dri2_dpy->fence->create_fence_fd) {
+ dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
+ dri2_ctx->dri_context,
+ dri2_sync->base.SyncFd);
+ }
+ if (!dri2_sync->fence) {
+ _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
+ free(dri2_sync);
+ return NULL;
+ }
+ break;
}
p_atomic_set(&dri2_sync->refcount, 1);
ret = EGL_FALSE;
}
}
+
dri2_egl_unref_sync(dri2_dpy, dri2_sync);
return ret;
}
+static EGLint
+dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
+{
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+ struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
+
+ assert(sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID);
+
+ if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ /* try to retrieve the actual native fence fd.. if rendering is
+ * not flushed this will just return -1, aka NO_NATIVE_FENCE_FD:
+ */
+ sync->SyncFd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
+ dri2_sync->fence);
+ }
+
+ if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ /* if native fence fd still not created, return an error: */
+ _eglError(EGL_BAD_PARAMETER, "eglDupNativeFenceFDANDROID");
+ return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+ }
+
+ return dup(sync->SyncFd);
+}
+
static EGLint
dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLint flags, EGLTime timeout)
switch (sync->Type) {
case EGL_SYNC_FENCE_KHR:
+ case EGL_SYNC_NATIVE_FENCE_ANDROID:
case EGL_SYNC_CL_EVENT_KHR:
if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL,
dri2_sync->fence, wait_flags,
const char *libname = "libglapi.0.dylib";
#elif defined(__CYGWIN__)
const char *libname = "cygglapi-0.dll";
-#elif defined(__linux__)
- const char *libname = "libglapi.so.0";
#else
-#error Unknown glapi provider for this platform
+ const char *libname = "libglapi.so.0";
#endif
void *handle;
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;
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;