Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

add destroy listener for textures #1962

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/headless/backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <wlr/interfaces/wlr_input_device.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/render/egl.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/util/log.h>
#include "backend/headless.h"
#include "util/signal.h"
Expand Down
1 change: 0 additions & 1 deletion examples/multi-pointer.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard.h>
Expand Down
1 change: 0 additions & 1 deletion examples/pointer.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard.h>
Expand Down
10 changes: 10 additions & 0 deletions include/render/gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ const enum wl_shm_format *get_gles2_wl_formats(size_t *len);

struct wlr_gles2_texture *gles2_get_texture(
struct wlr_texture *wlr_texture);
struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_renderer *wlr_renderer);

struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *renderer,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
const void *data);
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *renderer,
struct wl_resource *data);
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *renderer,
struct wlr_dmabuf_attributes *attribs);

void push_gles2_marker(const char *file, const char *func);
void pop_gles2_marker(void);
Expand Down
8 changes: 0 additions & 8 deletions include/wlr/render/gles2.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl);

struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer);

struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
const void *data);
struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
struct wl_resource *data);
struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
struct wlr_dmabuf_attributes *attribs);

struct wlr_gles2_texture_attribs {
GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */
GLuint tex;
Expand Down
2 changes: 1 addition & 1 deletion include/wlr/render/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ struct wlr_texture_impl {
};

void wlr_texture_init(struct wlr_texture *texture,
const struct wlr_texture_impl *impl);
struct wlr_renderer *renderer, const struct wlr_texture_impl *impl);

#endif
2 changes: 2 additions & 0 deletions include/wlr/render/wlr_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ struct wlr_texture_impl;

struct wlr_texture {
const struct wlr_texture_impl *impl;

struct wl_listener renderer_destroy;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This listener may run before or after other renderer destroy listeners (listener call order is undefined). This can cause a use-after-free if the texture listener is called first, then the buffer/output listener is called.

We should probably add a destroy signal to wlr_texture to prevent this.

};

/**
Expand Down
4 changes: 3 additions & 1 deletion include/wlr/types/wlr_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ struct wlr_client_buffer {
bool resource_released;
/**
* The buffer's texture, if any. A buffer will not have a texture if the
* client destroys the buffer before it has been released.
* client destroys the buffer before it has been released. The texture will
* be set to NULL if the renderer is destroyed.
*/
struct wlr_texture *texture;

struct wl_listener resource_destroy;
struct wl_listener release;
struct wl_listener renderer_destroy;
};

struct wlr_renderer;
Expand Down
1 change: 1 addition & 0 deletions include/wlr/types/wlr_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ struct wlr_output_cursor {

// only when using a software cursor without a surface
struct wlr_texture *texture;
struct wl_listener renderer_destroy;

// only when using a cursor surface
struct wlr_surface *surface;
Expand Down
23 changes: 1 addition & 22 deletions render/gles2/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct wlr_gles2_procs gles2_procs = {0};

static const struct wlr_renderer_impl renderer_impl;

static struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_renderer *wlr_renderer) {
assert(wlr_renderer->impl == &renderer_impl);
return (struct wlr_gles2_renderer *)wlr_renderer;
Expand Down Expand Up @@ -331,27 +331,6 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
return glGetError() == GL_NO_ERROR;
}

static struct wlr_texture *gles2_texture_from_pixels(
struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt,
uint32_t stride, uint32_t width, uint32_t height, const void *data) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
return wlr_gles2_texture_from_pixels(renderer->egl, wl_fmt, stride, width,
height, data);
}

static struct wlr_texture *gles2_texture_from_wl_drm(
struct wlr_renderer *wlr_renderer, struct wl_resource *data) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
return wlr_gles2_texture_from_wl_drm(renderer->egl, data);
}

static 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);
return wlr_gles2_texture_from_dmabuf(renderer->egl, attribs);
}

static bool gles2_init_wl_display(struct wlr_renderer *wlr_renderer,
struct wl_display *wl_display) {
struct wlr_gles2_renderer *renderer =
Expand Down
48 changes: 33 additions & 15 deletions render/gles2/texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
return;
}

wl_list_remove(&wlr_texture->renderer_destroy.link);

struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);

if (!wlr_egl_is_current(texture->egl)) {
Expand All @@ -142,9 +144,28 @@ static const struct wlr_texture_impl texture_impl = {
.destroy = gles2_texture_destroy,
};

struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
static struct wlr_gles2_texture *create_gles2_texture(
struct wlr_renderer *renderer){
struct wlr_gles2_texture *texture;

texture = calloc(1, sizeof(struct wlr_gles2_texture));
if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, renderer,
&texture_impl);

return texture;
}

struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *renderer,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
uint32_t height, const void *data) {

struct wlr_gles2_renderer *gles_renderer = gles2_get_renderer(renderer);
struct wlr_egl *egl = gles_renderer->egl;

if (!wlr_egl_is_current(egl)) {
wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL);
}
Expand All @@ -155,13 +176,10 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
return NULL;
}

struct wlr_gles2_texture *texture =
calloc(1, sizeof(struct wlr_gles2_texture));
struct wlr_gles2_texture *texture = create_gles2_texture(renderer);
if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl);
texture->egl = egl;
texture->width = width;
texture->height = height;
Expand All @@ -185,8 +203,11 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
return &texture->wlr_texture;
}

struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *renderer,
struct wl_resource *data) {
struct wlr_gles2_renderer *gles_renderer = gles2_get_renderer(renderer);
struct wlr_egl *egl = gles_renderer->egl;

if (!wlr_egl_is_current(egl)) {
wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL);
}
Expand All @@ -195,13 +216,10 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
return NULL;
}

