egl_dri2/wayland: handle creating xrgb8888 images
When creating an EGLImage from a struct wl_buffer * this ensures
that we create an XRGB8888 image if the wayland buffer doesn't have an
alpha channel. To determine if a wl_buffer has a valid alpha channel
this patch adds an internal wayland_drm_buffer_has_alpha() function.
It's important to get the internal format for an EGLImage right so that
if a GL texture is later created from the image then the GL driver will
know if it should sample the alpha from the texture or flatten it to
a constant of 1.0.
This avoids needing fragment program workarounds in wayland compositors
to manually ignore the alpha component of textures created from wayland
buffers.
krh: Edited to use wl_buffer_get_format() instead of wl_buffer_has_alpha().
Reviewed-by: Kristian Høgsberg <krh@bitplanet.net>
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 47de978..a7ebf59 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -993,16 +993,52 @@
}
static _EGLImage *
-dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
- EGLClientBuffer buffer, const EGLint *attr_list)
+dri2_create_image_drm_name(_EGLDisplay *disp, _EGLContext *ctx,
+ EGLint name,
+ const _EGLImageAttribs *attrs,
+ EGLint format,
+ EGLint pitch)
{
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
struct dri2_egl_image *dri2_img;
- EGLint format, name, pitch, err;
- _EGLImageAttribs attrs;
(void) ctx;
+ dri2_img = malloc(sizeof *dri2_img);
+ if (!dri2_img) {
+ _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm");
+ return NULL;
+ }
+
+ if (!_eglInitImage(&dri2_img->base, disp)) {
+ free(dri2_img);
+ return NULL;
+ }
+
+ dri2_img->dri_image =
+ dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
+ attrs->Width,
+ attrs->Height,
+ format,
+ name,
+ pitch,
+ dri2_img);
+ if (dri2_img->dri_image == NULL) {
+ free(dri2_img);
+ _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm");
+ return NULL;
+ }
+
+ return &dri2_img->base;
+}
+
+static _EGLImage *
+dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
+ EGLClientBuffer buffer, const EGLint *attr_list)
+{
+ EGLint format, name, pitch, err;
+ _EGLImageAttribs attrs;
+
name = (EGLint) (uintptr_t) buffer;
err = _eglParseImageAttribList(&attrs, disp, attr_list);
@@ -1027,76 +1063,53 @@
return NULL;
}
- dri2_img = malloc(sizeof *dri2_img);
- if (!dri2_img) {
- _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm");
- return NULL;
- }
-
- if (!_eglInitImage(&dri2_img->base, disp)) {
- free(dri2_img);
- return NULL;
- }
-
- dri2_img->dri_image =
- dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
- attrs.Width,
- attrs.Height,
- format,
- name,
- pitch,
- dri2_img);
- if (dri2_img->dri_image == NULL) {
- free(dri2_img);
- _eglError(EGL_BAD_ALLOC, "dri2_create_image_mesa_drm");
- return NULL;
- }
-
- return &dri2_img->base;
+ return dri2_create_image_drm_name (disp, ctx, name, &attrs, format, pitch);
}
#ifdef HAVE_WAYLAND_PLATFORM
static _EGLImage *
-dri2_reference_drm_image(_EGLDisplay *disp, _EGLContext *ctx,
- __DRIimage *dri_image, EGLint width, EGLint height)
-{
- struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
- EGLint attr_list[] = {
- EGL_WIDTH, 0,
- EGL_HEIGHT, 0,
- EGL_DRM_BUFFER_STRIDE_MESA, 0,
- EGL_DRM_BUFFER_FORMAT_MESA, EGL_DRM_BUFFER_FORMAT_ARGB32_MESA,
- EGL_NONE
- };
- EGLint name, stride;
-
- dri2_dpy->image->queryImage(dri_image, __DRI_IMAGE_ATTRIB_NAME, &name);
- dri2_dpy->image->queryImage(dri_image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
-
- attr_list[1] = width;
- attr_list[3] = height;
- attr_list[5] = stride / 4;
-
- return dri2_create_image_mesa_drm_buffer(disp, ctx,
- (EGLClientBuffer)(intptr_t) name,
- attr_list);
-}
-
-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;
- (void) attr_list;
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+ __DRIimage *dri_image;
+ _EGLImageAttribs attrs;
+ EGLint format, name, stride, pitch, err;
if (!wayland_buffer_is_drm(buffer))
return NULL;
- return dri2_reference_drm_image(disp, ctx,
- wayland_drm_buffer_get_buffer(buffer),
- buffer->width,
- buffer->height);
+ dri_image = wayland_drm_buffer_get_buffer(buffer);
+
+ dri2_dpy->image->queryImage(dri_image, __DRI_IMAGE_ATTRIB_NAME, &name);
+ dri2_dpy->image->queryImage(dri_image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
+
+ err = _eglParseImageAttribList(&attrs, disp, attr_list);
+ if (err != EGL_SUCCESS)
+ return NULL;
+
+ attrs.Width = buffer->width;
+ attrs.Height = buffer->height;
+
+ switch (wayland_drm_buffer_get_format(buffer)) {
+ case WL_DRM_FORMAT_ARGB32:
+ case WL_DRM_FORMAT_PREMULTIPLIED_ARGB32:
+ format = __DRI_IMAGE_FORMAT_ARGB8888;
+ break;
+ case WL_DRM_FORMAT_XRGB32:
+ _eglError(EGL_BAD_PARAMETER,
+ "dri2_create_image_khr: unsupported wl_buffer format");
+ format = __DRI_IMAGE_FORMAT_XRGB8888;
+ break;
+ default:
+ return NULL;
+ }
+
+ pitch = stride / 4;
+
+ return dri2_create_image_drm_name(disp, ctx, name, &attrs, format, pitch);
}
#endif
diff --git a/src/egl/wayland/wayland-drm/wayland-drm.c b/src/egl/wayland/wayland-drm/wayland-drm.c
index 82ca6aa..43f9169 100644
--- a/src/egl/wayland/wayland-drm/wayland-drm.c
+++ b/src/egl/wayland/wayland-drm/wayland-drm.c
@@ -205,6 +205,14 @@
(void (**)(void)) &drm_buffer_interface;
}
+uint32_t
+wayland_drm_buffer_get_format(struct wl_buffer *buffer_base)
+{
+ struct wl_drm_buffer *buffer = (struct wl_drm_buffer *) buffer_base;
+
+ return buffer->format;
+}
+
void *
wayland_drm_buffer_get_buffer(struct wl_buffer *buffer_base)
{
diff --git a/src/egl/wayland/wayland-drm/wayland-drm.h b/src/egl/wayland/wayland-drm/wayland-drm.h
index c9a90ca..bec50a5 100644
--- a/src/egl/wayland/wayland-drm/wayland-drm.h
+++ b/src/egl/wayland/wayland-drm/wayland-drm.h
@@ -29,6 +29,9 @@
int
wayland_buffer_is_drm(struct wl_buffer *buffer);
+uint32_t
+wayland_drm_buffer_get_format(struct wl_buffer *buffer_base);
+
void *
wayland_drm_buffer_get_buffer(struct wl_buffer *buffer);