mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2024-11-25 08:32:30 +00:00
Merge pull request #744 from emersion/texture-redesign
Redesign wlr_texture
This commit is contained in:
commit
330ee08126
@ -181,9 +181,6 @@ void wlr_drm_resources_free(struct wlr_drm_backend *drm) {
|
||||
if (plane->cursor_bo) {
|
||||
gbm_bo_destroy(plane->cursor_bo);
|
||||
}
|
||||
if (plane->wlr_tex) {
|
||||
wlr_texture_destroy(plane->wlr_tex);
|
||||
}
|
||||
}
|
||||
|
||||
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_matrix_projection(plane->matrix, plane->surf.width,
|
||||
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 };
|
||||
@ -637,13 +628,18 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
|
||||
|
||||
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_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_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_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_texture_destroy(texture);
|
||||
gbm_bo_unmap(plane->cursor_bo, bo_data);
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,10 @@
|
||||
#include "backend/drm/drm.h"
|
||||
#include "glapi.h"
|
||||
|
||||
#ifndef DRM_FORMAT_MOD_LINEAR
|
||||
#define DRM_FORMAT_MOD_LINEAR 0
|
||||
#endif
|
||||
|
||||
bool wlr_drm_renderer_init(struct wlr_drm_backend *drm,
|
||||
struct wlr_drm_renderer *renderer) {
|
||||
renderer->gbm = gbm_create_device(drm->fd);
|
||||
@ -178,47 +182,33 @@ static void free_eglimage(struct gbm_bo *bo, void *data) {
|
||||
static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer,
|
||||
struct gbm_bo *bo) {
|
||||
struct tex *tex = gbm_bo_get_user_data(bo);
|
||||
if (tex) {
|
||||
if (tex != NULL) {
|
||||
return tex->tex;
|
||||
}
|
||||
|
||||
// TODO: use wlr_texture_upload_dmabuf instead
|
||||
|
||||
tex = malloc(sizeof(*tex));
|
||||
if (!tex) {
|
||||
wlr_log_errno(L_ERROR, "Allocation failed");
|
||||
tex = calloc(1, sizeof(struct tex));
|
||||
if (tex == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tex->egl = &renderer->egl;
|
||||
|
||||
int dmabuf_fd = gbm_bo_get_fd(bo);
|
||||
uint32_t width = gbm_bo_get_width(bo);
|
||||
uint32_t height = gbm_bo_get_height(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,
|
||||
struct wlr_dmabuf_buffer_attribs attribs = {
|
||||
.n_planes = 1,
|
||||
.width = gbm_bo_get_width(bo),
|
||||
.height = gbm_bo_get_height(bo),
|
||||
.format = gbm_bo_get_format(bo),
|
||||
};
|
||||
attribs.offset[0] = 0;
|
||||
attribs.stride[0] = gbm_bo_get_stride_for_plane(bo, 0);
|
||||
attribs.modifier[0] = DRM_FORMAT_MOD_LINEAR;
|
||||
attribs.fd[0] = gbm_bo_get_fd(bo);
|
||||
|
||||
tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
|
||||
if (!tex->img) {
|
||||
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);
|
||||
|
||||
return tex->tex;
|
||||
}
|
||||
|
||||
|
@ -99,8 +99,6 @@ static bool wlr_wl_output_set_cursor(struct wlr_output *_output,
|
||||
return true;
|
||||
}
|
||||
|
||||
stride *= 4; // stride is given in pixels, we need it in bytes
|
||||
|
||||
if (!backend->shm || !backend->pointer) {
|
||||
wlr_log(L_INFO, "cannot set cursor, no shm or pointer");
|
||||
return false;
|
||||
|
@ -149,7 +149,7 @@ static void handle_input_add(struct compositor_state *state,
|
||||
sample->compositor);
|
||||
|
||||
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);
|
||||
|
||||
wl_list_insert(&sample->cursors, &cursor->link);
|
||||
|
@ -197,9 +197,9 @@ int main(int argc, char *argv[]) {
|
||||
compositor_init(&compositor);
|
||||
|
||||
state.renderer = wlr_gles2_renderer_create(compositor.backend);
|
||||
state.cat_texture = wlr_render_texture_create(state.renderer);
|
||||
wlr_texture_upload_pixels(state.cat_texture, WL_SHM_FORMAT_ABGR8888,
|
||||
cat_tex.width, cat_tex.width, cat_tex.height, cat_tex.pixel_data);
|
||||
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 (!wlr_backend_start(compositor.backend)) {
|
||||
wlr_log(L_ERROR, "Failed to start backend");
|
||||
|
@ -112,7 +112,7 @@ static void handle_output_add(struct output_state *ostate) {
|
||||
sample->compositor);
|
||||
|
||||
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);
|
||||
|
||||
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];
|
||||
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);
|
||||
|
||||
compositor_init(&compositor);
|
||||
|
@ -142,13 +142,13 @@ int main(int argc, char *argv[]) {
|
||||
wlr_log(L_ERROR, "Could not start compositor, OOM");
|
||||
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) {
|
||||
wlr_log(L_ERROR, "Could not start compositor, OOM");
|
||||
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)) {
|
||||
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_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;
|
||||
wl_list_for_each(p, &sample->touch_points, link) {
|
||||
int x = (int)(p->x * width) - sample->cat_texture->width / 2;
|
||||
int y = (int)(p->y * height) - sample->cat_texture->height / 2;
|
||||
int x = (int)(p->x * width) - tex_width / 2;
|
||||
int y = (int)(p->y * height) - tex_height / 2;
|
||||
wlr_render_texture(sample->renderer, sample->cat_texture,
|
||||
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");
|
||||
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) {
|
||||
wlr_log(L_ERROR, "Could not start compositor, OOM");
|
||||
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)) {
|
||||
wlr_log(L_ERROR, "Failed to start backend");
|
||||
|
@ -27,7 +27,6 @@ struct wlr_drm_plane {
|
||||
|
||||
// Only used by cursor
|
||||
float matrix[9];
|
||||
struct wlr_texture *wlr_tex;
|
||||
struct gbm_bo *cursor_bo;
|
||||
bool cursor_enabled;
|
||||
int32_t cursor_hotspot_x, cursor_hotspot_y;
|
||||
|
@ -39,21 +39,49 @@ struct wlr_gles2_renderer {
|
||||
} 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_texture wlr_texture;
|
||||
|
||||
struct wlr_egl *egl;
|
||||
GLuint tex_id;
|
||||
const struct gles2_pixel_format *pixel_format;
|
||||
struct wlr_gles2_renderer *renderer;
|
||||
enum wlr_gles2_texture_type type;
|
||||
int width, height;
|
||||
bool has_alpha;
|
||||
bool inverted_y;
|
||||
|
||||
// Not set if WLR_GLES2_TEXTURE_GLTEX
|
||||
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 enum wl_shm_format *gles2_formats(size_t *len);
|
||||
|
||||
struct wlr_texture *gles2_texture_create();
|
||||
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_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_pop_marker(void);
|
||||
|
@ -46,24 +46,12 @@ void wlr_egl_finish(struct wlr_egl *egl);
|
||||
*/
|
||||
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
|
||||
* The window must match the remote display the wlr_egl was created with.
|
||||
*/
|
||||
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
|
||||
* of the dmabuf with wlr_egl_check_import_dmabuf once first.
|
||||
|
@ -23,7 +23,6 @@ struct wlr_renderer_impl {
|
||||
void (*end)(struct wlr_renderer *renderer);
|
||||
void (*clear)(struct wlr_renderer *renderer, const float color[static 4]);
|
||||
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,
|
||||
struct wlr_texture *texture, const float matrix[static 9],
|
||||
float alpha);
|
||||
@ -33,14 +32,23 @@ struct wlr_renderer_impl {
|
||||
const float color[static 4], const float matrix[static 9]);
|
||||
const enum wl_shm_format *(*formats)(
|
||||
struct wlr_renderer *renderer, size_t *len);
|
||||
bool (*buffer_is_drm)(struct wlr_renderer *renderer,
|
||||
struct wl_resource *buffer);
|
||||
bool (*resource_is_wl_drm_buffer)(struct wlr_renderer *renderer,
|
||||
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,
|
||||
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,
|
||||
void *data);
|
||||
bool (*format_supported)(struct wlr_renderer *renderer,
|
||||
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);
|
||||
};
|
||||
|
||||
@ -48,30 +56,15 @@ void wlr_renderer_init(struct wlr_renderer *renderer,
|
||||
const struct wlr_renderer_impl *impl);
|
||||
|
||||
struct wlr_texture_impl {
|
||||
bool (*upload_pixels)(struct wlr_texture *texture,
|
||||
enum wl_shm_format format, int stride, int width, int height,
|
||||
const unsigned char *pixels);
|
||||
bool (*update_pixels)(struct wlr_texture *texture,
|
||||
enum wl_shm_format format, int stride, int x, int y,
|
||||
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 (*get_size)(struct wlr_texture *texture, int *width, int *height);
|
||||
bool (*write_pixels)(struct wlr_texture *texture,
|
||||
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);
|
||||
void (*destroy)(struct wlr_texture *texture);
|
||||
};
|
||||
|
||||
void wlr_texture_init(struct wlr_texture *texture,
|
||||
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
|
||||
|
@ -1,8 +1,6 @@
|
||||
#ifndef WLR_RENDER_WLR_RENDERER_H
|
||||
#define WLR_RENDER_WLR_RENDERER_H
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-protocol.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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -61,10 +55,15 @@ void wlr_render_ellipse_with_matrix(struct wlr_renderer *r,
|
||||
const enum wl_shm_format *wlr_renderer_get_formats(struct wlr_renderer *r,
|
||||
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);
|
||||
/**
|
||||
* 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
|
||||
* bytes.
|
||||
|
@ -5,62 +5,49 @@
|
||||
#include <EGL/eglext.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-server-protocol.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf.h>
|
||||
|
||||
struct wlr_renderer;
|
||||
struct wlr_texture_impl;
|
||||
|
||||
struct wlr_texture {
|
||||
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
|
||||
* returns.
|
||||
* Create a new texture from raw pixel data. `stride` is in bytes. The returned
|
||||
* texture is mutable.
|
||||
*/
|
||||
bool wlr_texture_upload_pixels(struct wlr_texture *tex,
|
||||
enum wl_shm_format format, int stride, int width, int height,
|
||||
const unsigned char *pixels);
|
||||
/**
|
||||
* Copies pixels to this texture. The 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_pixels(struct wlr_texture *surf,
|
||||
enum wl_shm_format format, int stride, int x, int y,
|
||||
int width, int height, const unsigned char *pixels);
|
||||
/**
|
||||
* Copies pixels from a wl_shm_buffer into this texture. The buffer is not
|
||||
* accessed after this function returns.
|
||||
*/
|
||||
bool wlr_texture_upload_shm(struct wlr_texture *tex, uint32_t format,
|
||||
struct wl_shm_buffer *shm);
|
||||
/**
|
||||
* Attaches the contents from the given wl_drm wl_buffer resource onto the
|
||||
* 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,
|
||||
struct wl_resource *drm_buffer);
|
||||
struct wlr_texture *wlr_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);
|
||||
|
||||
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
|
||||
* 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.
|
||||
* Create a new texture from a wayland DRM resource. The returned texture is
|
||||
* immutable.
|
||||
*/
|
||||
bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format,
|
||||
int x, int y, int width, int height, struct wl_shm_buffer *shm);
|
||||
struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer,
|
||||
struct wl_resource *data);
|
||||
|
||||
/**
|
||||
* Create a new texture from a DMA-BUF. The returned texture is immutable.
|
||||
*/
|
||||
struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
|
||||
struct wlr_dmabuf_buffer_attribs *attribs);
|
||||
|
||||
/**
|
||||
* Get the texture width and height.
|
||||
*/
|
||||
void wlr_texture_get_size(struct wlr_texture *texture, int *width, int *height);
|
||||
|
||||
/**
|
||||
* Update a texture with raw pixels. The texture must be mutable.
|
||||
*/
|
||||
bool wlr_texture_write_pixels(struct wlr_texture *texture,
|
||||
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.
|
||||
*/
|
||||
|
@ -11,6 +11,12 @@
|
||||
#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
|
||||
#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 {
|
||||
/* set via params_add */
|
||||
int n_planes;
|
||||
@ -22,7 +28,7 @@ struct wlr_dmabuf_buffer_attribs {
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
uint32_t format;
|
||||
uint32_t flags; /* enum zlinux_buffer_params_flags */
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
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 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 */
|
||||
struct wlr_linux_dmabuf {
|
||||
struct wl_global *wl_global;
|
||||
|
18
render/egl.c
18
render/egl.c
@ -220,24 +220,6 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display)
|
||||
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) {
|
||||
if (!eglDestroyImageKHR) {
|
||||
return false;
|
||||
|
@ -12,23 +12,27 @@
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "render/gles2.h"
|
||||
#include "glapi.h"
|
||||
#include "render/gles2.h"
|
||||
|
||||
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);
|
||||
struct wlr_gles2_renderer *renderer =
|
||||
(struct wlr_gles2_renderer *)wlr_renderer;
|
||||
return (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);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
|
||||
uint32_t height) {
|
||||
gles2_get_renderer(wlr_renderer);
|
||||
gles2_get_renderer_in_context(wlr_renderer);
|
||||
|
||||
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) {
|
||||
gles2_get_renderer(wlr_renderer);
|
||||
gles2_get_renderer_in_context(wlr_renderer);
|
||||
// no-op
|
||||
}
|
||||
|
||||
static void gles2_clear(struct wlr_renderer *wlr_renderer,
|
||||
const float color[static 4]) {
|
||||
gles2_get_renderer(wlr_renderer);
|
||||
gles2_get_renderer_in_context(wlr_renderer);
|
||||
|
||||
GLES2_DEBUG_PUSH;
|
||||
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,
|
||||
struct wlr_box *box) {
|
||||
gles2_get_renderer(wlr_renderer);
|
||||
gles2_get_renderer_in_context(wlr_renderer);
|
||||
|
||||
GLES2_DEBUG_PUSH;
|
||||
if (box != NULL) {
|
||||
@ -73,14 +77,6 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer,
|
||||
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() {
|
||||
GLfloat verts[] = {
|
||||
1, 0, // top right
|
||||
@ -107,21 +103,28 @@ static void draw_quad() {
|
||||
glDisableVertexAttribArray(1);
|
||||
}
|
||||
|
||||
static bool gles2_render_texture_with_matrix(
|
||||
struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture,
|
||||
const float matrix[static 9], float alpha) {
|
||||
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
|
||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||
if (!wlr_texture->valid) {
|
||||
wlr_log(L_ERROR, "attempt to render invalid texture");
|
||||
return false;
|
||||
}
|
||||
static bool gles2_render_texture_with_matrix(struct wlr_renderer *wlr_renderer,
|
||||
struct wlr_texture *wlr_texture, const float matrix[static 9],
|
||||
float alpha) {
|
||||
struct wlr_gles2_renderer *renderer =
|
||||
gles2_get_renderer_in_context(wlr_renderer);
|
||||
struct wlr_gles2_texture *texture =
|
||||
gles2_get_texture_in_context(wlr_texture);
|
||||
|
||||
GLuint prog = renderer->shaders.tex_rgba;
|
||||
if (texture->target == GL_TEXTURE_EXTERNAL_OES) {
|
||||
GLuint prog;
|
||||
GLenum target;
|
||||
switch (texture->type) {
|
||||
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;
|
||||
} else if (!texture->pixel_format->has_alpha) {
|
||||
prog = renderer->shaders.tex_rgbx;
|
||||
target = GL_TEXTURE_EXTERNAL_OES;
|
||||
break;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
GLES2_DEBUG_PUSH;
|
||||
glBindTexture(texture->target, texture->tex_id);
|
||||
glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
GLuint tex_id = texture->type == WLR_GLES2_TEXTURE_GLTEX ?
|
||||
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);
|
||||
|
||||
glUniformMatrix3fv(0, 1, GL_FALSE, transposition);
|
||||
glUniform1i(1, wlr_texture->inverted_y);
|
||||
glUniform1i(1, texture->inverted_y);
|
||||
glUniform1f(3, alpha);
|
||||
|
||||
draw_quad();
|
||||
|
||||
GLES2_DEBUG_POP;
|
||||
return true;
|
||||
}
|
||||
@ -146,7 +157,8 @@ static bool gles2_render_texture_with_matrix(
|
||||
|
||||
static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
|
||||
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
|
||||
// to GL_FALSE
|
||||
@ -163,7 +175,8 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
|
||||
|
||||
static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer,
|
||||
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
|
||||
// to GL_FALSE
|
||||
@ -183,20 +196,38 @@ static const enum wl_shm_format *gles2_renderer_formats(
|
||||
return gles2_formats(len);
|
||||
}
|
||||
|
||||
static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer,
|
||||
struct wl_resource *buffer) {
|
||||
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
|
||||
static bool gles2_resource_is_wl_drm_buffer(struct wlr_renderer *wlr_renderer,
|
||||
struct wl_resource *resource) {
|
||||
struct wlr_gles2_renderer *renderer =
|
||||
gles2_get_renderer_in_context(wlr_renderer);
|
||||
|
||||
EGLint format;
|
||||
return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT,
|
||||
&format);
|
||||
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;
|
||||
}
|
||||
|
||||
eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_WIDTH, width);
|
||||
eglQueryWaylandBufferWL(renderer->egl->display, buffer, EGL_HEIGHT, height);
|
||||
}
|
||||
|
||||
static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
|
||||
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, 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);
|
||||
if (fmt == NULL) {
|
||||
@ -254,14 +285,17 @@ static const struct wlr_renderer_impl renderer_impl = {
|
||||
.end = gles2_end,
|
||||
.clear = gles2_clear,
|
||||
.scissor = gles2_scissor,
|
||||
.texture_create = gles2_renderer_texture_create,
|
||||
.render_texture_with_matrix = gles2_render_texture_with_matrix,
|
||||
.render_quad_with_matrix = gles2_render_quad_with_matrix,
|
||||
.render_ellipse_with_matrix = gles2_render_ellipse_with_matrix,
|
||||
.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,
|
||||
.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) {
|
||||
|
@ -10,366 +10,262 @@
|
||||
#include <wlr/render/interface.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include "glapi.h"
|
||||
#include "render/gles2.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;
|
||||
|
||||
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);
|
||||
return (struct wlr_gles2_texture *)wlr_texture;
|
||||
}
|
||||
|
||||
static bool gles2_texture_upload_pixels(struct wlr_texture *wlr_texture,
|
||||
enum wl_shm_format format, int stride, int width, int height,
|
||||
const unsigned char *pixels) {
|
||||
struct wlr_gles2_texture *gles2_get_texture_in_context(
|
||||
struct wlr_texture *wlr_texture) {
|
||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||
|
||||
const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);
|
||||
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;
|
||||
assert(eglGetCurrentContext() == texture->renderer->egl->context);
|
||||
return texture;
|
||||
}
|
||||
|
||||
static bool gles2_texture_update_pixels(struct wlr_texture *wlr_texture,
|
||||
enum wl_shm_format format, int stride, int x, int y,
|
||||
int width, int height, const unsigned char *pixels) {
|
||||
static void gles2_texture_get_size(struct wlr_texture *wlr_texture, int *width,
|
||||
int *height) {
|
||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||
*width = texture->width;
|
||||
*height = texture->height;
|
||||
}
|
||||
|
||||
// TODO: Test if the unpack subimage extension is supported and adjust the
|
||||
// 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);
|
||||
static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
|
||||
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) {
|
||||
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 = texture->pixel_format;
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
// TODO: what if the unpack subimage extension isn't supported?
|
||||
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);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8));
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, src_x);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, src_y);
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
|
||||
fmt->gl_format, fmt->gl_type, data);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
||||
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,
|
||||
uint32_t format, struct wl_shm_buffer *buffer) {
|
||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||
|
||||
const struct gles2_pixel_format *fmt = gles2_format_from_wl(format);
|
||||
if (!fmt || !fmt->gl_format) {
|
||||
wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture",
|
||||
format);
|
||||
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;
|
||||
|
||||
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;
|
||||
wl_shm_buffer_end_access(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gles2_texture_update_shm(struct wlr_texture *wlr_texture,
|
||||
uint32_t format, int x, int y, int width, int height,
|
||||
struct wl_shm_buffer *buffer) {
|
||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||
|
||||
// TODO: Test if the unpack subimage extension is supported and adjust the
|
||||
// upload strategy if not
|
||||
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;
|
||||
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_ROWS_EXT, 0);
|
||||
GLES2_DEBUG_POP;
|
||||
|
||||
wl_shm_buffer_end_access(buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture,
|
||||
struct wl_resource *buf) {
|
||||
struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
|
||||
if (!glEGLImageTargetTexture2DOES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EGLint format;
|
||||
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,
|
||||
(EGLint*)&tex->wlr_texture.width);
|
||||
wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT,
|
||||
(EGLint*)&tex->wlr_texture.height);
|
||||
|
||||
EGLint inverted_y;
|
||||
if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL,
|
||||
&inverted_y)) {
|
||||
tex->wlr_texture.inverted_y = !!inverted_y;
|
||||
}
|
||||
|
||||
GLenum target;
|
||||
const struct gles2_pixel_format *pf;
|
||||
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;
|
||||
|
||||
EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE };
|
||||
|
||||
if (tex->image) {
|
||||
wlr_egl_destroy_image(tex->egl, tex->image);
|
||||
}
|
||||
|
||||
tex->image = wlr_egl_create_image(tex->egl, EGL_WAYLAND_BUFFER_WL,
|
||||
(EGLClientBuffer*) buf, attribs);
|
||||
if (!tex->image) {
|
||||
wlr_log(L_ERROR, "failed to create EGL image");
|
||||
return false;
|
||||
}
|
||||
|
||||
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,
|
||||
EGLImageKHR image, uint32_t width, uint32_t height) {
|
||||
struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
|
||||
|
||||
tex->image = image;
|
||||
tex->pixel_format = &external_pixel_format;
|
||||
tex->wlr_texture.valid = true;
|
||||
tex->wlr_texture.width = width;
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture,
|
||||
struct wl_resource *dmabuf_resource) {
|
||||
struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture);
|
||||
struct wlr_dmabuf_buffer *dmabuf =
|
||||
wlr_dmabuf_buffer_from_buffer_resource(dmabuf_resource);
|
||||
|
||||
if (!tex->egl->egl_exts.dmabuf_import) {
|
||||
wlr_log(L_ERROR, "Want dmabuf but extension not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
tex->wlr_texture.width = dmabuf->attributes.width;
|
||||
tex->wlr_texture.height = dmabuf->attributes.height;
|
||||
|
||||
if (tex->image) {
|
||||
wlr_egl_destroy_image(tex->egl, tex->image);
|
||||
}
|
||||
|
||||
if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) {
|
||||
wlr_texture->inverted_y = true;
|
||||
}
|
||||
|
||||
GLenum target;
|
||||
const struct gles2_pixel_format *pf;
|
||||
if (dmabuf->attributes.n_planes > 1) {
|
||||
target = GL_TEXTURE_EXTERNAL_OES;
|
||||
pf = &external_pixel_format;
|
||||
} else {
|
||||
target = GL_TEXTURE_2D;
|
||||
pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888);
|
||||
}
|
||||
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
|
||||
wl_resource *resource, int *width, int *height) {
|
||||
if (!wlr_dmabuf_resource_is_buffer(resource)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct wlr_dmabuf_buffer *dmabuf =
|
||||
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;
|
||||
}
|
||||
|
||||
*width = wl_shm_buffer_get_width(buffer);
|
||||
*height = wl_shm_buffer_get_height(buffer);
|
||||
}
|
||||
|
||||
static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
|
||||
if (wlr_texture == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
|
||||
|
||||
wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal,
|
||||
&texture->wlr_texture);
|
||||
if (texture->tex_id) {
|
||||
wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL);
|
||||
|
||||
GLES2_DEBUG_PUSH;
|
||||
glDeleteTextures(1, &texture->tex_id);
|
||||
GLES2_DEBUG_POP;
|
||||
|
||||
if (texture->image_tex) {
|
||||
glDeleteTextures(1, &texture->image_tex);
|
||||
}
|
||||
if (texture->image) {
|
||||
assert(eglDestroyImageKHR);
|
||||
eglDestroyImageKHR(texture->renderer->egl->display, texture->image);
|
||||
}
|
||||
|
||||
if (texture->image) {
|
||||
wlr_egl_destroy_image(texture->egl, texture->image);
|
||||
if (texture->type == WLR_GLES2_TEXTURE_GLTEX) {
|
||||
glDeleteTextures(1, &texture->gl_tex);
|
||||
}
|
||||
|
||||
GLES2_DEBUG_POP;
|
||||
|
||||
free(texture);
|
||||
}
|
||||
|
||||
static const struct wlr_texture_impl texture_impl = {
|
||||
.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,
|
||||
.get_size = gles2_texture_get_size,
|
||||
.write_pixels = gles2_texture_write_pixels,
|
||||
.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)))) {
|
||||
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;
|
||||
}
|
||||
|
||||
struct wlr_gles2_texture *texture =
|
||||
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->egl = egl;
|
||||
return &texture->wlr_texture;
|
||||
texture->renderer = renderer;
|
||||
texture->width = width;
|
||||
texture->height = height;
|
||||
texture->type = WLR_GLES2_TEXTURE_GLTEX;
|
||||
texture->has_alpha = fmt->has_alpha;
|
||||
|
||||
GLES2_DEBUG_PUSH;
|
||||
|
||||
glGenTextures(1, &texture->gl_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / (fmt->bpp / 8));
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0,
|
||||
fmt->gl_format, fmt->gl_type, data);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
|
||||
|
||||
GLES2_DEBUG_POP;
|
||||
return (struct wlr_texture *)texture;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!eglQueryWaylandBufferWL || !eglCreateImageKHR ||
|
||||
!glEGLImageTargetTexture2DOES) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EGLint fmt;
|
||||
if (!eglQueryWaylandBufferWL(renderer->egl->display, data,
|
||||
EGL_TEXTURE_FORMAT, &fmt)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EGLint width, height;
|
||||
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;
|
||||
}
|
||||
|
||||
struct wlr_gles2_texture *texture =
|
||||
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;
|
||||
switch (fmt) {
|
||||
case EGL_TEXTURE_RGB:
|
||||
case EGL_TEXTURE_RGBA:
|
||||
target = GL_TEXTURE_2D;
|
||||
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;
|
||||
}
|
||||
|
||||
EGLint attribs[] = {
|
||||
EGL_WAYLAND_PLANE_WL, 0,
|
||||
EGL_NONE,
|
||||
};
|
||||
texture->image = eglCreateImageKHR(renderer->egl->display,
|
||||
renderer->egl->context, EGL_WAYLAND_BUFFER_WL, data, attribs);
|
||||
if (texture->image == NULL) {
|
||||
free(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GLES2_DEBUG_PUSH;
|
||||
|
||||
glGenTextures(1, &texture->image_tex);
|
||||
glBindTexture(target, texture->image_tex);
|
||||
glEGLImageTargetTexture2DOES(target, texture->image);
|
||||
|
||||
GLES2_DEBUG_POP;
|
||||
return (struct wlr_texture *)texture;
|
||||
}
|
||||
|
||||
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
|
||||
struct wlr_dmabuf_buffer_attribs *attribs) {
|
||||
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
|
||||
|
||||
if (!glEGLImageTargetTexture2DOES) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!renderer->egl->egl_exts.dmabuf_import) {
|
||||
wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension "
|
||||
"unavailable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_gles2_texture *texture =
|
||||
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 = 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 <stdlib.h>
|
||||
#include <wlr/render/interface.h>
|
||||
@ -6,6 +7,15 @@
|
||||
|
||||
void wlr_renderer_init(struct wlr_renderer *renderer,
|
||||
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_with_matrix);
|
||||
assert(impl->render_ellipse_with_matrix);
|
||||
assert(impl->formats);
|
||||
assert(impl->format_supported);
|
||||
assert(impl->texture_from_pixels);
|
||||
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) {
|
||||
if (r->impl->end) {
|
||||
r->impl->end(r);
|
||||
}
|
||||
}
|
||||
|
||||
void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) {
|
||||
@ -33,16 +45,10 @@ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *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,
|
||||
const float projection[static 9], int x, int y, float alpha) {
|
||||
const struct wlr_box box = {
|
||||
.x = x, .y = y,
|
||||
.width = texture->width, .height = texture->height,
|
||||
};
|
||||
struct wlr_box box = { .x = x, .y = y };
|
||||
wlr_texture_get_size(texture, &box.width, &box.height);
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
||||
@ -90,15 +96,29 @@ const enum wl_shm_format *wlr_renderer_get_formats(
|
||||
return r->impl->formats(r, len);
|
||||
}
|
||||
|
||||
bool wlr_renderer_buffer_is_drm(struct wlr_renderer *r,
|
||||
struct wl_resource *buffer) {
|
||||
return r->impl->buffer_is_drm(r, buffer);
|
||||
bool wlr_renderer_resource_is_wl_drm_buffer(struct wlr_renderer *r,
|
||||
struct wl_resource *resource) {
|
||||
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,
|
||||
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,
|
||||
void *data) {
|
||||
if (!r->impl->read_pixels) {
|
||||
return false;
|
||||
}
|
||||
return r->impl->read_pixels(r, fmt, stride, width, height, src_x, src_y,
|
||||
dst_x, dst_y, data);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wlr/render/interface.h>
|
||||
@ -5,8 +6,9 @@
|
||||
|
||||
void wlr_texture_init(struct wlr_texture *texture,
|
||||
const struct wlr_texture_impl *impl) {
|
||||
assert(impl->get_size);
|
||||
assert(impl->write_pixels);
|
||||
texture->impl = impl;
|
||||
wl_signal_init(&texture->destroy_signal);
|
||||
}
|
||||
|
||||
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,
|
||||
int stride, int width, int height, const unsigned char *pixels) {
|
||||
return texture->impl->upload_pixels(texture, format, stride,
|
||||
width, height, pixels);
|
||||
struct wlr_texture *wlr_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) {
|
||||
return renderer->impl->texture_from_pixels(renderer, wl_fmt, stride, width,
|
||||
height, data);
|
||||
}
|
||||
|
||||
bool wlr_texture_update_pixels(struct wlr_texture *texture,
|
||||
enum wl_shm_format format, int stride, int x, int y,
|
||||
int width, int height, const unsigned char *pixels) {
|
||||
return texture->impl->update_pixels(texture, format, stride, x, y,
|
||||
width, height, pixels);
|
||||
struct wlr_texture *wlr_texture_from_wl_drm(struct wlr_renderer *renderer,
|
||||
struct wl_resource *data) {
|
||||
if (!renderer->impl->texture_from_wl_drm) {
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
|
||||
struct wlr_dmabuf_buffer_attribs *attribs) {
|
||||
if (!renderer->impl->texture_from_dmabuf) {
|
||||
return NULL;
|
||||
}
|
||||
return renderer->impl->texture_from_dmabuf(renderer, attribs);
|
||||
}
|
||||
|
||||
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);
|
||||
void wlr_texture_get_size(struct wlr_texture *texture, int *width,
|
||||
int *height) {
|
||||
return texture->impl->get_size(texture, width, height);
|
||||
}
|
||||
|
||||
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,
|
||||
EGLImageKHR image, uint32_t width, uint32_t height) {
|
||||
return texture->impl->upload_eglimage(texture, image, width, height);
|
||||
}
|
||||
|
||||
bool wlr_texture_upload_dmabuf(struct wlr_texture *texture,
|
||||
struct wl_resource *dmabuf_resource) {
|
||||
return texture->impl->upload_dmabuf(texture, dmabuf_resource);
|
||||
}
|
||||
|
||||
void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource
|
||||
*resource, int *width, int *height) {
|
||||
texture->impl->get_buffer_size(texture, resource, width, height);
|
||||
bool wlr_texture_write_pixels(struct wlr_texture *texture,
|
||||
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) {
|
||||
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,
|
||||
};
|
||||
|
||||
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) {
|
||||
if (!wl_resource_instance_of(buffer_resource, &wl_buffer_interface,
|
||||
&wl_buffer_impl)) {
|
||||
|
@ -731,15 +731,11 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cursor->texture == NULL) {
|
||||
cursor->texture = wlr_render_texture_create(renderer);
|
||||
if (cursor->texture == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wlr_texture_destroy(cursor->texture);
|
||||
|
||||
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);
|
||||
return cursor->texture != NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (cursor->texture != NULL) {
|
||||
wlr_texture_destroy(cursor->texture);
|
||||
}
|
||||
wl_list_remove(&cursor->link);
|
||||
free(cursor);
|
||||
}
|
||||
|
@ -155,8 +155,24 @@ static bool wlr_surface_update_size(struct wlr_surface *surface,
|
||||
int scale = state->scale;
|
||||
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);
|
||||
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 height = state->buffer_height / scale;
|
||||
@ -316,43 +332,40 @@ static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) {
|
||||
|
||||
static void wlr_surface_apply_damage(struct wlr_surface *surface,
|
||||
bool reupload_buffer) {
|
||||
if (!surface->current->buffer) {
|
||||
struct wl_resource *resource = surface->current->buffer;
|
||||
if (resource == NULL) {
|
||||
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);
|
||||
if (reupload_buffer) {
|
||||
wlr_texture_upload_shm(surface->texture, format, buffer);
|
||||
struct wl_shm_buffer *buf = wl_shm_buffer_get(resource);
|
||||
if (buf != NULL) {
|
||||
wl_shm_buffer_begin_access(buf);
|
||||
|
||||
enum wl_shm_format fmt = wl_shm_buffer_get_format(buf);
|
||||
int32_t stride = wl_shm_buffer_get_stride(buf);
|
||||
int32_t width = wl_shm_buffer_get_width(buf);
|
||||
int32_t height = wl_shm_buffer_get_height(buf);
|
||||
void *data = wl_shm_buffer_get_data(buf);
|
||||
|
||||
if (surface->texture == NULL || reupload_buffer) {
|
||||
wlr_texture_destroy(surface->texture);
|
||||
surface->texture = wlr_texture_from_pixels(surface->renderer, fmt,
|
||||
stride, width, height, data);
|
||||
} else {
|
||||
pixman_region32_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
pixman_region32_copy(&damage, &surface->current->buffer_damage);
|
||||
pixman_region32_intersect_rect(&damage, &damage, 0, 0,
|
||||
surface->current->buffer_width, surface->current->buffer_height);
|
||||
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 rect = rects[i];
|
||||
if (!wlr_texture_update_shm(surface->texture, format,
|
||||
rect.x1, rect.y1,
|
||||
rect.x2 - rect.x1,
|
||||
rect.y2 - rect.y1,
|
||||
buffer)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -360,7 +373,24 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface,
|
||||
pixman_region32_fini(&damage);
|
||||
}
|
||||
|
||||
release:
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (null_buffer_commit) {
|
||||
surface->texture->valid = false;
|
||||
wlr_texture_destroy(surface->texture);
|
||||
surface->texture = NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
surface->renderer = renderer;
|
||||
surface->texture = wlr_render_texture_create(renderer);
|
||||
surface->resource = res;
|
||||
|
||||
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) {
|
||||
return surface->texture && surface->texture->valid;
|
||||
return surface->texture != NULL;
|
||||
}
|
||||
|
||||
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];
|
||||
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,
|
||||
theme->scale);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user