egl: Add EGL_WAYLAND_PLANE_WL attribute

This lets us specify the plane to create the image for for multiplanar
wl_buffers.

Signed-off-by: Kristian Høgsberg <krh@bitplanet.net>
This commit is contained in:
Kristian Høgsberg 2012-07-05 16:43:04 -04:00
parent 1aaec8c609
commit e6a33570b7
8 changed files with 267 additions and 19 deletions

View file

@ -56,12 +56,34 @@ New Procedures and Functions
EGLBoolean eglUnbindWaylandDisplayWL(EGLDisplay dpy,
struct wl_display *display);
EGLBoolean eglQueryWaylandBufferWL(EGLDisplay dpy,
struct wl_buffer *buffer,
EGLint attribute, EGLint *value);
New Tokens
Accepted as <target> in eglCreateImageKHR
EGL_WAYLAND_BUFFER_WL 0x31D5
Accepted in the <attrib_list> parameter of eglCreateImageKHR:
EGL_WAYLAND_PLANE_WL 0x31D6
Accepted as a eglQueryWaylandBufferWL attribute:
EGL_WAYLAND_BUFFER_COMPONENTS_WL 0x31D7
Possible values for EGL_WAYLAND_BUFFER_COMPONENTS_WL:
EGL_WAYLAND_BUFFER_RGB_WL 0x31D8
EGL_WAYLAND_BUFFER_RGBA_WL 0x31D9
EGL_WAYLAND_BUFFER_Y_U_V_WL 0x31Da
EGL_WAYLAND_BUFFER_Y_UV_WL 0x31Db
EGL_WAYLAND_BUFFER_Y_XUXV_WL 0x31Dc
Additions to the EGL 1.4 Specification:
To bind a server side wl_display to an EGLDisplay, call
@ -80,9 +102,65 @@ Additions to the EGL 1.4 Specification:
eglUnbindWaylandDisplayWL returns EGL_FALSE when there is no
wl_display bound to the EGLDisplay currently otherwise EGL_TRUE.
Import a wl_buffer by calling eglCreateImageKHR with
wl_buffer as EGLClientBuffer, EGL_WAYLAND_BUFFER_WL as the target,
NULL context and an empty attribute_list.
A wl_buffer can have several planes, typically in case of planar
YUV formats. Depending on the exact YUV format in use, the
compositor will have to create one or more EGLImages for the
various planes. The eglQueryWaylandBufferWL function should be
used to first query the wl_buffer components using
EGL_WAYLAND_BUFFER_COMPONENTS_WL as the attribute. If the
wl_buffer object is not an EGL wl_buffer (wl_shm and other wayland
extensions can create wl_buffer objects), this query will return
EGL_FALSE. In that case the wl_buffer can not be used with EGL
and the compositor should have another way to get the buffer
contents.
If eglQueryWaylandBufferWL succeeds, the returned value will be
one of EGL_WAYLAND_BUFFER_RGB_WL, EGL_WAYLAND_BUFFER_RGBA_WL,
EGL_WAYLAND_BUFFER_Y_U_V_WL, EGL_WAYLAND_BUFFER_Y_UV_WL,
EGL_WAYLAND_BUFFER_Y_XUXV_WL. The value returned describes how
many EGLImages must be used, which components will be sampled from
each EGLImage and how they map to rgba components in the shader.
The naming conventions separates planes by _ and within each
plane, the order or R, G, B, A, Y, U, and V indicates how those
components map to the rgba value returned by the sampler. X
indicates that the corresponding component in the rgba value isn't
used.
RGB and RGBA buffer types:
EGL_WAYLAND_BUFFER_RGB_WL
One plane, samples RGB from the texture to rgb in the
shader. Alpha channel is not valid.
EGL_WAYLAND_BUFFER_RGBA_WL 0x31D9
One plane, samples RGBA from the texture to rgba in the
shader.
YUV buffer types:
EGL_WAYLAND_BUFFER_Y_U_V_WL 0x31Da
Three planes, samples Y from the first plane to r in
the shader, U from the second plane to r, and V from
the third plane to r.
EGL_WAYLAND_BUFFER_Y_UV_WL 0x31Db
Two planes, samples Y from the first plane to r in
the shader, U and V from the second plane to rg.
EGL_WAYLAND_BUFFER_Y_XUXV_WL 0x31Dc
Two planes, samples Y from the first plane to r in
the shader, U and V from the second plane to g and a.
After querying the wl_buffer layout, create EGLImages for the
planes by calling eglCreateImageKHR with wl_buffer as
EGLClientBuffer, EGL_WAYLAND_BUFFER_WL as the target, NULL
context. If no attributes are given, an EGLImage will be created
for the first plane. For multi-planar buffers, specify the plane
to create the EGLImage for by using the EGL_WAYLAND_PLANE_WL
attribute. The value of the attribute is the index of the plane,
as defined by the buffer format. Writing to an EGLImage created
from a wl_buffer in any way (such as glTexImage2D, binding the
EGLImage as a renderbuffer etc) will result in undefined behavior.
Issues
@ -90,3 +168,9 @@ Revision History
Version 1, March 1, 2011
Initial draft (Benjamin Franzke)
Version 2, July 5, 2012
Add EGL_WAYLAND_PLANE_WL attribute to allow creating an EGLImage
for different planes of planar buffer. (Kristian Høgsberg)
Version 3, July 10, 2012
Add eglQueryWaylandBufferWL and the various buffer
formats. (Kristian Høgsberg)

