egl: add initial EGL_MESA_image_dma_buf_export v2.4

At the moment to get an EGL image to a dma-buf file descriptor,
you have to use EGL_MESA_drm_image, and then use libdrm to
convert this to a file descriptor.

This extension just provides an API modelled on EGL_MESA_drm_image,
to return a dma-buf file descriptor.

v2: update spec for new API proposal
add internal queries to get the fourcc back from intel driver.

v2.1: add gallium pieces.

v2.2: add offsets to spec and API, rename fd->fds, stride->strides
in API. rewrite spec a bit more, add some q/a

v2.3:
add modifiers to query interface and 64-bit type for that (Daniel Stone)
specifiy what happens to num fds vs num planes differences. (Chad Versace)

v2.4:
fix grammar (Daniel Stone)

Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Dave Airlie 2014-03-03 13:57:16 +10:00
parent 22ccdf12dd
commit 8f7338f284
10 changed files with 332 additions and 5 deletions

View File

@ -0,0 +1,142 @@
Name
MESA_image_dma_buf_export
Name Strings
EGL_MESA_image_dma_buf_export
Contributors
Dave Airlie
Contact
Dave Airlie (airlied 'at' redhat 'dot' com)
Status
Proposal
Version
Version 2, Mar 30, 2015
Number
EGL Extension #not assigned
Dependencies
Reguires EGL 1.4 or later. This extension is written against the
wording of the EGL 1.4 specification.
EGL_KHR_base_image is required.
The EGL implementation must be running on a Linux kernel supporting the
dma_buf buffer sharing mechanism.
Overview
This extension provides entry points for integrating EGLImage with the
dma-buf infrastructure. The extension allows creating a Linux dma_buf
file descriptor or multiple file descriptors, in the case of multi-plane
YUV image, from an EGLImage.
It is designed to provide the complementary functionality to EGL_EXT_image_dma_buf_import.
IP Status
Open-source; freely implementable.
New Types
This is a 64 bit unsigned integer.
typedef khronos_uint64_t EGLuint64MESA;
New Procedures and Functions
EGLBoolean eglExportDMABUFImageQueryMESA(EGLDisplay dpy,
EGLImageKHR image,
int *fourcc,
int *num_planes,
EGLuint64MESA *modifiers);
EGLBoolean eglExportDMABUFImageMESA(EGLDisplay dpy,
EGLImageKHR image,
int *fds,
EGLint *strides,
EGLint *offsets);
New Tokens
None
Additions to the EGL 1.4 Specification:
To mirror the import extension, this extension attempts to return
enough information to enable an exported dma-buf to be imported
via eglCreateImageKHR and EGL_LINUX_DMA_BUF_EXT token.
Retrieving the information is a two step process, so two APIs
are required.
The first entrypoint
EGLBoolean eglExportDMABUFImageQueryMESA(EGLDisplay dpy,
EGLImageKHR image,
int *fourcc,
int *num_planes,
EGLuint64MESA *modifiers);
is used to retrieve the pixel format of the buffer, as specified by
drm_fourcc.h, the number of planes in the image and the Linux
drm modifiers. <fourcc>, <num_planes> and <modifiers> may be NULL,
in which case no value is retrieved.
The second entrypoint retrieves the dma_buf file descriptors,
strides and offsets for the image. The caller should pass
arrays sized according to the num_planes values retrieved previously.
Passing arrays of the wrong size will have undefined results.
If the number of fds is less than the number of planes, then
subsequent fd slots should contain -1.
EGLBoolean eglExportDMABUFImageMESA(EGLDisplay dpy,
EGLImageKHR image,
int *fds,
EGLint *strides,
EGLint *offsets);
<fds>, <strides>, <offsets> can be NULL if the infomatation isn't
required by the caller.
Issues
1. Should the API look more like an attribute getting API?
ANSWER: No, from a user interface pov, having to iterate across calling
the API up to 12 times using attribs seems like the wrong solution.
2. Should the API take a plane and just get the fd/stride/offset for that
plane?
ANSWER: UNKNOWN,this might be just as valid an API.
3. Does ownership of the file descriptor remain with the app?
ANSWER: Yes, the app is responsible for closing any fds retrieved.
4. If number of planes and number of fds differ what should we do?
ANSWER: Return -1 for the secondary slots, as this avoids having
to dup the fd extra times to make the interface sane.
Revision History
Version 2, March, 2015
Add a query interface (Dave Airlie)
Version 1, June 3, 2014
Initial draft (Dave Airlie)

