Redesign wlr_texture

- Textures are now immutable (apart from those created from raw
  pixels), no more invalid textures
- Move all wl_drm stuff in wlr_renderer
- Most of wlr_texture fields are now private
- Remove some duplicated DMA-BUF code in the DRM backend
- Add more assertions
- Stride is now always given as bytes rather than pixels
- Drop wl_shm functions

Fun fact: this patch has been written 10,000 meters up in the air.
master
emersion 7 years ago
parent 80d3561d32
commit c63d94483b
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48

@ -181,9 +181,6 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) {
if (plane->cursor_bo) { if (plane->cursor_bo) {
gbm_bo_destroy(plane->cursor_bo); gbm_bo_destroy(plane->cursor_bo);
} }
if (plane->wlr_tex) {
wlr_texture_destroy(plane->wlr_tex);
}
} }
free(drm->crtcs); free(drm->crtcs);
@ -586,12 +583,6 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
wlr_output_transform_invert(output->transform); wlr_output_transform_invert(output->transform);
wlr_matrix_projection(plane->matrix, plane->surf.width, wlr_matrix_projection(plane->matrix, plane->surf.width,
plane->surf.height, transform); plane->surf.height, transform);
plane->wlr_tex =
wlr_render_texture_create(plane->surf.renderer->wlr_rend);
if (!plane->wlr_tex) {
return false;
}
} }
struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y }; struct wlr_box hotspot = { .x = hotspot_x, .y = hotspot_y };
@ -637,13 +628,18 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
wlr_drm_surface_make_current(&plane->surf, NULL); wlr_drm_surface_make_current(&plane->surf, NULL);
wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888,
stride, width, height, buf);
struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; struct wlr_renderer *rend = plane->surf.renderer->wlr_rend;
struct wlr_texture *texture = wlr_texture_from_pixels(rend,
WL_SHM_FORMAT_ARGB8888, stride, width, height, buf);
if (texture == NULL) {
wlr_log(L_ERROR, "Unable to create texture");
return false;
}
wlr_renderer_begin(rend, plane->surf.width, plane->surf.height); wlr_renderer_begin(rend, plane->surf.width, plane->surf.height);
wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 }); wlr_renderer_clear(rend, (float[]){ 0.0, 0.0, 0.0, 0.0 });
wlr_render_texture(rend, plane->wlr_tex, plane->matrix, 0, 0, 1.0f); wlr_render_texture(rend, texture, plane->matrix, 0, 0, 1.0f);
wlr_renderer_end(rend); wlr_renderer_end(rend);
wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride,
@ -651,6 +647,7 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
wlr_drm_surface_swap_buffers(&plane->surf, NULL); wlr_drm_surface_swap_buffers(&plane->surf, NULL);
wlr_texture_destroy(texture);
gbm_bo_unmap(plane->cursor_bo, bo_data); gbm_bo_unmap(plane->cursor_bo, bo_data);
} }

@ -178,47 +178,33 @@ static void free_eglimage(struct gbm_bo *bo, void *data) {
static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer,
struct gbm_bo *bo) { struct gbm_bo *bo) {
struct tex *tex = gbm_bo_get_user_data(bo); struct tex *tex = gbm_bo_get_user_data(bo);
if (tex) { if (tex != NULL) {
return tex->tex; return tex->tex;
} }
// TODO: use wlr_texture_upload_dmabuf instead tex = calloc(1, sizeof(struct tex));
if (tex == NULL) {
tex = malloc(sizeof(*tex));
if (!tex) {
wlr_log_errno(L_ERROR, "Allocation failed");
return NULL; return NULL;
} }
tex->egl = &renderer->egl; struct wlr_dmabuf_buffer_attribs attribs = {
.n_planes = 1,
int dmabuf_fd = gbm_bo_get_fd(bo); .width = gbm_bo_get_width(bo),
uint32_t width = gbm_bo_get_width(bo); .height = gbm_bo_get_height(bo),
uint32_t height = gbm_bo_get_height(bo); .format = gbm_bo_get_format(bo),
EGLint attribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_LINUX_DRM_FOURCC_EXT, gbm_bo_get_format(bo),
EGL_DMA_BUF_PLANE0_FD_EXT, dmabuf_fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, gbm_bo_get_offset(bo, 0),
EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride_for_plane(bo, 0),
EGL_IMAGE_PRESERVED_KHR, EGL_FALSE,
EGL_NONE,
}; };
attribs.offset[0] = 0;
tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT, attribs.stride[0] = gbm_bo_get_stride_for_plane(bo, 0);
EGL_LINUX_DMA_BUF_EXT, NULL, attribs); attribs.modifier[0] = 0;
if (!tex->img) { attribs.fd[0] = gbm_bo_get_fd(bo);
wlr_log(L_ERROR, "Failed to create EGL image");
abort(); tex->tex = wlr_texture_from_dmabuf(renderer->wlr_rend, &attribs);
if (tex->tex == NULL) {
free(tex);
return NULL;
} }
tex->tex = wlr_render_texture_create(renderer->wlr_rend);
wlr_texture_upload_eglimage(tex->tex, tex->img, width, height);
gbm_bo_set_user_data(bo, tex, free_eglimage); gbm_bo_set_user_data(bo, tex, free_eglimage);
return tex->tex; return tex->tex;
} }

@ -99,8 +99,6 @@ static bool wlr_wl_output_set_cursor(struct wlr_output *_output,
return true; return true;
} }
stride *= 4; // stride is given in pixels, we need it in bytes
if (!backend->shm || !backend->pointer) { if (!backend->shm || !backend->pointer) {
wlr_log(L_INFO, "cannot set cursor, no shm or pointer"); wlr_log(L_INFO, "cannot set cursor, no shm or pointer");
return false; return false;

@ -149,7 +149,7 @@ static void handle_input_add(struct compositor_state *state,
sample->compositor); sample->compositor);
struct wlr_xcursor_image *image = sample->xcursor->images[0]; struct wlr_xcursor_image *image = sample->xcursor->images[0];
wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4,
image->width, image->height, image->hotspot_x, image->hotspot_y, 0); image->width, image->height, image->hotspot_x, image->hotspot_y, 0);
wl_list_insert(&sample->cursors, &cursor->link); wl_list_insert(&sample->cursors, &cursor->link);

@ -197,9 +197,9 @@ int main(int argc, char *argv[]) {
compositor_init(&compositor); compositor_init(&compositor);
state.renderer = wlr_gles2_renderer_create(compositor.backend); state.renderer = wlr_gles2_renderer_create(compositor.backend);
state.cat_texture = wlr_render_texture_create(state.renderer); state.cat_texture = wlr_texture_from_pixels(state.renderer,
wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888, WL_SHM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data); cat_tex.pixel_data);
if (!wlr_backend_start(compositor.backend)) { if (!wlr_backend_start(compositor.backend)) {
wlr_log(L_ERROR, "Failed to start backend"); wlr_log(L_ERROR, "Failed to start backend");

@ -112,7 +112,7 @@ static void handle_output_add(struct output_state *ostate) {
sample->compositor); sample->compositor);
struct wlr_xcursor_image *image = sample->xcursor->images[0]; struct wlr_xcursor_image *image = sample->xcursor->images[0];
wlr_cursor_set_image(sample->cursor, image->buffer, image->width, wlr_cursor_set_image(sample->cursor, image->buffer, image->width * 4,
image->width, image->height, image->hotspot_x, image->hotspot_y, 0); image->width, image->height, image->hotspot_x, image->hotspot_y, 0);
wlr_cursor_warp(sample->cursor, NULL, sample->cursor->x, sample->cursor->y); wlr_cursor_warp(sample->cursor, NULL, sample->cursor->x, sample->cursor->y);
@ -324,7 +324,7 @@ int main(int argc, char *argv[]) {
} }
struct wlr_xcursor_image *image = state.xcursor->images[0]; struct wlr_xcursor_image *image = state.xcursor->images[0];
wlr_cursor_set_image(state.cursor, image->buffer, image->width, wlr_cursor_set_image(state.cursor, image->buffer, image->width * 4,
image->width, image->height, image->hotspot_x, image->hotspot_y, 0); image->width, image->height, image->hotspot_x, image->hotspot_y, 0);
compositor_init(&compositor); compositor_init(&compositor);