View file

@ -113,13 +113,27 @@ typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDRMDISPLAYMESA) (int fd);
#define EGL_WL_bind_wayland_display 1
#define EGL_WAYLAND_BUFFER_WL 0x31D5 /* eglCreateImageKHR target */
#define EGL_WAYLAND_PLANE_WL 0x31D6 /* eglCreateImageKHR target */
#define EGL_WAYLAND_BUFFER_COMPONENTS_WL 0x31D7 /* eglQueryWaylandBufferWL attribute */
#define EGL_WAYLAND_BUFFER_RGB_WL 0x31D8
#define EGL_WAYLAND_BUFFER_RGBA_WL 0x31D9
#define EGL_WAYLAND_BUFFER_Y_U_V_WL 0x31Da
#define EGL_WAYLAND_BUFFER_Y_UV_WL 0x31Db
#define EGL_WAYLAND_BUFFER_Y_XUXV_WL 0x31Dc
struct wl_display;
struct wl_buffer;
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif
#ifndef EGL_NOK_swap_region

View file

@ -1052,20 +1052,120 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
}
#ifdef HAVE_WAYLAND_PLATFORM
/* This structure describes how a wl_buffer maps to one or more
* __DRIimages. A wl_drm_buffer stores the wl_drm format code and the
* offsets and strides of the planes in the buffer. This table maps a
* wl_drm format code to a description of the planes in the buffer
* that lets us create a __DRIimage for each of the planes. */
static const struct wl_drm_format_descriptor {
uint32_t wl_format;
EGLint components;
int nplanes;
struct {
int buffer_index;
int width_shift;
int height_shift;
uint32_t dri_format;
int cpp;
} planes[3];
} wl_drm_formats[] = {
{ WL_DRM_FORMAT_ARGB8888, EGL_WAYLAND_BUFFER_RGBA_WL, 1,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 }, } },
{ WL_DRM_FORMAT_XRGB8888, EGL_WAYLAND_BUFFER_RGB_WL, 1,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_XRGB8888, 4 }, } },
{ WL_DRM_FORMAT_YUV410, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 },
{ 2, 2, 2, __DRI_IMAGE_FORMAT_R8, 1 } } },
{ WL_DRM_FORMAT_YUV411, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 2, 2, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
{ WL_DRM_FORMAT_YUV420, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 },
{ 2, 1, 1, __DRI_IMAGE_FORMAT_R8, 1 } } },
{ WL_DRM_FORMAT_YUV422, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 2, 1, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
{ WL_DRM_FORMAT_YUV444, EGL_WAYLAND_BUFFER_Y_U_V_WL, 3,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 2, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 } } },
{ WL_DRM_FORMAT_NV12, EGL_WAYLAND_BUFFER_Y_UV_WL, 2,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 1, 1, __DRI_IMAGE_FORMAT_GR88, 2 } } },
{ WL_DRM_FORMAT_NV16, EGL_WAYLAND_BUFFER_Y_UV_WL, 2,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 1, 0, __DRI_IMAGE_FORMAT_GR88, 2 } } },
/* For YUYV buffers, we set up two overlapping DRI images and treat
* them as planar buffers in the compositors. Plane 0 is GR88 and
* samples YU or YV pairs and places Y into the R component, while
* plane 1 is ARGB and samples YUYV clusters and places pairs and
* places U into the G component and V into A. This lets the
* texture sampler interpolate the Y components correctly when
* sampling from plane 0, and interpolate U and V correctly when
* sampling from plane 1. */
{ WL_DRM_FORMAT_YUYV, EGL_WAYLAND_BUFFER_Y_XUXV_WL, 2,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_GR88, 2 },
{ 0, 1, 0, __DRI_IMAGE_FORMAT_ARGB8888, 4 } } }
};
static _EGLImage *
dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
EGLClientBuffer _buffer,
const EGLint *attr_list)
{
struct wl_buffer *buffer = (struct wl_buffer *) _buffer;
struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
__DRIimage *dri_image, *source;
__DRIimage *dri_image;
_EGLImageAttribs attrs;
EGLint err;
uint32_t format;
int32_t offset, stride, plane, width, height;
int cpp, index;
const struct wl_drm_format_descriptor *f;
if (!wayland_buffer_is_drm(buffer))
if (!wayland_buffer_is_drm(&buffer->buffer))
return NULL;
source = wayland_drm_buffer_get_buffer(buffer);
dri_image = dri2_dpy->image->dupImage(source, NULL);
err = _eglParseImageAttribList(&attrs, disp, attr_list);
plane = attrs.PlaneWL;
if (err != EGL_SUCCESS) {
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
return NULL;
}
f = buffer->driver_format;
if (plane < 0 || plane >= f->nplanes) {
_eglError(EGL_BAD_PARAMETER,
"dri2_create_image_wayland_wl_buffer (plane out of bounds)");
return NULL;
}
width = buffer->buffer.width >> f->planes[plane].width_shift;
height = buffer->buffer.height >> f->planes[plane].height_shift;
format = f->planes[plane].dri_format;
cpp = f->planes[plane].cpp;
index = f->planes[plane].buffer_index;
offset = buffer->offset[index];
stride = buffer->stride[index];
dri_image = dri2_dpy->image->createSubImage(buffer->driver_buffer,
width, height, format,
offset, stride / cpp, NULL);
return dri2_create_image(disp, dri_image);
}
@ -1226,23 +1326,22 @@ dri2_wl_reference_buffer(void *user_data, uint32_t name,
{
_EGLDisplay *disp = user_data;
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
int i;
switch (buffer->format) {
case WL_DRM_FORMAT_ARGB8888:
buffer->driver_format =__DRI_IMAGE_FORMAT_ARGB8888;
break;
case WL_DRM_FORMAT_XRGB8888:
buffer->driver_format = __DRI_IMAGE_FORMAT_XRGB8888;
break;
default:
for (i = 0; i < ARRAY_SIZE(wl_drm_formats); i++)
if (wl_drm_formats[i].wl_format == buffer->format) {
buffer->driver_format = &wl_drm_formats[i];
break;
}
if (buffer->driver_format == NULL)
return;
}
buffer->driver_buffer =
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
buffer->buffer.width,
buffer->buffer.height,
buffer->driver_format, name,
__DRI_IMAGE_FORMAT_NONE, name,
buffer->stride[0] / 4,
NULL);
}
@ -1302,6 +1401,26 @@ dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
return EGL_TRUE;
}
static EGLBoolean
dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
struct wl_buffer *_buffer,
EGLint attribute, EGLint *value)
{
struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) _buffer;
const struct wl_drm_format_descriptor *format;
if (!wayland_buffer_is_drm(&buffer->buffer))
return EGL_FALSE;
format = buffer->driver_format;
if (attribute == EGL_WAYLAND_BUFFER_COMPONENTS_WL) {
*value = format->components;
return EGL_TRUE;
}
return EGL_FALSE;
}
#endif
static void
@ -1399,6 +1518,7 @@ _eglBuiltInDriverDRI2(const char *args)
#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;
#endif
dri2_drv->base.Name = "DRI2";