View File

@ -170,6 +170,14 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOK) (EGLDisplay dpy, EG
#define EGL_NO_CONFIG_MESA ((EGLConfig)0)
#endif
#if KHRONOS_SUPPORT_INT64
#ifndef EGL_MESA_image_dma_buf_export
#define EGL_MESA_image_dma_buf_export 1
typedef khronos_uint64_t EGLuint64MESA;
EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageQueryMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *fourcc, EGLint *nplanes, EGLuint64MESA *modifiers);
EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1006,7 +1006,7 @@ struct __DRIdri2ExtensionRec {
* extensions.
*/
#define __DRI_IMAGE "DRI_IMAGE"
#define __DRI_IMAGE_VERSION 10
#define __DRI_IMAGE_VERSION 11
/**
* These formats correspond to the similarly named MESA_FORMAT_*
@ -1097,6 +1097,8 @@ struct __DRIdri2ExtensionRec {
#define __DRI_IMAGE_ATTRIB_FD 0x2007 /* available in versions
* 7+. Each query will return a
* new fd. */
#define __DRI_IMAGE_ATTRIB_FOURCC 0x2008 /* available in versions 11 */
#define __DRI_IMAGE_ATTRIB_NUM_PLANES 0x2009 /* available in versions 11 */
enum __DRIYUVColorSpace {
__DRI_YUV_COLOR_SPACE_UNDEFINED = 0,

View File

@ -525,8 +525,14 @@ dri2_setup_screen(_EGLDisplay *disp)
capabilities = dri2_dpy->image->getCapabilities(dri2_dpy->dri_screen);
disp->Extensions.MESA_drm_image = (capabilities & __DRI_IMAGE_CAP_GLOBAL_NAMES) != 0;
} else
if (dri2_dpy->image->base.version >= 11)
disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
} else {
disp->Extensions.MESA_drm_image = EGL_TRUE;
if (dri2_dpy->image->base.version >= 11)
disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
}
disp->Extensions.KHR_image_base = EGL_TRUE;
disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
@ -1965,6 +1971,55 @@ dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
return EGL_TRUE;
}
static EGLBoolean
dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp,
_EGLImage *img,
EGLint *fourcc, EGLint *nplanes,
EGLuint64MESA *modifiers)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
(void) drv;
if (nplanes)
dri2_dpy->image->queryImage(dri2_img->dri_image,
__DRI_IMAGE_ATTRIB_NUM_PLANES, nplanes);
if (fourcc)
dri2_dpy->image->queryImage(dri2_img->dri_image,
__DRI_IMAGE_ATTRIB_FOURCC, fourcc);
if (modifiers)
*modifiers = 0;
return EGL_TRUE;
}
static EGLBoolean
dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
int *fds, EGLint *strides, EGLint *offsets)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
(void) drv;
/* rework later to provide multiple fds/strides/offsets */
if (fds)
dri2_dpy->image->queryImage(dri2_img->dri_image,
__DRI_IMAGE_ATTRIB_FD, fds);
if (strides)
dri2_dpy->image->queryImage(dri2_img->dri_image,
__DRI_IMAGE_ATTRIB_STRIDE, strides);
if (offsets)
offsets[0] = 0;
return EGL_TRUE;
}
#endif
#ifdef HAVE_WAYLAND_PLATFORM
@ -2219,6 +2274,8 @@ _eglBuiltInDriverDRI2(const char *args)
#ifdef HAVE_LIBDRM
dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
dri2_drv->base.API.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa;
dri2_drv->base.API.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa;
#endif
#ifdef HAVE_WAYLAND_PLATFORM
dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;

View File