@ -142,13 +142,13 @@ int main(int argc, char *argv[]) {
wlr_log(L_ERROR, "Could not start compositor, OOM"); wlr_log(L_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
state.cat_texture = wlr_render_texture_create(state.renderer); state.cat_texture = wlr_texture_from_pixels(state.renderer,
WL_SHM_FORMAT_ABGR8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
cat_tex.pixel_data);
if (!state.cat_texture) { if (!state.cat_texture) {
wlr_log(L_ERROR, "Could not start compositor, OOM"); wlr_log(L_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888,
cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
if (!wlr_backend_start(compositor.backend)) { if (!wlr_backend_start(compositor.backend)) {
wlr_log(L_ERROR, "Failed to start backend"); wlr_log(L_ERROR, "Failed to start backend");

@ -45,10 +45,13 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts
wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1});
int tex_width, tex_height;
wlr_texture_get_size(sample->cat_texture, &tex_width, &tex_height);
struct touch_point *p; struct touch_point *p;
wl_list_for_each(p, &sample->touch_points, link) { wl_list_for_each(p, &sample->touch_points, link) {
int x = (int)(p->x * width) - sample->cat_texture->width / 2; int x = (int)(p->x * width) - tex_width / 2;
int y = (int)(p->y * height) - sample->cat_texture->height / 2; int y = (int)(p->y * height) - tex_height / 2;
wlr_render_texture(sample->renderer, sample->cat_texture, wlr_render_texture(sample->renderer, sample->cat_texture,
wlr_output->transform_matrix, x, y, 1.0f); wlr_output->transform_matrix, x, y, 1.0f);
} }
@ -110,13 +113,13 @@ int main(int argc, char *argv[]) {
wlr_log(L_ERROR, "Could not start compositor, OOM"); wlr_log(L_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
state.cat_texture = wlr_render_texture_create(state.renderer); state.cat_texture = wlr_texture_from_pixels(state.renderer,
WL_SHM_FORMAT_ARGB8888, cat_tex.width * 4, cat_tex.width, cat_tex.height,
cat_tex.pixel_data);
if (!state.cat_texture) { if (!state.cat_texture) {
wlr_log(L_ERROR, "Could not start compositor, OOM"); wlr_log(L_ERROR, "Could not start compositor, OOM");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ARGB8888,
cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
if (!wlr_backend_start(compositor.backend)) { if (!wlr_backend_start(compositor.backend)) {
wlr_log(L_ERROR, "Failed to start backend"); wlr_log(L_ERROR, "Failed to start backend");

@ -27,7 +27,6 @@ struct wlr_drm_plane {
// Only used by cursor // Only used by cursor
float matrix[9]; float matrix[9];
struct wlr_texture *wlr_tex;
struct gbm_bo *cursor_bo; struct gbm_bo *cursor_bo;
bool cursor_enabled; bool cursor_enabled;
int32_t cursor_hotspot_x, cursor_hotspot_y; int32_t cursor_hotspot_x, cursor_hotspot_y;

@ -38,21 +38,49 @@ struct wlr_gles2_renderer {
} shaders; } shaders;
}; };
enum wlr_gles2_texture_type {
WLR_GLES2_TEXTURE_GLTEX,
WLR_GLES2_TEXTURE_WL_DRM_GL,
WLR_GLES2_TEXTURE_WL_DRM_EXT,
WLR_GLES2_TEXTURE_DMABUF,
};
struct wlr_gles2_texture { struct wlr_gles2_texture {
struct wlr_texture wlr_texture; struct wlr_texture wlr_texture;
struct wlr_egl *egl; struct wlr_gles2_renderer *renderer;
GLuint tex_id; enum wlr_gles2_texture_type type;
const struct gles2_pixel_format *pixel_format; int width, height;
bool has_alpha;
bool inverted_y;
// Not set if WLR_GLES2_TEXTURE_GLTEX
EGLImageKHR image; EGLImageKHR image;
GLenum target; GLuint image_tex;
union {
GLuint gl_tex;
struct wl_resource *wl_drm;
};
}; };
const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt); const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt);
const enum wl_shm_format *gles2_formats(size_t *len); const enum wl_shm_format *gles2_formats(size_t *len);
struct wlr_texture *gles2_texture_create(); struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture); struct wlr_renderer *wlr_renderer);
struct wlr_gles2_renderer *gles2_get_renderer_in_context(
struct wlr_renderer *wlr_renderer);
struct wlr_gles2_texture *gles2_get_texture_in_context(
struct wlr_texture *wlr_texture);
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_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
struct wl_resource *data);
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_buffer_attribs *attribs);
void gles2_push_marker(const char *file, const char *func); void gles2_push_marker(const char *file, const char *func);
void gles2_pop_marker(void); void gles2_pop_marker(void);

@ -46,37 +46,25 @@ void wlr_egl_finish(struct wlr_egl *egl);
*/ */
bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display); bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display);
/**
* Refer to the eglQueryWaylandBufferWL extension function.
*/
bool wlr_egl_query_buffer(struct wlr_egl *egl, struct wl_resource *buf,
EGLint attrib, EGLint *value);
/** /**
* Returns a surface for the given native window * Returns a surface for the given native window
* The window must match the remote display the wlr_egl was created with. * The window must match the remote display the wlr_egl was created with.
*/ */
EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window); EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window);
/**
* Creates an egl image from the given client buffer and attributes.
*/
EGLImageKHR wlr_egl_create_image(struct wlr_egl *egl,
EGLenum target, EGLClientBuffer buffer, const EGLint *attribs);
/** /**
* Creates an egl image from the given dmabuf attributes. Check usability * Creates an egl image from the given dmabuf attributes. Check usability
* of the dmabuf with wlr_egl_check_import_dmabuf once first. * of the dmabuf with wlr_egl_check_import_dmabuf once first.
*/ */
EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl,
struct wlr_dmabuf_buffer_attribs *attributes); struct wlr_dmabuf_buffer_attribs *attributes);
/** /**
* Try to import the given dmabuf. On success return true false otherwise. * Try to import the given dmabuf. On success return true false otherwise.
* If this succeeds the dmabuf can be used for rendering on a texture * If this succeeds the dmabuf can be used for rendering on a texture
*/ */
bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl,
struct wlr_dmabuf_buffer *dmabuf); struct wlr_dmabuf_buffer *dmabuf);
/** /**
* Get the available dmabuf formats * Get the available dmabuf formats

@ -23,7 +23,6 @@ struct wlr_renderer_impl {
void (*end)(struct wlr_renderer *renderer); void (*end)(struct wlr_renderer *renderer);
void (*clear)(struct wlr_renderer *renderer, const float color[static 4]); void (*clear)(struct wlr_renderer *renderer, const float color[static 4]);
void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box); void (*scissor)(struct wlr_renderer *renderer, struct wlr_box *box);
struct wlr_texture *(*texture_create)(struct wlr_renderer *renderer);
bool (*render_texture_with_matrix)(struct wlr_renderer *renderer, bool (*render_texture_with_matrix)(struct wlr_renderer *renderer,
struct wlr_texture *texture, const float matrix[static 9], struct wlr_texture *texture, const float matrix[static 9],
float alpha); float alpha);
@ -33,45 +32,39 @@ struct wlr_renderer_impl {
const float color[static 4], const float matrix[static 9]); const float color[static 4], const float matrix[static 9]);
const enum wl_shm_format *(*formats)( const enum wl_shm_format *(*formats)(
struct wlr_renderer *renderer, size_t *len); struct wlr_renderer *renderer, size_t *len);
bool (*buffer_is_drm)(struct wlr_renderer *renderer, bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer,
struct wl_resource *buffer); struct wl_resource *resource);
void (*wl_drm_buffer_get_size)(struct wlr_renderer *renderer,
struct wl_resource *buffer, int *width, int *height);
bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt, bool (*read_pixels)(struct wlr_renderer *renderer, enum wl_shm_format fmt,
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,
void *data); void *data);
bool (*format_supported)(struct wlr_renderer *renderer, bool (*format_supported)(struct wlr_renderer *renderer,
enum wl_shm_format fmt); enum wl_shm_format fmt);
struct wlr_texture *(*texture_from_pixels)(struct wlr_renderer *renderer,
enum wl_shm_format fmt, uint32_t stride, uint32_t width,
uint32_t height, const void *data);
struct wlr_texture *(*texture_from_wl_drm)(struct wlr_renderer *renderer,
struct wl_resource *data);
struct wlr_texture *(*texture_from_dmabuf)(struct wlr_renderer *renderer,
struct wlr_dmabuf_buffer_attribs *attribs);
void (*destroy)(struct wlr_renderer *renderer); void (*destroy)(struct wlr_renderer *renderer);
}; };
void wlr_renderer_init(struct wlr_renderer *renderer, void wlr_renderer_init(struct wlr_renderer *renderer,
const struct wlr_renderer_impl *impl); const struct wlr_renderer_impl *impl);
struct wlr_texture_impl { struct wlr_texture_impl {
bool (*upload_pixels)(struct wlr_texture *texture, void (*get_size)(struct wlr_texture *texture, int *width, int *height);
enum wl_shm_format format, int stride, int width, int height, bool (*write_pixels)(struct wlr_texture *texture,
const unsigned char *pixels); enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
bool (*update_pixels)(struct wlr_texture *texture, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x,
enum wl_shm_format format, int stride, int x, int y, uint32_t dst_y, const void *data);
int width, int height, const unsigned char *pixels);
bool (*upload_shm)(struct wlr_texture *texture, uint32_t format,
struct wl_shm_buffer *shm);
bool (*update_shm)(struct wlr_texture *texture, uint32_t format,
int x, int y, int width, int height, struct wl_shm_buffer *shm);
bool (*upload_drm)(struct wlr_texture *texture,
struct wl_resource *drm_buf);
bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image,
uint32_t width, uint32_t height);
bool (*upload_dmabuf)(struct wlr_texture *texture,
struct wl_resource *dmabuf_resource);
void (*get_buffer_size)(struct wlr_texture *texture,
struct wl_resource *resource, int *width, int *height);
void (*destroy)(struct wlr_texture *texture); void (*destroy)(struct wlr_texture *texture);
}; };
void wlr_texture_init(struct wlr_texture *texture, void wlr_texture_init(struct wlr_texture *texture,
const struct wlr_texture_impl *impl); const struct wlr_texture_impl *impl);
void wlr_texture_get_buffer_size(struct wlr_texture *texture,
struct wl_resource *resource, int *width, int *height);
#endif #endif

@ -1,8 +1,6 @@
#ifndef WLR_RENDER_WLR_RENDERER_H #ifndef WLR_RENDER_WLR_RENDERER_H
#define WLR_RENDER_WLR_RENDERER_H #define WLR_RENDER_WLR_RENDERER_H
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <stdint.h> #include <stdint.h>
#include <wayland-server-protocol.h> #include <wayland-server-protocol.h>
#include <wlr/render/wlr_texture.h> #include <wlr/render/wlr_texture.h>
@ -21,10 +19,6 @@ void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]);
* box. * box.
*/ */
void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box);
/**
* Requests a texture handle from this renderer.
*/
struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r);
/** /**
* Renders the requested texture. * Renders the requested texture.
*/ */
@ -51,10 +45,15 @@ void wlr_render_colored_ellipse(struct wlr_renderer *r,
const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r, const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r,
size_t *len); size_t *len);
/** /**
* Returns true if this wl_buffer is a DRM buffer. * Returns true if this wl_buffer is a wl_drm buffer.
*/ */
bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *renderer,
struct wl_resource *buffer); struct wl_resource *buffer);
/**
* Gets the width and height of a wl_drm buffer.
*/
void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *renderer,
struct wl_resource *buffer, int *width, int *height);
/** /**
* Reads out of pixels of the currently bound surface into data. `stride` is in * Reads out of pixels of the currently bound surface into data. `stride` is in
* bytes. * bytes.

@ -5,62 +5,49 @@
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <stdint.h> #include <stdint.h>
#include <wayland-server-protocol.h> #include <wayland-server-protocol.h>
#include <wlr/types/wlr_linux_dmabuf.h>
struct wlr_renderer;
struct wlr_texture_impl; struct wlr_texture_impl;
struct wlr_texture { struct wlr_texture {
const struct wlr_texture_impl *impl; const struct wlr_texture_impl *impl;
bool valid;
uint32_t format;
int width, height;
bool inverted_y;
struct wl_signal destroy_signal;
struct wl_resource *resource;
}; };
/** /**
* Copies pixels to this texture. The buffer is not accessed after this function * Create a new texture from raw pixel data. `stride` is in bytes. The returned
* returns. * texture is mutable.
*/ */
bool wlr_texture_upload_pixels(struct wlr_texture *tex, struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
enum wl_shm_format format, int stride, int width, int height, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
const unsigned char *pixels); const void *data);
/** /**
* Copies pixels to this texture. The buffer is not accessed after this function * Create a new texture from a wayland DRM resource. The returned texture is
* returns. Under some circumstances, this function may re-upload the entire * immutable.
* buffer - therefore, the entire buffer must be valid.
*/ */
bool wlr_texture_update_pixels(struct wlr_texture *surf, struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer,
enum wl_shm_format format, int stride, int x, int y, struct wl_resource *data);
int width, int height, const unsigned char *pixels);
/** /**
* Copies pixels from a wl_shm_buffer into this texture. The buffer is not * Create a new texture from a DMA-BUF. The returned texture is immutable.
* accessed after this function returns.
*/ */
bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format, struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
struct wl_shm_buffer *shm); struct wlr_dmabuf_buffer_attribs *attribs);
/** /**
* Attaches the contents from the given wl_drm wl_buffer resource onto the * Get the texture width and height.
* texture. The wl_resource is not used after this call.
* Will fail (return false) if the given resource is no drm buffer.
*/ */
bool wlr_texture_upload_drm(struct wlr_texture *tex, void wlr_texture_get_size(struct wlr_texture *texture, int *width, int *height);
struct wl_resource *drm_buffer);
bool wlr_texture_upload_eglimage(struct wlr_texture *tex,
EGLImageKHR image, uint32_t width, uint32_t height);
bool wlr_texture_upload_dmabuf(struct wlr_texture *tex,
struct wl_resource *dmabuf_resource);
/** /**
* Copies a rectangle of pixels from a wl_shm_buffer onto the texture. The * Update a texture with raw pixels. The texture must be mutable.
* buffer is not accessed after this function returns. Under some circumstances,
* this function may re-upload the entire buffer - therefore, the entire buffer
* must be valid.
*/ */
bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format, bool wlr_texture_write_pixels(struct wlr_texture *texture,
int x, int y, int width, int height, struct wl_shm_buffer *shm); enum wl_shm_format wl_fmt, 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);
/** /**
* Destroys this wlr_texture. * Destroys this wlr_texture.
*/ */

