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
1 changed files with 43 additions and 29 deletions

View File

@ -26,13 +26,6 @@ struct wlr_gles2_texture *gles2_get_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) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
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 src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
const void *data) {
struct wlr_gles2_texture *texture =
get_gles2_texture_in_context(wlr_texture);
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
if (texture->target != GL_TEXTURE_2D) {
wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture");
wlr_egl_unset_current(texture->renderer->egl);
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);
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);
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);
wlr_egl_unset_current(texture->renderer->egl);
wlr_egl_restore_context(&prev_ctx);
return true;
}
@ -111,8 +107,11 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
return;
}
struct wlr_gles2_texture *texture =
get_gles2_texture_in_context(wlr_texture);
struct wlr_gles2_texture *texture = gles2_get_texture(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);
@ -121,7 +120,7 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
pop_gles2_debug(texture->renderer);
wlr_egl_unset_current(texture->renderer->egl);
wlr_egl_restore_context(&prev_ctx);
free(texture);
}
@ -138,8 +137,6 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
uint32_t height, const void *data) {
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);
if (fmt == NULL) {
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->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);
glGenTextures(1, &texture->tex);
@ -172,7 +173,8 @@ struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
pop_gles2_debug(renderer);
wlr_egl_unset_current(renderer->egl);
wlr_egl_restore_context(&prev_ctx);
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 wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_egl_make_current(renderer->egl);
if (!renderer->procs.glEGLImageTargetTexture2DOES) {
return NULL;
}
struct wlr_egl_context prev_ctx;
wlr_egl_save_context(&prev_ctx);
wlr_egl_make_current(renderer->egl);
EGLint fmt;
int width, height;
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);
if (image == EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Failed to create EGL image from wl_drm resource");
return NULL;
goto error_ctx;
}
struct wlr_gles2_texture *texture =
calloc(1, sizeof(struct wlr_gles2_texture));
if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
wlr_egl_destroy_image(renderer->egl, image);
return NULL;
goto error_image;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->renderer = renderer;
@ -220,9 +223,7 @@ struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
break;
default:
wlr_log(WLR_ERROR, "Invalid or unsupported EGL buffer format");
wlr_egl_destroy_image(renderer->egl, image);
free(texture);
return NULL;
goto error_texture;
}
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);
wlr_egl_unset_current(renderer->egl);
wlr_egl_restore_context(&prev_ctx);
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_dmabuf_attributes *attribs) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_egl_make_current(renderer->egl);
if (!renderer->procs.glEGLImageTargetTexture2DOES) {
return NULL;
}
@ -283,11 +291,16 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
texture->inverted_y =
(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;
texture->image =
wlr_egl_create_image_from_dmabuf(renderer->egl, attribs, &external_only);
if (texture->image == EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Failed to create EGL image from DMA-BUF");
wlr_egl_restore_context(&prev_ctx);
free(texture);
return NULL;
}
@ -303,7 +316,8 @@ struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
pop_gles2_debug(renderer);
wlr_egl_unset_current(renderer->egl);
wlr_egl_restore_context(&prev_ctx);
return &texture->wlr_texture;
}