aboutsummaryrefslogtreecommitdiff
path: root/render/gles2/texture.c
diff options
context:
space:
mode:
Diffstat (limited to 'render/gles2/texture.c')
-rw-r--r--render/gles2/texture.c442
1 files changed, 157 insertions, 285 deletions
diff --git a/render/gles2/texture.c b/render/gles2/texture.c
index 46193c78..45169daf 100644
--- a/render/gles2/texture.c
+++ b/render/gles2/texture.c
@@ -10,366 +10,238 @@
#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(wlr_egl_is_current(texture->egl));
+ 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);
-
- // 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);
- }
- 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;
+ *width = texture->width;
+ *height = texture->height;
}
-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);
+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 = gles2_format_from_wl(format);
- if (!fmt || !fmt->gl_format) {
- wlr_log(L_ERROR, "Unsupported pixel format %"PRIu32" for this texture",
- 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;
}
- 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_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;
-}
+ glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
-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);
+ 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);
- // 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);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, dst_x, dst_y, width, height,
+ fmt->gl_format, fmt->gl_type, data);
- 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_ROW_LENGTH_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
- GLES2_DEBUG_POP;
-
- wl_shm_buffer_end_access(buffer);
+ GLES2_DEBUG_POP;
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;
+static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
+ if (wlr_texture == NULL) {
+ return;
}
- 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;
- }
+ struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
- 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);
+ wlr_egl_make_current(texture->egl, EGL_NO_SURFACE, NULL);
+
+ GLES2_DEBUG_PUSH;
- 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;
+ if (texture->image_tex) {
+ glDeleteTextures(1, &texture->image_tex);
+ }
+ if (texture->image) {
+ assert(eglDestroyImageKHR);
+ wlr_egl_destroy_image(texture->egl, texture->image);
}
- 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;
+ if (texture->type == WLR_GLES2_TEXTURE_GLTEX) {
+ glDeleteTextures(1, &texture->gl_tex);
}
- 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 };
+ free(texture);
+}
+
+static const struct wlr_texture_impl texture_impl = {
+ .get_size = gles2_texture_get_size,
+ .write_pixels = gles2_texture_write_pixels,
+ .destroy = gles2_texture_destroy,
+};
+
+struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
+ enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
+ uint32_t height, const void *data) {
+ assert(wlr_egl_is_current(egl));
- if (tex->image) {
- wlr_egl_destroy_image(tex->egl, tex->image);
+ 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,
- (EGLClientBuffer*) buf, attribs);
- if (!tex->image) {
- wlr_log(L_ERROR, "failed to create EGL image");
- return false;
+ 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;
+ texture->width = width;
+ texture->height = height;
+ texture->type = WLR_GLES2_TEXTURE_GLTEX;
+ texture->has_alpha = fmt->has_alpha;
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);
+ glGenTextures(1, &texture->gl_tex);
+ glBindTexture(GL_TEXTURE_2D, texture->gl_tex);
- tex->image = image;
- tex->pixel_format = &external_pixel_format;
- tex->wlr_texture.valid = true;
- tex->wlr_texture.width = width;
- tex->wlr_texture.height = height;
+ 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_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;
+ return &texture->wlr_texture;
}
-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);
+struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
+ struct wl_resource *data) {
+ assert(wlr_egl_is_current(egl));
- if (!tex->egl->egl_exts.dmabuf_import) {
- wlr_log(L_ERROR, "Want dmabuf but extension not present");
- return false;
+ if (!glEGLImageTargetTexture2DOES) {
+ return NULL;
}
- 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);
+ 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;
+ texture->wl_drm = data;
- if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) {
- wlr_texture->inverted_y = true;
+ EGLint fmt;
+ texture->image = wlr_egl_create_image_from_wl_drm(egl, data, &fmt,
+ &texture->width, &texture->height, &texture->inverted_y);
+ if (texture->image == NULL) {
+ free(texture);
+ return NULL;
}
GLenum target;
- const struct gles2_pixel_format *pf;
- if (dmabuf->attributes.n_planes > 1) {
- target = GL_TEXTURE_EXTERNAL_OES;
- pf = &external_pixel_format;
- } else {
+ switch (fmt) {
+ case EGL_TEXTURE_RGB:
+ case EGL_TEXTURE_RGBA:
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;
+ 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;
}
- struct wlr_dmabuf_buffer *dmabuf =
- wlr_dmabuf_buffer_from_buffer_resource(resource);
- *width = dmabuf->attributes.width;
- *height = dmabuf->attributes.height;
- return true;
-}
+ GLES2_DEBUG_PUSH;
-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);
+ glGenTextures(1, &texture->image_tex);
+ glBindTexture(target, texture->image_tex);
+ glEGLImageTargetTexture2DOES(target, texture->image);
- return;
- }
-
- *width = wl_shm_buffer_get_width(buffer);
- *height = wl_shm_buffer_get_height(buffer);
+ GLES2_DEBUG_POP;
+ return &texture->wlr_texture;
}
-static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
- struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
+struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
+ struct wlr_dmabuf_buffer_attribs *attribs) {
+ assert(wlr_egl_is_current(egl));
- wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal,
- &texture->wlr_texture);
- if (texture->tex_id) {
- GLES2_DEBUG_PUSH;
- glDeleteTextures(1, &texture->tex_id);
- GLES2_DEBUG_POP;
+ if (!glEGLImageTargetTexture2DOES) {
+ return NULL;
}
- if (texture->image) {
- wlr_egl_destroy_image(texture->egl, texture->image);
+ if (!egl->egl_exts.dmabuf_import) {
+ wlr_log(L_ERROR, "Cannot create DMA-BUF texture: EGL extension "
+ "unavailable");
+ return NULL;
}
- 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,
- .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_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;
+ 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(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 &texture->wlr_texture;
}