@ -11,6 +11,12 @@
#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) #define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
#endif #endif
enum {
WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_Y_INVERT = 1,
WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_INTERLACED = 2,
WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_BOTTOM_FIRST = 4,
};
struct wlr_dmabuf_buffer_attribs { struct wlr_dmabuf_buffer_attribs {
/* set via params_add */ /* set via params_add */
int n_planes; int n_planes;
@ -22,7 +28,7 @@ struct wlr_dmabuf_buffer_attribs {
int32_t width; int32_t width;
int32_t height; int32_t height;
uint32_t format; uint32_t format;
uint32_t flags; /* enum zlinux_buffer_params_flags */ uint32_t flags;
}; };
struct wlr_dmabuf_buffer { struct wlr_dmabuf_buffer {
@ -52,11 +58,6 @@ struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource(
struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource(
struct wl_resource *params_resource); struct wl_resource *params_resource);
/**
* Returns true if the given dmabuf has y-axis inverted, false otherwise
*/
bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf);
/* the protocol interface */ /* the protocol interface */
struct wlr_linux_dmabuf { struct wlr_linux_dmabuf {
struct wl_global *wl_global; struct wl_global *wl_global;

@ -223,24 +223,6 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display)
return false; return false;
} }
bool wlr_egl_query_buffer(struct wlr_egl *egl, struct wl_resource *buf,
int attrib, int *value) {
if (!eglQueryWaylandBufferWL) {
return false;
}
return eglQueryWaylandBufferWL(egl->display, buf, attrib, value);
}
EGLImage wlr_egl_create_image(struct wlr_egl *egl, EGLenum target,
EGLClientBuffer buffer, const EGLint *attribs) {
if (!eglCreateImageKHR) {
return NULL;
}
return eglCreateImageKHR(egl->display, egl->context, target,
buffer, attribs);
}
bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) {
if (!eglDestroyImageKHR) { if (!eglDestroyImageKHR) {
return false; return false;

@ -12,23 +12,27 @@
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_matrix.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "render/gles2.h"
#include "glapi.h" #include "glapi.h"
#include "render/gles2.h"
static const struct wlr_renderer_impl renderer_impl; 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) { struct wlr_renderer *wlr_renderer) {
assert(wlr_renderer->impl == &renderer_impl); assert(wlr_renderer->impl == &renderer_impl);
struct wlr_gles2_renderer *renderer = return (struct wlr_gles2_renderer *)wlr_renderer;
(struct wlr_gles2_renderer *)wlr_renderer; }
struct wlr_gles2_renderer *gles2_get_renderer_in_context(
struct wlr_renderer *wlr_renderer) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
assert(eglGetCurrentContext() == renderer->egl->context); assert(eglGetCurrentContext() == renderer->egl->context);
return renderer; return renderer;
} }
static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
uint32_t height) { uint32_t height) {
gles2_get_renderer(wlr_renderer); gles2_get_renderer_in_context(wlr_renderer);
GLES2_DEBUG_PUSH; GLES2_DEBUG_PUSH;
@ -45,13 +49,13 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
} }
static void gles2_end(struct wlr_renderer *wlr_renderer) { static void gles2_end(struct wlr_renderer *wlr_renderer) {
gles2_get_renderer(wlr_renderer); gles2_get_renderer_in_context(wlr_renderer);
// no-op // no-op
} }
static void gles2_clear(struct wlr_renderer *wlr_renderer, static void gles2_clear(struct wlr_renderer *wlr_renderer,
const float color[static 4]) { const float color[static 4]) {
gles2_get_renderer(wlr_renderer); gles2_get_renderer_in_context(wlr_renderer);
GLES2_DEBUG_PUSH; GLES2_DEBUG_PUSH;
glClearColor(color[0], color[1], color[2], color[3]); glClearColor(color[0], color[1], color[2], color[3]);
@ -61,7 +65,7 @@ static void gles2_clear(struct wlr_renderer *wlr_renderer,
static void gles2_scissor(struct wlr_renderer *wlr_renderer, static void gles2_scissor(struct wlr_renderer *wlr_renderer,
struct wlr_box *box) { struct wlr_box *box) {
gles2_get_renderer(wlr_renderer); gles2_get_renderer_in_context(wlr_renderer);
GLES2_DEBUG_PUSH; GLES2_DEBUG_PUSH;
if (box != NULL) { if (box != NULL) {
@ -73,14 +77,6 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer,
GLES2_DEBUG_POP; GLES2_DEBUG_POP;
} }
static struct wlr_texture *gles2_renderer_texture_create(
struct wlr_renderer *wlr_renderer) {
assert(wlr_renderer->impl == &renderer_impl);
struct wlr_gles2_renderer *renderer =
(struct wlr_gles2_renderer *)wlr_renderer;
return gles2_texture_create(renderer->egl);
}
static void draw_quad() { static void draw_quad() {
GLfloat verts[] = { GLfloat verts[] = {
1, 0, // top right 1, 0, // top right
@ -107,21 +103,28 @@ static void draw_quad() {
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
} }
static bool gles2_render_texture_with_matrix( static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer,
struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, struct wlr_texture *wlr_texture, const float matrix[static 9],
const float matrix[static 9], float alpha) { float alpha) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer =
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); gles2_get_renderer_in_context(wlr_renderer);
if (!wlr_texture->valid) { struct wlr_gles2_texture *texture =
wlr_log(L_ERROR, "attempt to render invalid texture"); gles2_get_texture_in_context(wlr_texture);
return false;
} GLuint prog;
GLenum target;
GLuint prog = renderer->shaders.tex_rgba; switch (texture->type) {
if (texture->target == GL_TEXTURE_EXTERNAL_OES) { case WLR_GLES2_TEXTURE_GLTEX:
case WLR_GLES2_TEXTURE_WL_DRM_GL:
prog = texture->has_alpha ? renderer->shaders.tex_rgba :
renderer->shaders.tex_rgbx;
target = GL_TEXTURE_2D;
break;
case WLR_GLES2_TEXTURE_WL_DRM_EXT:
case WLR_GLES2_TEXTURE_DMABUF:
prog = renderer->shaders.tex_ext; prog = renderer->shaders.tex_ext;
} else if (!texture->pixel_format->has_alpha) { target = GL_TEXTURE_EXTERNAL_OES;
prog = renderer->shaders.tex_rgbx; break;
} }
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
@ -130,15 +133,23 @@ static bool gles2_render_texture_with_matrix(
wlr_matrix_transpose(transposition, matrix); wlr_matrix_transpose(transposition, matrix);
GLES2_DEBUG_PUSH; GLES2_DEBUG_PUSH;
glBindTexture(texture->target, texture->tex_id);
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GLuint tex_id = texture->type == WLR_GLES2_TEXTURE_GLTEX ?
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); texture->gl_tex : texture->image_tex;
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, tex_id);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUseProgram(prog); glUseProgram(prog);
glUniformMatrix3fv(0, 1, GL_FALSE, transposition); glUniformMatrix3fv(0, 1, GL_FALSE, transposition);
glUniform1i(1, wlr_texture->inverted_y); glUniform1i(1, texture->inverted_y);
glUniform1f(3, alpha); glUniform1f(3, alpha);
draw_quad(); draw_quad();
GLES2_DEBUG_POP; GLES2_DEBUG_POP;
return true; return true;
} }
@ -146,7 +157,8 @@ static bool gles2_render_texture_with_matrix(
static void gles2_render_quad(struct wlr_renderer *wlr_renderer, static void gles2_render_quad(struct wlr_renderer *wlr_renderer,
const float color[static 4], const float matrix[static 9]) { const float color[static 4], const float matrix[static 9]) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE // to GL_FALSE
@ -163,7 +175,8 @@ static void gles2_render_quad(struct wlr_renderer *wlr_renderer,
static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer, static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer,
const float color[static 4], const float matrix[static 9]) { const float color[static 4], const float matrix[static 9]) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
// OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set
// to GL_FALSE // to GL_FALSE
@ -183,20 +196,38 @@ static const enum wl_shm_format *gles2_renderer_formats(
return gles2_formats(len); return gles2_formats(len);
} }
static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer,
struct wl_resource *buffer) { struct wl_resource *resource) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
if (!eglQueryWaylandBufferWL) {
return false;
}
EGLint fmt;
return eglQueryWaylandBufferWL(renderer->egl->display, resource,
EGL_TEXTURE_FORMAT, &fmt);
}
static void gles2_wl_drm_buffer_get_size(struct wlr_renderer *wlr_renderer,
struct wl_resource *buffer, int *width, int *height) {
struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
if (!eglQueryWaylandBufferWL) {
return;
}
EGLint format; eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_WIDTH, width);
return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT, eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_HEIGHT, height);
&format);
} }
static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer, static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x,
uint32_t dst_y, void *data) { uint32_t dst_y, void *data) {
gles2_get_renderer(wlr_renderer); gles2_get_renderer_in_context(wlr_renderer);
const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt); const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
if (fmt == NULL) { if (fmt == NULL) {
@ -254,14 +285,17 @@ static const struct wlr_renderer_impl renderer_impl = {
.end = gles2_end, .end = gles2_end,
.clear = gles2_clear, .clear = gles2_clear,
.scissor = gles2_scissor, .scissor = gles2_scissor,
.texture_create = gles2_renderer_texture_create,
.render_texture_with_matrix = gles2_render_texture_with_matrix, .render_texture_with_matrix = gles2_render_texture_with_matrix,
.render_quad = gles2_render_quad, .render_quad = gles2_render_quad,
.render_ellipse = gles2_render_ellipse, .render_ellipse = gles2_render_ellipse,
.formats = gles2_renderer_formats, .formats = gles2_renderer_formats,
.buffer_is_drm = gles2_buffer_is_drm, .resource_is_wl_drm_buffer = gles2_resource_is_wl_drm_buffer,
.wl_drm_buffer_get_size = gles2_wl_drm_buffer_get_size,
.read_pixels = gles2_read_pixels, .read_pixels = gles2_read_pixels,
.format_supported = gles2_format_supported, .format_supported = gles2_format_supported,
.texture_from_pixels = gles2_texture_from_pixels,
.texture_from_wl_drm = gles2_texture_from_wl_drm,
.texture_from_dmabuf = gles2_texture_from_dmabuf,
}; };
void gles2_push_marker(const char *file, const char *func) { void gles2_push_marker(const char *file, const char *func) {

@ -10,366 +10,262 @@
#include <wlr/render/interface.h> #include <wlr/render/interface.h>
#include <wlr/types/wlr_matrix.h> #include <wlr/types/wlr_matrix.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "glapi.h"
#include "render/gles2.h" #include "render/gles2.h"
#include "util/signal.h" #include "util/signal.h"
static struct gles2_pixel_format external_pixel_format = {
.wl_format = 0,
.depth = 0,
.bpp = 0,
.gl_format = 0,
.gl_type = 0,
};
static void gles2_texture_ensure(struct wlr_gles2_texture *texture,
GLenum target) {
if (texture->tex_id) {
return;
}
texture->target = target;
glGenTextures(1, &texture->tex_id);
glBindTexture(target, texture->tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
static const struct wlr_texture_impl texture_impl; static const struct wlr_texture_impl texture_impl;
struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture) { static struct wlr_gles2_texture *gles2_get_texture(
struct wlr_texture *wlr_texture) {
assert(wlr_texture->impl == &texture_impl); assert(wlr_texture->impl == &texture_impl);
return (struct wlr_gles2_texture *)wlr_texture; return (struct wlr_gles2_texture *)wlr_texture;
} }
static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture, struct wlr_gles2_texture *gles2_get_texture_in_context(
enum wl_shm_format format, int stride, int width, int height, struct wlr_texture *wlr_texture) {
const unsigned char *pixels) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
assert(eglGetCurrentContext() == texture->renderer->egl->context);
const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); return texture;
if (!fmt || !fmt->gl_format) {
wlr_log(L_ERROR, "No supported pixel format for this texture");
return false;
}
texture->wlr_texture.width = width;
texture->wlr_texture.height = height;
texture->wlr_texture.format = format;
texture->pixel_format = fmt;
GLES2_DEBUG_PUSH;
gles2_texture_ensure(texture, GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride);
glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
fmt->gl_format, fmt->gl_type, pixels);
GLES2_DEBUG_POP;
texture->wlr_texture.valid = true;
return true;
} }
static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture, static void gles2_texture_get_size(struct wlr_texture *wlr_texture, int *width,
enum wl_shm_format format, int stride, int x, int y, int *height) {
int width, int height, const unsigned char *pixels) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
*width = texture->width;
// TODO: Test if the unpack subimage extension is supported and adjust the *height = texture->height;
// upload strategy if not
if (!texture->wlr_texture.valid
|| texture->wlr_texture.format != format
/* || unpack not supported */) {
return gles2_texture_upload_pixels(&texture->wlr_texture, format,
stride, width, height, pixels);
}
const struct gles2_pixel_format *fmt = texture->pixel_format;
GLES2_DEBUG_PUSH;
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format,
fmt->gl_type, pixels);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
GLES2_DEBUG_POP;
return true;
} }
static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture, static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
uint32_t format, struct wl_shm_buffer *buffer) { enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); 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 =
gles2_get_texture_in_context(wlr_texture);
if (texture->type != WLR_GLES2_TEXTURE_GLTEX) {
wlr_log(L_ERROR, "Cannot write pixels to immutable texture");
return false;
}
const struct gles2_pixel_format *fmt = gles2_format_from_wl(format); const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
if (!fmt || !fmt->gl_format) { if (fmt == NULL) {
wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture", wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt);
format);
return false; return false;
} }
wl_shm_buffer_begin_access(buffer);
uint8_t *pixels = wl_shm_buffer_get_data(buffer);
int width = wl_shm_buffer_get_width(buffer);
int height = wl_shm_buffer_get_height(buffer);
int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8);
texture->wlr_texture.width = width;
texture->wlr_texture.height = height;
texture->wlr_texture.format = format;
texture->pixel_format = fmt;
// TODO: what if the unpack subimage extension isn't supported?
GLES2_DEBUG_PUSH; GLES2_DEBUG_PUSH;
gles2_texture_ensure(texture, GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
fmt->gl_format, fmt->gl_type, pixels);
GLES2_DEBUG_POP;
texture->wlr_texture.valid = true; glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
wl_shm_buffer_end_access(buffer);
return true;
}
static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture, glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8));
uint32_t format, int x, int y, int width, int height, glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x);
struct wl_shm_buffer *buffer) { glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y);
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
// TODO: Test if the unpack subimage extension is supported and adjust the glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
// upload strategy if not fmt->gl_format, fmt->gl_type, data);
assert(texture);
if (!texture->wlr_texture.valid
|| texture->wlr_texture.format != format
/* || unpack not supported */) {
return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer);
}
const struct gles2_pixel_format *fmt = texture->pixel_format;
wl_shm_buffer_begin_access(buffer);
uint8_t *pixels = wl_shm_buffer_get_data(buffer);
int pitch = wl_shm_buffer_get_stride(buffer) / (fmt->bpp / 8);
GLES2_DEBUG_PUSH; glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
fmt->gl_format, fmt->gl_type, pixels);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
GLES2_DEBUG_POP;
wl_shm_buffer_end_access(buffer);
GLES2_DEBUG_POP;
return true; return true;
} }
static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture, static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
struct wl_resource *buf) { if (wlr_texture == NULL) {
struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); return;
if (!glEGLImageTargetTexture2DOES) {
return false;
} }
EGLint format; struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
if (!wlr_egl_query_buffer(tex->egl, buf, EGL_TEXTURE_FORMAT, &format)) {
wlr_log(L_INFO, "upload_drm called with no drm buffer");
return false;
}
wlr_egl_query_buffer(tex->egl, buf, EGL_WIDTH, wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL);
(EGLint*)&tex->wlr_texture.width);
wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT,
(EGLint*)&tex->wlr_texture.height);
EGLint inverted_y; GLES2_DEBUG_PUSH;
if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL,
&inverted_y)) { if (texture->image_tex) {
tex->wlr_texture.inverted_y = !!inverted_y; glDeleteTextures(1, &texture->image_tex);
}
if (texture->image) {
assert(eglDestroyImageKHR);
eglDestroyImageKHR(texture->renderer->egl->display, texture->image);
} }
GLenum target; if (texture->type == WLR_GLES2_TEXTURE_GLTEX) {
const struct gles2_pixel_format *pf; glDeleteTextures(1, &texture->gl_tex);
switch (format) {
case EGL_TEXTURE_RGB:
case EGL_TEXTURE_RGBA:
target = GL_TEXTURE_2D;
pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
break;
case EGL_TEXTURE_EXTERNAL_WL:
target = GL_TEXTURE_EXTERNAL_OES;
pf = &external_pixel_format;
break;
default:
wlr_log(L_ERROR, "invalid/unsupported egl buffer format");
return false;
} }
GLES2_DEBUG_PUSH;
gles2_texture_ensure(tex, target);
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
GLES2_DEBUG_POP; GLES2_DEBUG_POP;
EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; free(texture);
}
if (tex->image) { static const struct wlr_texture_impl texture_impl = {
wlr_egl_destroy_image(tex->egl, tex->image); .get_size = gles2_texture_get_size,
.write_pixels = gles2_texture_write_pixels,
.destroy = gles2_texture_destroy,
};
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_in_context(wlr_renderer);
const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt);
if (fmt == NULL) {
wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32, wl_fmt);
return NULL;
} }
tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL, struct wlr_gles2_texture *texture =
(EGLClientBuffer*) buf, attribs); calloc(1, sizeof(struct wlr_gles2_texture));
if (!tex->image) { if (texture == NULL) {
wlr_log(L_ERROR, "failed to create EGL image"); wlr_log(L_ERROR, "Allocation failed");
return false; return NULL;
} }
wlr_texture_init(&texture->wlr_texture, &texture_impl);
texture->renderer = renderer;
texture->width = width;
texture->height = height;
texture->type = WLR_GLES2_TEXTURE_GLTEX;
texture->has_alpha = fmt->has_alpha;
GLES2_DEBUG_PUSH; GLES2_DEBUG_PUSH;
glActiveTexture(GL_TEXTURE0);
glBindTexture(target, tex->tex_id);
glEGLImageTargetTexture2DOES(target, tex->image);
GLES2_DEBUG_POP;
tex->wlr_texture.valid = true;
tex->pixel_format = pf;
return true;
}
static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture, glGenTextures(1, &texture->gl_tex);
EGLImageKHR image, uint32_t width, uint32_t height) { glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
tex->image = image; glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8));
tex->pixel_format = &external_pixel_format; glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
tex->wlr_texture.valid = true; fmt->gl_format, fmt->gl_type, data);
tex->wlr_texture.width = width; glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
tex->wlr_texture.height = height;
GLES2_DEBUG_PUSH;
gles2_texture_ensure(tex, GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image);
GLES2_DEBUG_POP; GLES2_DEBUG_POP;
return (struct wlr_texture *)texture;
return true;
} }
static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
struct wl_resource *dmabuf_resource) { struct wl_resource *data) {
struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
struct wlr_dmabuf_buffer *dmabuf =
wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource);
if (!tex->egl->egl_exts.dmabuf_import) { if (!eglQueryWaylandBufferWL || !eglCreateImageKHR ||
wlr_log(L_ERROR, "Want dmabuf but extension not present"); !glEGLImageTargetTexture2DOES) {
return false; return NULL;
} }
tex->wlr_texture.width = dmabuf->attributes.width; EGLint fmt;
tex->wlr_texture.height = dmabuf->attributes.height; if (!eglQueryWaylandBufferWL(renderer->egl->display, data,
EGL_TEXTURE_FORMAT, &fmt)) {
return NULL;
}
if (tex->image) { EGLint width, height;
wlr_egl_destroy_image(tex->egl, tex->image); eglQueryWaylandBufferWL(renderer->egl->display, data, EGL_WIDTH, &width);
eglQueryWaylandBufferWL(renderer->egl->display, data, EGL_HEIGHT, &height);
EGLint inverted_y;
if (!eglQueryWaylandBufferWL(renderer->egl->display, data,
EGL_WAYLAND_Y_INVERTED_WL, &inverted_y)) {
inverted_y = 0;
} }
if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { struct wlr_gles2_texture *texture =
wlr_texture->inverted_y = true; calloc(1, sizeof(struct wlr_gles2_texture));
if (texture == NULL) {
wlr_log(L_ERROR, "Allocation failed");
return NULL;
} }
wlr_texture_init(&texture->wlr_texture, &texture_impl);
texture->renderer = renderer;
texture->width = width;
texture->height = height;
texture->wl_drm = data;
texture->inverted_y = !!inverted_y;
GLenum target; GLenum target;
const struct gles2_pixel_format *pf; switch (fmt) {
if (dmabuf->attributes.n_planes > 1) { case EGL_TEXTURE_RGB:
target = GL_TEXTURE_EXTERNAL_OES; case EGL_TEXTURE_RGBA:
pf = &external_pixel_format;
} else {
target = GL_TEXTURE_2D; target = GL_TEXTURE_2D;
pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); texture->type = WLR_GLES2_TEXTURE_WL_DRM_GL;
texture->has_alpha = fmt == EGL_TEXTURE_RGBA;
break;
case EGL_TEXTURE_EXTERNAL_WL:
target = GL_TEXTURE_EXTERNAL_OES;
texture->type = WLR_GLES2_TEXTURE_WL_DRM_EXT;
texture->has_alpha = true;
break;
default:
wlr_log(L_ERROR, "Invalid or unsupported EGL buffer format");
free(texture);
return NULL;
} }
GLES2_DEBUG_PUSH;
gles2_texture_ensure(tex, target);
glBindTexture(target, tex->tex_id);
tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes);
glActiveTexture(GL_TEXTURE0);
glEGLImageTargetTexture2DOES(target, tex->image);
GLES2_DEBUG_POP;
tex->pixel_format = pf;
tex->wlr_texture.valid = true;
return true;
}
static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct EGLint attribs[] = {
wl_resource *resource, int *width, int *height) { EGL_WAYLAND_PLANE_WL, 0,
if (!wlr_dmabuf_resource_is_buffer(resource)) { EGL_NONE,
return false; };
texture->image = eglCreateImageKHR(renderer->egl->display,
renderer->egl->context, EGL_WAYLAND_BUFFER_WL, data, attribs);
if (texture->image == NULL) {
free(texture);
return NULL;
} }
struct wlr_dmabuf_buffer *dmabuf = GLES2_DEBUG_PUSH;
wlr_dmabuf_buffer_from_buffer_resource(resource);
*width = dmabuf->attributes.width;
*height = dmabuf->attributes.height;
return true;
}
static void gles2_texture_get_buffer_size(struct wlr_texture *texture,
struct wl_resource *resource, int *width, int *height) {
struct wl_shm_buffer *buffer = wl_shm_buffer_get(resource);
if (!buffer) {
struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)texture;
if (!glEGLImageTargetTexture2DOES) {
return;
}
if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH,
(EGLint*)width)) {
if (!gles2_texture_get_dmabuf_size(texture, resource, width,
height)) {
wlr_log(L_ERROR, "could not get size of the buffer");
return;
}
}
wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height);
return; glGenTextures(1, &texture->image_tex);
} glBindTexture(target, texture->image_tex);
glEGLImageTargetTexture2DOES(target, texture->image);
*width = wl_shm_buffer_get_width(buffer); GLES2_DEBUG_POP;
*height = wl_shm_buffer_get_height(buffer); return (struct wlr_texture *)texture;
} }
static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); struct wlr_dmabuf_buffer_attribs *attribs) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, if (!glEGLImageTargetTexture2DOES) {
&texture->wlr_texture); return NULL;
if (texture->tex_id) {
GLES2_DEBUG_PUSH;
glDeleteTextures(1, &texture->tex_id);
GLES2_DEBUG_POP;
} }
if (texture->image) { if (!renderer->egl->egl_exts.dmabuf_import) {
wlr_egl_destroy_image(texture->egl, texture->image); wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension "
"unavailable");
return NULL;
} }
free(texture); struct wlr_gles2_texture *texture =
} calloc(1, sizeof(struct wlr_gles2_texture));
if (texture == NULL) {
static const struct wlr_texture_impl texture_impl = { wlr_log(L_ERROR, "Allocation failed");
.upload_pixels = gles2_texture_upload_pixels,
.update_pixels = gles2_texture_update_pixels,
.upload_shm = gles2_texture_upload_shm,
.update_shm = gles2_texture_update_shm,
.upload_drm = gles2_texture_upload_drm,
.upload_dmabuf = gles2_texture_upload_dmabuf,
.upload_eglimage = gles2_texture_upload_eglimage,
.get_buffer_size = gles2_texture_get_buffer_size,
.destroy = gles2_texture_destroy,
};
struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) {
struct wlr_gles2_texture *texture;
if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) {
return NULL; return NULL;
} }
wlr_texture_init(&texture->wlr_texture, &texture_impl); wlr_texture_init(&texture->wlr_texture, &texture_impl);
texture->egl = egl; texture->renderer = renderer;
return &texture->wlr_texture; texture->width = attribs->width;
texture->height = attribs->height;
texture->type = WLR_GLES2_TEXTURE_DMABUF;
texture->has_alpha = true;
texture->inverted_y =
(attribs->flags & WLR_DMABUF_BUFFER_ATTRIBS_FLAGS_Y_INVERT) != 0;
texture->image = wlr_egl_create_image_from_dmabuf(renderer->egl, attribs);
if (texture->image == NULL) {
free(texture);
return NULL;
}
GLES2_DEBUG_PUSH;
glGenTextures(1, &texture->image_tex);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->image_tex);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, texture->image);
GLES2_DEBUG_POP;
return (struct wlr_texture *)texture;
} }