struct wlr_gles2_texture *texture =
calloc(1, sizeof(struct wlr_gles2_texture));
struct wlr_gles2_texture *texture = create_gles2_texture(renderer);
if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl);
texture->egl = egl;

EGLint fmt;
Expand Down Expand Up @@ -241,8 +259,11 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
return &texture->wlr_texture;
}

struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *renderer,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_gles2_renderer *gles_renderer = gles2_get_renderer(renderer);
struct wlr_egl *egl = gles_renderer->egl;

if (!wlr_egl_is_current(egl)) {
wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL);
}
Expand All @@ -269,13 +290,10 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
break;
}

struct wlr_gles2_texture *texture =
calloc(1, sizeof(struct wlr_gles2_texture));
struct wlr_gles2_texture *texture = create_gles2_texture(renderer);
if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl);
texture->egl = egl;
texture->width = attribs->width;
texture->height = attribs->height;
Expand Down
14 changes: 13 additions & 1 deletion render/wlr_texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@
#include <stdlib.h>
#include <wlr/render/interface.h>
#include <wlr/render/wlr_texture.h>
#include <wlr/render/wlr_renderer.h>

static void wlr_texture_handle_renderer_destroy(struct wl_listener *listener,
void *data){
struct wlr_texture *wlr_texture;
wlr_texture = wl_container_of(listener, wlr_texture, renderer_destroy);
wlr_texture_destroy(wlr_texture);
}


void wlr_texture_init(struct wlr_texture *texture,
const struct wlr_texture_impl *impl) {
struct wlr_renderer *renderer, const struct wlr_texture_impl *impl) {
assert(impl->get_size);
assert(impl->write_pixels);
texture->impl = impl;

texture->renderer_destroy.notify = wlr_texture_handle_renderer_destroy;
wl_signal_add(&renderer->events.destroy, &texture->renderer_destroy);
}

void wlr_texture_destroy(struct wlr_texture *texture) {
Expand Down
16 changes: 14 additions & 2 deletions types/wlr_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ static void client_buffer_destroy(struct wlr_buffer *_buffer) {
}

wl_list_remove(&buffer->resource_destroy.link);
wl_list_remove(&buffer->renderer_destroy.link);
wlr_texture_destroy(buffer->texture);
free(buffer);
}
Expand Down Expand Up @@ -165,6 +166,14 @@ static void client_buffer_handle_release(struct wl_listener *listener,
}
}

static void client_buffer_renderer_handle_destroy(struct wl_listener *listener,
void * data) {
// The renderer destroys the texture, set texture to NULL to prevent use-after-free
struct wlr_client_buffer *buffer;
buffer = wl_container_of(listener, buffer, renderer_destroy);
buffer->texture = NULL;
}

struct wlr_client_buffer *wlr_client_buffer_import(
struct wlr_renderer *renderer, struct wl_resource *resource) {
assert(wlr_resource_is_buffer(resource));
Expand Down Expand Up @@ -231,6 +240,8 @@ struct wlr_client_buffer *wlr_client_buffer_import(

wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
buffer->resource_destroy.notify = client_buffer_resource_handle_destroy;
wl_signal_add(&renderer->events.destroy, &buffer->renderer_destroy);
buffer->renderer_destroy.notify = client_buffer_renderer_handle_destroy;

buffer->release.notify = client_buffer_handle_release;
wl_signal_add(&buffer->base.events.release, &buffer->release);
Expand All @@ -247,8 +258,9 @@ struct wlr_client_buffer *wlr_client_buffer_apply_damage(
pixman_region32_t *damage) {
assert(wlr_resource_is_buffer(resource));

if (buffer->base.n_locks > 1) {
// Someone else still has a reference to the buffer
if (buffer->base.n_locks > 1 || !buffer->texture) {
// Someone else still has a reference to the buffer or the texture has
// been destroyed
return NULL;
}

Expand Down
14 changes: 14 additions & 0 deletions types/wlr_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,14 @@ static void output_scissor(struct wlr_output *output, pixman_box32_t *rect) {
wlr_renderer_scissor(renderer, &box);
}

static void output_cursor_renderer_handle_destroy(struct wl_listener *listener,
void * data) {
// The renderer destroys the texture, set texture to NULL to prevent use-after-free
struct wlr_output_cursor *cursor;
cursor = wl_container_of(listener, cursor, renderer_destroy);
cursor->texture = NULL;
}

static void output_cursor_get_box(struct wlr_output_cursor *cursor,
struct wlr_box *box);

Expand Down Expand Up @@ -1002,6 +1010,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
cursor->hotspot_y = hotspot_y;
output_cursor_update_visible(cursor);

wl_list_remove(&cursor->renderer_destroy.link);
wl_list_init(&cursor->renderer_destroy.link);
wlr_texture_destroy(cursor->texture);
cursor->texture = NULL;

Expand All @@ -1012,6 +1022,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
if (cursor->texture == NULL) {
return false;
}
wl_signal_add(&renderer->events.destroy, &cursor->renderer_destroy);
cursor->renderer_destroy.notify = output_cursor_renderer_handle_destroy;
cursor->enabled = true;
}

Expand Down Expand Up @@ -1158,6 +1170,7 @@ struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) {
wl_list_init(&cursor->surface_destroy.link);
cursor->surface_destroy.notify = output_cursor_handle_destroy;
wl_list_insert(&output->cursors, &cursor->link);
wl_list_init(&cursor->renderer_destroy.link);
cursor->visible = true; // default position is at (0, 0)
return cursor;
}
Expand All @@ -1178,6 +1191,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
}
wlr_texture_destroy(cursor->texture);
wl_list_remove(&cursor->link);
wl_list_remove(&cursor->renderer_destroy.link);
free(cursor);
}

Expand Down