aboutsummaryrefslogtreecommitdiff
path: root/render/gles2/texture.c
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2021-01-14 15:02:19 +0100
committerSimon Ser <contact@emersion.fr>2021-01-15 10:19:31 +0100
commit642b349e94cfd78d3719a3fbaeba9904b1e41104 (patch)
treecb8e1113a0235703806aca74c91e0eb00138227c /render/gles2/texture.c
parentcc56b4f0737398c3cc7f5d8d0296d2ca8930afa9 (diff)
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.
Diffstat (limited to 'render/gles2/texture.c')
-rw-r--r--render/gles2/texture.c72
1 files changed, 43 insertions, 29 deletions
diff --git a/render/gles2/texture.c b/render/gles2/texture.c
index 9f886391..c4b82fa4 100644
--- a/render/gles2/texture.c
+++ b/render/gles2/texture.c
@@ -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;
}