@ -1,3 +1,4 @@
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/render/interface.h> #include <wlr/render/interface.h>
@ -6,6 +7,15 @@
void wlr_renderer_init(struct wlr_renderer *renderer, void wlr_renderer_init(struct wlr_renderer *renderer,
const struct wlr_renderer_impl *impl) { const struct wlr_renderer_impl *impl) {
assert(impl->begin);
assert(impl->clear);
assert(impl->scissor);
assert(impl->render_texture_with_matrix);
assert(impl->render_quad);
assert(impl->render_ellipse);
assert(impl->formats);
assert(impl->format_supported);
assert(impl->texture_from_pixels);
renderer->impl = impl; renderer->impl = impl;
} }
@ -22,7 +32,9 @@ void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) {
} }
void wlr_renderer_end(struct wlr_renderer *r) { void wlr_renderer_end(struct wlr_renderer *r) {
r->impl->end(r); if (r->impl->end) {
r->impl->end(r);
}
} }
void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) { void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) {
@ -33,16 +45,15 @@ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box) {
r->impl->scissor(r, box); r->impl->scissor(r, box);
} }
struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) {
return r->impl->texture_create(r);
}
bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture,
const float projection[static 9], int x, int y, float alpha) { const float projection[static 9], int x, int y, float alpha) {
int width, height;
wlr_texture_get_size(texture, &width, &height);
float mat[9]; float mat[9];
wlr_matrix_identity(mat); wlr_matrix_identity(mat);
wlr_matrix_translate(mat, x, y); wlr_matrix_translate(mat, x, y);
wlr_matrix_scale(mat, texture->width, texture->height); wlr_matrix_scale(mat, width, height);
wlr_matrix_multiply(mat, projection, mat); wlr_matrix_multiply(mat, projection, mat);
return wlr_render_texture_with_matrix(r, texture, mat, alpha); return wlr_render_texture_with_matrix(r, texture, mat, alpha);
@ -69,15 +80,29 @@ const enum wl_shm_format *wlr_renderer_get_formats(
return r->impl->formats(r, len); return r->impl->formats(r, len);
} }
bool wlr_renderer_buffer_is_drm(struct wlr_renderer *r, bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *r,
struct wl_resource *buffer) { struct wl_resource *resource) {
return r->impl->buffer_is_drm(r, buffer); if (!r->impl->resource_is_wl_drm_buffer) {
return false;
}
return r->impl->resource_is_wl_drm_buffer(r, resource);
}
void wlr_renderer_wl_drm_buffer_get_size(struct wlr_renderer *r,
struct wl_resource *buffer, int *width, int *height) {
if (!r->impl->wl_drm_buffer_get_size) {
return;
}
return r->impl->wl_drm_buffer_get_size(r, buffer, width, height);
} }
bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt, bool wlr_renderer_read_pixels(struct wlr_renderer *r, enum wl_shm_format fmt,
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,
void *data) { void *data) {
if (!r->impl->read_pixels) {
return false;
}
return r->impl->read_pixels(r, fmt, stride, width, height, src_x, src_y, return r->impl->read_pixels(r, fmt, stride, width, height, src_x, src_y,
dst_x, dst_y, data); dst_x, dst_y, data);
} }

