diff options
-rw-r--r-- | docs/WL_bind_wayland_display.spec | 90 | ||||
-rw-r--r-- | include/EGL/eglmesaext.h | 14 | ||||
-rw-r--r-- | src/egl/drivers/dri2/egl_dri2.c | 150 | ||||
-rw-r--r-- | src/egl/main/eglapi.c | 20 | ||||
-rw-r--r-- | src/egl/main/eglapi.h | 2 | ||||
-rw-r--r-- | src/egl/main/eglimage.c | 5 | ||||
-rw-r--r-- | src/egl/main/eglimage.h | 3 | ||||
-rw-r--r-- | src/egl/wayland/wayland-drm/wayland-drm.h | 2 |
8 files changed, 267 insertions, 19 deletions
diff --git a/docs/WL_bind_wayland_display.spec b/docs/WL_bind_wayland_display.spec index e2fde3c507b..e1aca538003 100644 --- a/docs/WL_bind_wayland_display.spec +++ b/docs/WL_bind_wayland_display.spec @@ -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) diff --git a/include/EGL/eglmesaext.h b/include/EGL/eglmesaext.h index 52dd5b108fd..74d8ced37f3 100644 --- a/include/EGL/eglmesaext.h +++ b/include/EGL/eglmesaext.h @@ -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 diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 0fc33e01513..fcb226443b3 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -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"; diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index b27aac16748..ffc404cc2d7 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -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 diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index 14085cb4d83..ec3ad7ec973 100644 --- a/src/egl/main/eglapi.h +++ b/src/egl/main/eglapi.h @@ -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; diff --git a/src/egl/main/eglimage.c b/src/egl/main/eglimage.c index 1174d0aef1f..bfae709bb3c 100644 --- a/src/egl/main/eglimage.c +++ b/src/egl/main/eglimage.c @@ -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; diff --git a/src/egl/main/eglimage.h b/src/egl/main/eglimage.h index acb36aaeb18..9cc86d58b2d 100644 --- a/src/egl/main/eglimage.h +++ b/src/egl/main/eglimage.h @@ -50,6 +50,9 @@ struct _egl_image_attribs EGLint DRMBufferFormatMESA; EGLint DRMBufferUseMESA; EGLint DRMBufferStrideMESA; + + /* EGL_WL_bind_wayland_display */ + EGLint PlaneWL; }; /** diff --git a/src/egl/wayland/wayland-drm/wayland-drm.h b/src/egl/wayland/wayland-drm/wayland-drm.h index 46aab6984d1..4ef286fe6c5 100644 --- a/src/egl/wayland/wayland-drm/wayland-drm.h +++ b/src/egl/wayland/wayland-drm/wayland-drm.h @@ -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; |