View file

@ -940,6 +940,7 @@ eglGetProcAddress(const char *procname)
#ifdef EGL_WL_bind_wayland_display
{ "eglBindWaylandDisplayWL", (_EGLProc) eglBindWaylandDisplayWL },
{ "eglUnbindWaylandDisplayWL", (_EGLProc) eglUnbindWaylandDisplayWL },
{ "eglQueryWaylandBufferWL", (_EGLProc) eglQueryWaylandBufferWL },
#endif
{ "eglPostSubBufferNV", (_EGLProc) eglPostSubBufferNV },
{ NULL, NULL }
@ -1540,6 +1541,25 @@ eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display)
RETURN_EGL_EVAL(disp, ret);
}
EGLBoolean EGLAPIENTRY
eglQueryWaylandBufferWL(EGLDisplay dpy,struct wl_buffer *buffer,
EGLint attribute, EGLint *value)
{
_EGLDisplay *disp = _eglLockDisplay(dpy);
_EGLDriver *drv;
EGLBoolean ret;
_EGL_CHECK_DISPLAY(disp, EGL_FALSE, drv);
assert(disp->Extensions.WL_bind_wayland_display);
if (!buffer)
RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_FALSE);
ret = drv->API.QueryWaylandBufferWL(drv, disp, buffer, attribute, value);
RETURN_EGL_EVAL(disp, ret);
}
#endif