@ -1,3 +1,4 @@
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/render/interface.h> #include <wlr/render/interface.h>
@ -5,8 +6,9 @@
void wlr_texture_init(struct wlr_texture *texture, void wlr_texture_init(struct wlr_texture *texture,
const struct wlr_texture_impl *impl) { const struct wlr_texture_impl *impl) {
assert(impl->get_size);
assert(impl->write_pixels);
texture->impl = impl; texture->impl = impl;
wl_signal_init(&texture->destroy_signal);
} }
void wlr_texture_destroy(struct wlr_texture *texture) { void wlr_texture_destroy(struct wlr_texture *texture) {
@ -17,45 +19,38 @@ void wlr_texture_destroy(struct wlr_texture *texture) {
} }
} }
bool wlr_texture_upload_pixels(struct wlr_texture *texture, uint32_t format, struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
int stride, int width, int height, const unsigned char *pixels) { enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
return texture->impl->upload_pixels(texture, format, stride, uint32_t height, const void *data) {
width, height, pixels); return renderer->impl->texture_from_pixels(renderer, wl_fmt, stride, width,
height, data);
} }
bool wlr_texture_update_pixels(struct wlr_texture *texture, struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer,
enum wl_shm_format format, int stride, int x, int y, struct wl_resource *data) {
int width, int height, const unsigned char *pixels) { if (!renderer->impl->texture_from_wl_drm) {
return texture->impl->update_pixels(texture, format, stride, x, y, return NULL;
width, height, pixels); }
} return renderer->impl->texture_from_wl_drm(renderer, data);
bool wlr_texture_upload_shm(struct wlr_texture *texture, uint32_t format,
struct wl_shm_buffer *shm) {
return texture->impl->upload_shm(texture, format, shm);
}
bool wlr_texture_update_shm(struct wlr_texture *texture, uint32_t format,
int x, int y, int width, int height, struct wl_shm_buffer *shm) {
return texture->impl->update_shm(texture, format, x, y, width, height, shm);
}
bool wlr_texture_upload_drm(struct wlr_texture *texture,
struct wl_resource *drm_buffer) {
return texture->impl->upload_drm(texture, drm_buffer);
} }
bool wlr_texture_upload_eglimage(struct wlr_texture *texture, struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
EGLImageKHR image, uint32_t width, uint32_t height) { struct wlr_dmabuf_buffer_attribs *attribs) {
return texture->impl->upload_eglimage(texture, image, width, height); if (!renderer->impl->texture_from_dmabuf) {
return NULL;
}
return renderer->impl->texture_from_dmabuf(renderer, attribs);
} }
bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, void wlr_texture_get_size(struct wlr_texture *texture, int *width,
struct wl_resource *dmabuf_resource) { int *height) {
return texture->impl->upload_dmabuf(texture, dmabuf_resource); return texture->impl->get_size(texture, width, height);
} }
void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource bool wlr_texture_write_pixels(struct wlr_texture *texture,
*resource, int *width, int *height) { enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
texture->impl->get_buffer_size(texture, resource, width, height); uint32_t height, uint32_t src_x, uint32_t src_y, uint32_t dst_x,
uint32_t dst_y, const void *data) {
return texture->impl->write_pixels(texture, wl_fmt, stride, width, height,
src_x, src_y, dst_x, dst_y, data);
} }

