gl-renderer: Store EGL buffer state in weston_buffer

Introduce a renderer_private hook for weston_buffer, and use this to
store a copy of the gl_buffer_state for EGL buffers (i.e. non-dmabuf, via
EGL_WL_bind_wayland_display).

As part of this, we create the EGLImage along with the weston_buffer
information, and just take a reference to it each time it is attached.
If you have bisected a failure to update surface content to this commit,
it very likely means that your EGL implementation requires images to be
recreated rather than only rebound in order to have their content
updated, which is contrary to specification.

Signed-off-by: Daniel Stone <daniels@collabora.com>
dev
Daniel Stone 3 years ago
parent 8544a4d09b
commit 8b167a1703
  1. 1
      include/libweston/libweston.h
  2. 161
      libweston/renderer-gl/gl-renderer.c

@ -1221,6 +1221,7 @@ struct weston_buffer {
} buffer_origin; } buffer_origin;
bool direct_display; bool direct_display;
void *renderer_private;
void *backend_private; void *backend_private;
const struct pixel_format_info *pixel_format; const struct pixel_format_info *pixel_format;

@ -180,6 +180,8 @@ struct gl_buffer_state {
int offset[3]; /* offset per plane */ int offset[3]; /* offset per plane */
int hsub[3]; /* horizontal subsampling per plane */ int hsub[3]; /* horizontal subsampling per plane */
int vsub[3]; /* vertical subsampling per plane */ int vsub[3]; /* vertical subsampling per plane */
struct wl_listener destroy_listener;
}; };
struct gl_surface_state { struct gl_surface_state {
@ -1944,6 +1946,32 @@ done:
weston_buffer_release_reference(&gs->buffer_release_ref, NULL); weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
} }
static void
destroy_buffer_state(struct gl_buffer_state *gb)
{
int i;
for (i = 0; i < gb->num_images; i++)
egl_image_unref(gb->images[i]);
wl_list_remove(&gb->destroy_listener.link);
free(gb);
}
static void
handle_buffer_destroy(struct wl_listener *listener, void *data)
{
struct weston_buffer *buffer = data;
struct gl_buffer_state *gb =
container_of(listener, struct gl_buffer_state, destroy_listener);
assert(gb == buffer->renderer_private);
buffer->renderer_private = NULL;
destroy_buffer_state(gb);
}
static void static void
ensure_textures(struct gl_surface_state *gs, GLenum target, int num_textures) ensure_textures(struct gl_surface_state *gs, GLenum target, int num_textures)
{ {
@ -2177,10 +2205,15 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec,
struct weston_buffer *buffer) struct weston_buffer *buffer)
{ {
struct gl_renderer *gr = get_renderer(ec); struct gl_renderer *gr = get_renderer(ec);
struct gl_buffer_state *gb = zalloc(sizeof(*gb));
EGLint format; EGLint format;
uint32_t fourcc; uint32_t fourcc;
EGLint y_inverted; EGLint y_inverted;
bool ret = true; bool ret = true;
int i;
if (!gb)
return false;
buffer->legacy_buffer = (struct wl_buffer *)buffer->resource; buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer, ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
@ -2189,8 +2222,11 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec,
EGL_HEIGHT, &buffer->height); EGL_HEIGHT, &buffer->height);
ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer, ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
EGL_TEXTURE_FORMAT, &format); EGL_TEXTURE_FORMAT, &format);
if (!ret) if (!ret) {
return false; weston_log("eglQueryWaylandBufferWL failed\n");
gl_renderer_print_egl_error_state();
goto err_free;
}
/* The legacy EGL buffer interface only describes the channels we can /* The legacy EGL buffer interface only describes the channels we can
* sample from; not their depths or order. Take a stab at something * sample from; not their depths or order. Take a stab at something
@ -2199,19 +2235,33 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec,
switch (format) { switch (format) {
case EGL_TEXTURE_RGB: case EGL_TEXTURE_RGB:
fourcc = DRM_FORMAT_XRGB8888; fourcc = DRM_FORMAT_XRGB8888;
gb->num_images = 1;
gb->shader_variant = SHADER_VARIANT_RGBA;
break; break;
case EGL_TEXTURE_EXTERNAL_WL:
case EGL_TEXTURE_RGBA: case EGL_TEXTURE_RGBA:
fourcc = DRM_FORMAT_ARGB8888; fourcc = DRM_FORMAT_ARGB8888;
gb->num_images = 1;
gb->shader_variant = SHADER_VARIANT_RGBA;
break;
case EGL_TEXTURE_EXTERNAL_WL:
fourcc = DRM_FORMAT_ARGB8888;
gb->num_images = 1;
gb->shader_variant = SHADER_VARIANT_EXTERNAL;
break; break;
case EGL_TEXTURE_Y_XUXV_WL: case EGL_TEXTURE_Y_XUXV_WL:
fourcc = DRM_FORMAT_YUYV; fourcc = DRM_FORMAT_YUYV;
gb->num_images = 2;
gb->shader_variant = SHADER_VARIANT_Y_XUXV;
break; break;
case EGL_TEXTURE_Y_UV_WL: case EGL_TEXTURE_Y_UV_WL:
fourcc = DRM_FORMAT_NV12; fourcc = DRM_FORMAT_NV12;
gb->num_images = 2;
gb->shader_variant = SHADER_VARIANT_Y_UV;
break; break;
case EGL_TEXTURE_Y_U_V_WL: case EGL_TEXTURE_Y_U_V_WL:
fourcc = DRM_FORMAT_YUV420; fourcc = DRM_FORMAT_YUV420;
gb->num_images = 2;
gb->shader_variant = SHADER_VARIANT_Y_U_V;
break; break;
default: default:
assert(0 && "not reached"); assert(0 && "not reached");
@ -2230,7 +2280,33 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec,
else else
buffer->buffer_origin = ORIGIN_BOTTOM_LEFT; buffer->buffer_origin = ORIGIN_BOTTOM_LEFT;
for (i = 0; i < gb->num_images; i++) {
const EGLint attribs[] = {
EGL_WAYLAND_PLANE_WL, i,
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE
};
gb->images[i] = egl_image_create(gr, EGL_WAYLAND_BUFFER_WL,
buffer->legacy_buffer,
attribs);
if (!gb->images[i]) {
weston_log("couldn't create EGLImage for plane %d\n", i);
goto err_img;
}
}
buffer->renderer_private = gb;
gb->destroy_listener.notify = handle_buffer_destroy;
wl_signal_add(&buffer->destroy_signal, &gb->destroy_listener);
return true; return true;
err_img:
while (--i >= 0)
egl_image_unref(gb->images[i]);
err_free:
free(gb);
return false;
} }
static bool static bool
@ -2239,72 +2315,33 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer)
struct weston_compositor *ec = es->compositor; struct weston_compositor *ec = es->compositor;
struct gl_renderer *gr = get_renderer(ec); struct gl_renderer *gr = get_renderer(ec);
struct gl_surface_state *gs = get_surface_state(es); struct gl_surface_state *gs = get_surface_state(es);
struct gl_buffer_state *gb = &gs->buffer; struct gl_buffer_state *gb;
EGLint attribs[5];
EGLint format;
GLenum target; GLenum target;
int i, num_planes; int i;
for (i = 0; i < gb->num_images; i++) { assert(buffer->renderer_private);
egl_image_unref(gb->images[i]);
gb->images[i] = NULL;
}
if (!gr->has_bind_display || /* The old gl_buffer_state stored in the gl_surface_state might still
!gr->query_buffer(gr->egl_display, buffer->legacy_buffer, * hold a ref to some other EGLImages: make sure we drop those. */
EGL_TEXTURE_FORMAT, &format)) { for (i = 0; i < gs->buffer.num_images; i++) {
weston_log("eglQueryWaylandBufferWL failed\n"); egl_image_unref(gs->buffer.images[i]);
gl_renderer_print_egl_error_state(); gs->buffer.images[i] = NULL;
return false;
} }
switch (format) { /* Copy over our gl_buffer_state */
case EGL_TEXTURE_RGB: memcpy(&gs->buffer, buffer->renderer_private, sizeof(gs->buffer));
/* fallthrough */ gb = &gs->buffer;
case EGL_TEXTURE_RGBA:
default:
num_planes = 1;
gb->shader_variant = SHADER_VARIANT_RGBA;
break;
case EGL_TEXTURE_EXTERNAL_WL:
num_planes = 1;
gb->shader_variant = SHADER_VARIANT_EXTERNAL;
break;
case EGL_TEXTURE_Y_UV_WL:
num_planes = 2;
gb->shader_variant = SHADER_VARIANT_Y_UV;
break;
case EGL_TEXTURE_Y_U_V_WL:
num_planes = 3;
gb->shader_variant = SHADER_VARIANT_Y_U_V;
break;
case EGL_TEXTURE_Y_XUXV_WL:
num_planes = 2;
gb->shader_variant = SHADER_VARIANT_Y_XUXV;
break;
}
gb->num_images = num_planes;
target = gl_shader_texture_variant_get_target(gb->shader_variant); target = gl_shader_texture_variant_get_target(gb->shader_variant);
ensure_textures(gs, target, num_planes); ensure_textures(gs, target, gb->num_images);
for (i = 0; i < num_planes; i++) { for (i = 0; i < gb->num_images; i++) {
attribs[0] = EGL_WAYLAND_PLANE_WL; /* The gl_buffer_state stored in buffer->renderer_private lives
attribs[1] = i; * as long as the buffer does, and holds a ref to the EGLImage
attribs[2] = EGL_IMAGE_PRESERVED_KHR; * for this buffer; in copying to the gl_buffer_state inlined
attribs[3] = EGL_TRUE; * as part of gl_surface_state, we take an extra ref, which is
attribs[4] = EGL_NONE; * destroyed on different attachments, e.g. at the start of
* this function. */
gb->images[i] = egl_image_create(gr, gb->images[i] = egl_image_ref(gb->images[i]);
EGL_WAYLAND_BUFFER_WL,
buffer->legacy_buffer,
attribs);
if (!gb->images[i]) {
weston_log("failed to create img for plane %d\n", i);
while (--i >= 0)
egl_image_unref(gb->images[i]);
return false;
}
glActiveTexture(GL_TEXTURE0 + i); glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(target, gs->textures[i]); glBindTexture(target, gs->textures[i]);
gr->image_target_texture_2d(target, gb->images[i]->image); gr->image_target_texture_2d(target, gb->images[i]->image);

Loading…
Cancel
Save