@ -423,6 +423,8 @@ _eglCreateExtensionsString(_EGLDisplay *dpy)
_EGL_CHECK_EXTENSION(EXT_image_dma_buf_import);
_EGL_CHECK_EXTENSION(NV_post_sub_buffer);
_EGL_CHECK_EXTENSION(MESA_image_dma_buf_export);
#undef _EGL_CHECK_EXTENSION
}
@ -1239,6 +1241,10 @@ eglGetProcAddress(const char *procname)
{ "eglCreatePlatformWindowSurfaceEXT", (_EGLProc) eglCreatePlatformWindowSurfaceEXT },
{ "eglCreatePlatformPixmapSurfaceEXT", (_EGLProc) eglCreatePlatformPixmapSurfaceEXT },
{ "eglGetSyncValuesCHROMIUM", (_EGLProc) eglGetSyncValuesCHROMIUM },
#ifdef EGL_MESA_drm_buf_image_export
{ "eglExportDMABUFImageQueryMESA", (_EGLProc) eglExportDMABUFImageQueryMESA },
{ "eglExportDMABUFImageMESA", (_EGLProc) eglExportDMABUFImageMESA },
#endif
{ NULL, NULL }
};
EGLint i;
@ -1926,3 +1932,47 @@ eglGetSyncValuesCHROMIUM(EGLDisplay display, EGLSurface surface,
RETURN_EGL_EVAL(disp, ret);
}
#ifdef EGL_MESA_image_dma_buf_export
EGLBoolean EGLAPIENTRY
eglExportDMABUFImageQueryMESA(EGLDisplay dpy, EGLImageKHR image,
EGLint *fourcc, EGLint *nplanes,
EGLuint64MESA *modifiers)
{
_EGLDisplay *disp = _eglLockDisplay(dpy);
_EGLImage *img = _eglLookupImage(image, disp);
_EGLDriver *drv;
EGLBoolean ret;
_EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
assert(disp->Extensions.MESA_image_dma_buf_export);
if (!img)
RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
ret = drv->API.ExportDMABUFImageQueryMESA(drv, disp, img, fourcc, nplanes,
modifiers);
RETURN_EGL_EVAL(disp, ret);
}
EGLBoolean EGLAPIENTRY
eglExportDMABUFImageMESA(EGLDisplay dpy, EGLImageKHR image,
int *fds, EGLint *strides, EGLint *offsets)
{
_EGLDisplay *disp = _eglLockDisplay(dpy);
_EGLImage *img = _eglLookupImage(image, disp);
_EGLDriver *drv;
EGLBoolean ret;
_EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
assert(disp->Extensions.MESA_image_dma_buf_export);
if (!img)
RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
ret = drv->API.ExportDMABUFImageMESA(drv, disp, img, fds, strides, offsets);
RETURN_EGL_EVAL(disp, ret);
}
#endif

View File

@ -140,6 +140,11 @@ typedef EGLBoolean (*SwapBuffersWithDamageEXT_t) (_EGLDriver *drv, _EGLDisplay *
typedef EGLBoolean (*GetSyncValuesCHROMIUM_t) (_EGLDisplay *dpy, _EGLSurface *surface, EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc);
#ifdef EGL_MESA_image_dma_buf_export
typedef EGLBoolean (*ExportDMABUFImageQueryMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, EGLint *fourcc, EGLint *stride, EGLuint64MESA *modifiers);
typedef EGLBoolean (*ExportDMABUFImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img, EGLint *fds, EGLint *strides, EGLint *offsets);
#endif
/**
* The API dispatcher jumps through these functions
*/
@ -226,6 +231,11 @@ struct _egl_api
QueryBufferAge_t QueryBufferAge;
GetSyncValuesCHROMIUM_t GetSyncValuesCHROMIUM;
#ifdef EGL_MESA_image_dma_buf_export
ExportDMABUFImageQueryMESA_t ExportDMABUFImageQueryMESA;
ExportDMABUFImageMESA_t ExportDMABUFImageMESA;
#endif
};
#endif /* EGLAPI_INCLUDED */

View File

@ -123,6 +123,8 @@ struct _egl_extensions
EGLBoolean EXT_buffer_age;
EGLBoolean EXT_swap_buffers_with_damage;
EGLBoolean EXT_image_dma_buf_import;
EGLBoolean MESA_image_dma_buf_export;
};