@ -19,11 +19,6 @@ static const struct wl_buffer_interface wl_buffer_impl = {
wl_buffer_destroy, wl_buffer_destroy,
}; };
bool wlr_dmabuf_buffer_has_inverted_y(struct wlr_dmabuf_buffer *dmabuf) {
return dmabuf->attributes.flags
& ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
}
bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) { bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource) {
if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface, if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
&wl_buffer_impl)) { &wl_buffer_impl)) {

@ -731,15 +731,11 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
return true; return true;
} }
if (cursor->texture == NULL) { wlr_texture_destroy(cursor->texture);
cursor->texture = wlr_render_texture_create(renderer);
if (cursor->texture == NULL) {
return false;
}
}
return wlr_texture_upload_pixels(cursor->texture, WL_SHM_FORMAT_ARGB8888, cursor->texture = wlr_texture_from_pixels(renderer, WL_SHM_FORMAT_ARGB8888,
stride, width, height, pixels); stride, width, height, pixels);
return cursor->texture != NULL;
} }
static void output_cursor_commit(struct wlr_output_cursor *cursor) { static void output_cursor_commit(struct wlr_output_cursor *cursor) {
@ -901,9 +897,7 @@ void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor) {
} }
cursor->output->hardware_cursor = NULL; cursor->output->hardware_cursor = NULL;
} }
if (cursor->texture != NULL) { wlr_texture_destroy(cursor->texture);
wlr_texture_destroy(cursor->texture);
}
wl_list_remove(&cursor->link); wl_list_remove(&cursor->link);
free(cursor); free(cursor);
} }