View file

@ -123,6 +123,7 @@ typedef EGLBoolean (*ExportDRMImageMESA_t)(_EGLDriver *drv, _EGLDisplay *disp, _
struct wl_display;
typedef EGLBoolean (*BindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *display);
typedef EGLBoolean (*UnbindWaylandDisplayWL_t)(_EGLDriver *drv, _EGLDisplay *disp, struct wl_display *display);
typedef EGLBoolean (*QueryWaylandBufferWL_t)(_EGLDriver *drv, _EGLDisplay *displ, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif
typedef EGLBoolean (*PostSubBufferNV_t)(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surface, EGLint x, EGLint y, EGLint width, EGLint height);
@ -199,6 +200,7 @@ struct _egl_api
#ifdef EGL_WL_bind_wayland_display
BindWaylandDisplayWL_t BindWaylandDisplayWL;
UnbindWaylandDisplayWL_t UnbindWaylandDisplayWL;
QueryWaylandBufferWL_t QueryWaylandBufferWL;
#endif
PostSubBufferNV_t PostSubBufferNV;

View file

@ -88,6 +88,11 @@ _eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *dpy,
attrs->DRMBufferStrideMESA = val;
break;
/* EGL_WL_bind_wayland_display */
case EGL_WAYLAND_PLANE_WL:
attrs->PlaneWL = val;
break;
default:
/* unknown attrs are ignored */
break;

View file

@ -50,6 +50,9 @@ struct _egl_image_attribs
EGLint DRMBufferFormatMESA;
EGLint DRMBufferUseMESA;
EGLint DRMBufferStrideMESA;
/* EGL_WL_bind_wayland_display */
EGLint PlaneWL;
};
/**

View file

@ -13,7 +13,7 @@ struct wl_drm_buffer {
struct wl_buffer buffer;
struct wl_drm *drm;
uint32_t format;
uint32_t driver_format;
const void *driver_format;
int32_t offset[3];
int32_t stride[3];
void *driver_buffer;