diff options
-rw-r--r-- | backend/drm/backend.c | 4 | ||||
-rw-r--r-- | backend/drm/drm.c | 2 | ||||
-rw-r--r-- | backend/egl.c | 94 | ||||
-rw-r--r-- | backend/wayland/backend.c | 2 | ||||
-rw-r--r-- | examples/compositor.h | 4 | ||||
-rw-r--r-- | examples/compositor/wl_compositor.c | 11 | ||||
-rw-r--r-- | examples/tablet.c | 1 | ||||
-rw-r--r-- | include/backend/egl.h | 57 | ||||
-rw-r--r-- | include/render/gles2.h | 8 | ||||
-rw-r--r-- | include/wlr/render.h | 13 | ||||
-rw-r--r-- | include/wlr/render/gles2.h | 1 | ||||
-rw-r--r-- | include/wlr/render/interface.h | 3 | ||||
-rw-r--r-- | include/wlr/types/wlr_surface.h | 4 | ||||
-rw-r--r-- | render/gles2/renderer.c | 28 | ||||
-rw-r--r-- | render/gles2/shaders.c | 10 | ||||
-rw-r--r-- | render/gles2/texture.c | 83 | ||||
-rw-r--r-- | render/wlr_texture.c | 5 | ||||
-rw-r--r-- | types/wlr_output.c | 4 | ||||
-rw-r--r-- | types/wlr_surface.c | 16 |
19 files changed, 322 insertions, 28 deletions
diff --git a/backend/drm/backend.c b/backend/drm/backend.c index e361358e..bcc81624 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -149,6 +149,10 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, goto error_event; } + if (!wlr_egl_bind_display(&drm->renderer.egl, display)) { + wlr_log(L_INFO, "Failed to bind egl/wl display: %s", egl_error()); + } + return backend; error_event: diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 1c83af3e..e11751e2 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -579,7 +579,7 @@ static bool wlr_drm_output_set_cursor(struct wlr_output_state *output, wlr_matrix_texture(plane->matrix, plane->width, plane->height, output->base->transform ^ WL_OUTPUT_TRANSFORM_FLIPPED_180); - plane->wlr_rend = wlr_gles2_renderer_init(); + plane->wlr_rend = wlr_gles2_renderer_init(&output->renderer->egl); if (!plane->wlr_rend) { return false; } diff --git a/backend/egl.c b/backend/egl.c index a547523c..15a2c58e 100644 --- a/backend/egl.c +++ b/backend/egl.c @@ -1,10 +1,17 @@ #include <EGL/egl.h> #include <EGL/eglext.h> -#include <GLES3/gl3.h> +#include <GLES2/gl2.h> #include <gbm.h> // GBM_FORMAT_XRGB8888 +#include <stdlib.h> #include <wlr/util/log.h> #include "backend/egl.h" +// Extension documentation +// https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt. +// https://cgit.freedesktop.org/mesa/mesa/tree/docs/specs/WL_bind_wayland_display.spec + +struct wlr_egl *egl_global; + const char *egl_error(void) { switch (eglGetError()) { case EGL_SUCCESS: @@ -46,6 +53,12 @@ const char *egl_error(void) { PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display; PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window_surface; +PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; +PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; +PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL; +PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL; +PFNEGLUNBINDWAYLANDDISPLAYWL eglUnbindWaylandDisplayWL; + static bool egl_exts() { get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT"); @@ -109,7 +122,8 @@ static bool egl_get_config(EGLDisplay disp, EGLConfig *out, EGLenum platform) { return false; } -bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display) { +bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, + void *remote_display) { if (!egl_exts()) { return false; } @@ -119,7 +133,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display) { goto error; } - egl->display = get_platform_display(platform, display, NULL); + egl->display = get_platform_display(platform, remote_display, NULL); if (egl->display == EGL_NO_DISPLAY) { wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error()); goto error; @@ -147,11 +161,31 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display) { } eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->context); + egl->egl_exts = eglQueryString(egl->display, EGL_EXTENSIONS); + if (strstr(egl->egl_exts, "EGL_WL_bind_wayland_display") == NULL || + strstr(egl->egl_exts, "EGL_KHR_image_base") == NULL) { + wlr_log(L_ERROR, "Required egl extensions not supported"); + goto error; + } + + eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) + eglGetProcAddress("eglCreateImageKHR"); + eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) + eglGetProcAddress("eglDestroyImageKHR"); + eglQueryWaylandBufferWL = (PFNEGLQUERYWAYLANDBUFFERWL) + (void*) eglGetProcAddress("eglQueryWaylandBufferWL"); + eglBindWaylandDisplayWL = (PFNEGLBINDWAYLANDDISPLAYWL) + (void*) eglGetProcAddress("eglBindWaylandDisplayWL"); + eglUnbindWaylandDisplayWL = (PFNEGLUNBINDWAYLANDDISPLAYWL) + (void*) eglGetProcAddress("eglUnbindWaylandDisplayWL"); + + egl_global = egl; + + egl->gl_exts = (const char*) glGetString(GL_EXTENSIONS); wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); - wlr_log(L_INFO, "Supported EGL extensions: %s", eglQueryString(egl->display, - EGL_EXTENSIONS)); + wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts); wlr_log(L_INFO, "Using %s", glGetString(GL_VERSION)); - wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", glGetString(GL_EXTENSIONS)); + wlr_log(L_INFO, "Supported OpenGL ES extensions: %s", egl->gl_exts); return true; error: @@ -162,11 +196,57 @@ error: } void wlr_egl_free(struct wlr_egl *egl) { - eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (egl->wl_display && eglUnbindWaylandDisplayWL) { + eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); + } + eglDestroyContext(egl->display, egl->context); eglTerminate(egl->display); eglReleaseThread(); eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + + if (egl_global == egl) + egl_global = NULL; +} + +bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { + if (!eglBindWaylandDisplayWL) { + return false; + } + + if (eglBindWaylandDisplayWL(egl->display, local_display)) { + egl->wl_display = local_display; + return true; + } + + return false; +} + +bool wlr_egl_query_buffer(struct wl_resource *buf, int attrib, int *value) { + if (!egl_global || !eglQueryWaylandBufferWL) { + return false; + } + + return eglQueryWaylandBufferWL(egl_global->display, buf, attrib, value); +} + +EGLImage wlr_egl_create_image(EGLenum target, + EGLClientBuffer buffer, const EGLint *attribs) { + if (!egl_global || !eglCreateImageKHR) { + return false; + } + + return eglCreateImageKHR(egl_global->display, egl_global->context, target, + buffer, attribs); +} + +bool wlr_egl_destroy_image(EGLImage image) { + if (!egl_global || !eglDestroyImageKHR) { + return false; + } + + eglDestroyImageKHR(egl_global->display, image); + return true; } EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index ef480c18..a0fb0be6 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -52,6 +52,8 @@ static bool wlr_wl_backend_init(struct wlr_backend_state* state) { } wlr_egl_init(&state->egl, EGL_PLATFORM_WAYLAND_EXT, state->remote_display); + wlr_egl_bind_display(&state->egl, state->local_display); + for (size_t i = 0; i < state->requested_outputs; ++i) { wlr_wl_output_create(state->backend); } diff --git a/examples/compositor.h b/examples/compositor.h index 4649a8d3..2847808f 100644 --- a/examples/compositor.h +++ b/examples/compositor.h @@ -14,6 +14,10 @@ struct wl_compositor_state { void wl_compositor_init(struct wl_display *display, struct wl_compositor_state *state, struct wlr_renderer *renderer); +struct wlr_surface; +void wl_compositor_surface_destroyed(struct wl_compositor_state *compositor, + struct wlr_surface *surface); + struct wl_shell_state { struct wl_global *wl_global; struct wl_list wl_resources; diff --git a/examples/compositor/wl_compositor.c b/examples/compositor/wl_compositor.c index e5b1120e..e25dddac 100644 --- a/examples/compositor/wl_compositor.c +++ b/examples/compositor/wl_compositor.c @@ -7,9 +7,8 @@ #include "compositor.h" static void destroy_surface_listener(struct wl_listener *listener, void *data) { - struct wl_compositor_state *state; - struct wlr_surface *surface = data; - state = wl_container_of(listener, state, destroy_surface_listener); + struct wlr_surface *surface = wl_resource_get_user_data(data); + struct wl_compositor_state *state = surface->compositor_data; struct wl_resource *res = NULL; wl_list_for_each(res, &state->surfaces, link) { @@ -26,8 +25,11 @@ static void wl_compositor_create_surface(struct wl_client *client, struct wl_resource *surface_resource = wl_resource_create(client, &wl_surface_interface, wl_resource_get_version(resource), id); struct wlr_surface *surface = wlr_surface_create(surface_resource, state->renderer); + surface->compositor_data = state; + surface->compositor_listener.notify = &destroy_surface_listener; + wl_resource_add_destroy_listener(surface_resource, &surface->compositor_listener); + wl_list_insert(&state->surfaces, wl_resource_get_link(surface_resource)); - wl_signal_add(&surface->signals.destroy, &state->destroy_surface_listener); } static void wl_compositor_create_region(struct wl_client *client, @@ -74,7 +76,6 @@ void wl_compositor_init(struct wl_display *display, &wl_compositor_interface, 4, state, wl_compositor_bind); state->wl_global = wl_global; state->renderer = renderer; - state->destroy_surface_listener.notify = destroy_surface_listener; wl_list_init(&state->wl_resources); wl_list_init(&state->surfaces); } diff --git a/examples/tablet.c b/examples/tablet.c index 0be6dcb9..4a7d9f74 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -153,7 +153,6 @@ int main(int argc, char *argv[]) { compositor_init(&compositor); state.renderer = wlr_gles2_renderer_init(); - compositor_run(&compositor); wlr_renderer_destroy(state.renderer); diff --git a/include/backend/egl.h b/include/backend/egl.h index 0422a52b..b649c55b 100644 --- a/include/backend/egl.h +++ b/include/backend/egl.h @@ -2,17 +2,72 @@ #define WLR_BACKEND_EGL_H #include <EGL/egl.h> +#include <EGL/eglext.h> #include <stdbool.h> struct wlr_egl { EGLDisplay display; EGLConfig config; EGLContext context; + + const char *egl_exts; + const char *gl_exts; + + struct wl_display *wl_display; }; -const char *egl_error(void); +/** + * Initializes an egl context for the given platform and remote display. + * Will attempt to load all possibly required api functions. + */ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *display); + +/** + * Frees all related egl resources, makes the context not-current and + * unbinds a bound wayland display. + */ void wlr_egl_free(struct wlr_egl *egl); + +/** + * Binds the given display to the egl instance. + * This will allow clients to create egl surfaces from wayland ones and render to it. + */ +bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display); + +/** + * Queries information about the given (potential egl/drm) buffer, returns + * the information in value. + * Refer to eglQueryWaylandBufferWL for more information about attrib and value. + * Makes only sense when a wl_display was bound to it since otherwise there + * cannot be any egl/drm buffers. + * Will only work after a wlr_egl objct was initialized and if the needed egl extension + * is present. + */ +bool wlr_egl_query_buffer(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. + * Will only work after a wlr_egl objct was initialized and if the needed egl extension + * is present. + */ +EGLImageKHR wlr_egl_create_image(EGLenum target, EGLClientBuffer buffer, + const EGLint *attribs); + +/** + * Destroys an egl image created with the given wlr_egl. + */ +bool wlr_egl_destroy_image(EGLImageKHR image); + +/** + * Returns a string for the last error ocurred with egl. + */ +const char *egl_error(void); + #endif diff --git a/include/render/gles2.h b/include/render/gles2.h index 41af0593..cb78a181 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -4,9 +4,14 @@ #include <string.h> #include <stdbool.h> #include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> #include <wlr/render.h> #include <wlr/util/log.h> +extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + struct pixel_format { uint32_t wl_format; GLint gl_format, gl_type; @@ -18,6 +23,7 @@ struct wlr_texture_state { struct wlr_texture *wlr_texture; GLuint tex_id; const struct pixel_format *pixel_format; + EGLImageKHR image; }; struct shaders { @@ -25,6 +31,7 @@ struct shaders { GLuint rgba, rgbx; GLuint quad; GLuint ellipse; + GLuint external; }; extern struct shaders shaders; @@ -39,6 +46,7 @@ extern const GLchar ellipse_fragment_src[]; extern const GLchar vertex_src[]; extern const GLchar fragment_src_rgba[]; extern const GLchar fragment_src_rgbx[]; +extern const GLchar fragment_src_external[]; bool _gles2_flush_errors(const char *file, int line); #define gles2_flush_errors(...) \ diff --git a/include/wlr/render.h b/include/wlr/render.h index 61169333..47e2ff57 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -65,7 +65,7 @@ struct wlr_texture { * Copies pixels to this texture. The buffer is not accessed after this function * returns. */ -bool wlr_texture_upload_pixels(struct wlr_texture *surf, +bool wlr_texture_upload_pixels(struct wlr_texture *tex, enum wl_shm_format format, int stride, int width, int height, const unsigned char *pixels); /** @@ -80,8 +80,17 @@ bool wlr_texture_update_pixels(struct wlr_texture *surf, * 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 *surf, uint32_t format, +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); + /** * 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, diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index a779ffff..43d4719e 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -2,6 +2,7 @@ #define _WLR_GLES2_RENDERER_H #include <wlr/render.h> +struct wlr_egl; struct wlr_renderer *wlr_gles2_renderer_init(); #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index be9ffe7a..4a4b22e2 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -42,7 +42,8 @@ struct wlr_texture_impl { struct wl_shm_buffer *shm); bool (*update_shm)(struct wlr_texture_state *surf, uint32_t format, int x, int y, int width, int height, struct wl_shm_buffer *shm); - // TODO: egl + bool (*upload_drm)(struct wlr_texture_state *state, + struct wl_resource *drm_buf); void (*get_matrix)(struct wlr_texture_state *state, float (*matrix)[16], const float (*projection)[16], int x, int y); void (*bind)(struct wlr_texture_state *state); diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index e8e747cd..c9cbeba6 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -37,11 +37,13 @@ struct wlr_surface { float surface_to_buffer_matrix[16]; struct { - struct wl_signal destroy; struct wl_signal commit; } signals; struct wl_list frame_callback_list; // wl_surface.frame + + struct wl_listener compositor_listener; // destroy listener used by compositor + void *compositor_data; }; struct wlr_renderer; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 703edd46..0de777cc 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -2,14 +2,17 @@ #include <stdlib.h> #include <assert.h> #include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> #include <wayland-util.h> #include <wayland-server-protocol.h> #include <wlr/render.h> #include <wlr/render/interface.h> #include <wlr/render/matrix.h> #include <wlr/util/log.h> +#include "backend/egl.h" #include "render/gles2.h" +PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL; struct shaders shaders; static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { @@ -65,13 +68,36 @@ static void init_default_shaders() { if (!compile_program(quad_vertex_src, ellipse_fragment_src, &shaders.ellipse)) { goto error; } + if (glEGLImageTargetTexture2DOES) { + if (!compile_program(quad_vertex_src, fragment_src_external, &shaders.external)) { + goto error; + } + } + wlr_log(L_DEBUG, "Compiled default shaders"); return; error: wlr_log(L_ERROR, "Failed to set up default shaders!"); } +static void init_image_ext() { + if (glEGLImageTargetTexture2DOES) + return; + + const char *exts = (const char*) glGetString(GL_EXTENSIONS); + if (strstr(exts, "GL_OES_EGL_image_external")) { + glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) + eglGetProcAddress("glEGLImageTargetTexture2DOES"); + } + + if (!glEGLImageTargetTexture2DOES) { + wlr_log(L_INFO, "Failed to load glEGLImageTargetTexture2DOES " + "Will not be able to attach drm buffers"); + } +} + static void init_globals() { + init_image_ext(); init_default_shaders(); } @@ -184,7 +210,7 @@ static struct wlr_renderer_impl wlr_renderer_impl = { .destroy = wlr_gles2_destroy }; -struct wlr_renderer *wlr_gles2_renderer_init() { +struct wlr_renderer *wlr_gles2_renderer_init(struct wlr_egl *egl) { init_globals(); return wlr_renderer_init(NULL, &wlr_renderer_impl); } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index f5e61dd6..c1db6e20 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -90,3 +90,13 @@ const GLchar fragment_src_rgbx[] = " gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" " gl_FragColor.a = alpha;" "}"; + +const GLchar fragment_src_external[] = +"#extension GL_OES_EGL_image_external : require\n" +"precision mediump float;" +"uniform samplerExternalOES texture0;" +"varying vec2 v_uv;" +"void main() {" +" vec4 col = texture2D(texture0, v_uv);" +" gl_FragColor = vec4(col.rgb, col.a);" +"}"; diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 7a030f25..2a2073c6 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -10,6 +10,27 @@ #include <wlr/render/matrix.h> #include <wlr/util/log.h> #include "render/gles2.h" +#include "backend/egl.h" + +static struct pixel_format external_pixel_format = { + .wl_format = 0, + .depth = 0, + .bpp = 0, + .gl_format = 0, + .gl_type = 0, + .shader = &shaders.external +}; + +static void gles2_texture_gen_texture(struct wlr_texture_state *surface) { + if (surface->tex_id) { + return; + } + + GL_CALL(glGenTextures(1, &surface->tex_id)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, surface->tex_id)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); +} static bool gles2_texture_upload_pixels(struct wlr_texture_state *texture, enum wl_shm_format format, int stride, int width, int height, @@ -24,7 +45,8 @@ static bool gles2_texture_upload_pixels(struct wlr_texture_state *texture, texture->wlr_texture->height = height; texture->wlr_texture->format = format; texture->pixel_format = fmt; - GL_CALL(glGenTextures(1, &texture->tex_id)); + + gles2_texture_gen_texture(texture); GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, @@ -74,7 +96,7 @@ static bool gles2_texture_upload_shm(struct wlr_texture_state *texture, texture->wlr_texture->format = format; texture->pixel_format = fmt; - GL_CALL(glGenTextures(1, &texture->tex_id)); + gles2_texture_gen_texture(texture); GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, pitch)); GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); @@ -113,6 +135,62 @@ static bool gles2_texture_update_shm(struct wlr_texture_state *texture, GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); wl_shm_buffer_end_access(buffer); + + return true; +} + +static bool gles2_texture_upload_drm(struct wlr_texture_state *texture, + struct wl_resource* buf) { + if (!glEGLImageTargetTexture2DOES) { + return false; + } + + EGLint format; + if (!wlr_egl_query_buffer(buf, EGL_TEXTURE_FORMAT, &format)) { + wlr_log(L_INFO, "upload_drm called with no drm buffer"); + return false; + } + + wlr_egl_query_buffer(buf, EGL_WIDTH, (EGLint*) &texture->wlr_texture->width); + wlr_egl_query_buffer(buf, EGL_HEIGHT, (EGLint*) &texture->wlr_texture->height); + + EGLint inverted_y; + wlr_egl_query_buffer(buf, EGL_WAYLAND_Y_INVERTED_WL, &inverted_y); + + GLenum target; + const struct pixel_format *pf; + switch (format) { + case EGL_TEXTURE_RGB: + case EGL_TEXTURE_RGBA: + target = GL_TEXTURE_2D; + pf = gl_format_for_wl_format(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_texture_gen_texture(texture); + GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); + + EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; + texture->image = wlr_egl_create_image(EGL_WAYLAND_BUFFER_WL, + (EGLClientBuffer*) buf, attribs); + if (!texture->image) { + wlr_log(L_ERROR, "failed to create egl image: %s", egl_error()); + return false; + } + + GL_CALL(glActiveTexture(GL_TEXTURE0)); + GL_CALL(glBindTexture(target, texture->tex_id)); + GL_CALL(glEGLImageTargetTexture2DOES(target, texture->image)); + texture->wlr_texture->valid = true; + texture->pixel_format = pf; + return true; } @@ -146,6 +224,7 @@ static struct wlr_texture_impl wlr_texture_impl = { .update_pixels = gles2_texture_update_pixels, .upload_shm = gles2_texture_upload_shm, .update_shm = gles2_texture_update_shm, + .upload_drm = gles2_texture_upload_drm, .get_matrix = gles2_texture_get_matrix, .bind = gles2_texture_bind, .destroy = gles2_texture_destroy, diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 64f90990..0d4362dc 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -43,6 +43,11 @@ bool wlr_texture_update_shm(struct wlr_texture *texture, uint32_t 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->state, drm_buffer); +} + void wlr_texture_get_matrix(struct wlr_texture *texture, float (*matrix)[16], const float (*projection)[16], int x, int y) { texture->impl->get_matrix(texture->state, matrix, projection, x, y); diff --git a/types/wlr_output.c b/types/wlr_output.c index 63727394..9f051956 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -133,6 +133,7 @@ bool wlr_output_set_cursor(struct wlr_output *output, return true; } + /* wlr_log(L_INFO, "Falling back to software cursor"); output->cursor.is_sw = true; @@ -149,8 +150,9 @@ bool wlr_output_set_cursor(struct wlr_output *output, wlr_texture_upload_pixels(output->cursor.texture, WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); + */ - return true; + return false; } bool wlr_output_move_cursor(struct wlr_output *output, int x, int y) { diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 25c8e0df..1ce4926e 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -4,6 +4,7 @@ #include <wlr/util/log.h> #include <wlr/render/interface.h> #include <wlr/types/wlr_surface.h> +#include "backend/egl.h" static void surface_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); @@ -123,8 +124,14 @@ void wlr_surface_flush_damage(struct wlr_surface *surface) { } struct wl_shm_buffer *buffer = wl_shm_buffer_get(surface->current.buffer); if (!buffer) { - wlr_log(L_INFO, "Unknown buffer handle attached"); - return; + EGLint format; + if (wlr_egl_query_buffer(surface->current.buffer, EGL_TEXTURE_FORMAT, &format)) { + wlr_texture_upload_drm(surface->texture, surface->pending.buffer); + goto release; + } else { + wlr_log(L_INFO, "Unknown buffer handle attached"); + return; + } } pixman_region32_t damage = surface->current.surface_damage; if (!pixman_region32_not_empty(&damage)) { @@ -182,13 +189,13 @@ const struct wl_surface_interface surface_interface = { static void destroy_surface(struct wl_resource *resource) { struct wlr_surface *surface = wl_resource_get_user_data(resource); - wl_signal_emit(&surface->signals.destroy, surface); - wlr_texture_destroy(surface->texture); + wlr_texture_destroy(surface->texture); struct wlr_frame_callback *cb, *next; wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link) { wl_resource_destroy(cb->resource); } + free(surface); } @@ -198,7 +205,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, surface->texture = wlr_render_texture_init(renderer); surface->resource = res; wl_signal_init(&surface->signals.commit); - wl_signal_init(&surface->signals.destroy); wl_list_init(&surface->frame_callback_list); wl_resource_set_implementation(res, &surface_interface, surface, destroy_surface); |