@ -155,8 +155,24 @@ static bool wlr_surface_update_size(struct wlr_surface *surface,
int scale = state->scale; int scale = state->scale;
enum wl_output_transform transform = state->transform; enum wl_output_transform transform = state->transform;
wlr_texture_get_buffer_size(surface->texture, state->buffer, struct wl_shm_buffer *buf = wl_shm_buffer_get(state->buffer);
&state->buffer_width, &state->buffer_height); if (buf != NULL) {
state->buffer_width = wl_shm_buffer_get_width(buf);
state->buffer_height = wl_shm_buffer_get_height(buf);
} else if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer,
state->buffer)) {
wlr_renderer_wl_drm_buffer_get_size(surface->renderer, state->buffer,
&state->buffer_width, &state->buffer_height);
} else if (wlr_dmabuf_resource_is_buffer(state->buffer)) {
struct wlr_dmabuf_buffer *dmabuf =
wlr_dmabuf_buffer_from_buffer_resource(state->buffer);
state->buffer_width = dmabuf->attributes.width;
state->buffer_height = dmabuf->attributes.height;
} else {
wlr_log(L_ERROR, "Unknown buffer handle attached");
state->buffer_width = 0;
state->buffer_height = 0;
}
int width = state->buffer_width / scale; int width = state->buffer_width / scale;
int height = state->buffer_height / scale; int height = state->buffer_height / scale;
@ -316,51 +332,65 @@ static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) {
static void wlr_surface_apply_damage(struct wlr_surface *surface, static void wlr_surface_apply_damage(struct wlr_surface *surface,
bool reupload_buffer) { bool reupload_buffer) {
if (!surface->current->buffer) { struct wl_resource *resource = surface->current->buffer;
if (resource == NULL) {
return; return;
} }
struct wl_shm_buffer *buffer = wl_shm_buffer_get(surface->current->buffer);
if (!buffer) {
if (wlr_renderer_buffer_is_drm(surface->renderer,
surface->current->buffer)) {
wlr_texture_upload_drm(surface->texture, surface->current->buffer);
goto release;
} else if (wlr_dmabuf_resource_is_buffer(surface->current->buffer)) {
wlr_texture_upload_dmabuf(surface->texture, surface->current->buffer);
goto release;
} else {
wlr_log(L_INFO, "Unknown buffer handle attached");
return;
}
}
uint32_t format = wl_shm_buffer_get_format(buffer); struct wl_shm_buffer *buf = wl_shm_buffer_get(resource);
if (reupload_buffer) { if (buf != NULL) {
wlr_texture_upload_shm(surface->texture, format, buffer); wl_shm_buffer_begin_access(buf);
} else {
pixman_region32_t damage; enum wl_shm_format fmt = wl_shm_buffer_get_format(buf);
pixman_region32_init(&damage); int32_t stride = wl_shm_buffer_get_stride(buf);
pixman_region32_copy(&damage, &surface->current->buffer_damage); int32_t width = wl_shm_buffer_get_width(buf);
pixman_region32_intersect_rect(&damage, &damage, 0, 0, int32_t height = wl_shm_buffer_get_height(buf);
surface->current->buffer_width, surface->current->buffer_height); void *data = wl_shm_buffer_get_data(buf);
int n; if (surface->texture == NULL || reupload_buffer) {
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n); wlr_texture_destroy(surface->texture);
for (int i = 0; i < n; ++i) { surface->texture = wlr_texture_from_pixels(surface->renderer, fmt,
pixman_box32_t rect = rects[i]; stride, width, height, data);
if (!wlr_texture_update_shm(surface->texture, format, } else {
rect.x1, rect.y1, pixman_region32_t damage;
rect.x2 - rect.x1, pixman_region32_init(&damage);
rect.y2 - rect.y1, pixman_region32_copy(&damage, &surface->current->buffer_damage);
buffer)) { pixman_region32_intersect_rect(&damage, &damage, 0, 0,
break; surface->current->buffer_width,
surface->current->buffer_height);
int n;
pixman_box32_t *rects = pixman_region32_rectangles(&damage, &n);
for (int i = 0; i < n; ++i) {
pixman_box32_t *r = &rects[i];
if (!wlr_texture_write_pixels(surface->texture, fmt, stride,
r->x2 - r->x1, r->y2 - r->y1, r->x1, r->y1,
r->x1, r->y1, data)) {
break;
}
} }
pixman_region32_fini(&damage);
} }
pixman_region32_fini(&damage); wl_shm_buffer_end_access(buf);
} else if (!surface->texture || reupload_buffer) {
wlr_texture_destroy(surface->texture);
if (wlr_renderer_resource_is_wl_drm_buffer(surface->renderer, resource)) {
surface->texture =
wlr_texture_from_wl_drm(surface->renderer, resource);
} else if (wlr_dmabuf_resource_is_buffer(resource)) {
struct wlr_dmabuf_buffer *dmabuf =
wlr_dmabuf_buffer_from_buffer_resource(resource);
surface->texture =
wlr_texture_from_dmabuf(surface->renderer, &dmabuf->attributes);
} else {
surface->texture = NULL;
wlr_log(L_ERROR, "Unknown buffer handle attached");
}
} }
release:
wlr_surface_state_release_buffer(surface->current); wlr_surface_state_release_buffer(surface->current);
} }
@ -375,7 +405,8 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) {
wlr_surface_move_state(surface, surface->pending, surface->current); wlr_surface_move_state(surface, surface->pending, surface->current);
if (null_buffer_commit) { if (null_buffer_commit) {
surface->texture->valid = false; wlr_texture_destroy(surface->texture);
surface->texture = NULL;
} }
bool reupload_buffer = oldw != surface->current->buffer_width || bool reupload_buffer = oldw != surface->current->buffer_width ||
@ -611,7 +642,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
} }
wlr_log(L_DEBUG, "New wlr_surface %p (res %p)", surface, res); wlr_log(L_DEBUG, "New wlr_surface %p (res %p)", surface, res);
surface->renderer = renderer; surface->renderer = renderer;
surface->texture = wlr_render_texture_create(renderer);
surface->resource = res; surface->resource = res;
surface->current = wlr_surface_state_create(); surface->current = wlr_surface_state_create();
@ -628,7 +658,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
} }
bool wlr_surface_has_buffer(struct wlr_surface *surface) { bool wlr_surface_has_buffer(struct wlr_surface *surface) {
return surface->texture && surface->texture->valid; return surface->texture != NULL;
} }
int wlr_surface_set_role(struct wlr_surface *surface, const char *role, int wlr_surface_set_role(struct wlr_surface *surface, const char *role,

@ -77,7 +77,7 @@ void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager,
} }
struct wlr_xcursor_image *image = xcursor->images[0]; struct wlr_xcursor_image *image = xcursor->images[0];
wlr_cursor_set_image(cursor, image->buffer, image->width, wlr_cursor_set_image(cursor, image->buffer, image->width * 4,
image->width, image->height, image->hotspot_x, image->hotspot_y, image->width, image->height, image->hotspot_x, image->hotspot_y,
theme->scale); theme->scale);
} }

Loading…
Cancel
Save