View File

@ -118,4 +118,9 @@ _eglInitDriverFallbacks(_EGLDriver *drv)
#ifdef EGL_NOK_swap_region
drv->API.SwapBuffersRegionNOK = NULL;
#endif
#ifdef EGL_MESA_dma_buf_image_export
drv->API.ExportDMABUFImageQueryMESA = NULL;
drv->API.ExportDMABUFImageMESA = NULL;
#endif
}

View File

@ -76,6 +76,30 @@ static int convert_fourcc(int format, int *dri_components_p)
return format;
}
static int convert_to_fourcc(int format)
{
switch(format) {
case __DRI_IMAGE_FORMAT_RGB565:
format = __DRI_IMAGE_FOURCC_RGB565;
break;
case __DRI_IMAGE_FORMAT_ARGB8888:
format = __DRI_IMAGE_FOURCC_ARGB8888;
break;
case __DRI_IMAGE_FORMAT_XRGB8888:
format = __DRI_IMAGE_FOURCC_XRGB8888;
break;
case __DRI_IMAGE_FORMAT_ABGR8888:
format = __DRI_IMAGE_FOURCC_ABGR8888;
break;
case __DRI_IMAGE_FORMAT_XBGR8888:
format = __DRI_IMAGE_FOURCC_XBGR8888;
break;
default:
return -1;
}
return format;
}
/**
* DRI2 flush extension.
*/
@ -909,6 +933,12 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
return GL_FALSE;
*value = image->dri_components;
return GL_TRUE;
case __DRI_IMAGE_ATTRIB_FOURCC:
*value = convert_to_fourcc(image->dri_format);
return GL_TRUE;
case __DRI_IMAGE_ATTRIB_NUM_PLANES:
*value = 1;
return GL_TRUE;
default:
return GL_FALSE;
}
@ -1203,7 +1233,7 @@ dri2_get_capabilities(__DRIscreen *_screen)
/* The extension is modified during runtime if DRI_PRIME is detected */
static __DRIimageExtension dri2ImageExtension = {
.base = { __DRI_IMAGE, 10 },
.base = { __DRI_IMAGE, 11 },
.createImageFromName = dri2_create_image_from_name,
.createImageFromRenderbuffer = dri2_create_image_from_renderbuffer,

View File

@ -300,6 +300,17 @@ intel_image_format_lookup(int fourcc)
return f;
}
static boolean intel_lookup_fourcc(int dri_format, int *fourcc)
{
for (unsigned i = 0; i < ARRAY_SIZE(intel_image_formats); i++) {
if (intel_image_formats[i].planes[0].dri_format == dri_format) {
*fourcc = intel_image_formats[i].fourcc;
return true;
}
}
return false;
}
static __DRIimage *
intel_allocate_image(int dri_format, void *loaderPrivate)
{
@ -559,6 +570,14 @@ intel_query_image(__DRIimage *image, int attrib, int *value)
if (drm_intel_bo_gem_export_to_prime(image->bo, value) == 0)
return true;
return false;
case __DRI_IMAGE_ATTRIB_FOURCC:
if (intel_lookup_fourcc(image->dri_format, value))
return true;
return false;
case __DRI_IMAGE_ATTRIB_NUM_PLANES:
*value = 1;
return true;
default:
return false;
}
@ -784,7 +803,7 @@ intel_from_planar(__DRIimage *parent, int plane, void *loaderPrivate)
}
static const __DRIimageExtension intelImageExtension = {
.base = { __DRI_IMAGE, 8 },
.base = { __DRI_IMAGE, 11 },
.createImageFromName = intel_create_image_from_name,
.createImageFromRenderbuffer = intel_create_image_from_renderbuffer,
@ -797,7 +816,9 @@ static const __DRIimageExtension intelImageExtension = {
.fromPlanar = intel_from_planar,
.createImageFromTexture = intel_create_image_from_texture,
.createImageFromFds = intel_create_image_from_fds,
.createImageFromDmaBufs = intel_create_image_from_dma_bufs
.createImageFromDmaBufs = intel_create_image_from_dma_bufs,
.blitImage = NULL,
.getCapabilities = NULL
};
static int