render/gles2: restore EGL context after texture operations

It can be surprising and unexpected that texture operations (such as
texture upload and import) change the current EGL context, especially
when it's done under-the-hood by wlroots in response to wl_surface
requests.

To prevent surprises, save and restore the previous EGL context.
This commit is contained in:
Simon Ser 2021-01-14 15:02:19 +01:00
parent cc56b4f073
commit 642b349e94

View file

@ -26,13 +26,6 @@ struct wlr_gles2_texture *gles2_get_texture(
return (struct wlr_gles2_texture *)wlr_texture; return (struct wlr_gles2_texture *)wlr_texture;
} }
static struct wlr_gles2_texture *get_gles2_texture_in_context(
struct wlr_texture *wlr_texture) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
wlr_egl_make_current(texture->renderer->egl);
return texture;
}
static bool gles2_texture_is_opaque(struct wlr_texture *wlr_texture) { static bool gles2_texture_is_opaque(struct wlr_texture *wlr_texture) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
return !texture->has_alpha; return !texture->has_alpha;
@ -42,12 +35,10 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
uint32_t stride, uint32_t width, uint32_t height, uint32_t stride, uint32_t width, uint32_t height,
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
const void *data) { const void *data) {
struct wlr_gles2_texture *texture = struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
get_gles2_texture_in_context(wlr_texture);
if (texture->target != GL_TEXTURE_2D) { if (texture->target != GL_TEXTURE_2D) {
wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture"); wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture");
wlr_egl_unset_current(texture->renderer->egl);
return false; return false;
} }
@ -55,6 +46,10 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
get_gles2_format_from_wl(texture->wl_format); get_gles2_format_from_wl(texture->wl_format);
assert(fmt); assert(fmt);
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(texture->renderer->egl);
push_gles2_debug(texture->renderer); push_gles2_debug(texture->renderer);
glBindTexture(GL_TEXTURE_2D, texture->tex); glBindTexture(GL_TEXTURE_2D, texture->tex);
@ -74,7 +69,8 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
pop_gles2_debug(texture->renderer); pop_gles2_debug(texture->renderer);
wlr_egl_unset_current(texture->renderer->egl); wlr_egl_restore_context(&prev_ctx);
return true; return true;
} }
@ -111,8 +107,11 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
return; return;
} }
struct wlr_gles2_texture *texture = struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
get_gles2_texture_in_context(wlr_texture);
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(texture->renderer->egl);
push_gles2_debug(texture->renderer); push_gles2_debug(texture->renderer);
@ -121,7 +120,7 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
pop_gles2_debug(texture->renderer); pop_gles2_debug(texture->renderer);
wlr_egl_unset_current(texture->renderer->egl); wlr_egl_restore_context(&prev_ctx);
free(texture); free(texture);
} }
@ -138,8 +137,6 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
uint32_t height, const void *data) { uint32_t height, const void *data) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_egl_make_current(renderer->egl);
const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt); const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt);
if (fmt == NULL) { if (fmt == NULL) {
wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt); wlr_log(WLR_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt);
@ -158,6 +155,10 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
texture->has_alpha = fmt->has_alpha; texture->has_alpha = fmt->has_alpha;
texture->wl_format = fmt->wl_format; texture->wl_format = fmt->wl_format;
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(renderer->egl);
push_gles2_debug(renderer); push_gles2_debug(renderer);
glGenTextures(1, &texture->tex); glGenTextures(1, &texture->tex);
@ -172,7 +173,8 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
pop_gles2_debug(renderer); pop_gles2_debug(renderer);
wlr_egl_unset_current(renderer->egl); wlr_egl_restore_context(&prev_ctx);
return &texture->wlr_texture; return &texture->wlr_texture;
} }
@ -180,12 +182,14 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
struct wl_resource *resource) { struct wl_resource *resource) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_egl_make_current(renderer->egl);
if (!renderer->procs.glEGLImageTargetTexture2DOES) { if (!renderer->procs.glEGLImageTargetTexture2DOES) {
return NULL; return NULL;
} }
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(renderer->egl);
EGLint fmt; EGLint fmt;
int width, height; int width, height;
bool inverted_y; bool inverted_y;
@ -193,15 +197,14 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
&fmt, &width, &height, &inverted_y); &fmt, &width, &height, &inverted_y);
if (image == EGL_NO_IMAGE_KHR) { if (image == EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Failed to create EGL image from wl_drm resource"); wlr_log(WLR_ERROR, "Failed to create EGL image from wl_drm resource");
return NULL; goto error_ctx;
} }
struct wlr_gles2_texture *texture = struct wlr_gles2_texture *texture =
calloc(1, sizeof(struct wlr_gles2_texture)); calloc(1, sizeof(struct wlr_gles2_texture));
if (texture == NULL) { if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed"); wlr_log(WLR_ERROR, "Allocation failed");
wlr_egl_destroy_image(renderer->egl, image); goto error_image;
return NULL;
} }
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height); wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->renderer = renderer; texture->renderer = renderer;
@ -220,9 +223,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
break; break;
default: default:
wlr_log(WLR_ERROR, "Invalid or unsupported EGL buffer format"); wlr_log(WLR_ERROR, "Invalid or unsupported EGL buffer format");
wlr_egl_destroy_image(renderer->egl, image); goto error_texture;
free(texture);
return NULL;
} }
texture->target = GL_TEXTURE_EXTERNAL_OES; texture->target = GL_TEXTURE_EXTERNAL_OES;
@ -237,16 +238,23 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
pop_gles2_debug(renderer); pop_gles2_debug(renderer);
wlr_egl_unset_current(renderer->egl); wlr_egl_restore_context(&prev_ctx);
return &texture->wlr_texture; return &texture->wlr_texture;
error_texture:
free(texture);
error_image:
wlr_egl_destroy_image(renderer->egl, image);
error_ctx:
wlr_egl_restore_context(&prev_ctx);
return NULL;
} }
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer, struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_attributes *attribs) { struct wlr_dmabuf_attributes *attribs) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_egl_make_current(renderer->egl);
if (!renderer->procs.glEGLImageTargetTexture2DOES) { if (!renderer->procs.glEGLImageTargetTexture2DOES) {
return NULL; return NULL;
} }
@ -283,11 +291,16 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
texture->inverted_y = texture->inverted_y =
(attribs->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) != 0; (attribs->flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT) != 0;
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(renderer->egl);
bool external_only; bool external_only;
texture->image = texture->image =
wlr_egl_create_image_from_dmabuf(renderer->egl, attribs, &external_only); wlr_egl_create_image_from_dmabuf(renderer->egl, attribs, &external_only);
if (texture->image == EGL_NO_IMAGE_KHR) { if (texture->image == EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Failed to create EGL image from DMA-BUF"); wlr_log(WLR_ERROR, "Failed to create EGL image from DMA-BUF");
wlr_egl_restore_context(&prev_ctx);
free(texture); free(texture);
return NULL; return NULL;
} }
@ -303,7 +316,8 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
pop_gles2_debug(renderer); pop_gles2_debug(renderer);
wlr_egl_unset_current(renderer->egl); wlr_egl_restore_context(&prev_ctx);
return &texture->wlr_texture; return &texture->wlr_texture;
} }