From 6c7e1c867caf5c9a7c1046273f22b01cda30f034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Thu, 1 Mar 2018 16:20:15 +0100 Subject: [PATCH 01/52] protocol: sort protocols from wayland-protocols alphabetically --- protocol/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/meson.build b/protocol/meson.build index 6c87a887..200cbd7a 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -21,9 +21,9 @@ wayland_scanner_client = generator( ) protocols = [ - [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], 'gamma-control.xml', 'gtk-primary-selection.xml', 'idle.xml', From c27fd1e1ee9826ea0668d2bb5aa8644daec29a7f Mon Sep 17 00:00:00 2001 From: emersion Date: Fri, 9 Mar 2018 10:29:22 +0100 Subject: [PATCH 02/52] rootston: add view_map and view_unmap --- include/rootston/desktop.h | 6 ++-- include/rootston/view.h | 1 - rootston/desktop.c | 60 ++++++++++++++++++++++++++------------ rootston/wl_shell.c | 10 ++----- rootston/xdg_shell.c | 11 ++----- rootston/xdg_shell_v6.c | 11 ++----- rootston/xwayland.c | 43 ++++----------------------- 7 files changed, 60 insertions(+), 82 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 467de8ab..61fe47b0 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -71,14 +71,16 @@ struct roots_output *desktop_output_from_wlr_output( struct roots_view *desktop_view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); -void view_init(struct roots_view *view, struct roots_desktop *desktop); -void view_finish(struct roots_view *view); +struct roots_view *view_create(struct roots_desktop *desktop); +void view_destroy(struct roots_view *view); void view_activate(struct roots_view *view, bool activate); void view_apply_damage(struct roots_view *view); void view_damage_whole(struct roots_view *view); void view_update_position(struct roots_view *view, double x, double y); void view_update_size(struct roots_view *view, uint32_t width, uint32_t height); void view_initial_focus(struct roots_view *view); +void view_map(struct roots_view *view, struct wlr_surface *surface); +void view_unmap(struct roots_view *view); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xdg_shell_surface(struct wl_listener *listener, void *data); diff --git a/include/rootston/view.h b/include/rootston/view.h index ff5ef44a..66a0cb3d 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -181,7 +181,6 @@ struct roots_xdg_popup { struct wl_listener new_popup; }; -struct roots_view *view_create(); void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); diff --git a/rootston/desktop.c b/rootston/desktop.c index 3628b051..66c7ac2b 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -23,13 +23,15 @@ #include "rootston/view.h" #include "rootston/xcursor.h" - -struct roots_view *view_create() { +struct roots_view *view_create(struct roots_desktop *desktop) { struct roots_view *view = calloc(1, sizeof(struct roots_view)); if (!view) { return NULL; } + view->desktop = desktop; view->alpha = 1.0f; + wl_signal_init(&view->events.destroy); + wl_list_init(&view->children); return view; } @@ -402,20 +404,18 @@ struct roots_subsurface *subsurface_create(struct roots_view *view, return subsurface; } -void view_finish(struct roots_view *view) { - view_damage_whole(view); +void view_destroy(struct roots_view *view) { + if (view == NULL) { + return; + } + + if (view->wlr_surface != NULL) { + view_unmap(view); + } + wl_signal_emit(&view->events.destroy, view); - wl_list_remove(&view->new_subsurface.link); - - struct roots_view_child *child, *tmp; - wl_list_for_each_safe(child, tmp, &view->children, link) { - child->destroy(child); - } - - if (view->fullscreen_output) { - view->fullscreen_output->fullscreen_view = NULL; - } + free(view); } static void view_handle_new_subsurface(struct wl_listener *listener, @@ -425,12 +425,10 @@ static void view_handle_new_subsurface(struct wl_listener *listener, subsurface_create(view, wlr_subsurface); } -void view_init(struct roots_view *view, struct roots_desktop *desktop) { - assert(view->wlr_surface); +void view_map(struct roots_view *view, struct wlr_surface *surface) { + assert(view->wlr_surface == NULL); - view->desktop = desktop; - wl_signal_init(&view->events.destroy); - wl_list_init(&view->children); + view->wlr_surface = surface; struct wlr_subsurface *subsurface; wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, @@ -442,9 +440,33 @@ void view_init(struct roots_view *view, struct roots_desktop *desktop) { wl_signal_add(&view->wlr_surface->events.new_subsurface, &view->new_subsurface); + wl_list_insert(&view->desktop->views, &view->link); view_damage_whole(view); } +void view_unmap(struct roots_view *view) { + assert(view->wlr_surface != NULL); + + view_damage_whole(view); + wl_list_remove(&view->link); + + wl_list_remove(&view->new_subsurface.link); + + struct roots_view_child *child, *tmp; + wl_list_for_each_safe(child, tmp, &view->children, link) { + child->destroy(child); + } + + if (view->fullscreen_output != NULL) { + output_damage_whole(view->fullscreen_output); + view->fullscreen_output->fullscreen_view = NULL; + view->fullscreen_output = NULL; + } + + view->wlr_surface = NULL; + view->width = view->height = 0; +} + void view_initial_focus(struct roots_view *view) { struct roots_input *input = view->desktop->server->input; // TODO what seat gets focus? the one with the last input event? diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 899df1c6..6326d9d7 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -181,9 +181,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_surface->request_fullscreen.link); wl_list_remove(&roots_surface->set_state.link); wl_list_remove(&roots_surface->surface_commit.link); - wl_list_remove(&roots_surface->view->link); - view_finish(roots_surface->view); - free(roots_surface->view); + view_destroy(roots_surface->view); free(roots_surface); } @@ -227,7 +225,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); - struct roots_view *view = view_create(); + struct roots_view *view = view_create(desktop); if (!view) { free(roots_surface); return; @@ -238,13 +236,11 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { view->wl_shell_surface = surface; view->roots_wl_shell_surface = roots_surface; - view->wlr_surface = surface->surface; view->resize = resize; view->close = close; roots_surface->view = view; - view_init(view, desktop); - wl_list_insert(&desktop->views, &view->link); + view_map(view, surface->surface); view_setup(view); if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) { diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 9368ce0b..1733eb4e 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -287,9 +287,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_xdg_surface->request_resize.link); wl_list_remove(&roots_xdg_surface->request_maximize.link); wl_list_remove(&roots_xdg_surface->request_fullscreen.link); - wl_list_remove(&roots_xdg_surface->view->link); - view_finish(roots_xdg_surface->view); - free(roots_xdg_surface->view); + view_destroy(roots_xdg_surface->view); free(roots_xdg_surface); } @@ -333,7 +331,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { roots_surface->new_popup.notify = handle_new_popup; wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); - struct roots_view *view = view_create(); + struct roots_view *view = view_create(desktop); if (!view) { free(roots_surface); return; @@ -342,7 +340,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { view->xdg_surface = surface; view->roots_xdg_surface = roots_surface; - view->wlr_surface = surface->surface; view->activate = activate; view->resize = resize; view->move_resize = move_resize; @@ -356,8 +353,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { view->width = box.width; view->height = box.height; - view_init(view, desktop); - wl_list_insert(&desktop->views, &view->link); - + view_map(view, surface->surface); view_setup(view); } diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index eda349cb..c49bd911 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -287,9 +287,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_xdg_surface->request_resize.link); wl_list_remove(&roots_xdg_surface->request_maximize.link); wl_list_remove(&roots_xdg_surface->request_fullscreen.link); - wl_list_remove(&roots_xdg_surface->view->link); - view_finish(roots_xdg_surface->view); - free(roots_xdg_surface->view); + view_destroy(roots_xdg_surface->view); free(roots_xdg_surface); } @@ -333,7 +331,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { roots_surface->new_popup.notify = handle_new_popup; wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); - struct roots_view *view = view_create(); + struct roots_view *view = view_create(desktop); if (!view) { free(roots_surface); return; @@ -342,7 +340,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->xdg_surface_v6 = surface; view->roots_xdg_surface_v6 = roots_surface; - view->wlr_surface = surface->surface; view->activate = activate; view->resize = resize; view->move_resize = move_resize; @@ -356,8 +353,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->width = box.width; view->height = box.height; - view_init(view, desktop); - wl_list_insert(&desktop->views, &view->link); - + view_map(view, surface->surface); view_setup(view); } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 56f068ea..f95e5f81 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -109,8 +109,6 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) { static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); - struct wlr_xwayland_surface *xwayland_surface = - roots_surface->view->xwayland_surface; wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_configure.link); wl_list_remove(&roots_surface->request_move.link); @@ -118,11 +116,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_surface->request_maximize.link); wl_list_remove(&roots_surface->map_notify.link); wl_list_remove(&roots_surface->unmap_notify.link); - if (xwayland_surface->mapped) { - wl_list_remove(&roots_surface->view->link); - } - view_finish(roots_surface->view); - free(roots_surface->view); + view_destroy(roots_surface->view); free(roots_surface); } @@ -231,22 +225,13 @@ static void handle_map_notify(struct wl_listener *listener, void *data) { wl_container_of(listener, roots_surface, map_notify); struct wlr_xwayland_surface *xsurface = data; struct roots_view *view = roots_surface->view; - struct roots_desktop *desktop = view->desktop; - view->wlr_surface = xsurface->surface; view->x = xsurface->x; view->y = xsurface->y; view->width = xsurface->surface->current->width; view->height = xsurface->surface->current->height; - wl_list_insert(&desktop->views, &view->link); - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, - parent_link) { - subsurface_create(view, subsurface); - } - - view_damage_whole(view); + view_map(view, xsurface->surface); roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&xsurface->surface->events.commit, @@ -260,22 +245,7 @@ static void handle_unmap_notify(struct wl_listener *listener, void *data) { wl_list_remove(&roots_surface->surface_commit.link); - view_damage_whole(view); - - struct roots_view_child *child, *tmp; - wl_list_for_each_safe(child, tmp, &view->children, link) { - child->destroy(child); - } - - if (view->fullscreen_output != NULL) { - output_damage_whole(view->fullscreen_output); - view->fullscreen_output->fullscreen_view = NULL; - view->fullscreen_output = NULL; - } - - view->wlr_surface = NULL; - view->width = view->height = 0; - wl_list_remove(&view->link); + view_unmap(view); } void handle_xwayland_surface(struct wl_listener *listener, void *data) { @@ -317,7 +287,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); - struct roots_view *view = view_create(); + struct roots_view *view = view_create(desktop); if (view == NULL) { free(roots_surface); return; @@ -330,7 +300,6 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->xwayland_surface = surface; view->roots_xwayland_surface = roots_surface; - view->wlr_surface = surface->surface; view->activate = activate; view->resize = resize; view->move = move; @@ -339,8 +308,8 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->set_fullscreen = set_fullscreen; view->close = close; roots_surface->view = view; - view_init(view, desktop); - wl_list_insert(&desktop->views, &view->link); + + view_map(view, surface->surface); if (!surface->override_redirect) { if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) { From 3f072bedd98969974ec1d3e8ffd9bae4150e52d4 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 10 Mar 2018 11:18:50 +0100 Subject: [PATCH 03/52] xdg-shell-v6: add map signal --- include/rootston/view.h | 2 ++ include/wlr/types/wlr_xdg_shell_v6.h | 5 ++-- rootston/desktop.c | 16 +++++++++--- rootston/output.c | 7 ++++- rootston/xdg_shell_v6.c | 38 ++++++++++++++++++++++------ types/wlr_xdg_shell_v6.c | 18 +++++++++++-- 6 files changed, 70 insertions(+), 16 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 66a0cb3d..0844a6da 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -27,6 +27,8 @@ struct roots_xdg_surface_v6 { struct wl_listener destroy; struct wl_listener new_popup; + struct wl_listener map; + struct wl_listener unmap; struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 7dc746ce..959d420f 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -107,8 +107,7 @@ struct wlr_xdg_surface_v6 { struct wl_list popups; // wlr_xdg_popup_v6::link - bool configured; - bool added; + bool added, configured, mapped; uint32_t configure_serial; struct wl_event_source *configure_idle; uint32_t configure_next_serial; @@ -127,6 +126,8 @@ struct wlr_xdg_surface_v6 { struct wl_signal destroy; struct wl_signal ping_timeout; struct wl_signal new_popup; + struct wl_signal map; + struct wl_signal unmap; struct wl_signal request_maximize; struct wl_signal request_fullscreen; diff --git a/rootston/desktop.c b/rootston/desktop.c index 66c7ac2b..278f4fea 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -54,7 +54,8 @@ void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) { box->height += (view->border_width * 2 + view->titlebar_height); } -enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, double sy) { +enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, + double sy) { if (!view->decorated) { return ROOTS_DECO_PART_NONE; } @@ -94,9 +95,15 @@ enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, doub static void view_update_output(const struct roots_view *view, const struct wlr_box *before) { struct roots_desktop *desktop = view->desktop; - struct roots_output *output; + + if (view->wlr_surface == NULL) { + return; + } + struct wlr_box box; view_get_box(view, &box); + + struct roots_output *output; wl_list_for_each(output, &desktop->outputs, link) { bool intersected = before != NULL && wlr_output_layout_intersects( desktop->layout, output->wlr_output, before); @@ -479,7 +486,10 @@ void view_initial_focus(struct roots_view *view) { void view_setup(struct roots_view *view) { view_initial_focus(view); - view_center(view); + if (view->fullscreen_output == NULL) { + view_center(view); + } + view_update_output(view, NULL); } diff --git a/rootston/output.c b/rootston/output.c index 4d0a9c05..adcbb961 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -501,7 +501,9 @@ static void render_output(struct roots_output *output) { goto renderer_end; } - view_for_each_surface(view, render_surface, &data); + if (view->wlr_surface != NULL) { + view_for_each_surface(view, render_surface, &data); + } // During normal rendering the xwayland window tree isn't traversed // because all windows are rendered. Here we only want to render @@ -570,6 +572,9 @@ void output_damage_whole(struct roots_output *output) { static bool view_accept_damage(struct roots_output *output, struct roots_view *view) { + if (view->wlr_surface == NULL) { + return false; + } if (output->fullscreen_view == NULL) { return true; } diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index c49bd911..4591f642 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -243,6 +243,10 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + if (!surface->mapped) { + return; + } + view_apply_damage(view); struct wlr_box size; @@ -277,6 +281,28 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { popup_create(roots_xdg_surface->view, wlr_popup); } +static void handle_map(struct wl_listener *listener, void *data) { + struct roots_xdg_surface_v6 *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, map); + struct roots_view *view = roots_xdg_surface->view; + + struct wlr_box box; + get_size(view, &box); + view->width = box.width; + view->height = box.height; + + view_map(view, view->xdg_surface_v6->surface); + view_setup(view); +} + +static void handle_unmap(struct wl_listener *listener, void *data) { + struct roots_xdg_surface_v6 *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, unmap); + struct roots_view *view = roots_xdg_surface->view; + + view_unmap(view); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); @@ -317,6 +343,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { &roots_surface->surface_commit); roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); + roots_surface->map.notify = handle_map; + wl_signal_add(&surface->events.map, &roots_surface->map); + roots_surface->unmap.notify = handle_unmap; + wl_signal_add(&surface->events.unmap, &roots_surface->unmap); roots_surface->request_move.notify = handle_request_move; wl_signal_add(&surface->events.request_move, &roots_surface->request_move); roots_surface->request_resize.notify = handle_request_resize; @@ -347,12 +377,4 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->set_fullscreen = set_fullscreen; view->close = close; roots_surface->view = view; - - struct wlr_box box; - get_size(view, &box); - view->width = box.width; - view->height = box.height; - - view_map(view, surface->surface); - view_setup(view); } diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index e07d78a1..18f7393d 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -481,6 +481,7 @@ static void xdg_popup_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_popup_resource(resource); if (surface != NULL) { + // TODO: don't destroy the surface, unmap it xdg_surface_destroy(surface); } } @@ -792,6 +793,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); if (surface != NULL) { + // TODO: don't destroy the surface, unmap it xdg_surface_destroy(surface); } } @@ -1172,9 +1174,19 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, break; } - if (surface->configured && !surface->added) { + if (!surface->added) { surface->added = true; - wlr_signal_emit_safe(&surface->client->shell->events.new_surface, surface); + wlr_signal_emit_safe(&surface->client->shell->events.new_surface, + surface); + } + if (surface->configured && wlr_surface_has_buffer(surface->surface) && + !surface->mapped) { + surface->mapped = true; + wlr_signal_emit_safe(&surface->events.map, surface); + } + if (surface->configured && !wlr_surface_has_buffer(surface->surface) && + surface->mapped) { + // TODO: unmap the surface } } @@ -1249,6 +1261,8 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.ping_timeout); wl_signal_init(&surface->events.new_popup); + wl_signal_init(&surface->events.map); + wl_signal_init(&surface->events.unmap); wl_signal_add(&surface->surface->events.destroy, &surface->surface_destroy_listener); From 2d0db169422b74e5ef7c07965c376273c7bb2961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 7 Mar 2018 15:41:12 +0100 Subject: [PATCH 04/52] render: Flip textures in case of inverted_y --- include/wlr/render.h | 1 + render/gles2/renderer.c | 3 ++- render/gles2/shaders.c | 7 ++++++- render/gles2/texture.c | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/wlr/render.h b/include/wlr/render.h index 747603da..77449556 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -85,6 +85,7 @@ struct wlr_texture { bool valid; uint32_t format; int width, height; + bool inverted_y; struct wl_signal destroy_signal; struct wl_resource *resource; }; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index ad739cf8..ba03f599 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -179,7 +179,8 @@ static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, wlr_texture_bind(texture); GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); - GL_CALL(glUniform1f(2, alpha)); + GL_CALL(glUniform1i(1, texture->inverted_y)); + GL_CALL(glUniform1f(3, alpha)); draw_quad(); return true; } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 46a10248..38c61f9c 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -50,6 +50,7 @@ const GLchar ellipse_fragment_src[] = // Textured quads const GLchar vertex_src[] = "uniform mat4 proj;" +"uniform bool invert_y;" "attribute vec2 pos;" "attribute vec2 texcoord;" "varying vec2 v_texcoord;" @@ -69,7 +70,11 @@ const GLchar vertex_src[] = "}" "void main() {" " gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" -" v_texcoord = texcoord;" +" if (invert_y) {" +" v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);" +" } else {" +" v_texcoord = texcoord;" +" }" "}"; const GLchar fragment_src_rgba[] = diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 241b94a8..d25d1809 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -164,6 +164,7 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, EGLint inverted_y; 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 pixel_format *pf; From 1f8854f2172b124572f53976b9067fc4ef33a8a1 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 12 Mar 2018 09:00:59 +0100 Subject: [PATCH 05/52] rootston: remove xdg-shell-v6 map/unmap listeners on destroy --- rootston/xdg_shell_v6.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 4591f642..12e22afb 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -309,6 +309,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_xdg_surface->surface_commit.link); wl_list_remove(&roots_xdg_surface->destroy.link); wl_list_remove(&roots_xdg_surface->new_popup.link); + wl_list_remove(&roots_xdg_surface->map.link); + wl_list_remove(&roots_xdg_surface->unmap.link); wl_list_remove(&roots_xdg_surface->request_move.link); wl_list_remove(&roots_xdg_surface->request_resize.link); wl_list_remove(&roots_xdg_surface->request_maximize.link); From 6ac3534df6ce1ac35932fb71584675d32507fed7 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 12 Mar 2018 09:17:06 +0100 Subject: [PATCH 06/52] rootston: add destroy to view interface --- include/rootston/view.h | 1 + rootston/desktop.c | 4 ++++ rootston/wl_shell.c | 22 ++++++++++++++-------- rootston/xdg_shell.c | 21 +++++++++++++-------- rootston/xdg_shell_v6.c | 30 +++++++++++++++++------------- rootston/xwayland.c | 14 ++++++++++---- 6 files changed, 59 insertions(+), 33 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 0844a6da..1e5c0933 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -142,6 +142,7 @@ struct roots_view { void (*maximize)(struct roots_view *view, bool maximized); void (*set_fullscreen)(struct roots_view *view, bool fullscreen); void (*close)(struct roots_view *view); + void (*destroy)(struct roots_view *view); }; struct roots_view_child { diff --git a/rootston/desktop.c b/rootston/desktop.c index 278f4fea..19b7768c 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -422,6 +422,10 @@ void view_destroy(struct roots_view *view) { wl_signal_emit(&view->events.destroy, view); + if (view->destroy) { + view->destroy(view); + } + free(view); } diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 6326d9d7..d58f030a 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -78,6 +78,19 @@ static void close(struct roots_view *view) { wl_client_destroy(surf->client); } +static void destroy(struct roots_view *view) { + assert(view->type == ROOTS_WL_SHELL_VIEW); + struct roots_wl_shell_surface *roots_surface = view->roots_wl_shell_surface; + wl_list_remove(&roots_surface->destroy.link); + wl_list_remove(&roots_surface->request_move.link); + wl_list_remove(&roots_surface->request_resize.link); + wl_list_remove(&roots_surface->request_maximize.link); + wl_list_remove(&roots_surface->request_fullscreen.link); + wl_list_remove(&roots_surface->set_state.link); + wl_list_remove(&roots_surface->surface_commit.link); + free(roots_surface); +} + static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, request_move); @@ -174,15 +187,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); - wl_list_remove(&roots_surface->destroy.link); - wl_list_remove(&roots_surface->request_move.link); - wl_list_remove(&roots_surface->request_resize.link); - wl_list_remove(&roots_surface->request_maximize.link); - wl_list_remove(&roots_surface->request_fullscreen.link); - wl_list_remove(&roots_surface->set_state.link); - wl_list_remove(&roots_surface->surface_commit.link); view_destroy(roots_surface->view); - free(roots_surface); } void handle_wl_shell_surface(struct wl_listener *listener, void *data) { @@ -238,6 +243,7 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { view->roots_wl_shell_surface = roots_surface; view->resize = resize; view->close = close; + view->destroy = destroy; roots_surface->view = view; view_map(view, surface->surface); diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 1733eb4e..24c57bd5 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -180,6 +180,18 @@ static void close(struct roots_view *view) { } } +static void destroy(struct roots_view *view) { + struct roots_xdg_surface *roots_xdg_surface = view->roots_xdg_surface; + wl_list_remove(&roots_xdg_surface->surface_commit.link); + wl_list_remove(&roots_xdg_surface->destroy.link); + wl_list_remove(&roots_xdg_surface->new_popup.link); + wl_list_remove(&roots_xdg_surface->request_move.link); + wl_list_remove(&roots_xdg_surface->request_resize.link); + wl_list_remove(&roots_xdg_surface->request_maximize.link); + wl_list_remove(&roots_xdg_surface->request_fullscreen.link); + free(roots_xdg_surface); +} + static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_move); @@ -280,15 +292,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); - wl_list_remove(&roots_xdg_surface->surface_commit.link); - wl_list_remove(&roots_xdg_surface->destroy.link); - wl_list_remove(&roots_xdg_surface->new_popup.link); - wl_list_remove(&roots_xdg_surface->request_move.link); - wl_list_remove(&roots_xdg_surface->request_resize.link); - wl_list_remove(&roots_xdg_surface->request_maximize.link); - wl_list_remove(&roots_xdg_surface->request_fullscreen.link); view_destroy(roots_xdg_surface->view); - free(roots_xdg_surface); } void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { @@ -346,6 +350,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { view->maximize = maximize; view->set_fullscreen = set_fullscreen; view->close = close; + view->destroy = destroy; roots_surface->view = view; struct wlr_box box; diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 12e22afb..1f6f25eb 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -180,6 +180,21 @@ static void close(struct roots_view *view) { } } +static void destroy(struct roots_view *view) { + assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); + struct roots_xdg_surface_v6 *roots_xdg_surface = view->roots_xdg_surface_v6; + wl_list_remove(&roots_xdg_surface->surface_commit.link); + wl_list_remove(&roots_xdg_surface->destroy.link); + wl_list_remove(&roots_xdg_surface->new_popup.link); + wl_list_remove(&roots_xdg_surface->map.link); + wl_list_remove(&roots_xdg_surface->unmap.link); + wl_list_remove(&roots_xdg_surface->request_move.link); + wl_list_remove(&roots_xdg_surface->request_resize.link); + wl_list_remove(&roots_xdg_surface->request_maximize.link); + wl_list_remove(&roots_xdg_surface->request_fullscreen.link); + free(roots_xdg_surface); +} + static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_move); @@ -298,25 +313,13 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, unmap); - struct roots_view *view = roots_xdg_surface->view; - - view_unmap(view); + view_unmap(roots_xdg_surface->view); } static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); - wl_list_remove(&roots_xdg_surface->surface_commit.link); - wl_list_remove(&roots_xdg_surface->destroy.link); - wl_list_remove(&roots_xdg_surface->new_popup.link); - wl_list_remove(&roots_xdg_surface->map.link); - wl_list_remove(&roots_xdg_surface->unmap.link); - wl_list_remove(&roots_xdg_surface->request_move.link); - wl_list_remove(&roots_xdg_surface->request_resize.link); - wl_list_remove(&roots_xdg_surface->request_maximize.link); - wl_list_remove(&roots_xdg_surface->request_fullscreen.link); view_destroy(roots_xdg_surface->view); - free(roots_xdg_surface); } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { @@ -378,5 +381,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->maximize = maximize; view->set_fullscreen = set_fullscreen; view->close = close; + view->destroy = destroy; roots_surface->view = view; } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index f95e5f81..53331b1f 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -106,9 +106,9 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) { wlr_xwayland_surface_set_fullscreen(view->xwayland_surface, fullscreen); } -static void handle_destroy(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, destroy); +static void destroy(struct roots_view *view) { + assert(view->type == ROOTS_XWAYLAND_VIEW); + struct roots_xwayland_surface *roots_surface = view->roots_xwayland_surface; wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_configure.link); wl_list_remove(&roots_surface->request_move.link); @@ -116,10 +116,15 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_surface->request_maximize.link); wl_list_remove(&roots_surface->map_notify.link); wl_list_remove(&roots_surface->unmap_notify.link); - view_destroy(roots_surface->view); free(roots_surface); } +static void handle_destroy(struct wl_listener *listener, void *data) { + struct roots_xwayland_surface *roots_surface = + wl_container_of(listener, roots_surface, destroy); + view_destroy(roots_surface->view); +} + static void handle_request_configure(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_configure); @@ -307,6 +312,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->maximize = maximize; view->set_fullscreen = set_fullscreen; view->close = close; + view->destroy = destroy; roots_surface->view = view; view_map(view, surface->surface); From adec3f5c0fec7cc3aae5c68128d23dfe24950fb3 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 12 Mar 2018 10:41:57 +0100 Subject: [PATCH 07/52] xdg-shell-v6: add unmap support, add more protocol errors --- types/wlr_xdg_shell_v6.c | 237 ++++++++++++++++++++++++--------------- 1 file changed, 148 insertions(+), 89 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 18f7393d..5da25f62 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -34,7 +34,7 @@ struct wlr_xdg_positioner_v6 { }; -static void resource_destroy(struct wl_client *client, +static void resource_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } @@ -159,22 +159,16 @@ static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( } -static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { +static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { + assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); + // TODO: probably need to ungrab before this event - wlr_signal_emit_safe(&surface->events.destroy, surface); - - if (surface->configure_idle) { - wl_event_source_remove(surface->configure_idle); - } - - struct wlr_xdg_surface_v6_configure *configure, *tmp; - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - free(configure); - } + wlr_signal_emit_safe(&surface->events.unmap, surface); if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { wl_resource_set_user_data(surface->toplevel_state->resource, NULL); free(surface->toplevel_state); + surface->toplevel_state = NULL; } if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { @@ -185,16 +179,6 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { xdg_shell_popup_grab_from_seat(surface->client->shell, surface->popup_state->seat); - struct wlr_xdg_surface_v6 *topmost = - xdg_popup_grab_get_topmost(grab); - - if (topmost != surface) { - wl_resource_post_error(surface->client->resource, - ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was destroyed while it was not the topmost " - "popup."); - } - wl_list_remove(&surface->popup_state->grab_link); if (wl_list_empty(&grab->popups)) { @@ -209,16 +193,47 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { wl_list_remove(&surface->popup_state->link); free(surface->popup_state); + surface->popup_state = NULL; } + surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; + free(surface->title); + surface->title = NULL; + free(surface->app_id); + surface->app_id = NULL; + + surface->added = surface->configured = surface->mapped = false; + surface->configure_serial = 0; + if (surface->configure_idle) { + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + } + surface->configure_next_serial = 0; + + struct wlr_xdg_surface_v6_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + wl_list_remove(&configure->link); + free(configure); + } + + surface->has_next_geometry = false; + memset(surface->geometry, 0, sizeof(struct wlr_box)); + memset(surface->next_geometry, 0, sizeof(struct wlr_box)); +} + +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { + if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { + xdg_surface_unmap(surface); + } + + wlr_signal_emit_safe(&surface->events.destroy, surface); + wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->link); wl_list_remove(&surface->surface_destroy_listener.link); wlr_surface_set_role_committed(surface->surface, NULL, NULL); free(surface->geometry); free(surface->next_geometry); - free(surface->title); - free(surface->app_id); free(surface); } @@ -237,10 +252,9 @@ static void xdg_positioner_destroy(struct wl_resource *resource) { struct wlr_xdg_positioner_v6 *positioner = xdg_positioner_from_resource(resource); free(positioner); - } -static void xdg_positioner_protocol_set_size(struct wl_client *client, +static void xdg_positioner_handle_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_positioner_v6 *positioner = xdg_positioner_from_resource(resource); @@ -256,7 +270,7 @@ static void xdg_positioner_protocol_set_size(struct wl_client *client, positioner->size.height = height; } -static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, +static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_positioner_v6 *positioner = @@ -275,7 +289,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, positioner->anchor_rect.height = height; } -static void xdg_positioner_protocol_set_anchor(struct wl_client *client, +static void xdg_positioner_handle_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { struct wlr_xdg_positioner_v6 *positioner = xdg_positioner_from_resource(resource); @@ -293,7 +307,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client, positioner->anchor = anchor; } -static void xdg_positioner_protocol_set_gravity(struct wl_client *client, +static void xdg_positioner_handle_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { struct wlr_xdg_positioner_v6 *positioner = xdg_positioner_from_resource(resource); @@ -311,7 +325,7 @@ static void xdg_positioner_protocol_set_gravity(struct wl_client *client, positioner->gravity = gravity; } -static void xdg_positioner_protocol_set_constraint_adjustment( +static void xdg_positioner_handle_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { struct wlr_xdg_positioner_v6 *positioner = @@ -320,7 +334,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( positioner->constraint_adjustment = constraint_adjustment; } -static void xdg_positioner_protocol_set_offset(struct wl_client *client, +static void xdg_positioner_handle_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { struct wlr_xdg_positioner_v6 *positioner = xdg_positioner_from_resource(resource); @@ -331,17 +345,17 @@ static void xdg_positioner_protocol_set_offset(struct wl_client *client, static const struct zxdg_positioner_v6_interface zxdg_positioner_v6_implementation = { - .destroy = resource_destroy, - .set_size = xdg_positioner_protocol_set_size, - .set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, - .set_anchor = xdg_positioner_protocol_set_anchor, - .set_gravity = xdg_positioner_protocol_set_gravity, + .destroy = resource_handle_destroy, + .set_size = xdg_positioner_handle_set_size, + .set_anchor_rect = xdg_positioner_handle_set_anchor_rect, + .set_anchor = xdg_positioner_handle_set_anchor, + .set_gravity = xdg_positioner_handle_set_gravity, .set_constraint_adjustment = - xdg_positioner_protocol_set_constraint_adjustment, - .set_offset = xdg_positioner_protocol_set_offset, + xdg_positioner_handle_set_constraint_adjustment, + .set_offset = xdg_positioner_handle_set_offset, }; -static void xdg_shell_create_positioner(struct wl_client *wl_client, +static void xdg_shell_handle_create_positioner(struct wl_client *wl_client, struct wl_resource *resource, uint32_t id) { struct wlr_xdg_positioner_v6 *positioner = calloc(1, sizeof(struct wlr_xdg_positioner_v6)); @@ -430,7 +444,7 @@ static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource( return wl_resource_get_user_data(resource); } -static void xdg_popup_protocol_grab(struct wl_client *client, +static void xdg_popup_handle_grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface_v6 *surface = @@ -472,17 +486,37 @@ static void xdg_popup_protocol_grab(struct wl_client *client, &popup_grab->keyboard_grab); } +static void xdg_popup_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = + xdg_surface_from_xdg_popup_resource(resource); + struct wlr_xdg_popup_grab_v6 *grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + surface->popup_state->seat); + struct wlr_xdg_surface_v6 *topmost = + xdg_popup_grab_get_topmost(grab); + + if (topmost != surface) { + wl_resource_post_error(surface->client->resource, + ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was destroyed while it was not the topmost " + "popup"); + return; + } + + wl_resource_destroy(resource); +} + static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { - .destroy = resource_destroy, - .grab = xdg_popup_protocol_grab, + .destroy = xdg_popup_handle_destroy, + .grab = xdg_popup_handle_grab, }; static void xdg_popup_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_popup_resource(resource); if (surface != NULL) { - // TODO: don't destroy the surface, unmap it - xdg_surface_destroy(surface); + xdg_surface_unmap(surface); } } @@ -495,7 +529,7 @@ static struct wlr_xdg_surface_v6 *xdg_surface_from_resource( return wl_resource_get_user_data(resource); } -static void xdg_surface_get_popup(struct wl_client *client, +static void xdg_surface_handle_get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, struct wl_resource *positioner_resource) { @@ -557,7 +591,7 @@ static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource( return wl_resource_get_user_data(resource); } -static void xdg_toplevel_protocol_set_parent(struct wl_client *client, +static void xdg_toplevel_handle_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -570,7 +604,7 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client, surface->toplevel_state->parent = parent; } -static void xdg_toplevel_protocol_set_title(struct wl_client *client, +static void xdg_toplevel_handle_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -584,7 +618,7 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client, surface->title = tmp; } -static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, +static void xdg_toplevel_handle_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -598,7 +632,7 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, surface->app_id = tmp; } -static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, +static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { struct wlr_xdg_surface_v6 *surface = @@ -629,7 +663,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event); } -static void xdg_toplevel_protocol_move(struct wl_client *client, +static void xdg_toplevel_handle_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface_v6 *surface = @@ -658,7 +692,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_move, &event); } -static void xdg_toplevel_protocol_resize(struct wl_client *client, +static void xdg_toplevel_handle_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { struct wlr_xdg_surface_v6 *surface = @@ -688,7 +722,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_resize, &event); } -static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, +static void xdg_toplevel_handle_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -696,7 +730,7 @@ static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, surface->toplevel_state->next.max_height = height; } -static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, +static void xdg_toplevel_handle_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -704,7 +738,7 @@ static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, surface->toplevel_state->next.min_height = height; } -static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, +static void xdg_toplevel_handle_set_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -712,7 +746,7 @@ static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_maximize, surface); } -static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, +static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -720,7 +754,7 @@ static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_maximize, surface); } -static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -741,7 +775,7 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); } -static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -757,7 +791,7 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); } -static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, +static void xdg_toplevel_handle_set_minimized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -766,20 +800,20 @@ static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = { - .destroy = resource_destroy, - .set_parent = xdg_toplevel_protocol_set_parent, - .set_title = xdg_toplevel_protocol_set_title, - .set_app_id = xdg_toplevel_protocol_set_app_id, - .show_window_menu = xdg_toplevel_protocol_show_window_menu, - .move = xdg_toplevel_protocol_move, - .resize = xdg_toplevel_protocol_resize, - .set_max_size = xdg_toplevel_protocol_set_max_size, - .set_min_size = xdg_toplevel_protocol_set_min_size, - .set_maximized = xdg_toplevel_protocol_set_maximized, - .unset_maximized = xdg_toplevel_protocol_unset_maximized, - .set_fullscreen = xdg_toplevel_protocol_set_fullscreen, - .unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, - .set_minimized = xdg_toplevel_protocol_set_minimized + .destroy = resource_handle_destroy, + .set_parent = xdg_toplevel_handle_set_parent, + .set_title = xdg_toplevel_handle_set_title, + .set_app_id = xdg_toplevel_handle_set_app_id, + .show_window_menu = xdg_toplevel_handle_show_window_menu, + .move = xdg_toplevel_handle_move, + .resize = xdg_toplevel_handle_resize, + .set_max_size = xdg_toplevel_handle_set_max_size, + .set_min_size = xdg_toplevel_handle_set_min_size, + .set_maximized = xdg_toplevel_handle_set_maximized, + .unset_maximized = xdg_toplevel_handle_unset_maximized, + .set_fullscreen = xdg_toplevel_handle_set_fullscreen, + .unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, + .set_minimized = xdg_toplevel_handle_set_minimized }; static void xdg_surface_resource_destroy(struct wl_resource *resource) { @@ -793,12 +827,11 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); if (surface != NULL) { - // TODO: don't destroy the surface, unmap it - xdg_surface_destroy(surface); + xdg_surface_unmap(surface); } } -static void xdg_surface_get_toplevel(struct wl_client *client, +static void xdg_surface_handle_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); @@ -840,7 +873,7 @@ static void wlr_xdg_toplevel_v6_ack_configure( surface->toplevel_state->pending.height = 0; } -static void xdg_surface_ack_configure(struct wl_client *client, +static void xdg_surface_handle_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); @@ -889,7 +922,7 @@ static void xdg_surface_ack_configure(struct wl_client *client, free(configure); } -static void xdg_surface_set_window_geometry(struct wl_client *client, +static void xdg_surface_handle_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); @@ -906,15 +939,27 @@ static void xdg_surface_set_window_geometry(struct wl_client *client, surface->next_geometry->width = width; surface->next_geometry->x = x; surface->next_geometry->y = y; +} +static void xdg_surface_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource); + + if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { + wlr_log(L_ERROR, "Tried to destroy an xdg_surface before its role " + "object"); + return; + } + + wl_resource_destroy(resource); } static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { - .destroy = resource_destroy, - .get_toplevel = xdg_surface_get_toplevel, - .get_popup = xdg_surface_get_popup, - .ack_configure = xdg_surface_ack_configure, - .set_window_geometry = xdg_surface_set_window_geometry, + .destroy = xdg_surface_handle_destroy, + .get_toplevel = xdg_surface_handle_get_toplevel, + .get_popup = xdg_surface_handle_get_popup, + .ack_configure = xdg_surface_handle_ack_configure, + .set_window_geometry = xdg_surface_handle_set_window_geometry, }; static bool wlr_xdg_surface_v6_toplevel_state_compare( @@ -1186,7 +1231,7 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, } if (surface->configured && !wlr_surface_has_buffer(surface->surface) && surface->mapped) { - // TODO: unmap the surface + xdg_surface_unmap(surface); } } @@ -1199,7 +1244,7 @@ static struct wlr_xdg_client_v6 *xdg_client_from_resource( return wl_resource_get_user_data(resource); } -static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, +static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *client_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_xdg_client_v6 *client = @@ -1277,7 +1322,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, wl_list_insert(&client->surfaces, &surface->link); } -static void xdg_shell_pong(struct wl_client *wl_client, +static void xdg_shell_handle_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); @@ -1289,11 +1334,25 @@ static void xdg_shell_pong(struct wl_client *wl_client, client->ping_serial = 0; } +static void xdg_shell_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) { + struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource); + + if (!wl_list_empty(&client->surfaces)) { + wl_resource_post_error(client->resource, + ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES, + "xdg_wm_base was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + static const struct zxdg_shell_v6_interface xdg_shell_impl = { - .destroy = resource_destroy, - .create_positioner = xdg_shell_create_positioner, - .get_xdg_surface = xdg_shell_get_xdg_surface, - .pong = xdg_shell_pong, + .destroy = xdg_shell_handle_destroy, + .create_positioner = xdg_shell_handle_create_positioner, + .get_xdg_surface = xdg_shell_handle_get_xdg_surface, + .pong = xdg_shell_handle_pong, }; static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { From 42637a52cf2779ec05f0fdb97df416e21438a77b Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 12 Mar 2018 10:42:41 +0100 Subject: [PATCH 08/52] rootston: don't segfault when getting size of an unmapped xdg-shell view --- rootston/xdg_shell_v6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 1f6f25eb..c81cd16a 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -63,9 +63,11 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) { if (surface->geometry->width > 0 && surface->geometry->height > 0) { box->width = surface->geometry->width; box->height = surface->geometry->height; - } else { + } else if (view->wlr_surface != NULL) { box->width = view->wlr_surface->current->width; box->height = view->wlr_surface->current->height; + } else { + box->width = box->height = 0; } } From c1c88bfe5d88b7f6330f5ce5be04ef6951123c3d Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Mar 2018 12:31:45 +0100 Subject: [PATCH 09/52] rootston: destroy seat view on unmap --- include/rootston/seat.h | 1 + include/rootston/view.h | 1 + rootston/desktop.c | 1 + rootston/seat.c | 9 +++++++++ 4 files changed, 12 insertions(+) diff --git a/include/rootston/seat.h b/include/rootston/seat.h index cc0293b5..0b1dbe2d 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -39,6 +39,7 @@ struct roots_seat_view { struct wl_list link; // roots_seat::views + struct wl_listener view_unmap; struct wl_listener view_destroy; }; diff --git a/include/rootston/view.h b/include/rootston/view.h index 1e5c0933..92d1feb5 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -130,6 +130,7 @@ struct roots_view { struct wl_listener new_subsurface; struct { + struct wl_signal unmap; struct wl_signal destroy; } events; diff --git a/rootston/desktop.c b/rootston/desktop.c index 19b7768c..afe2c221 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -30,6 +30,7 @@ struct roots_view *view_create(struct roots_desktop *desktop) { } view->desktop = desktop; view->alpha = 1.0f; + wl_signal_init(&view->events.unmap); wl_signal_init(&view->events.destroy); wl_list_init(&view->children); return view; diff --git a/rootston/seat.c b/rootston/seat.c index 9acbb737..c4535c7c 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -645,6 +645,7 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) { seat->cursor->pointer_view = NULL; } + wl_list_remove(&seat_view->view_unmap.link); wl_list_remove(&seat_view->view_destroy.link); wl_list_remove(&seat_view->link); free(seat_view); @@ -657,6 +658,12 @@ static void seat_view_destroy(struct roots_seat_view *seat_view) { } } +static void seat_view_handle_unmap(struct wl_listener *listener, void *data) { + struct roots_seat_view *seat_view = + wl_container_of(listener, seat_view, view_unmap); + seat_view_destroy(seat_view); +} + static void seat_view_handle_destroy(struct wl_listener *listener, void *data) { struct roots_seat_view *seat_view = wl_container_of(listener, seat_view, view_destroy); @@ -675,6 +682,8 @@ static struct roots_seat_view *seat_add_view(struct roots_seat *seat, wl_list_insert(seat->views.prev, &seat_view->link); + seat_view->view_unmap.notify = seat_view_handle_unmap; + wl_signal_add(&view->events.unmap, &seat_view->view_unmap); seat_view->view_destroy.notify = seat_view_handle_destroy; wl_signal_add(&view->events.destroy, &seat_view->view_destroy); From 125138f1a0448927c26c0f8a2761fed2df09b6ad Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Mar 2018 12:34:29 +0100 Subject: [PATCH 10/52] rootston: unmap view after emitting destroy signal in view_destroy --- rootston/desktop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rootston/desktop.c b/rootston/desktop.c index afe2c221..b1e6f874 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -417,12 +417,12 @@ void view_destroy(struct roots_view *view) { return; } + wl_signal_emit(&view->events.destroy, view); + if (view->wlr_surface != NULL) { view_unmap(view); } - wl_signal_emit(&view->events.destroy, view); - if (view->destroy) { view->destroy(view); } From e74ddaaf10f1c8078cf078f55428b9e86776ca93 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Mar 2018 19:57:21 +0100 Subject: [PATCH 11/52] xdg-shell-v6: redesign the configure/ack_configure workflow --- include/wlr/types/wlr_xdg_shell_v6.h | 23 ++++++----------- rootston/output.c | 3 ++- rootston/xdg_shell_v6.c | 7 +++++ types/wlr_xdg_shell_v6.c | 38 ++++++++++++++++++---------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 959d420f..86a42181 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -62,19 +62,10 @@ enum wlr_xdg_surface_v6_role { }; struct wlr_xdg_toplevel_v6_state { - bool maximized; - bool fullscreen; - bool resizing; - bool activated; - - uint32_t width; - uint32_t height; - - uint32_t max_width; - uint32_t max_height; - - uint32_t min_width; - uint32_t min_height; + bool maximized, fullscreen, resizing, activated; + uint32_t width, height; + uint32_t max_width, max_height; + uint32_t min_width, min_height; }; struct wlr_xdg_toplevel_v6 { @@ -90,7 +81,8 @@ struct wlr_xdg_toplevel_v6 { struct wlr_xdg_surface_v6_configure { struct wl_list link; // wlr_xdg_surface_v6::configure_list uint32_t serial; - struct wlr_xdg_toplevel_v6_state state; + + struct wlr_xdg_toplevel_v6_state toplevel_state; // TODO: should be null-able }; struct wlr_xdg_surface_v6 { @@ -100,6 +92,7 @@ struct wlr_xdg_surface_v6 { struct wl_list link; // wlr_xdg_client_v6::surfaces enum wlr_xdg_surface_v6_role role; + // TODO: the _state prefix should be dropped union { struct wlr_xdg_toplevel_v6 *toplevel_state; struct wlr_xdg_popup_v6 *popup_state; @@ -118,7 +111,7 @@ struct wlr_xdg_surface_v6 { bool has_next_geometry; struct wlr_box *next_geometry; - struct wlr_box *geometry; + struct wlr_box *geometry; // TODO: should not be a pointer struct wl_listener surface_destroy_listener; diff --git a/rootston/output.c b/rootston/output.c index adcbb961..f772ea24 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -433,7 +433,8 @@ static void render_output(struct roots_output *output) { float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; // Check if we can delegate the fullscreen surface to the output - if (output->fullscreen_view != NULL) { + if (output->fullscreen_view != NULL && + output->fullscreen_view->wlr_surface != NULL) { struct roots_view *view = output->fullscreen_view; // Make sure the view is centered on screen diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index c81cd16a..84c76d16 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -385,4 +385,11 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->close = close; view->destroy = destroy; roots_surface->view = view; + + if (surface->toplevel_state->next.maximized) { + view_maximize(view, true); + } + if (surface->toplevel_state->next.fullscreen) { + view_set_fullscreen(view, true, NULL); + } } diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 5da25f62..8c2e9d58 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -868,9 +868,15 @@ static void wlr_xdg_toplevel_v6_ack_configure( struct wlr_xdg_surface_v6 *surface, struct wlr_xdg_surface_v6_configure *configure) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel_state->next = configure->state; - surface->toplevel_state->pending.width = 0; - surface->toplevel_state->pending.height = 0; + + surface->toplevel_state->current.maximized = + configure->toplevel_state.maximized; + surface->toplevel_state->current.fullscreen = + configure->toplevel_state.fullscreen; + surface->toplevel_state->current.resizing = + configure->toplevel_state.resizing; + surface->toplevel_state->current.activated = + configure->toplevel_state.activated; } static void xdg_surface_handle_ack_configure(struct wl_client *client, @@ -982,9 +988,9 @@ static bool wlr_xdg_surface_v6_toplevel_state_compare( } else { struct wlr_xdg_surface_v6_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = configure->state; - configured.width = configure->state.width; - configured.height = configure->state.height; + configured.state = configure->toplevel_state; + configured.width = configure->toplevel_state.width; + configured.height = configure->toplevel_state.height; } if (state->pending.activated != configured.state.activated) { @@ -1019,7 +1025,7 @@ static void wlr_xdg_toplevel_v6_send_configure( uint32_t *s; struct wl_array states; - configure->state = surface->toplevel_state->pending; + configure->toplevel_state = surface->toplevel_state->pending; wl_array_init(&states); if (surface->toplevel_state->pending.maximized) { @@ -1160,8 +1166,7 @@ static void wlr_xdg_surface_v6_toplevel_committed( struct wlr_xdg_surface_v6 *surface) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - if (!wlr_surface_has_buffer(surface->surface) - && !surface->toplevel_state->added) { + if (!surface->toplevel_state->added) { // on the first commit, send a configure request to tell the client it // is added wlr_xdg_surface_v6_schedule_configure(surface); @@ -1169,11 +1174,15 @@ static void wlr_xdg_surface_v6_toplevel_committed( return; } - if (!wlr_surface_has_buffer(surface->surface)) { - return; - } - - surface->toplevel_state->current = surface->toplevel_state->next; + // update state that doesn't need compositor approval + surface->toplevel_state->current.max_width = + surface->toplevel_state->next.max_width; + surface->toplevel_state->current.min_width = + surface->toplevel_state->next.min_width; + surface->toplevel_state->current.max_height = + surface->toplevel_state->next.max_height; + surface->toplevel_state->current.min_height = + surface->toplevel_state->next.min_height; } static void wlr_xdg_surface_v6_popup_committed( @@ -1482,6 +1491,7 @@ uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel_state->pending.width = width; surface->toplevel_state->pending.height = height; + wlr_log(L_DEBUG, "wlr_xdg_toplevel_v6_set_size %d", width); return wlr_xdg_surface_v6_schedule_configure(surface); } From 657e5c8c0d162958f96c45069767acfa56075843 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Mar 2018 22:05:35 +0100 Subject: [PATCH 12/52] xdg-shell-v6: changed wlr_xdg_surface_v6_configure.toplevel_state to be NULL if surface isn't a toplevel --- include/wlr/types/wlr_xdg_shell_v6.h | 2 +- types/wlr_xdg_shell_v6.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 86a42181..9140fa64 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -82,7 +82,7 @@ struct wlr_xdg_surface_v6_configure { struct wl_list link; // wlr_xdg_surface_v6::configure_list uint32_t serial; - struct wlr_xdg_toplevel_v6_state toplevel_state; // TODO: should be null-able + struct wlr_xdg_toplevel_v6_state *toplevel_state; }; struct wlr_xdg_surface_v6 { diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 8c2e9d58..5ea1fb8b 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -868,15 +868,19 @@ static void wlr_xdg_toplevel_v6_ack_configure( struct wlr_xdg_surface_v6 *surface, struct wlr_xdg_surface_v6_configure *configure) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + assert(configure->toplevel_state != NULL); surface->toplevel_state->current.maximized = - configure->toplevel_state.maximized; + configure->toplevel_state->maximized; surface->toplevel_state->current.fullscreen = - configure->toplevel_state.fullscreen; + configure->toplevel_state->fullscreen; surface->toplevel_state->current.resizing = - configure->toplevel_state.resizing; + configure->toplevel_state->resizing; surface->toplevel_state->current.activated = - configure->toplevel_state.activated; + configure->toplevel_state->activated; + + free(configure->toplevel_state); + configure->toplevel_state = NULL; } static void xdg_surface_handle_ack_configure(struct wl_client *client, @@ -988,9 +992,9 @@ static bool wlr_xdg_surface_v6_toplevel_state_compare( } else { struct wlr_xdg_surface_v6_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = configure->toplevel_state; - configured.width = configure->toplevel_state.width; - configured.height = configure->toplevel_state.height; + configured.state = *configure->toplevel_state; + configured.width = configure->toplevel_state->width; + configured.height = configure->toplevel_state->height; } if (state->pending.activated != configured.state.activated) { @@ -1025,7 +1029,12 @@ static void wlr_xdg_toplevel_v6_send_configure( uint32_t *s; struct wl_array states; - configure->toplevel_state = surface->toplevel_state->pending; + configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); + if (configure->toplevel_state == NULL) { + wlr_log(L_ERROR, "Allocation failed"); + return; + } + *configure->toplevel_state = surface->toplevel_state->pending; wl_array_init(&states); if (surface->toplevel_state->pending.maximized) { From 149209b72ed069f3c6026e6bf7ffb4ffff0de190 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Mar 2018 22:09:44 +0100 Subject: [PATCH 13/52] xdg-shell-v6: rename toplevel and popup fields in wlr_xdg_surface_v6 for consistency --- include/wlr/types/wlr_xdg_shell_v6.h | 5 +- rootston/xdg_shell_v6.c | 8 +- types/wlr_xdg_shell_v6.c | 172 +++++++++++++-------------- 3 files changed, 92 insertions(+), 93 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 9140fa64..2358feec 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -92,10 +92,9 @@ struct wlr_xdg_surface_v6 { struct wl_list link; // wlr_xdg_client_v6::surfaces enum wlr_xdg_surface_v6_role role; - // TODO: the _state prefix should be dropped union { - struct wlr_xdg_toplevel_v6 *toplevel_state; - struct wlr_xdg_popup_v6 *popup_state; + struct wlr_xdg_toplevel_v6 *toplevel; + struct wlr_xdg_popup_v6 *popup; }; struct wl_list popups; // wlr_xdg_popup_v6::link diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 84c76d16..59637105 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -85,7 +85,7 @@ static void apply_size_constraints(struct wlr_xdg_surface_v6 *surface, *dest_width = width; *dest_height = height; - struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel_state->current; + struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel->current; if (width < state->min_width) { *dest_width = state->min_width; } else if (state->max_width > 0 && @@ -236,7 +236,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) { return; } - view_maximize(view, surface->toplevel_state->next.maximized); + view_maximize(view, surface->toplevel->next.maximized); } static void handle_request_fullscreen(struct wl_listener *listener, @@ -386,10 +386,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->destroy = destroy; roots_surface->view = view; - if (surface->toplevel_state->next.maximized) { + if (surface->toplevel->next.maximized) { view_maximize(view, true); } - if (surface->toplevel_state->next.fullscreen) { + if (surface->toplevel->next.fullscreen) { view_set_fullscreen(view, true, NULL); } } diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 5ea1fb8b..214f818c 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -166,20 +166,20 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { wlr_signal_emit_safe(&surface->events.unmap, surface); if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - wl_resource_set_user_data(surface->toplevel_state->resource, NULL); - free(surface->toplevel_state); - surface->toplevel_state = NULL; + wl_resource_set_user_data(surface->toplevel->resource, NULL); + free(surface->toplevel); + surface->toplevel = NULL; } if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { - wl_resource_set_user_data(surface->popup_state->resource, NULL); + wl_resource_set_user_data(surface->popup->resource, NULL); - if (surface->popup_state->seat) { + if (surface->popup->seat) { struct wlr_xdg_popup_grab_v6 *grab = xdg_shell_popup_grab_from_seat(surface->client->shell, - surface->popup_state->seat); + surface->popup->seat); - wl_list_remove(&surface->popup_state->grab_link); + wl_list_remove(&surface->popup->grab_link); if (wl_list_empty(&grab->popups)) { if (grab->seat->pointer_state.grab == &grab->pointer_grab) { @@ -191,9 +191,9 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { } } - wl_list_remove(&surface->popup_state->link); - free(surface->popup_state); - surface->popup_state = NULL; + wl_list_remove(&surface->popup->link); + free(surface->popup); + surface->popup = NULL; } surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; @@ -452,8 +452,8 @@ static void xdg_popup_handle_grab(struct wl_client *client, struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); - if (surface->popup_state->committed) { - wl_resource_post_error(surface->popup_state->resource, + if (surface->popup->committed) { + wl_resource_post_error(surface->popup->resource, ZXDG_POPUP_V6_ERROR_INVALID_GRAB, "xdg_popup is already mapped"); return; @@ -465,10 +465,10 @@ static void xdg_popup_handle_grab(struct wl_client *client, struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); bool parent_is_toplevel = - surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + surface->popup->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup_state->parent)) { + (topmost != NULL && topmost != surface->popup->parent)) { wl_resource_post_error(surface->client->resource, ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, "xdg_popup was not created on the topmost popup"); @@ -476,9 +476,9 @@ static void xdg_popup_handle_grab(struct wl_client *client, } popup_grab->client = surface->client->client; - surface->popup_state->seat = seat_client->seat; + surface->popup->seat = seat_client->seat; - wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + wl_list_insert(&popup_grab->popups, &surface->popup->grab_link); wlr_seat_pointer_start_grab(seat_client->seat, &popup_grab->pointer_grab); @@ -492,7 +492,7 @@ static void xdg_popup_handle_destroy(struct wl_client *client, xdg_surface_from_xdg_popup_resource(resource); struct wlr_xdg_popup_grab_v6 *grab = xdg_shell_popup_grab_from_seat(surface->client->shell, - surface->popup_state->seat); + surface->popup->seat); struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(grab); @@ -552,33 +552,33 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, return; } - surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup_v6)); - if (!surface->popup_state) { + surface->popup = calloc(1, sizeof(struct wlr_xdg_popup_v6)); + if (!surface->popup) { wl_resource_post_no_memory(resource); return; } - surface->popup_state->resource = + surface->popup->resource = wl_resource_create(client, &zxdg_popup_v6_interface, wl_resource_get_version(resource), id); - if (surface->popup_state->resource == NULL) { - free(surface->popup_state); + if (surface->popup->resource == NULL) { + free(surface->popup); wl_resource_post_no_memory(resource); return; } surface->role = WLR_XDG_SURFACE_V6_ROLE_POPUP; - surface->popup_state->base = surface; - surface->popup_state->parent = parent; - surface->popup_state->geometry = + surface->popup->base = surface; + surface->popup->parent = parent; + surface->popup->geometry = xdg_positioner_get_geometry(positioner, surface, parent); - wl_list_insert(&parent->popups, &surface->popup_state->link); + wl_list_insert(&parent->popups, &surface->popup->link); - wl_resource_set_implementation(surface->popup_state->resource, + wl_resource_set_implementation(surface->popup->resource, &zxdg_popup_v6_implementation, surface, xdg_popup_resource_destroy); - wlr_signal_emit_safe(&parent->events.new_popup, surface->popup_state); + wlr_signal_emit_safe(&parent->events.new_popup, surface->popup); } @@ -601,7 +601,7 @@ static void xdg_toplevel_handle_set_parent(struct wl_client *client, parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); } - surface->toplevel_state->parent = parent; + surface->toplevel->parent = parent; } static void xdg_toplevel_handle_set_title(struct wl_client *client, @@ -641,7 +641,7 @@ static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { - wl_resource_post_error(surface->toplevel_state->resource, + wl_resource_post_error(surface->toplevel->resource, ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -672,7 +672,7 @@ static void xdg_toplevel_handle_move(struct wl_client *client, wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { - wl_resource_post_error(surface->toplevel_state->resource, + wl_resource_post_error(surface->toplevel->resource, ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -701,7 +701,7 @@ static void xdg_toplevel_handle_resize(struct wl_client *client, wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { - wl_resource_post_error(surface->toplevel_state->resource, + wl_resource_post_error(surface->toplevel->resource, ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -726,23 +726,23 @@ static void xdg_toplevel_handle_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.max_width = width; - surface->toplevel_state->next.max_height = height; + surface->toplevel->next.max_width = width; + surface->toplevel->next.max_height = height; } static void xdg_toplevel_handle_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.min_width = width; - surface->toplevel_state->next.min_height = height; + surface->toplevel->next.min_width = width; + surface->toplevel->next.min_height = height; } static void xdg_toplevel_handle_set_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.maximized = true; + surface->toplevel->next.maximized = true; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } @@ -750,7 +750,7 @@ static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.maximized = false; + surface->toplevel->next.maximized = false; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } @@ -764,7 +764,7 @@ static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, output = wlr_output_from_resource(output_resource); } - surface->toplevel_state->next.fullscreen = true; + surface->toplevel->next.fullscreen = true; struct wlr_xdg_toplevel_v6_set_fullscreen_event event = { .surface = surface, @@ -780,7 +780,7 @@ static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, struct wlr_xdg_surface_v6 *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.fullscreen = false; + surface->toplevel->next.fullscreen = false; struct wlr_xdg_toplevel_v6_set_fullscreen_event event = { .surface = surface, @@ -840,24 +840,24 @@ static void xdg_surface_handle_get_toplevel(struct wl_client *client, return; } - surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); - if (surface->toplevel_state == NULL) { + surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); + if (surface->toplevel == NULL) { wl_resource_post_no_memory(resource); return; } surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; - surface->toplevel_state->base = surface; + surface->toplevel->base = surface; struct wl_resource *toplevel_resource = wl_resource_create(client, &zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id); if (toplevel_resource == NULL) { - free(surface->toplevel_state); + free(surface->toplevel); wl_resource_post_no_memory(resource); return; } - surface->toplevel_state->resource = toplevel_resource; + surface->toplevel->resource = toplevel_resource; wl_resource_set_implementation(toplevel_resource, &zxdg_toplevel_v6_implementation, surface, @@ -870,13 +870,13 @@ static void wlr_xdg_toplevel_v6_ack_configure( assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); assert(configure->toplevel_state != NULL); - surface->toplevel_state->current.maximized = + surface->toplevel->current.maximized = configure->toplevel_state->maximized; - surface->toplevel_state->current.fullscreen = + surface->toplevel->current.fullscreen = configure->toplevel_state->fullscreen; - surface->toplevel_state->current.resizing = + surface->toplevel->current.resizing = configure->toplevel_state->resizing; - surface->toplevel_state->current.activated = + surface->toplevel->current.activated = configure->toplevel_state->activated; free(configure->toplevel_state); @@ -1034,10 +1034,10 @@ static void wlr_xdg_toplevel_v6_send_configure( wlr_log(L_ERROR, "Allocation failed"); return; } - *configure->toplevel_state = surface->toplevel_state->pending; + *configure->toplevel_state = surface->toplevel->pending; wl_array_init(&states); - if (surface->toplevel_state->pending.maximized) { + if (surface->toplevel->pending.maximized) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); @@ -1045,7 +1045,7 @@ static void wlr_xdg_toplevel_v6_send_configure( } *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; } - if (surface->toplevel_state->pending.fullscreen) { + if (surface->toplevel->pending.fullscreen) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); @@ -1053,7 +1053,7 @@ static void wlr_xdg_toplevel_v6_send_configure( } *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; } - if (surface->toplevel_state->pending.resizing) { + if (surface->toplevel->pending.resizing) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); @@ -1061,7 +1061,7 @@ static void wlr_xdg_toplevel_v6_send_configure( } *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; } - if (surface->toplevel_state->pending.activated) { + if (surface->toplevel->pending.activated) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); @@ -1070,15 +1070,15 @@ static void wlr_xdg_toplevel_v6_send_configure( *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; } - uint32_t width = surface->toplevel_state->pending.width; - uint32_t height = surface->toplevel_state->pending.height; + uint32_t width = surface->toplevel->pending.width; + uint32_t height = surface->toplevel->pending.height; if (width == 0 || height == 0) { width = surface->geometry->width; height = surface->geometry->height; } - zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, width, + zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, height, &states); wl_array_release(&states); @@ -1086,7 +1086,7 @@ static void wlr_xdg_toplevel_v6_send_configure( error_out: wl_array_release(&states); - wl_resource_post_no_memory(surface->toplevel_state->resource); + wl_resource_post_no_memory(surface->toplevel->resource); } static void wlr_xdg_surface_send_configure(void *user_data) { @@ -1112,11 +1112,11 @@ static void wlr_xdg_surface_send_configure(void *user_data) { wlr_xdg_toplevel_v6_send_configure(surface, configure); break; case WLR_XDG_SURFACE_V6_ROLE_POPUP: - zxdg_popup_v6_send_configure(surface->popup_state->resource, - surface->popup_state->geometry.x, - surface->popup_state->geometry.y, - surface->popup_state->geometry.width, - surface->popup_state->geometry.height); + zxdg_popup_v6_send_configure(surface->popup->resource, + surface->popup->geometry.x, + surface->popup->geometry.y, + surface->popup->geometry.width, + surface->popup->geometry.height); break; } @@ -1135,7 +1135,7 @@ static uint32_t wlr_xdg_surface_v6_schedule_configure( break; case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: pending_same = - wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); + wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel); break; case WLR_XDG_SURFACE_V6_ROLE_POPUP: break; @@ -1175,32 +1175,32 @@ static void wlr_xdg_surface_v6_toplevel_committed( struct wlr_xdg_surface_v6 *surface) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - if (!surface->toplevel_state->added) { + if (!surface->toplevel->added) { // on the first commit, send a configure request to tell the client it // is added wlr_xdg_surface_v6_schedule_configure(surface); - surface->toplevel_state->added = true; + surface->toplevel->added = true; return; } // update state that doesn't need compositor approval - surface->toplevel_state->current.max_width = - surface->toplevel_state->next.max_width; - surface->toplevel_state->current.min_width = - surface->toplevel_state->next.min_width; - surface->toplevel_state->current.max_height = - surface->toplevel_state->next.max_height; - surface->toplevel_state->current.min_height = - surface->toplevel_state->next.min_height; + surface->toplevel->current.max_width = + surface->toplevel->next.max_width; + surface->toplevel->current.min_width = + surface->toplevel->next.min_width; + surface->toplevel->current.max_height = + surface->toplevel->next.max_height; + surface->toplevel->current.min_height = + surface->toplevel->next.min_height; } static void wlr_xdg_surface_v6_popup_committed( struct wlr_xdg_surface_v6 *surface) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); - if (!surface->popup_state->committed) { + if (!surface->popup->committed) { wlr_xdg_surface_v6_schedule_configure(surface); - surface->popup_state->committed = true; + surface->popup->committed = true; } } @@ -1498,8 +1498,8 @@ void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) { uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, uint32_t width, uint32_t height) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel_state->pending.width = width; - surface->toplevel_state->pending.height = height; + surface->toplevel->pending.width = width; + surface->toplevel->pending.height = height; wlr_log(L_DEBUG, "wlr_xdg_toplevel_v6_set_size %d", width); return wlr_xdg_surface_v6_schedule_configure(surface); @@ -1508,7 +1508,7 @@ uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, bool activated) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel_state->pending.activated = activated; + surface->toplevel->pending.activated = activated; return wlr_xdg_surface_v6_schedule_configure(surface); } @@ -1516,7 +1516,7 @@ uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, bool maximized) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel_state->pending.maximized = maximized; + surface->toplevel->pending.maximized = maximized; return wlr_xdg_surface_v6_schedule_configure(surface); } @@ -1524,7 +1524,7 @@ uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, bool fullscreen) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel_state->pending.fullscreen = fullscreen; + surface->toplevel->pending.fullscreen = fullscreen; return wlr_xdg_surface_v6_schedule_configure(surface); } @@ -1532,23 +1532,23 @@ uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, bool resizing) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - surface->toplevel_state->pending.resizing = resizing; + surface->toplevel->pending.resizing = resizing; return wlr_xdg_surface_v6_schedule_configure(surface); } void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - zxdg_toplevel_v6_send_close(surface->toplevel_state->resource); + zxdg_toplevel_v6_send_close(surface->toplevel->resource); } void wlr_xdg_surface_v6_popup_get_position(struct wlr_xdg_surface_v6 *surface, double *popup_sx, double *popup_sy) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); - struct wlr_xdg_surface_v6 *parent = surface->popup_state->parent; - *popup_sx = parent->geometry->x + surface->popup_state->geometry.x - + struct wlr_xdg_surface_v6 *parent = surface->popup->parent; + *popup_sx = parent->geometry->x + surface->popup->geometry.x - surface->geometry->x; - *popup_sy = parent->geometry->y + surface->popup_state->geometry.y - + *popup_sy = parent->geometry->y + surface->popup->geometry.y - surface->geometry->y; } From ace738dbca9cadb9b9bc5e15aeac19131bab3998 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 13 Mar 2018 22:17:25 +0100 Subject: [PATCH 14/52] xdg-shell-v6: next_geometry and geometry fields are not longer pointers in wlr_xdg_surface_v6 --- include/wlr/types/wlr_xdg_shell_v6.h | 4 +- rootston/xdg_shell_v6.c | 6 +-- types/wlr_xdg_shell_v6.c | 78 ++++++++++------------------ 3 files changed, 32 insertions(+), 56 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 2358feec..d8503d28 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -109,8 +109,8 @@ struct wlr_xdg_surface_v6 { char *app_id; bool has_next_geometry; - struct wlr_box *next_geometry; - struct wlr_box *geometry; // TODO: should not be a pointer + struct wlr_box next_geometry; + struct wlr_box geometry; struct wl_listener surface_destroy_listener; diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 59637105..13d25331 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -60,9 +60,9 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; - if (surface->geometry->width > 0 && surface->geometry->height > 0) { - box->width = surface->geometry->width; - box->height = surface->geometry->height; + if (surface->geometry.width > 0 && surface->geometry.height > 0) { + box->width = surface->geometry.width; + box->height = surface->geometry.height; } else if (view->wlr_surface != NULL) { box->width = view->wlr_surface->current->width; box->height = view->wlr_surface->current->height; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 214f818c..aabd9f2b 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -217,8 +217,8 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { } surface->has_next_geometry = false; - memset(surface->geometry, 0, sizeof(struct wlr_box)); - memset(surface->next_geometry, 0, sizeof(struct wlr_box)); + memset(&surface->geometry, 0, sizeof(struct wlr_box)); + memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); } static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { @@ -232,8 +232,6 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { wl_list_remove(&surface->link); wl_list_remove(&surface->surface_destroy_listener.link); wlr_surface_set_role_committed(surface->surface, NULL, NULL); - free(surface->geometry); - free(surface->next_geometry); free(surface); } @@ -945,10 +943,10 @@ static void xdg_surface_handle_set_window_geometry(struct wl_client *client, } surface->has_next_geometry = true; - surface->next_geometry->height = height; - surface->next_geometry->width = width; - surface->next_geometry->x = x; - surface->next_geometry->y = y; + surface->next_geometry.height = height; + surface->next_geometry.width = width; + surface->next_geometry.x = x; + surface->next_geometry.y = y; } static void xdg_surface_handle_destroy(struct wl_client *client, @@ -1073,11 +1071,6 @@ static void wlr_xdg_toplevel_v6_send_configure( uint32_t width = surface->toplevel->pending.width; uint32_t height = surface->toplevel->pending.height; - if (width == 0 || height == 0) { - width = surface->geometry->width; - height = surface->geometry->height; - } - zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, height, &states); @@ -1217,10 +1210,10 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, if (surface->has_next_geometry) { surface->has_next_geometry = false; - surface->geometry->x = surface->next_geometry->x; - surface->geometry->y = surface->next_geometry->y; - surface->geometry->width = surface->next_geometry->width; - surface->geometry->height = surface->next_geometry->height; + surface->geometry.x = surface->next_geometry.x; + surface->geometry.y = surface->next_geometry.y; + surface->geometry.width = surface->next_geometry.width; + surface->geometry.height = surface->next_geometry.height; } switch (surface->role) { @@ -1268,21 +1261,9 @@ static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, struct wlr_xdg_client_v6 *client = xdg_client_from_resource(client_resource); - struct wlr_xdg_surface_v6 *surface; - if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { - wl_client_post_no_memory(wl_client); - return; - } - - if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { - free(surface); - wl_client_post_no_memory(wl_client); - return; - } - - if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { - free(surface->geometry); - free(surface); + struct wlr_xdg_surface_v6 *surface = + calloc(1, sizeof(struct wlr_xdg_surface_v6)); + if (surface == NULL) { wl_client_post_no_memory(wl_client); return; } @@ -1294,8 +1275,6 @@ static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, &zxdg_surface_v6_interface, wl_resource_get_version(client_resource), id); if (surface->resource == NULL) { - free(surface->next_geometry); - free(surface->geometry); free(surface); wl_client_post_no_memory(wl_client); return; @@ -1303,8 +1282,6 @@ static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, if (wlr_surface_has_buffer(surface->surface)) { wl_resource_destroy(surface->resource); - free(surface->next_geometry); - free(surface->geometry); free(surface); wl_resource_post_error(surface_resource, ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, @@ -1500,7 +1477,6 @@ uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel->pending.width = width; surface->toplevel->pending.height = height; - wlr_log(L_DEBUG, "wlr_xdg_toplevel_v6_set_size %d", width); return wlr_xdg_surface_v6_schedule_configure(surface); } @@ -1546,10 +1522,10 @@ void wlr_xdg_surface_v6_popup_get_position(struct wlr_xdg_surface_v6 *surface, double *popup_sx, double *popup_sy) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); struct wlr_xdg_surface_v6 *parent = surface->popup->parent; - *popup_sx = parent->geometry->x + surface->popup->geometry.x - - surface->geometry->x; - *popup_sy = parent->geometry->y + surface->popup->geometry.y - - surface->geometry->y; + *popup_sx = parent->geometry.x + surface->popup->geometry.x - + surface->geometry.x; + *popup_sy = parent->geometry.y + surface->popup->geometry.y - + surface->geometry.y; } struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( @@ -1563,30 +1539,30 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( struct wlr_xdg_surface_v6 *popup = popup_state->base; double _popup_sx = - surface->geometry->x + popup_state->geometry.x; + surface->geometry.x + popup_state->geometry.x; double _popup_sy = - surface->geometry->y + popup_state->geometry.y; + surface->geometry.y + popup_state->geometry.y; int popup_width = popup_state->geometry.width; int popup_height = popup_state->geometry.height; struct wlr_xdg_surface_v6 *_popup = wlr_xdg_surface_v6_popup_at(popup, - sx - _popup_sx + popup->geometry->x, - sy - _popup_sy + popup->geometry->y, + sx - _popup_sx + popup->geometry.x, + sy - _popup_sy + popup->geometry.y, popup_sx, popup_sy); if (_popup) { - *popup_sx = *popup_sx + _popup_sx - popup->geometry->x; - *popup_sy = *popup_sy + _popup_sy - popup->geometry->y; + *popup_sx = *popup_sx + _popup_sx - popup->geometry.x; + *popup_sy = *popup_sy + _popup_sy - popup->geometry.y; return _popup; } if ((sx > _popup_sx && sx < _popup_sx + popup_width) && (sy > _popup_sy && sy < _popup_sy + popup_height)) { if (pixman_region32_contains_point(&popup->surface->current->input, - sx - _popup_sx + popup->geometry->x, - sy - _popup_sy + popup->geometry->y, NULL)) { - *popup_sx = _popup_sx - popup->geometry->x; - *popup_sy = _popup_sy - popup->geometry->y; + sx - _popup_sx + popup->geometry.x, + sy - _popup_sy + popup->geometry.y, NULL)) { + *popup_sx = _popup_sx - popup->geometry.x; + *popup_sy = _popup_sy - popup->geometry.y; return popup; } } From dd8a7a29e19f4e304e2620aa1665dd6761a1370e Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 14 Mar 2018 00:01:28 +0100 Subject: [PATCH 15/52] rootston: don't center view if maximized --- rootston/desktop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootston/desktop.c b/rootston/desktop.c index b1e6f874..e9a9425c 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -491,7 +491,7 @@ void view_initial_focus(struct roots_view *view) { void view_setup(struct roots_view *view) { view_initial_focus(view); - if (view->fullscreen_output == NULL) { + if (view->fullscreen_output == NULL && !view->maximized) { view_center(view); } From b2926a6c62d2658bc6bf80f25c93292095384827 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 13 Mar 2018 19:11:02 -0400 Subject: [PATCH 16/52] differentiate xdg-toplevel roles --- types/wlr_xdg_shell_v6.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index e07d78a1..48dfa3ac 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -13,8 +13,8 @@ #include "util/signal.h" #include "xdg-shell-unstable-v6-protocol.h" -static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; -static const char *wlr_desktop_xdg_popup_role = "xdg_popup"; +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel_v6"; +static const char *wlr_desktop_xdg_popup_role = "xdg_popup_v6"; struct wlr_xdg_positioner_v6 { struct wl_resource *resource; From 3bd1d876aefc146f5eb950a19ebdc40856974d73 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 14 Mar 2018 19:21:36 +0100 Subject: [PATCH 17/52] examples: simplify screenshot client --- examples/screenshot.c | 181 ++++++++---------------------------------- 1 file changed, 31 insertions(+), 150 deletions(-) diff --git a/examples/screenshot.c b/examples/screenshot.c index e73989c6..fb37f32c 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,33 +37,22 @@ #include #include #include "screenshooter-client-protocol.h" -#include "util/os-compatibility.h" static struct wl_shm *shm = NULL; static struct orbital_screenshooter *screenshooter = NULL; static struct wl_list output_list; -int min_x, min_y, max_x, max_y; -int buffer_copy_done; +static bool buffer_copy_done; struct screenshooter_output { struct wl_output *output; - struct wl_buffer *buffer; - int width, height, offset_x, offset_y; - enum wl_output_transform transform; - void *data; + int width, height; struct wl_list link; }; static void output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, int physical_width, int physical_height, int subpixel, const char *make, const char *model, int transform) { - struct screenshooter_output *output = wl_output_get_user_data(wl_output); - - if (wl_output == output->output) { - output->offset_x = x; - output->offset_y = y; - output->transform = transform; - } + // No-op } static void output_handle_mode(void *data, struct wl_output *wl_output, @@ -86,7 +76,7 @@ static const struct wl_output_listener output_listener = { }; static void screenshot_done(void *data, struct orbital_screenshot *screenshot) { - buffer_copy_done = 1; + buffer_copy_done = true; } static const struct orbital_screenshot_listener screenshot_listener = { @@ -113,7 +103,7 @@ static void handle_global(void *data, struct wl_registry *registry, static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { - // Unimplemented + // Who cares? } static const struct wl_registry_listener registry_listener = { @@ -123,14 +113,15 @@ static const struct wl_registry_listener registry_listener = { static int backingfile(off_t size) { char template[] = "/tmp/wlroots-shared-XXXXXX"; - int fd, ret; - - fd = mkstemp(template); + int fd = mkstemp(template); if (fd < 0) { return -1; } - while ((ret = ftruncate(fd, size)) == EINTR) {} + int ret; + while ((ret = ftruncate(fd, size)) == EINTR) { + // No-op + } if (ret < 0) { close(fd); return -1; @@ -140,7 +131,6 @@ static int backingfile(off_t size) { return fd; } - static struct wl_buffer *create_shm_buffer(int width, int height, void **data_out) { int stride = width * 4; @@ -170,91 +160,8 @@ static struct wl_buffer *create_shm_buffer(int width, int height, return buffer; } -static void write_image(const char *filename, int width, int height) { - int buffer_stride = width * 4; - - void *data = calloc(1, buffer_stride * height); - if (!data) { - return; - } - - struct screenshooter_output *output, *next; - wl_list_for_each_safe(output, next, &output_list, link) { - int output_stride = output->width * 4; - uint32_t *src = (uint32_t *)output->data; - uint32_t *dst = (uint32_t *)(data + - (output->offset_y - min_y) * buffer_stride + - (output->offset_x - min_x) * 4); - - switch (output->transform) { - case WL_OUTPUT_TRANSFORM_NORMAL: - for (int i = 0; i < output->height; i++) { - memcpy(dst, src, output_stride); - dst += width; - src += output->width; - } - break; - case WL_OUTPUT_TRANSFORM_FLIPPED: - for (int i = 0; i < output->height; ++i) { - for (int j = 0; j < output->width; ++j) { - dst[i * width + j] = - src[i * output->width + output->width - 1 - j]; - } - } - break; - case WL_OUTPUT_TRANSFORM_90: - for (int i = 0; i < output->width; ++i) { - for (int j = 0; j < output->height; ++j) { - dst[i * width + j] = - src[j * output->width + output->width - 1 - i]; - } - } - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - for (int i = 0; i < output->width; ++i) { - for (int j = 0; j < output->height; ++j) { - dst[i * width + j] = - src[(output->height - 1 - j) * output->width + output->width - 1 - i]; - } - } - break; - case WL_OUTPUT_TRANSFORM_180: - for (int i = 0; i < output->height; ++i) { - for (int j = 0; j < output->width; ++j) { - dst[i * width + j] = - src[(output->height - 1 - i) * output->width + output->width - 1 - j]; - } - } - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - for (int i = 0; i < output->height; ++i) { - for (int j = 0; j < output->width; ++j) { - dst[i * width + j] = - src[(output->height - 1 - i) * output->width + j]; - } - } - break; - case WL_OUTPUT_TRANSFORM_270: - for (int i = 0; i < output->width; ++i) { - for (int j = 0; j < output->height; ++j) { - dst[i * width + j] = - src[(output->height - 1 - j) * output->width + i]; - } - } - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - for (int i = 0; i < output->width; ++i) { - for (int j = 0; j < output->height; ++j) { - dst[i * width + j] = - src[j * output->width + i]; - } - } - break; - } - - free(output); - } - +static void write_image(const char *filename, int width, int height, + void *data) { char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits sprintf(size, "%dx%d+0", width, height); @@ -270,12 +177,11 @@ static void write_image(const char *filename, int width, int height) { exit(EXIT_FAILURE); } else if (child != 0) { close(fd[0]); - if (write(fd[1], data, buffer_stride * height) < 0) { + if (write(fd[1], data, 4 * width * height) < 0) { fprintf(stderr, "write() failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } close(fd[1]); - free(data); waitpid(child, NULL, 0); } else { close(fd[1]); @@ -293,38 +199,9 @@ static void write_image(const char *filename, int width, int height) { } } -static int set_buffer_size(int *width, int *height) { - int owidth, oheight; - min_x = min_y = INT_MAX; - max_x = max_y = INT_MIN; - - struct screenshooter_output *output; - wl_list_for_each(output, &output_list, link) { - if (output->transform & 0x1) { - owidth = output->height; - oheight = output->width; - } else { - owidth = output->width; - oheight = output->height; - } - min_x = MIN(min_x, output->offset_x); - min_y = MIN(min_y, output->offset_y); - max_x = MAX(max_x, output->offset_x + owidth); - max_y = MAX(max_y, output->offset_y + oheight); - } - - if (max_x <= min_x || max_y <= min_y) { - return -1; - } - - *width = max_x - min_x; - *height = max_y - min_y; - - return 0; -} - int main(int argc, char *argv[]) { wlr_log_init(L_DEBUG, NULL); + struct wl_display * display = wl_display_connect(NULL); if (display == NULL) { fprintf(stderr, "failed to create display: %m\n"); @@ -342,27 +219,31 @@ int main(int argc, char *argv[]) { return -1; } - int width, height; - if (set_buffer_size(&width, &height)) { - fprintf(stderr, "cannot set buffer size\n"); - return -1; - } - + int i = 0; struct screenshooter_output *output; wl_list_for_each(output, &output_list, link) { - output->buffer = create_shm_buffer(output->width, output->height, &output->data); - if (output->buffer == NULL) { + void *data = NULL; + struct wl_buffer *buffer = + create_shm_buffer(output->width, output->height, &data); + if (buffer == NULL) { return -1; } struct orbital_screenshot *screenshot = orbital_screenshooter_shoot( - screenshooter, output->output, output->buffer); - orbital_screenshot_add_listener(screenshot, &screenshot_listener, screenshot); - buffer_copy_done = 0; + screenshooter, output->output, buffer); + orbital_screenshot_add_listener(screenshot, &screenshot_listener, + screenshot); + buffer_copy_done = false; while (!buffer_copy_done) { wl_display_roundtrip(display); } + + char filename[24 + 10]; // int32_t are max 10 digits + snprintf(filename, sizeof(filename), "wayland-screenshot-%d.png", i); + + write_image(filename, output->width, output->height, data); + wl_buffer_destroy(buffer); + ++i; } - write_image("wayland-screenshot.png", width, height); return EXIT_SUCCESS; } From b6a3f240c7621d1ebb5774fcdf7784d976500ee1 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 09:11:03 +0100 Subject: [PATCH 18/52] matrix: move to types/ --- backend/drm/drm.c | 2 +- backend/drm/renderer.c | 2 +- examples/multi-pointer.c | 2 +- examples/output-layout.c | 2 +- examples/pointer.c | 2 +- examples/rotation.c | 2 +- examples/tablet.c | 2 +- examples/touch.c | 2 +- include/wlr/{render/matrix.h => types/wlr_matrix.h} | 4 ++-- render/gles2/renderer.c | 2 +- render/gles2/texture.c | 2 +- render/meson.build | 1 - rootston/output.c | 2 +- types/meson.build | 3 ++- render/matrix.c => types/wlr_matrix.c | 2 +- types/wlr_output.c | 2 +- types/wlr_surface.c | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) rename include/wlr/{render/matrix.h => types/wlr_matrix.h} (92%) rename render/matrix.c => types/wlr_matrix.c (99%) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 0d1d527d..af701c6a 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7ee13843..13311df3 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include "backend/drm/drm.h" #include "glapi.h" diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index d3d425f2..6e56bfdc 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/output-layout.c b/examples/output-layout.c index 45257be9..8ba77861 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/pointer.c b/examples/pointer.c index 0dbd02d2..e80b346a 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/rotation.c b/examples/rotation.c index 1158ccc4..e38d53f4 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/tablet.c b/examples/tablet.c index 5bfa1271..aa02c6f4 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/touch.c b/examples/touch.c index 278252cc..7b4559b9 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/wlr/render/matrix.h b/include/wlr/types/wlr_matrix.h similarity index 92% rename from include/wlr/render/matrix.h rename to include/wlr/types/wlr_matrix.h index a333bf0f..498b643c 100644 --- a/include/wlr/render/matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -1,5 +1,5 @@ -#ifndef WLR_RENDER_MATRIX_H -#define WLR_RENDER_MATRIX_H +#ifndef WLR_TYPES_WLR_MATRIX_H +#define WLR_TYPES_WLR_MATRIX_H #include #include diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index ad739cf8..5b1395fb 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include "render/gles2.h" #include "glapi.h" diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 241b94a8..7a180446 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include "render/gles2.h" #include "util/signal.h" diff --git a/render/meson.build b/render/meson.build index 8aa70cea..4fe9ea67 100644 --- a/render/meson.build +++ b/render/meson.build @@ -15,7 +15,6 @@ lib_wlr_render = static_library( 'gles2/shaders.c', 'gles2/texture.c', 'gles2/util.c', - 'matrix.c', 'wlr_renderer.c', 'wlr_texture.c', ), diff --git a/rootston/output.c b/rootston/output.c index 4d0a9c05..bdf025ad 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/types/meson.build b/types/meson.build index 703b06ca..91b4326d 100644 --- a/types/meson.build +++ b/types/meson.build @@ -6,10 +6,12 @@ lib_wlr_types = static_library( 'wlr_cursor.c', 'wlr_data_device.c', 'wlr_gamma_control.c', + 'wlr_idle_inhibit_v1.c', 'wlr_idle.c', 'wlr_input_device.c', 'wlr_keyboard.c', 'wlr_list.c', + 'wlr_matrix.c', 'wlr_output_damage.c', 'wlr_output_layout.c', 'wlr_output.c', @@ -27,7 +29,6 @@ lib_wlr_types = static_library( 'wlr_xcursor_manager.c', 'wlr_xdg_shell_v6.c', 'wlr_xdg_shell.c', - 'wlr_idle_inhibit_v1.c', ), include_directories: wlr_inc, dependencies: [pixman, xkbcommon, wayland_server, wlr_protos], diff --git a/render/matrix.c b/types/wlr_matrix.c similarity index 99% rename from render/matrix.c rename to types/wlr_matrix.c index d5d7f49d..f3546e0e 100644 --- a/render/matrix.c +++ b/types/wlr_matrix.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include diff --git a/types/wlr_output.c b/types/wlr_output.c index 7f19d1fe..21343a68 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 23966cd1..5d52fd2a 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include From d26b67cb06509fb39d9ed473a5d27b1f241ff635 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 11:10:56 +0100 Subject: [PATCH 19/52] matrix: unify API, don't use array pointers --- backend/drm/drm.c | 4 +- backend/drm/renderer.c | 2 +- examples/output-layout.c | 8 +- examples/rotation.c | 8 +- examples/tablet.c | 19 ++--- examples/touch.c | 10 +-- include/wlr/render.h | 12 +-- include/wlr/render/interface.h | 13 +-- include/wlr/types/wlr_matrix.h | 21 ++--- include/wlr/types/wlr_surface.h | 7 +- render/gles2/renderer.c | 21 ++--- render/gles2/texture.c | 14 ++-- render/wlr_renderer.c | 9 +- render/wlr_texture.c | 4 +- rootston/output.c | 14 ++-- types/wlr_matrix.c | 141 ++++++++++++++++---------------- types/wlr_output.c | 16 ++-- types/wlr_surface.c | 16 ++-- 18 files changed, 172 insertions(+), 167 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index af701c6a..1e78d301 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -648,9 +648,9 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, glClear(GL_COLOR_BUFFER_BIT); float matrix[16]; - wlr_texture_get_matrix(plane->wlr_tex, &matrix, &plane->matrix, 0, 0); + wlr_texture_get_matrix(plane->wlr_tex, matrix, plane->matrix, 0, 0); wlr_render_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex, - &matrix, 1.0f); + matrix, 1.0f); glFinish(); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 13311df3..ab56e6c2 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -239,7 +239,7 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, glViewport(0, 0, dest->width, dest->height); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); - wlr_render_with_matrix(dest->renderer->wlr_rend, tex, &matrix, 1.0f); + wlr_render_with_matrix(dest->renderer->wlr_rend, tex, matrix, 1.0f); return wlr_drm_surface_swap_buffers(dest, NULL); } diff --git a/examples/output-layout.c b/examples/output-layout.c index 8ba77861..f4df73a0 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -102,7 +102,7 @@ static void handle_output_frame(struct output_state *output, wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); animate_cat(sample, output->output); @@ -119,10 +119,10 @@ static void handle_output_frame(struct output_state *output, wlr_output_layout_output_coords(sample->layout, output->output, &local_x, &local_y); - wlr_texture_get_matrix(sample->cat_texture, &matrix, - &wlr_output->transform_matrix, local_x, local_y); + wlr_texture_get_matrix(sample->cat_texture, matrix, + wlr_output->transform_matrix, local_x, local_y); wlr_render_with_matrix(sample->renderer, - sample->cat_texture, &matrix, 1.0f); + sample->cat_texture, matrix, 1.0f); } wlr_renderer_end(sample->renderer); diff --git a/examples/rotation.c b/examples/rotation.c index e38d53f4..0b0c6adf 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -44,15 +44,15 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[16]; for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { for (int x = -128 + (int)odata->x_offs; x < width; x += 128) { - wlr_texture_get_matrix(sample->cat_texture, &matrix, - &wlr_output->transform_matrix, x, y); + wlr_texture_get_matrix(sample->cat_texture, matrix, + wlr_output->transform_matrix, x, y); wlr_render_with_matrix(sample->renderer, - sample->cat_texture, &matrix, 1.0f); + sample->cat_texture, matrix, 1.0f); } } diff --git a/examples/tablet.c b/examples/tablet.c index aa02c6f4..82f86553 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -47,7 +47,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[16]; float distance = 0.8f * (1 - sample->distance); @@ -65,9 +65,8 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts .x = left, .y = top, .width = pad_width, .height = pad_height, }; - wlr_matrix_project_box(&matrix, &box, 0, 0, - &wlr_output->transform_matrix); - wlr_render_colored_quad(sample->renderer, &sample->pad_color, &matrix); + wlr_matrix_project_box(matrix, &box, 0, 0, wlr_output->transform_matrix); + wlr_render_colored_quad(sample->renderer, sample->pad_color, matrix); if (sample->proximity) { struct wlr_box box = { @@ -76,16 +75,16 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts .width = 16 * (sample->pressure + 1), .height = 16 * (sample->pressure + 1), }; - wlr_matrix_project_box(&matrix, &box, 0, sample->ring, - &wlr_output->transform_matrix); - wlr_render_colored_quad(sample->renderer, &tool_color, &matrix); + wlr_matrix_project_box(matrix, &box, 0, sample->ring, + wlr_output->transform_matrix); + wlr_render_colored_quad(sample->renderer, tool_color, matrix); box.x += sample->x_tilt; box.y += sample->y_tilt; box.width /= 2; box.height /= 2; - wlr_matrix_project_box(&matrix, &box, 0, 0, - &wlr_output->transform_matrix); - wlr_render_colored_quad(sample->renderer, &tool_color, &matrix); + wlr_matrix_project_box(matrix, &box, 0, 0, + wlr_output->transform_matrix); + wlr_render_colored_quad(sample->renderer, tool_color, matrix); } wlr_renderer_end(sample->renderer); diff --git a/examples/touch.c b/examples/touch.c index 7b4559b9..6f4821ad 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -43,17 +43,17 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output, NULL); wlr_renderer_begin(sample->renderer, wlr_output); - wlr_renderer_clear(sample->renderer, &(float[]){0.25f, 0.25f, 0.25f, 1}); + wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[16]; struct touch_point *p; wl_list_for_each(p, &sample->touch_points, link) { - wlr_texture_get_matrix(sample->cat_texture, &matrix, - &wlr_output->transform_matrix, + wlr_texture_get_matrix(sample->cat_texture, matrix, + wlr_output->transform_matrix, (int)(p->x * width) - sample->cat_texture->width / 2, (int)(p->y * height) - sample->cat_texture->height / 2); - wlr_render_with_matrix(sample->renderer, - sample->cat_texture, &matrix, 1.0f); + wlr_render_with_matrix(sample->renderer, sample->cat_texture, + matrix, 1.0f); } wlr_renderer_end(sample->renderer); diff --git a/include/wlr/render.h b/include/wlr/render.h index 747603da..50c2dd13 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -13,7 +13,7 @@ struct wlr_renderer; void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); void wlr_renderer_end(struct wlr_renderer *r); -void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]); +void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); /** * Defines a scissor box. Only pixels that lie within the scissor box can be * modified by drawing functions. Providing a NULL `box` disables the scissor @@ -38,18 +38,18 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); * This will render the texture at <123, 321> with an alpha channel of 0.5. */ bool wlr_render_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float (*matrix)[16], float alpha); + struct wlr_texture *texture, const float matrix[static 16], float alpha); /** * Renders a solid quad in the specified color. */ void wlr_render_colored_quad(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]); + const float color[static 4], const float matrix[static 16]); /** * Renders a solid ellipse in the specified color. */ void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]); + const float color[static 4], const float matrix[static 16]); /** * Returns a list of pixel formats supported by this renderer. */ @@ -139,8 +139,8 @@ bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format, * width) and [0, height], and the x and y coordinates provided are used as * such. */ -void wlr_texture_get_matrix(struct wlr_texture *texture, - float (*matrix)[16], const float (*projection)[16], int x, int y); +void wlr_texture_get_matrix(struct wlr_texture *texture, float mat[static 16], + const float projection[static 16], int x, int y); /** * Destroys this wlr_texture. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index eda5af1c..4d81bdf9 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -18,15 +18,16 @@ struct wlr_renderer { struct wlr_renderer_impl { void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output); void (*end)(struct wlr_renderer *renderer); - void (*clear)(struct wlr_renderer *renderer, const float (*color)[4]); + 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_with_matrix)(struct wlr_renderer *renderer, - struct wlr_texture *texture, const float (*matrix)[16], float alpha); + struct wlr_texture *texture, const float matrix[static 16], + float alpha); void (*render_quad)(struct wlr_renderer *renderer, - const float (*color)[4], const float (*matrix)[16]); + const float color[static 4], const float matrix[static 16]); void (*render_ellipse)(struct wlr_renderer *renderer, - const float (*color)[4], const float (*matrix)[16]); + const float color[static 4], const float matrix[static 16]); const enum wl_shm_format *(*formats)( struct wlr_renderer *renderer, size_t *len); bool (*buffer_is_drm)(struct wlr_renderer *renderer, @@ -58,8 +59,8 @@ struct wlr_texture_impl { struct wl_resource *drm_buf); bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image, uint32_t width, uint32_t height); - void (*get_matrix)(struct wlr_texture *state, - float (*matrix)[16], const float (*projection)[16], int x, int y); + void (*get_matrix)(struct wlr_texture *state, float mat[static 16], + const float projection[static 16], int x, int y); void (*get_buffer_size)(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height); void (*bind)(struct wlr_texture *texture); diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h index 498b643c..cf5ad20d 100644 --- a/include/wlr/types/wlr_matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -4,19 +4,20 @@ #include #include -void wlr_matrix_identity(float (*output)[16]); -void wlr_matrix_translate(float (*output)[16], float x, float y, float z); -void wlr_matrix_scale(float (*output)[16], float x, float y, float z); -void wlr_matrix_rotate(float (*output)[16], float radians); -void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]); +void wlr_matrix_identity(float mat[static 16]); +void wlr_matrix_translate(float mat[static 16], float x, float y, float z); +void wlr_matrix_scale(float mat[static 16], float x, float y, float z); +void wlr_matrix_rotate(float mat[static 16], float radians); +void wlr_matrix_mul(float mat[static 16], const float x[static 16], + const float y[static 16]); enum wl_output_transform; void wlr_matrix_transform(float mat[static 16], - enum wl_output_transform transform); + enum wl_output_transform transform); void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, - enum wl_output_transform transform); -void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box, - enum wl_output_transform transform, float rotation, float - (*projection)[16]); + enum wl_output_transform transform); +void wlr_matrix_project_box(float mat[static 16], const struct wlr_box *box, + enum wl_output_transform transform, float rotation, + const float projection[static 16]); #endif diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 203345bd..1d4c1f01 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -99,6 +99,7 @@ struct wlr_surface { struct wlr_renderer; struct wlr_surface *wlr_surface_create(struct wl_resource *res, struct wlr_renderer *renderer); + /** * Gets a matrix you can pass into wlr_render_with_matrix to display this * surface. `matrix` is the output matrix, `projection` is the wlr_output @@ -108,9 +109,9 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, * from 0 to 1 in both dimensions. */ void wlr_surface_get_matrix(struct wlr_surface *surface, - float (*matrix)[16], - const float (*projection)[16], - const float (*transform)[16]); + float mat[static 16], + const float projection[static 16], + const float transform[static 16]); /** diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 5b1395fb..9134a2fd 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -122,8 +122,8 @@ static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) { } static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, - const float (*color)[4]) { - glClearColor((*color)[0], (*color)[1], (*color)[2], (*color)[3]); + const float color[static 4]) { + glClearColor(color[0], color[1], color[2], color[3]); glClear(GL_COLOR_BUFFER_BIT); } @@ -171,14 +171,15 @@ static void draw_quad() { } static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, - struct wlr_texture *texture, const float (*matrix)[16], float alpha) { + struct wlr_texture *texture, const float matrix[static 16], + float alpha) { if (!texture || !texture->valid) { wlr_log(L_ERROR, "attempt to render invalid texture"); return false; } wlr_texture_bind(texture); - GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); + GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, matrix)); GL_CALL(glUniform1f(2, alpha)); draw_quad(); return true; @@ -186,18 +187,18 @@ static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, - const float (*color)[4], const float (*matrix)[16]) { + const float color[static 4], const float matrix[static 16]) { GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, *matrix)); - GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); + GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, matrix)); + GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, - const float (*color)[4], const float (*matrix)[16]) { + const float color[static 4], const float matrix[static 16]) { GL_CALL(glUseProgram(shaders.ellipse)); - GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); - GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); + GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, matrix)); + GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 7a180446..0dfebc48 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -227,16 +227,16 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, } static void gles2_texture_get_matrix(struct wlr_texture *_texture, - float (*matrix)[16], const float (*projection)[16], int x, int y) { + float mat[static 16], const float projection[static 16], int x, int y) { struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; float world[16]; - wlr_matrix_identity(matrix); - wlr_matrix_translate(&world, x, y, 0); - wlr_matrix_mul(matrix, &world, matrix); - wlr_matrix_scale(&world, + wlr_matrix_identity(mat); + wlr_matrix_translate(world, x, y, 0); + wlr_matrix_mul(mat, mat, world); + wlr_matrix_scale(world, texture->wlr_texture.width, texture->wlr_texture.height, 1); - wlr_matrix_mul(matrix, &world, matrix); - wlr_matrix_mul(projection, matrix, matrix); + wlr_matrix_mul(mat, mat, world); + wlr_matrix_mul(mat, projection, mat); } static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index ce8fbe36..372e4caf 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -23,7 +23,7 @@ void wlr_renderer_end(struct wlr_renderer *r) { r->impl->end(r); } -void wlr_renderer_clear(struct wlr_renderer *r, const float (*color)[4]) { +void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]) { r->impl->clear(r, color); } @@ -36,17 +36,18 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) { } bool wlr_render_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float (*matrix)[16], float alpha) { + struct wlr_texture *texture, const float matrix[static 16], + float alpha) { return r->impl->render_with_matrix(r, texture, matrix, alpha); } void wlr_render_colored_quad(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]) { + const float color[static 4], const float matrix[static 16]) { r->impl->render_quad(r, color, matrix); } void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float (*color)[4], const float (*matrix)[16]) { + const float color[static 4], const float matrix[static 16]) { r->impl->render_ellipse(r, color, matrix); } diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a82a16b2..0bfac32c 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -54,8 +54,8 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture, } 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, matrix, projection, x, y); + float mat[static 16], const float projection[static 16], int x, int y) { + texture->impl->get_matrix(texture, mat, projection, x, y); } void wlr_texture_get_buffer_size(struct wlr_texture *texture, struct wl_resource diff --git a/rootston/output.c b/rootston/output.c index bdf025ad..47236720 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -290,14 +290,14 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, float matrix[16]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); - wlr_matrix_project_box(&matrix, &box, transform, rotation, - &output->wlr_output->transform_matrix); + wlr_matrix_project_box(matrix, &box, transform, rotation, + output->wlr_output->transform_matrix); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_with_matrix(renderer, surface->texture, &matrix, data->alpha); + wlr_render_with_matrix(renderer, surface->texture, matrix, data->alpha); } damage_finish: @@ -354,8 +354,8 @@ static void render_decorations(struct roots_view *view, } float matrix[16]; - wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, - view->rotation, &output->wlr_output->transform_matrix); + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, + view->rotation, output->wlr_output->transform_matrix); float color[] = { 0.2, 0.2, 0.2, view->alpha }; int nrects; @@ -363,7 +363,7 @@ static void render_decorations(struct roots_view *view, pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_colored_quad(renderer, &color, &matrix); + wlr_render_colored_quad(renderer, color, matrix); } damage_finish: @@ -489,7 +489,7 @@ static void render_output(struct roots_output *output) { pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_renderer_clear(renderer, &clear_color); + wlr_renderer_clear(renderer, clear_color); } // If a view is fullscreen on this output, render it diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c index f3546e0e..a6be9908 100644 --- a/types/wlr_matrix.c +++ b/types/wlr_matrix.c @@ -10,79 +10,80 @@ static inline int mind(int row, int col) { return (row - 1) * 4 + col - 1; } -void wlr_matrix_identity(float (*output)[16]) { +void wlr_matrix_identity(float mat[static 16]) { static const float identity[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f + 0.0f, 0.0f, 0.0f, 1.0f, }; - memcpy(*output, identity, sizeof(identity)); + memcpy(mat, identity, sizeof(identity)); } -void wlr_matrix_translate(float (*output)[16], float x, float y, float z) { - wlr_matrix_identity(output); - (*output)[mind(1, 4)] = x; - (*output)[mind(2, 4)] = y; - (*output)[mind(3, 4)] = z; +void wlr_matrix_translate(float mat[static 16], float x, float y, float z) { + wlr_matrix_identity(mat); + mat[mind(1, 4)] = x; + mat[mind(2, 4)] = y; + mat[mind(3, 4)] = z; } -void wlr_matrix_scale(float (*output)[16], float x, float y, float z) { - wlr_matrix_identity(output); - (*output)[mind(1, 1)] = x; - (*output)[mind(2, 2)] = y; - (*output)[mind(3, 3)] = z; +void wlr_matrix_scale(float mat[static 16], float x, float y, float z) { + wlr_matrix_identity(mat); + mat[mind(1, 1)] = x; + mat[mind(2, 2)] = y; + mat[mind(3, 3)] = z; } -void wlr_matrix_rotate(float (*output)[16], float radians) { - wlr_matrix_identity(output); +void wlr_matrix_rotate(float mat[static 16], float radians) { + wlr_matrix_identity(mat); float _cos = cosf(radians); float _sin = sinf(radians); - (*output)[mind(1, 1)] = _cos; - (*output)[mind(1, 2)] = _sin; - (*output)[mind(2, 1)] = -_sin; - (*output)[mind(2, 2)] = _cos; + mat[mind(1, 1)] = _cos; + mat[mind(1, 2)] = _sin; + mat[mind(2, 1)] = -_sin; + mat[mind(2, 2)] = _cos; } -void wlr_matrix_mul(const float (*x)[16], const float (*y)[16], float (*product)[16]) { - float _product[16] = { - (*x)[mind(1, 1)] * (*y)[mind(1, 1)] + (*x)[mind(1, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(1, 3)] * (*y)[mind(3, 1)] + (*x)[mind(1, 4)] * (*y)[mind(4, 1)], - (*x)[mind(1, 1)] * (*y)[mind(1, 2)] + (*x)[mind(1, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(1, 3)] * (*y)[mind(3, 2)] + (*x)[mind(1, 4)] * (*y)[mind(4, 2)], - (*x)[mind(1, 1)] * (*y)[mind(1, 3)] + (*x)[mind(1, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(1, 3)] * (*y)[mind(3, 3)] + (*x)[mind(1, 4)] * (*y)[mind(4, 3)], - (*x)[mind(1, 1)] * (*y)[mind(1, 4)] + (*x)[mind(1, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(1, 4)] * (*y)[mind(3, 4)] + (*x)[mind(1, 4)] * (*y)[mind(4, 4)], +void wlr_matrix_mul(float mat[static 16], const float x[static 16], + const float y[static 16]) { + float product[16] = { + x[mind(1, 1)] * y[mind(1, 1)] + x[mind(1, 2)] * y[mind(2, 1)] + + x[mind(1, 3)] * y[mind(3, 1)] + x[mind(1, 4)] * y[mind(4, 1)], + x[mind(1, 1)] * y[mind(1, 2)] + x[mind(1, 2)] * y[mind(2, 2)] + + x[mind(1, 3)] * y[mind(3, 2)] + x[mind(1, 4)] * y[mind(4, 2)], + x[mind(1, 1)] * y[mind(1, 3)] + x[mind(1, 2)] * y[mind(2, 3)] + + x[mind(1, 3)] * y[mind(3, 3)] + x[mind(1, 4)] * y[mind(4, 3)], + x[mind(1, 1)] * y[mind(1, 4)] + x[mind(1, 2)] * y[mind(2, 4)] + + x[mind(1, 4)] * y[mind(3, 4)] + x[mind(1, 4)] * y[mind(4, 4)], - (*x)[mind(2, 1)] * (*y)[mind(1, 1)] + (*x)[mind(2, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(2, 3)] * (*y)[mind(3, 1)] + (*x)[mind(2, 4)] * (*y)[mind(4, 1)], - (*x)[mind(2, 1)] * (*y)[mind(1, 2)] + (*x)[mind(2, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(2, 3)] * (*y)[mind(3, 2)] + (*x)[mind(2, 4)] * (*y)[mind(4, 2)], - (*x)[mind(2, 1)] * (*y)[mind(1, 3)] + (*x)[mind(2, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(2, 3)] * (*y)[mind(3, 3)] + (*x)[mind(2, 4)] * (*y)[mind(4, 3)], - (*x)[mind(2, 1)] * (*y)[mind(1, 4)] + (*x)[mind(2, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(2, 4)] * (*y)[mind(3, 4)] + (*x)[mind(2, 4)] * (*y)[mind(4, 4)], + x[mind(2, 1)] * y[mind(1, 1)] + x[mind(2, 2)] * y[mind(2, 1)] + + x[mind(2, 3)] * y[mind(3, 1)] + x[mind(2, 4)] * y[mind(4, 1)], + x[mind(2, 1)] * y[mind(1, 2)] + x[mind(2, 2)] * y[mind(2, 2)] + + x[mind(2, 3)] * y[mind(3, 2)] + x[mind(2, 4)] * y[mind(4, 2)], + x[mind(2, 1)] * y[mind(1, 3)] + x[mind(2, 2)] * y[mind(2, 3)] + + x[mind(2, 3)] * y[mind(3, 3)] + x[mind(2, 4)] * y[mind(4, 3)], + x[mind(2, 1)] * y[mind(1, 4)] + x[mind(2, 2)] * y[mind(2, 4)] + + x[mind(2, 4)] * y[mind(3, 4)] + x[mind(2, 4)] * y[mind(4, 4)], - (*x)[mind(3, 1)] * (*y)[mind(1, 1)] + (*x)[mind(3, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(3, 3)] * (*y)[mind(3, 1)] + (*x)[mind(3, 4)] * (*y)[mind(4, 1)], - (*x)[mind(3, 1)] * (*y)[mind(1, 2)] + (*x)[mind(3, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(3, 3)] * (*y)[mind(3, 2)] + (*x)[mind(3, 4)] * (*y)[mind(4, 2)], - (*x)[mind(3, 1)] * (*y)[mind(1, 3)] + (*x)[mind(3, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(3, 3)] * (*y)[mind(3, 3)] + (*x)[mind(3, 4)] * (*y)[mind(4, 3)], - (*x)[mind(3, 1)] * (*y)[mind(1, 4)] + (*x)[mind(3, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(3, 4)] * (*y)[mind(3, 4)] + (*x)[mind(3, 4)] * (*y)[mind(4, 4)], + x[mind(3, 1)] * y[mind(1, 1)] + x[mind(3, 2)] * y[mind(2, 1)] + + x[mind(3, 3)] * y[mind(3, 1)] + x[mind(3, 4)] * y[mind(4, 1)], + x[mind(3, 1)] * y[mind(1, 2)] + x[mind(3, 2)] * y[mind(2, 2)] + + x[mind(3, 3)] * y[mind(3, 2)] + x[mind(3, 4)] * y[mind(4, 2)], + x[mind(3, 1)] * y[mind(1, 3)] + x[mind(3, 2)] * y[mind(2, 3)] + + x[mind(3, 3)] * y[mind(3, 3)] + x[mind(3, 4)] * y[mind(4, 3)], + x[mind(3, 1)] * y[mind(1, 4)] + x[mind(3, 2)] * y[mind(2, 4)] + + x[mind(3, 4)] * y[mind(3, 4)] + x[mind(3, 4)] * y[mind(4, 4)], - (*x)[mind(4, 1)] * (*y)[mind(1, 1)] + (*x)[mind(4, 2)] * (*y)[mind(2, 1)] + - (*x)[mind(4, 3)] * (*y)[mind(3, 1)] + (*x)[mind(4, 4)] * (*y)[mind(4, 1)], - (*x)[mind(4, 1)] * (*y)[mind(1, 2)] + (*x)[mind(4, 2)] * (*y)[mind(2, 2)] + - (*x)[mind(4, 3)] * (*y)[mind(3, 2)] + (*x)[mind(4, 4)] * (*y)[mind(4, 2)], - (*x)[mind(4, 1)] * (*y)[mind(1, 3)] + (*x)[mind(4, 2)] * (*y)[mind(2, 3)] + - (*x)[mind(4, 3)] * (*y)[mind(3, 3)] + (*x)[mind(4, 4)] * (*y)[mind(4, 3)], - (*x)[mind(4, 1)] * (*y)[mind(1, 4)] + (*x)[mind(4, 2)] * (*y)[mind(2, 4)] + - (*x)[mind(4, 4)] * (*y)[mind(3, 4)] + (*x)[mind(4, 4)] * (*y)[mind(4, 4)], + x[mind(4, 1)] * y[mind(1, 1)] + x[mind(4, 2)] * y[mind(2, 1)] + + x[mind(4, 3)] * y[mind(3, 1)] + x[mind(4, 4)] * y[mind(4, 1)], + x[mind(4, 1)] * y[mind(1, 2)] + x[mind(4, 2)] * y[mind(2, 2)] + + x[mind(4, 3)] * y[mind(3, 2)] + x[mind(4, 4)] * y[mind(4, 2)], + x[mind(4, 1)] * y[mind(1, 3)] + x[mind(4, 2)] * y[mind(2, 3)] + + x[mind(4, 3)] * y[mind(3, 3)] + x[mind(4, 4)] * y[mind(4, 3)], + x[mind(4, 1)] * y[mind(1, 4)] + x[mind(4, 2)] * y[mind(2, 4)] + + x[mind(4, 4)] * y[mind(3, 4)] + x[mind(4, 4)] * y[mind(4, 4)], }; - memcpy(*product, _product, sizeof(_product)); + memcpy(mat, product, sizeof(product)); } static const float transforms[][4] = { @@ -161,9 +162,9 @@ void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, mat[15] = 1.0f; } -void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box, +void wlr_matrix_project_box(float mat[static 16], const struct wlr_box *box, enum wl_output_transform transform, float rotation, - float (*projection)[16]) { + const float projection[static 16]) { int x = box->x; int y = box->y; int width = box->width; @@ -173,38 +174,38 @@ void wlr_matrix_project_box(float (*mat)[16], struct wlr_box *box, if (rotation != 0) { float translate_center[16]; - wlr_matrix_translate(&translate_center, width/2, height/2, 0); + wlr_matrix_translate(translate_center, width/2, height/2, 0); float rotate[16]; - wlr_matrix_rotate(&rotate, rotation); + wlr_matrix_rotate(rotate, rotation); float translate_origin[16]; - wlr_matrix_translate(&translate_origin, -width/2, -height/2, 0); + wlr_matrix_translate(translate_origin, -width/2, -height/2, 0); - wlr_matrix_mul(mat, &translate_center, mat); - wlr_matrix_mul(mat, &rotate, mat); - wlr_matrix_mul(mat, &translate_origin, mat); + wlr_matrix_mul(mat, mat, translate_center); + wlr_matrix_mul(mat, mat, rotate); + wlr_matrix_mul(mat, mat, translate_origin); } float scale[16]; - wlr_matrix_scale(&scale, width, height, 1); + wlr_matrix_scale(scale, width, height, 1); - wlr_matrix_mul(mat, &scale, mat); + wlr_matrix_mul(mat, mat, scale); if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { float surface_translate_center[16]; - wlr_matrix_translate(&surface_translate_center, 0.5, 0.5, 0); + wlr_matrix_translate(surface_translate_center, 0.5, 0.5, 0); float surface_transform[16]; wlr_matrix_transform(surface_transform, transform); float surface_translate_origin[16]; - wlr_matrix_translate(&surface_translate_origin, -0.5, -0.5, 0); + wlr_matrix_translate(surface_translate_origin, -0.5, -0.5, 0); - wlr_matrix_mul(mat, &surface_translate_center, mat); - wlr_matrix_mul(mat, &surface_transform, mat); - wlr_matrix_mul(mat, &surface_translate_origin, mat); + wlr_matrix_mul(mat, mat, surface_translate_center); + wlr_matrix_mul(mat, mat, surface_transform); + wlr_matrix_mul(mat, mat, surface_translate_origin); } - wlr_matrix_mul(projection, mat, mat); + wlr_matrix_mul(mat, projection, mat); } diff --git a/types/wlr_output.c b/types/wlr_output.c index 21343a68..a9fb01c5 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -368,7 +368,7 @@ static void output_fullscreen_surface_render(struct wlr_output *output, assert(renderer); if (!wlr_surface_has_buffer(surface)) { - wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); + wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0}); return; } @@ -378,15 +378,15 @@ static void output_fullscreen_surface_render(struct wlr_output *output, float matrix[16]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); - wlr_matrix_project_box(&matrix, &box, transform, 0, - &output->transform_matrix); + wlr_matrix_project_box(matrix, &box, transform, 0, + output->transform_matrix); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); for (int i = 0; i < nrects; ++i) { output_scissor(output, &rects[i]); - wlr_renderer_clear(renderer, &(float[]){0, 0, 0, 0}); - wlr_render_with_matrix(surface->renderer, surface->texture, &matrix, 1.0f); + wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0}); + wlr_render_with_matrix(surface->renderer, surface->texture, matrix, 1.0f); } wlr_renderer_scissor(renderer, NULL); @@ -436,14 +436,14 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, } float matrix[16]; - wlr_matrix_project_box(&matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, - &cursor->output->transform_matrix); + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + cursor->output->transform_matrix); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); for (int i = 0; i < nrects; ++i) { output_scissor(cursor->output, &rects[i]); - wlr_render_with_matrix(renderer, texture, &matrix, 1.0f); + wlr_render_with_matrix(renderer, texture, matrix, 1.0f); } wlr_renderer_scissor(renderer, NULL); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 5d52fd2a..04dcb141 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -625,19 +625,19 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, } void wlr_surface_get_matrix(struct wlr_surface *surface, - float (*matrix)[16], - const float (*projection)[16], - const float (*transform)[16]) { + float mat[static 16], + const float projection[static 16], + const float transform[static 16]) { int width = surface->texture->width; int height = surface->texture->height; float scale[16]; - wlr_matrix_identity(matrix); + wlr_matrix_identity(mat); if (transform) { - wlr_matrix_mul(matrix, transform, matrix); + wlr_matrix_mul(mat, mat, transform); } - wlr_matrix_scale(&scale, width, height, 1); - wlr_matrix_mul(matrix, &scale, matrix); - wlr_matrix_mul(projection, matrix, matrix); + wlr_matrix_scale(scale, width, height, 1); + wlr_matrix_mul(mat, mat, scale); + wlr_matrix_mul(mat, projection, mat); } bool wlr_surface_has_buffer(struct wlr_surface *surface) { From 14cdb6153f4293d7e058465ab4acaebd6e1f647c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 23 Feb 2018 18:45:16 +0100 Subject: [PATCH 20/52] Add initial linux_dmabuf protocol support Tested with ./weston-simple-dmabuf-drm ./weston-simple-dmabuf-drm --import-immediate=1 ./weston-simple-dmabuf-drm --y-inverted=1 (and combinations) Supports only single plane XRGB dmabufs for now. --- include/wlr/render.h | 2 + include/wlr/render/egl.h | 28 ++ include/wlr/render/interface.h | 3 + include/wlr/types/wlr_linux_dmabuf.h | 84 +++++ protocol/meson.build | 1 + render/egl.c | 135 ++++++++ render/glapi.txt | 2 + render/gles2/texture.c | 62 +++- render/wlr_texture.c | 5 + types/meson.build | 1 + types/wlr_linux_dmabuf.c | 464 +++++++++++++++++++++++++++ types/wlr_surface.c | 4 + 12 files changed, 787 insertions(+), 4 deletions(-) create mode 100644 include/wlr/types/wlr_linux_dmabuf.h create mode 100644 types/wlr_linux_dmabuf.c diff --git a/include/wlr/render.h b/include/wlr/render.h index 77449556..9080175f 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -123,6 +123,8 @@ bool wlr_texture_upload_drm(struct wlr_texture *tex, 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, diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 97a28016..f05a9837 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -6,6 +6,7 @@ #include #include #include +#include struct wlr_egl { EGLDisplay display; @@ -18,6 +19,8 @@ struct wlr_egl { struct { bool buffer_age; bool swap_buffers_with_damage; + bool dmabuf_import; + bool dmabuf_import_modifiers; } egl_exts; struct wl_display *wl_display; @@ -61,6 +64,31 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window); 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. + */ +EGLImageKHR wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer_attribs *attributes); + +/** + * Try to import the given dmabuf. On success return true false otherwise. + * If this succeeds the dmabuf can be used for rendering on a texture + */ +bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer *dmabuf); + +/** + * Get the available dmabuf formats + */ +int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, int **formats); + +/** + * Get the available dmabuf modifiers for a given format + */ +int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, + uint64_t **modifiers); + /** * Destroys an egl image created with the given wlr_egl. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index eda5af1c..2ba584d9 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -8,6 +8,7 @@ #include #include #include +#include struct wlr_renderer_impl; @@ -58,6 +59,8 @@ struct wlr_texture_impl { 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_matrix)(struct wlr_texture *state, float (*matrix)[16], const float (*projection)[16], int x, int y); void (*get_buffer_size)(struct wlr_texture *texture, diff --git a/include/wlr/types/wlr_linux_dmabuf.h b/include/wlr/types/wlr_linux_dmabuf.h new file mode 100644 index 00000000..9d71e598 --- /dev/null +++ b/include/wlr/types/wlr_linux_dmabuf.h @@ -0,0 +1,84 @@ +#ifndef WLR_TYPES_WLR_LINUX_DMABUF_H +#define WLR_TYPES_WLR_LINUX_DMABUF_H + +#define WLR_LINUX_DMABUF_MAX_PLANES 4 + +#include +#include + +/* So we don't have to pull in linux specific drm headers */ +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1) +#endif + +struct wlr_dmabuf_buffer_attribs { + /* set via params_add */ + int n_planes; + uint32_t offset[WLR_LINUX_DMABUF_MAX_PLANES]; + uint32_t stride[WLR_LINUX_DMABUF_MAX_PLANES]; + uint64_t modifier[WLR_LINUX_DMABUF_MAX_PLANES]; + int fd[WLR_LINUX_DMABUF_MAX_PLANES]; + /* set via params_create */ + int32_t width; + int32_t height; + uint32_t format; + uint32_t flags; /* enum zlinux_buffer_params_flags */ +}; + +struct wlr_dmabuf_buffer { + struct wlr_egl *egl; + struct wl_resource *buffer_resource; + struct wl_resource *params_resource; + struct wlr_dmabuf_buffer_attribs attributes; +}; + +/** + * Returns true if the given resource was created via the linux-dmabuf + * buffer protocol, false otherwise + */ +bool wlr_dmabuf_resource_is_buffer(struct wl_resource *buffer_resource); + +/** + * Returns the wlr_dmabuf_buffer if the given resource was created + * via the linux-dmabuf buffer protocol + */ +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( + struct wl_resource *buffer_resource); + +/** + * Returns the wlr_dmabuf_buffer if the given resource was created + * via the linux-dmabuf params protocol + */ +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; + struct wl_listener display_destroy; + struct wlr_egl *egl; +}; + +/** + * Create linux-dmabuf interface + */ +struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, + struct wlr_egl *egl); +/** + * Destroy the linux-dmabuf interface + */ +void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf); + +/** + * Returns the wlr_linux_dmabuf if the given resource was created + * via the linux_dmabuf protocol + */ +struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource( + struct wl_resource *resource); + +#endif diff --git a/protocol/meson.build b/protocol/meson.build index 200cbd7a..638b0c46 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -23,6 +23,7 @@ wayland_scanner_client = generator( protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], + [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], 'gamma-control.xml', 'gtk-primary-selection.xml', diff --git a/render/egl.c b/render/egl.c index 0a68d6e5..55809983 100644 --- a/render/egl.c +++ b/render/egl.c @@ -167,6 +167,12 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, check_egl_ext(egl->egl_exts_str, "EGL_EXT_swap_buffers_with_damage") || check_egl_ext(egl->egl_exts_str, "EGL_KHR_swap_buffers_with_damage"); + egl->egl_exts.dmabuf_import = + check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import"); + egl->egl_exts.dmabuf_import_modifiers = + check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import_modifiers") + && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; + return true; error: @@ -299,3 +305,132 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, } return true; } + +EGLImage wlr_egl_create_image_from_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer_attribs *attributes) { + int atti = 0; + EGLint attribs[20]; + attribs[atti++] = EGL_WIDTH; + attribs[atti++] = attributes->width; + attribs[atti++] = EGL_HEIGHT; + attribs[atti++] = attributes->height; + attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[atti++] = attributes->format; + + bool has_modifier = false; + if (attributes->modifier[0] != DRM_FORMAT_MOD_INVALID) { + if (!egl->egl_exts.dmabuf_import_modifiers) { + return NULL; + } + has_modifier = true; + } + + /* TODO: YUV planes have up four planes but we only support a + single EGLImage for now */ + if (attributes->n_planes > 1) { + return NULL; + } + + attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; + attribs[atti++] = attributes->fd[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; + attribs[atti++] = attributes->offset[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; + attribs[atti++] = attributes->stride[0]; + if (has_modifier) { + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + attribs[atti++] = attributes->modifier[0] & 0xFFFFFFFF; + attribs[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + attribs[atti++] = attributes->modifier[0] >> 32; + } + attribs[atti++] = EGL_NONE; + return eglCreateImageKHR(egl->display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL, attribs); +} + +#ifndef DRM_FORMAT_BIG_ENDIAN +# define DRM_FORMAT_BIG_ENDIAN 0x80000000 +#endif +bool wlr_egl_check_import_dmabuf(struct wlr_egl *egl, + struct wlr_dmabuf_buffer *dmabuf) { + switch (dmabuf->attributes.format & ~DRM_FORMAT_BIG_ENDIAN) { + /* YUV based formats not yet supported */ + case WL_SHM_FORMAT_YUYV: + case WL_SHM_FORMAT_YVYU: + case WL_SHM_FORMAT_UYVY: + case WL_SHM_FORMAT_VYUY: + case WL_SHM_FORMAT_AYUV: + return false; + default: + break; + } + + EGLImage egl_image = wlr_egl_create_image_from_dmabuf(egl, + &dmabuf->attributes); + if (egl_image) { + /* We can import the image, good. No need to keep it + since wlr_texture_upload_dmabuf will import it again */ + wlr_egl_destroy_image(egl, egl_image); + return true; + } + /* TODO: import yuv dmabufs */ + return false; +} + +int wlr_egl_get_dmabuf_formats(struct wlr_egl *egl, + int **formats) { + if (!egl->egl_exts.dmabuf_import || + !egl->egl_exts.dmabuf_import_modifiers) { + wlr_log(L_ERROR, "dmabuf extension not present"); + return -1; + } + + EGLint num; + if (!eglQueryDmaBufFormatsEXT(egl->display, 0, NULL, &num)) { + wlr_log(L_ERROR, "failed to query number of dmabuf formats"); + return -1; + } + + *formats = calloc(num, sizeof(int)); + if (*formats == NULL) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + return -1; + } + + if (!eglQueryDmaBufFormatsEXT(egl->display, num, *formats, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf format"); + free(*formats); + return -1; + } + return num; +} + +int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, + int format, uint64_t **modifiers) { + if (!egl->egl_exts.dmabuf_import || + !egl->egl_exts.dmabuf_import_modifiers) { + wlr_log(L_ERROR, "dmabuf extension not present"); + return -1; + } + + EGLint num; + if (!eglQueryDmaBufModifiersEXT(egl->display, format, 0, + NULL, NULL, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf number of modifiers"); + return -1; + } + + *modifiers = calloc(num, sizeof(uint64_t)); + if (*modifiers == NULL) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + return -1; + } + + if (!eglQueryDmaBufModifiersEXT(egl->display, format, num, + *modifiers, NULL, &num)) { + wlr_log(L_ERROR, "failed to query dmabuf modifiers"); + free(*modifiers); + return -1; + } + return num; +} diff --git a/render/glapi.txt b/render/glapi.txt index 0b0b452c..02ac7dd8 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -8,3 +8,5 @@ eglCreatePlatformWindowSurfaceEXT -glEGLImageTargetTexture2DOES -eglSwapBuffersWithDamageEXT -eglSwapBuffersWithDamageKHR +-eglQueryDmaBufFormatsEXT +-eglQueryDmaBufModifiersEXT diff --git a/render/gles2/texture.c b/render/gles2/texture.c index d25d1809..5e84890f 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -227,6 +227,42 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, return true; } + +static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, + struct wl_resource *dmabuf_resource) { + struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; + 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)) { + _tex->inverted_y = true; + } + + GLenum target = GL_TEXTURE_2D; + const struct pixel_format *pf = + gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); + gles2_texture_ensure_texture(tex); + GL_CALL(glBindTexture(target, tex->tex_id)); + tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); + GL_CALL(glActiveTexture(GL_TEXTURE0)); + GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); + tex->pixel_format = pf; + tex->wlr_texture.valid = true; + return true; +} + static void gles2_texture_get_matrix(struct wlr_texture *_texture, float (*matrix)[16], const float (*projection)[16], int x, int y) { struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; @@ -240,6 +276,21 @@ static void gles2_texture_get_matrix(struct wlr_texture *_texture, wlr_matrix_mul(projection, matrix, matrix); } + +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); @@ -250,10 +301,12 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct } if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH, (EGLint*)width)) { - wlr_log(L_ERROR, "could not get size of the buffer " - "(no buffer found)"); - return; - }; + 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); @@ -292,6 +345,7 @@ static struct wlr_texture_impl wlr_texture_impl = { .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_matrix = gles2_texture_get_matrix, .get_buffer_size = gles2_texture_get_buffer_size, diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a82a16b2..e4e6b9ff 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -53,6 +53,11 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture, 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_matrix(struct wlr_texture *texture, float (*matrix)[16], const float (*projection)[16], int x, int y) { texture->impl->get_matrix(texture, matrix, projection, x, y); diff --git a/types/meson.build b/types/meson.build index 703b06ca..11aa5e20 100644 --- a/types/meson.build +++ b/types/meson.build @@ -9,6 +9,7 @@ lib_wlr_types = static_library( 'wlr_idle.c', 'wlr_input_device.c', 'wlr_keyboard.c', + 'wlr_linux_dmabuf.c', 'wlr_list.c', 'wlr_output_damage.c', 'wlr_output_layout.c', diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c new file mode 100644 index 00000000..407a5717 --- /dev/null +++ b/types/wlr_linux_dmabuf.c @@ -0,0 +1,464 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux-dmabuf-unstable-v1-protocol.h" + +static void wl_buffer_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +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)) { + return false; + } + + struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource); + if (buffer && buffer->buffer_resource && !buffer->params_resource && + buffer->buffer_resource == buffer_resource) { + return true; + } + + return false; +} + +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_buffer_resource( + struct wl_resource *buffer_resource) { + assert(wl_resource_instance_of(buffer_resource, &wl_buffer_interface, + &wl_buffer_impl)); + + struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(buffer_resource); + assert(buffer); + assert(buffer->buffer_resource); + assert(!buffer->params_resource); + assert(buffer->buffer_resource == buffer_resource); + + return buffer; +} + +static void linux_dmabuf_buffer_destroy(struct wlr_dmabuf_buffer *buffer) { + for (int i = 0; i < buffer->attributes.n_planes; i++) { + close(buffer->attributes.fd[i]); + buffer->attributes.fd[i] = -1; + } + buffer->attributes.n_planes = 0; + free(buffer); +} + +static void params_destroy(struct wl_client *client, struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void params_add(struct wl_client *client, + struct wl_resource *params_resource, int32_t name_fd, + uint32_t plane_idx, uint32_t offset, uint32_t stride, + uint32_t modifier_hi, uint32_t modifier_lo) { + struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_params_resource( + params_resource); + + if (!buffer) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, + "params was already used to create a wl_buffer"); + close(name_fd); + return; + } + + if (plane_idx >= WLR_LINUX_DMABUF_MAX_PLANES) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, + "plane index %u > %u", plane_idx, WLR_LINUX_DMABUF_MAX_PLANES); + close(name_fd); + return; + } + + if (buffer->attributes.fd[plane_idx] != -1) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET, + "a dmabuf with id %d has already been added for plane %u", + buffer->attributes.fd[plane_idx], + plane_idx); + close(name_fd); + return; + } + + buffer->attributes.fd[plane_idx] = name_fd; + buffer->attributes.offset[plane_idx] = offset; + buffer->attributes.stride[plane_idx] = stride; + buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) | + modifier_lo; + buffer->attributes.n_planes++; +} + +static void handle_buffer_destroy(struct wl_resource *buffer_resource) +{ + struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_buffer_resource( + buffer_resource); + + linux_dmabuf_buffer_destroy(buffer); +} + +static void params_create_common(struct wl_client *client, + struct wl_resource *params_resource, uint32_t buffer_id, int32_t width, + int32_t height, uint32_t format, uint32_t flags) { + if (!wl_resource_get_user_data(params_resource)) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, + "params was already used to create a wl_buffer"); + return; + } + struct wlr_dmabuf_buffer *buffer = wlr_dmabuf_buffer_from_params_resource( + params_resource); + + /* Switch the linux_dmabuf_buffer object from params resource to + * eventually wl_buffer resource. */ + wl_resource_set_user_data(buffer->params_resource, NULL); + buffer->params_resource = NULL; + + if (!buffer->attributes.n_planes) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, + "no dmabuf has been added to the params"); + goto err_out; + } + + /* TODO: support more planes */ + if (buffer->attributes.n_planes != 1) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, + "only single plane buffers supported not %d", + buffer->attributes.n_planes); + goto err_out; + } + + if (buffer->attributes.fd[0] == -1) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, + "no dmabuf has been added for plane"); + goto err_out; + } + + buffer->attributes.width = width; + buffer->attributes.height = height; + buffer->attributes.format = format; + buffer->attributes.flags = flags; + + if (width < 1 || height < 1) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS, + "invalid width %d or height %d", width, height); + goto err_out; + } + + if ((uint64_t)buffer->attributes.offset[0] + buffer->attributes.stride[0] > UINT32_MAX) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "size overflow for plane"); + goto err_out; + } + + if ((uint64_t)buffer->attributes.offset[0] + + (uint64_t) buffer->attributes.stride[0] * height > UINT32_MAX) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "size overflow for plane"); + goto err_out; + } + + off_t size = lseek(buffer->attributes.fd[0], 0, SEEK_END); + if (size != -1) { /* Skip checks if kernel does no support seek on buffer */ + if (buffer->attributes.offset[0] >= size) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "invalid offset %i for plane", + buffer->attributes.offset[0]); + goto err_out; + } + + if (buffer->attributes.offset[0] + buffer->attributes.stride[0] > size) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "invalid stride %i for plane", + buffer->attributes.stride[0]); + goto err_out; + } + + if (buffer->attributes.offset[0] + buffer->attributes.stride[0] * height > size) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + "invalid buffer stride or height for plane"); + goto err_out; + } + } + + /* reject unknown flags */ + if (buffer->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) { + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, + "Unknown dmabuf flags %"PRIu32, buffer->attributes.flags); + goto err_out; + } + + /* Check if dmabuf is usable */ + if (!wlr_egl_check_import_dmabuf(buffer->egl, buffer)) { + goto err_failed; + } + + buffer->buffer_resource = wl_resource_create(client, &wl_buffer_interface, + 1, buffer_id); + if (!buffer->buffer_resource) { + wl_resource_post_no_memory(params_resource); + goto err_failed; + } + + wl_resource_set_implementation(buffer->buffer_resource, + &wl_buffer_impl, buffer, handle_buffer_destroy); + + /* send 'created' event when the request is not for an immediate + * import, that is buffer_id is zero */ + if (buffer_id == 0) { + zwp_linux_buffer_params_v1_send_created(params_resource, + buffer->buffer_resource); + } + return; + +err_failed: + if (buffer_id == 0) { + zwp_linux_buffer_params_v1_send_failed(params_resource); + } else { + /* since the behavior is left implementation defined by the + * protocol in case of create_immed failure due to an unknown cause, + * we choose to treat it as a fatal error and immediately kill the + * client instead of creating an invalid handle and waiting for it + * to be used. + */ + wl_resource_post_error(params_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER, + "importing the supplied dmabufs failed"); + } +err_out: + linux_dmabuf_buffer_destroy(buffer); + return; +} + +static void params_create(struct wl_client *client, + struct wl_resource *params_resource, + int32_t width, int32_t height,uint32_t format, uint32_t flags) { + params_create_common(client, params_resource, 0, width, height, format, flags); +} + +static void params_create_immed(struct wl_client *client, + struct wl_resource *params_resource, uint32_t buffer_id, + int32_t width, int32_t height,uint32_t format, uint32_t flags) { + params_create_common(client, params_resource, buffer_id, width, height, format, flags); +} + +static const struct zwp_linux_buffer_params_v1_interface linux_buffer_params_impl = { + params_destroy, + params_add, + params_create, + params_create_immed, +}; + +struct wlr_dmabuf_buffer *wlr_dmabuf_buffer_from_params_resource( + struct wl_resource *params_resource) { + assert(wl_resource_instance_of(params_resource, + &zwp_linux_buffer_params_v1_interface, + &linux_buffer_params_impl)); + + struct wlr_dmabuf_buffer *buffer = wl_resource_get_user_data(params_resource); + assert(buffer); + assert(buffer->params_resource); + assert(!buffer->buffer_resource); + assert(buffer->params_resource == params_resource); + + return buffer; +} + +static void handle_params_destroy(struct wl_resource *params_resource) { + /* Check for NULL since wlr_dmabuf_buffer_from_params_resource will choke */ + if (!wl_resource_get_user_data(params_resource)) { + return; + } + + struct wlr_dmabuf_buffer *buffer = + wlr_dmabuf_buffer_from_params_resource(params_resource); + linux_dmabuf_buffer_destroy(buffer); +} + +static void linux_dmabuf_create_params(struct wl_client *client, + struct wl_resource *linux_dmabuf_resource, + uint32_t params_id) { + struct wlr_linux_dmabuf *linux_dmabuf = wlr_linux_dmabuf_from_resource( + linux_dmabuf_resource); + + uint32_t version = wl_resource_get_version(linux_dmabuf_resource); + struct wlr_dmabuf_buffer *buffer = calloc(1, sizeof *buffer); + if (!buffer) { + goto err; + } + + for (int i = 0; i < WLR_LINUX_DMABUF_MAX_PLANES; i++) { + buffer->attributes.fd[i] = -1; + } + + buffer->egl = linux_dmabuf->egl; + buffer->params_resource = wl_resource_create(client, + &zwp_linux_buffer_params_v1_interface, + version, params_id); + if (!buffer->params_resource) { + goto err_free; + } + + wl_resource_set_implementation(buffer->params_resource, + &linux_buffer_params_impl,buffer, handle_params_destroy); + return; + +err_free: + free(buffer); +err: + wl_resource_post_no_memory(linux_dmabuf_resource); +} + +static void linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_impl = { + linux_dmabuf_destroy, + linux_dmabuf_create_params +}; + +struct wlr_linux_dmabuf *wlr_linux_dmabuf_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &zwp_linux_dmabuf_v1_interface, + &linux_dmabuf_impl)); + + struct wlr_linux_dmabuf *dmabuf = wl_resource_get_user_data(resource); + assert(dmabuf); + return dmabuf; +} + +static void linux_dmabuf_send_modifiers(struct wlr_linux_dmabuf *linux_dmabuf, + struct wl_resource *resource) { + struct wlr_egl *egl = linux_dmabuf->egl; + /* + * Use EGL_EXT_image_dma_buf_import_modifiers to query and advertise + * format/modifier codes. + */ + uint64_t modifier_invalid = DRM_FORMAT_MOD_INVALID; + int *formats = NULL; + int num_formats = wlr_egl_get_dmabuf_formats(egl, &formats); + + if (num_formats < 0) { + return; + } + + for (int i = 0; i < num_formats; i++) { + int num_modifiers; + uint64_t *modifiers = NULL; + + num_modifiers = wlr_egl_get_dmabuf_modifiers(egl, formats[i], + &modifiers); + if (num_modifiers < 0) { + return; + } + /* send DRM_FORMAT_MOD_INVALID token when no modifiers are supported + * for this format */ + if (num_modifiers == 0) { + num_modifiers = 1; + modifiers = &modifier_invalid; + } + for (int j = 0; j < num_modifiers; j++) { + uint32_t modifier_lo = modifiers[j] & 0xFFFFFFFF; + uint32_t modifier_hi = modifiers[j] >> 32; + zwp_linux_dmabuf_v1_send_modifier(resource, formats[i], + modifier_hi, + modifier_lo); + } + if (modifiers != &modifier_invalid) { + free(modifiers); + } + } + free(formats); +} + +static void linux_dmabuf_bind(struct wl_client *client, + void *data, uint32_t version, uint32_t id) { + struct wlr_linux_dmabuf *linux_dmabuf = data; + struct wl_resource *resource = wl_resource_create(client, + &zwp_linux_dmabuf_v1_interface, + version, id); + + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &linux_dmabuf_impl, + linux_dmabuf, NULL); + if (version < ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) { + return; + } + + linux_dmabuf_send_modifiers(linux_dmabuf, resource); +} + +void wlr_linux_dmabuf_destroy(struct wlr_linux_dmabuf *linux_dmabuf) { + if (!linux_dmabuf) { + return; + } + wl_list_remove(&linux_dmabuf->display_destroy.link); + + wl_global_destroy(linux_dmabuf->wl_global); + free(linux_dmabuf); +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_linux_dmabuf *linux_dmabuf = wl_container_of(listener, linux_dmabuf, display_destroy); + wlr_linux_dmabuf_destroy(linux_dmabuf); +} + +struct wlr_linux_dmabuf *wlr_linux_dmabuf_create(struct wl_display *display, + struct wlr_egl *egl) { + struct wlr_linux_dmabuf *linux_dmabuf = + calloc(1, sizeof(struct wlr_linux_dmabuf)); + if (linux_dmabuf == NULL) { + wlr_log(L_ERROR, "could not create simple dmabuf manager"); + return NULL; + } + + linux_dmabuf->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &linux_dmabuf->display_destroy); + + linux_dmabuf->wl_global = + wl_global_create(display, &zwp_linux_dmabuf_v1_interface, + 3, linux_dmabuf, linux_dmabuf_bind); + + linux_dmabuf->egl = egl; + if (!linux_dmabuf->wl_global) { + wlr_log(L_ERROR, "could not create linux dmabuf v1 wl global"); + free(linux_dmabuf); + return NULL; + } + + return linux_dmabuf; +} diff --git a/types/wlr_surface.c b/types/wlr_surface.c index d63fc1f1..fd5bf4f1 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -325,6 +325,10 @@ static void wlr_surface_apply_damage(struct wlr_surface *surface, 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; From eb4337b5eea47e5f3ec337639d2f62c2bae15797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 11 Mar 2018 19:05:11 +0100 Subject: [PATCH 21/52] Wire up linux_dmabuf in rootston --- include/rootston/desktop.h | 2 ++ rootston/desktop.c | 3 +++ types/wlr_linux_dmabuf.c | 8 ++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 467de8ab..db8a088e 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ struct roots_desktop { struct wlr_primary_selection_device_manager *primary_selection_device_manager; struct wlr_idle *idle; struct wlr_idle_inhibit_manager_v1 *idle_inhibit; + struct wlr_linux_dmabuf *linux_dmabuf; struct wl_listener new_output; struct wl_listener layout_change; diff --git a/rootston/desktop.c b/rootston/desktop.c index 3628b051..a130fe38 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -729,6 +730,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->idle = wlr_idle_create(server->wl_display); desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display); + struct wlr_egl *egl = wlr_backend_get_egl(server->backend); + desktop->linux_dmabuf = wlr_linux_dmabuf_create(server->wl_display, egl); return desktop; } diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index 407a5717..3b86166e 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -176,7 +176,7 @@ static void params_create_common(struct wl_client *client, } if ((uint64_t)buffer->attributes.offset[0] + - (uint64_t) buffer->attributes.stride[0] * height > UINT32_MAX) { + (uint64_t)buffer->attributes.stride[0] * height > UINT32_MAX) { wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, "size overflow for plane"); @@ -205,15 +205,15 @@ static void params_create_common(struct wl_client *client, wl_resource_post_error(params_resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, "invalid buffer stride or height for plane"); - goto err_out; + goto err_out; } } /* reject unknown flags */ if (buffer->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) { wl_resource_post_error(params_resource, - ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, - "Unknown dmabuf flags %"PRIu32, buffer->attributes.flags); + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, + "Unknown dmabuf flags %"PRIu32, buffer->attributes.flags); goto err_out; } From 653bc282a7f814341f6d7429000928bc696e215e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 11 Mar 2018 19:32:23 +0100 Subject: [PATCH 22/52] Indent GLSL by two spaces since this is the most established indentation --- render/gles2/shaders.c | 53 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 38c61f9c..c8ba2ae6 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -10,17 +10,17 @@ const GLchar quad_vertex_src[] = "varying vec4 v_color;" "varying vec2 v_texcoord;" "mat4 transpose(in mat4 inMatrix) {" -" vec4 i0 = inMatrix[0];" -" vec4 i1 = inMatrix[1];" -" vec4 i2 = inMatrix[2];" -" vec4 i3 = inMatrix[3];" -" mat4 outMatrix = mat4(" -" vec4(i0.x, i1.x, i2.x, i3.x)," -" vec4(i0.y, i1.y, i2.y, i3.y)," -" vec4(i0.z, i1.z, i2.z, i3.z)," -" vec4(i0.w, i1.w, i2.w, i3.w)" -" );" -" return outMatrix;" +" vec4 i0 = inMatrix[0];" +" vec4 i1 = inMatrix[1];" +" vec4 i2 = inMatrix[2];" +" vec4 i3 = inMatrix[3];" +" mat4 outMatrix = mat4(" +" vec4(i0.x, i1.x, i2.x, i3.x)," +" vec4(i0.y, i1.y, i2.y, i3.y)," +" vec4(i0.z, i1.z, i2.z, i3.z)," +" vec4(i0.w, i1.w, i2.w, i3.w)" +" );" +" return outMatrix;" "}" "void main() {" " gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" @@ -55,21 +55,20 @@ const GLchar vertex_src[] = "attribute vec2 texcoord;" "varying vec2 v_texcoord;" "mat4 transpose(in mat4 inMatrix) {" -" vec4 i0 = inMatrix[0];" -" vec4 i1 = inMatrix[1];" -" vec4 i2 = inMatrix[2];" -" vec4 i3 = inMatrix[3];" -" mat4 outMatrix = mat4(" -" vec4(i0.x, i1.x, i2.x, i3.x)," -" vec4(i0.y, i1.y, i2.y, i3.y)," -" vec4(i0.z, i1.z, i2.z, i3.z)," -" vec4(i0.w, i1.w, i2.w, i3.w)" -" );" -"" -" return outMatrix;" +" vec4 i0 = inMatrix[0];" +" vec4 i1 = inMatrix[1];" +" vec4 i2 = inMatrix[2];" +" vec4 i3 = inMatrix[3];" +" mat4 outMatrix = mat4(" +" vec4(i0.x, i1.x, i2.x, i3.x)," +" vec4(i0.y, i1.y, i2.y, i3.y)," +" vec4(i0.z, i1.z, i2.z, i3.z)," +" vec4(i0.w, i1.w, i2.w, i3.w)" +" );" +" return outMatrix;" "}" "void main() {" -" gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" +" gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" " if (invert_y) {" " v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);" " } else {" @@ -83,7 +82,7 @@ const GLchar fragment_src_rgba[] = "uniform sampler2D tex;" "uniform float alpha;" "void main() {" -" gl_FragColor = alpha * texture2D(tex, v_texcoord);" +" gl_FragColor = alpha * texture2D(tex, v_texcoord);" "}"; const GLchar fragment_src_rgbx[] = @@ -92,8 +91,8 @@ const GLchar fragment_src_rgbx[] = "uniform sampler2D tex;" "uniform float alpha;" "void main() {" -" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" -" gl_FragColor.a = alpha;" +" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" +" gl_FragColor.a = alpha;" "}"; const GLchar fragment_src_external[] = From 824a95ad19062e867178593f0937d14049422989 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 15:33:58 +0100 Subject: [PATCH 23/52] matrix: use 2D matrices --- backend/drm/drm.c | 4 +- backend/drm/renderer.c | 20 +-- examples/output-layout.c | 6 +- examples/rotation.c | 4 +- examples/tablet.c | 2 +- examples/touch.c | 4 +- include/backend/drm/drm.h | 2 +- include/wlr/render.h | 20 +-- include/wlr/render/interface.h | 12 +- include/wlr/types/wlr_matrix.h | 24 ++-- include/wlr/types/wlr_output.h | 2 +- include/wlr/types/wlr_surface.h | 10 +- render/gles2/renderer.c | 24 ++-- render/gles2/shaders.c | 67 +++++---- render/gles2/texture.c | 13 +- render/wlr_renderer.c | 10 +- render/wlr_texture.c | 2 +- rootston/output.c | 6 +- types/wlr_matrix.c | 231 +++++++++++++------------------- types/wlr_output.c | 8 +- types/wlr_surface.c | 16 +-- 21 files changed, 216 insertions(+), 271 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 1e78d301..e956f280 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -647,9 +647,9 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); - float matrix[16]; + float matrix[9]; wlr_texture_get_matrix(plane->wlr_tex, matrix, plane->matrix, 0, 0); - wlr_render_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex, + wlr_render_texture_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex, matrix, 1.0f); glFinish(); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index ab56e6c2..f700dd59 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -226,20 +227,21 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, wlr_drm_surface_make_current(dest, NULL); struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); + assert(tex); - static const float matrix[16] = { + static const float color[] = {0.0, 0.0, 0.0, 1.0}; + + static const float mat[9] = { [0] = 2.0f, - [3] = -1.0f, - [5] = 2.0f, - [7] = -1.0f, - [10] = 1.0f, - [15] = 1.0f, + [2] = -1.0f, + [4] = 2.0f, + [5] = -1.0f, + [8] = 1.0f, }; glViewport(0, 0, dest->width, dest->height); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - wlr_render_with_matrix(dest->renderer->wlr_rend, tex, matrix, 1.0f); + wlr_renderer_clear(dest->renderer->wlr_rend, color); + wlr_render_texture_with_matrix(dest->renderer->wlr_rend, tex, mat, 1.0f); return wlr_drm_surface_swap_buffers(dest, NULL); } diff --git a/examples/output-layout.c b/examples/output-layout.c index f4df73a0..9c914137 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -111,7 +111,7 @@ static void handle_output_frame(struct output_state *output, .width = 128, .height = 128, }; if (wlr_output_layout_intersects(sample->layout, output->output, &box)) { - float matrix[16]; + float matrix[9]; // transform global coordinates to local coordinates double local_x = sample->x_offs; @@ -121,8 +121,8 @@ static void handle_output_frame(struct output_state *output, wlr_texture_get_matrix(sample->cat_texture, matrix, wlr_output->transform_matrix, local_x, local_y); - wlr_render_with_matrix(sample->renderer, - sample->cat_texture, matrix, 1.0f); + wlr_render_texture_with_matrix(sample->renderer, sample->cat_texture, + matrix, 1.0f); } wlr_renderer_end(sample->renderer); diff --git a/examples/rotation.c b/examples/rotation.c index 0b0c6adf..4431f60a 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -46,12 +46,12 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_renderer_begin(sample->renderer, wlr_output); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); - float matrix[16]; + float matrix[9]; for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { for (int x = -128 + (int)odata->x_offs; x < width; x += 128) { wlr_texture_get_matrix(sample->cat_texture, matrix, wlr_output->transform_matrix, x, y); - wlr_render_with_matrix(sample->renderer, + wlr_render_texture_with_matrix(sample->renderer, sample->cat_texture, matrix, 1.0f); } } diff --git a/examples/tablet.c b/examples/tablet.c index 82f86553..521447b9 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -49,7 +49,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_renderer_begin(sample->renderer, wlr_output); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); - float matrix[16]; + float matrix[9]; float distance = 0.8f * (1 - sample->distance); float tool_color[4] = { distance, distance, distance, 1 }; for (size_t i = 0; sample->button && i < 4; ++i) { diff --git a/examples/touch.c b/examples/touch.c index 6f4821ad..47bbebc2 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -45,14 +45,14 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_renderer_begin(sample->renderer, wlr_output); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); - float matrix[16]; + float matrix[9]; struct touch_point *p; wl_list_for_each(p, &sample->touch_points, link) { wlr_texture_get_matrix(sample->cat_texture, matrix, wlr_output->transform_matrix, (int)(p->x * width) - sample->cat_texture->width / 2, (int)(p->y * height) - sample->cat_texture->height / 2); - wlr_render_with_matrix(sample->renderer, sample->cat_texture, + wlr_render_texture_with_matrix(sample->renderer, sample->cat_texture, matrix, 1.0f); } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index ee3fd38e..26189340 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -26,7 +26,7 @@ struct wlr_drm_plane { struct wlr_drm_surface mgpu_surf; // Only used by cursor - float matrix[16]; + float matrix[9]; struct wlr_texture *wlr_tex; struct gbm_bo *cursor_bo; bool cursor_enabled; diff --git a/include/wlr/render.h b/include/wlr/render.h index 50c2dd13..d1498b07 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -30,26 +30,26 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); * * struct wlr_renderer *renderer; * struct wlr_texture *texture; - * float projection[16]; - * float matrix[16]; - * wlr_texture_get_matrix(texture, &matrix, &projection, 123, 321); - * wlr_render_with_matrix(renderer, texture, &matrix, 0.5f); + * float projection[9]; + * float matrix[9]; + * wlr_texture_get_matrix(texture, matrix, projection, 123, 321); + * wlr_render_texture_with_matrix(renderer, texture, matrix, 0.5f); * * This will render the texture at <123, 321> with an alpha channel of 0.5. */ -bool wlr_render_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float matrix[static 16], float alpha); +bool wlr_render_texture_with_matrix(struct wlr_renderer *r, + struct wlr_texture *texture, const float matrix[static 9], float alpha); /** * Renders a solid quad in the specified color. */ void wlr_render_colored_quad(struct wlr_renderer *r, - const float color[static 4], const float matrix[static 16]); + const float color[static 4], const float matrix[static 9]); /** * Renders a solid ellipse in the specified color. */ void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float color[static 4], const float matrix[static 16]); + const float color[static 4], const float matrix[static 9]); /** * Returns a list of pixel formats supported by this renderer. */ @@ -139,8 +139,8 @@ bool wlr_texture_update_shm(struct wlr_texture *surf, uint32_t format, * width) and [0, height], and the x and y coordinates provided are used as * such. */ -void wlr_texture_get_matrix(struct wlr_texture *texture, float mat[static 16], - const float projection[static 16], int x, int y); +void wlr_texture_get_matrix(struct wlr_texture *texture, float mat[static 9], + const float projection[static 9], int x, int y); /** * Destroys this wlr_texture. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 4d81bdf9..03b8309f 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -21,13 +21,13 @@ struct wlr_renderer_impl { 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_with_matrix)(struct wlr_renderer *renderer, - struct wlr_texture *texture, const float matrix[static 16], + bool (*render_texture_with_matrix)(struct wlr_renderer *renderer, + struct wlr_texture *texture, const float matrix[static 9], float alpha); void (*render_quad)(struct wlr_renderer *renderer, - const float color[static 4], const float matrix[static 16]); + const float color[static 4], const float matrix[static 9]); void (*render_ellipse)(struct wlr_renderer *renderer, - const float color[static 4], const float matrix[static 16]); + 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, @@ -59,8 +59,8 @@ struct wlr_texture_impl { struct wl_resource *drm_buf); bool (*upload_eglimage)(struct wlr_texture *texture, EGLImageKHR image, uint32_t width, uint32_t height); - void (*get_matrix)(struct wlr_texture *state, float mat[static 16], - const float projection[static 16], int x, int y); + void (*get_matrix)(struct wlr_texture *state, float mat[static 9], + const float projection[static 9], int x, int y); void (*get_buffer_size)(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height); void (*bind)(struct wlr_texture *texture); diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h index cf5ad20d..5255980a 100644 --- a/include/wlr/types/wlr_matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -2,22 +2,22 @@ #define WLR_TYPES_WLR_MATRIX_H #include +#include #include -void wlr_matrix_identity(float mat[static 16]); -void wlr_matrix_translate(float mat[static 16], float x, float y, float z); -void wlr_matrix_scale(float mat[static 16], float x, float y, float z); -void wlr_matrix_rotate(float mat[static 16], float radians); -void wlr_matrix_mul(float mat[static 16], const float x[static 16], - const float y[static 16]); +void wlr_matrix_identity(float mat[static 9]); +void wlr_matrix_translate(float mat[static 9], float x, float y); +void wlr_matrix_scale(float mat[static 9], float x, float y); +void wlr_matrix_rotate(float mat[static 9], float rad); +void wlr_matrix_multiply(float mat[static 9], const float a[static 9], + const float b[static 9]); +void wlr_matrix_transform(float mat[static 9], + enum wl_output_transform transform); -enum wl_output_transform; -void wlr_matrix_transform(float mat[static 16], +void wlr_matrix_texture(float mat[static 9], int32_t width, int32_t height, enum wl_output_transform transform); -void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, - enum wl_output_transform transform); -void wlr_matrix_project_box(float mat[static 16], const struct wlr_box *box, +void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box, enum wl_output_transform transform, float rotation, - const float projection[static 16]); + const float projection[static 9]); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index a8138a80..b838a737 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -76,7 +76,7 @@ struct wlr_output { // damage for cursors and fullscreen surface, in output-local coordinates pixman_region32_t damage; bool frame_pending; - float transform_matrix[16]; + float transform_matrix[9]; struct { struct wl_signal frame; diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 1d4c1f01..2bfd1bc9 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -70,8 +70,8 @@ struct wlr_surface { struct wlr_surface_state *current, *pending; const char *role; // the lifetime-bound role or null - float buffer_to_surface_matrix[16]; - float surface_to_buffer_matrix[16]; + float buffer_to_surface_matrix[9]; + float surface_to_buffer_matrix[9]; struct { struct wl_signal commit; @@ -109,9 +109,9 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, * from 0 to 1 in both dimensions. */ void wlr_surface_get_matrix(struct wlr_surface *surface, - float mat[static 16], - const float projection[static 16], - const float transform[static 16]); + float mat[static 9], + const float projection[static 9], + const float transform[static 9]); /** diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 9134a2fd..e0a98d29 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -85,11 +85,13 @@ static void init_default_shaders() { if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) { goto error; } - if (!compile_program(quad_vertex_src, ellipse_fragment_src, &shaders.ellipse)) { + 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)) { + if (!compile_program(quad_vertex_src, fragment_src_external, + &shaders.external)) { goto error; } } @@ -170,16 +172,16 @@ static void draw_quad() { GL_CALL(glDisableVertexAttribArray(1)); } -static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, - struct wlr_texture *texture, const float matrix[static 16], - float alpha) { +static bool wlr_gles2_render_texture_with_matrix( + struct wlr_renderer *wlr_renderer, struct wlr_texture *texture, + const float matrix[static 9], float alpha) { if (!texture || !texture->valid) { wlr_log(L_ERROR, "attempt to render invalid texture"); return false; } wlr_texture_bind(texture); - GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, matrix)); GL_CALL(glUniform1f(2, alpha)); draw_quad(); return true; @@ -187,17 +189,17 @@ static bool wlr_gles2_render_texture(struct wlr_renderer *wlr_renderer, static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, - const float color[static 4], const float matrix[static 16]) { + const float color[static 4], const float matrix[static 9]) { GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix4fv(0, 1, GL_FALSE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, matrix)); GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, - const float color[static 4], const float matrix[static 16]) { + const float color[static 4], const float matrix[static 9]) { GL_CALL(glUseProgram(shaders.ellipse)); - GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_TRUE, matrix)); GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } @@ -258,7 +260,7 @@ static struct wlr_renderer_impl wlr_renderer_impl = { .clear = wlr_gles2_clear, .scissor = wlr_gles2_scissor, .texture_create = wlr_gles2_texture_create, - .render_with_matrix = wlr_gles2_render_texture, + .render_texture_with_matrix = wlr_gles2_render_texture_with_matrix, .render_quad = wlr_gles2_render_quad, .render_ellipse = wlr_gles2_render_ellipse, .formats = wlr_gles2_formats, diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 46a10248..9d3a67c2 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -3,29 +3,29 @@ // Colored quads const GLchar quad_vertex_src[] = -"uniform mat4 proj;" +"uniform mat3 proj;" "uniform vec4 color;" "attribute vec2 pos;" "attribute vec2 texcoord;" "varying vec4 v_color;" "varying vec2 v_texcoord;" -"mat4 transpose(in mat4 inMatrix) {" -" vec4 i0 = inMatrix[0];" -" vec4 i1 = inMatrix[1];" -" vec4 i2 = inMatrix[2];" -" vec4 i3 = inMatrix[3];" -" mat4 outMatrix = mat4(" -" vec4(i0.x, i1.x, i2.x, i3.x)," -" vec4(i0.y, i1.y, i2.y, i3.y)," -" vec4(i0.z, i1.z, i2.z, i3.z)," -" vec4(i0.w, i1.w, i2.w, i3.w)" -" );" -" return outMatrix;" +"" +"mat3 transpose(in mat3 inMatrix) {" +" vec3 i0 = inMatrix[0];" +" vec3 i1 = inMatrix[1];" +" vec3 i2 = inMatrix[2];" +" mat3 outMatrix = mat3(" +" vec3(i0.x, i1.x, i2.x)," +" vec3(i0.y, i1.y, i2.y)," +" vec3(i0.z, i1.z, i2.z)" +" );" +" return outMatrix;" "}" +"" "void main() {" -" gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" -" v_color = color;" -" v_texcoord = texcoord;" +" gl_Position = vec4(transpose(proj) * vec3(pos, 1.0), 1.0);" +" v_color = color;" +" v_texcoord = texcoord;" "}"; const GLchar quad_fragment_src[] = @@ -49,26 +49,25 @@ const GLchar ellipse_fragment_src[] = // Textured quads const GLchar vertex_src[] = -"uniform mat4 proj;" +"uniform mat3 proj;" "attribute vec2 pos;" "attribute vec2 texcoord;" "varying vec2 v_texcoord;" -"mat4 transpose(in mat4 inMatrix) {" -" vec4 i0 = inMatrix[0];" -" vec4 i1 = inMatrix[1];" -" vec4 i2 = inMatrix[2];" -" vec4 i3 = inMatrix[3];" -" mat4 outMatrix = mat4(" -" vec4(i0.x, i1.x, i2.x, i3.x)," -" vec4(i0.y, i1.y, i2.y, i3.y)," -" vec4(i0.z, i1.z, i2.z, i3.z)," -" vec4(i0.w, i1.w, i2.w, i3.w)" -" );" "" -" return outMatrix;" +"mat3 transpose(in mat3 inMatrix) {" +" vec3 i0 = inMatrix[0];" +" vec3 i1 = inMatrix[1];" +" vec3 i2 = inMatrix[2];" +" mat3 outMatrix = mat3(" +" vec3(i0.x, i1.x, i2.x)," +" vec3(i0.y, i1.y, i2.y)," +" vec3(i0.z, i1.z, i2.z)" +" );" +" return outMatrix;" "}" +"" "void main() {" -" gl_Position = transpose(proj) * vec4(pos, 0.0, 1.0);" +" gl_Position = vec4(transpose(proj) * vec3(pos, 1.0), 1.0);" " v_texcoord = texcoord;" "}"; @@ -87,8 +86,8 @@ const GLchar fragment_src_rgbx[] = "uniform sampler2D tex;" "uniform float alpha;" "void main() {" -" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" -" gl_FragColor.a = alpha;" +" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" +" gl_FragColor.a = alpha;" "}"; const GLchar fragment_src_external[] = @@ -97,6 +96,6 @@ const GLchar fragment_src_external[] = "varying vec2 v_texcoord;" "uniform samplerExternalOES texture0;" "void main() {" -" vec4 col = texture2D(texture0, v_texcoord);" -" gl_FragColor = vec4(col.rgb, col.a);" +" vec4 col = texture2D(texture0, v_texcoord);" +" gl_FragColor = vec4(col.rgb, col.a);" "}"; diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 0dfebc48..9ee2a3e3 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -227,16 +227,13 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, } static void gles2_texture_get_matrix(struct wlr_texture *_texture, - float mat[static 16], const float projection[static 16], int x, int y) { + float mat[static 9], const float projection[static 9], int x, int y) { struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - float world[16]; wlr_matrix_identity(mat); - wlr_matrix_translate(world, x, y, 0); - wlr_matrix_mul(mat, mat, world); - wlr_matrix_scale(world, - texture->wlr_texture.width, texture->wlr_texture.height, 1); - wlr_matrix_mul(mat, mat, world); - wlr_matrix_mul(mat, projection, mat); + wlr_matrix_translate(mat, x, y); + wlr_matrix_scale(mat, texture->wlr_texture.width, + texture->wlr_texture.height); + wlr_matrix_multiply(mat, projection, mat); } static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 372e4caf..e847fcc2 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -35,19 +35,19 @@ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r) { return r->impl->texture_create(r); } -bool wlr_render_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float matrix[static 16], +bool wlr_render_texture_with_matrix(struct wlr_renderer *r, + struct wlr_texture *texture, const float matrix[static 9], float alpha) { - return r->impl->render_with_matrix(r, texture, matrix, alpha); + return r->impl->render_texture_with_matrix(r, texture, matrix, alpha); } void wlr_render_colored_quad(struct wlr_renderer *r, - const float color[static 4], const float matrix[static 16]) { + const float color[static 4], const float matrix[static 9]) { r->impl->render_quad(r, color, matrix); } void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float color[static 4], const float matrix[static 16]) { + const float color[static 4], const float matrix[static 9]) { r->impl->render_ellipse(r, color, matrix); } diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 0bfac32c..1ec9beb9 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -54,7 +54,7 @@ bool wlr_texture_upload_eglimage(struct wlr_texture *texture, } void wlr_texture_get_matrix(struct wlr_texture *texture, - float mat[static 16], const float projection[static 16], int x, int y) { + float mat[static 9], const float projection[static 9], int x, int y) { texture->impl->get_matrix(texture, mat, projection, x, y); } diff --git a/rootston/output.c b/rootston/output.c index 47236720..29fb1202 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -287,7 +287,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, goto damage_finish; } - float matrix[16]; + float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); wlr_matrix_project_box(matrix, &box, transform, rotation, @@ -297,7 +297,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_with_matrix(renderer, surface->texture, matrix, data->alpha); + wlr_render_texture_with_matrix(renderer, surface->texture, matrix, data->alpha); } damage_finish: @@ -353,7 +353,7 @@ static void render_decorations(struct roots_view *view, goto damage_finish; } - float matrix[16]; + float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, view->rotation, output->wlr_output->transform_matrix); float color[] = { 0.2, 0.2, 0.2, view->alpha }; diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c index a6be9908..85a294d9 100644 --- a/types/wlr_matrix.c +++ b/types/wlr_matrix.c @@ -5,143 +5,113 @@ #include #include -/* Obtains the index for the given row/column */ -static inline int mind(int row, int col) { - return (row - 1) * 4 + col - 1; -} - -void wlr_matrix_identity(float mat[static 16]) { - static const float identity[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, +void wlr_matrix_identity(float mat[static 9]) { + static const float identity[9] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }; memcpy(mat, identity, sizeof(identity)); } -void wlr_matrix_translate(float mat[static 16], float x, float y, float z) { - wlr_matrix_identity(mat); - mat[mind(1, 4)] = x; - mat[mind(2, 4)] = y; - mat[mind(3, 4)] = z; -} +void wlr_matrix_multiply(float mat[static 9], const float a[static 9], + const float b[static 9]) { + float product[9]; -void wlr_matrix_scale(float mat[static 16], float x, float y, float z) { - wlr_matrix_identity(mat); - mat[mind(1, 1)] = x; - mat[mind(2, 2)] = y; - mat[mind(3, 3)] = z; -} + product[0] = a[0]*b[0] + a[1]*b[3] + a[2]*b[6]; + product[1] = a[0]*b[1] + a[1]*b[4] + a[2]*b[7]; + product[2] = a[0]*b[2] + a[1]*b[5] + a[2]*b[8]; -void wlr_matrix_rotate(float mat[static 16], float radians) { - wlr_matrix_identity(mat); - float _cos = cosf(radians); - float _sin = sinf(radians); - mat[mind(1, 1)] = _cos; - mat[mind(1, 2)] = _sin; - mat[mind(2, 1)] = -_sin; - mat[mind(2, 2)] = _cos; -} + product[3] = a[3]*b[0] + a[4]*b[3] + a[5]*b[6]; + product[4] = a[3]*b[1] + a[4]*b[4] + a[5]*b[7]; + product[5] = a[3]*b[2] + a[4]*b[5] + a[5]*b[8]; -void wlr_matrix_mul(float mat[static 16], const float x[static 16], - const float y[static 16]) { - float product[16] = { - x[mind(1, 1)] * y[mind(1, 1)] + x[mind(1, 2)] * y[mind(2, 1)] + - x[mind(1, 3)] * y[mind(3, 1)] + x[mind(1, 4)] * y[mind(4, 1)], - x[mind(1, 1)] * y[mind(1, 2)] + x[mind(1, 2)] * y[mind(2, 2)] + - x[mind(1, 3)] * y[mind(3, 2)] + x[mind(1, 4)] * y[mind(4, 2)], - x[mind(1, 1)] * y[mind(1, 3)] + x[mind(1, 2)] * y[mind(2, 3)] + - x[mind(1, 3)] * y[mind(3, 3)] + x[mind(1, 4)] * y[mind(4, 3)], - x[mind(1, 1)] * y[mind(1, 4)] + x[mind(1, 2)] * y[mind(2, 4)] + - x[mind(1, 4)] * y[mind(3, 4)] + x[mind(1, 4)] * y[mind(4, 4)], + product[6] = a[6]*b[0] + a[7]*b[3] + a[8]*b[6]; + product[7] = a[6]*b[1] + a[7]*b[4] + a[8]*b[7]; + product[8] = a[6]*b[2] + a[7]*b[5] + a[8]*b[8]; - x[mind(2, 1)] * y[mind(1, 1)] + x[mind(2, 2)] * y[mind(2, 1)] + - x[mind(2, 3)] * y[mind(3, 1)] + x[mind(2, 4)] * y[mind(4, 1)], - x[mind(2, 1)] * y[mind(1, 2)] + x[mind(2, 2)] * y[mind(2, 2)] + - x[mind(2, 3)] * y[mind(3, 2)] + x[mind(2, 4)] * y[mind(4, 2)], - x[mind(2, 1)] * y[mind(1, 3)] + x[mind(2, 2)] * y[mind(2, 3)] + - x[mind(2, 3)] * y[mind(3, 3)] + x[mind(2, 4)] * y[mind(4, 3)], - x[mind(2, 1)] * y[mind(1, 4)] + x[mind(2, 2)] * y[mind(2, 4)] + - x[mind(2, 4)] * y[mind(3, 4)] + x[mind(2, 4)] * y[mind(4, 4)], - - x[mind(3, 1)] * y[mind(1, 1)] + x[mind(3, 2)] * y[mind(2, 1)] + - x[mind(3, 3)] * y[mind(3, 1)] + x[mind(3, 4)] * y[mind(4, 1)], - x[mind(3, 1)] * y[mind(1, 2)] + x[mind(3, 2)] * y[mind(2, 2)] + - x[mind(3, 3)] * y[mind(3, 2)] + x[mind(3, 4)] * y[mind(4, 2)], - x[mind(3, 1)] * y[mind(1, 3)] + x[mind(3, 2)] * y[mind(2, 3)] + - x[mind(3, 3)] * y[mind(3, 3)] + x[mind(3, 4)] * y[mind(4, 3)], - x[mind(3, 1)] * y[mind(1, 4)] + x[mind(3, 2)] * y[mind(2, 4)] + - x[mind(3, 4)] * y[mind(3, 4)] + x[mind(3, 4)] * y[mind(4, 4)], - - x[mind(4, 1)] * y[mind(1, 1)] + x[mind(4, 2)] * y[mind(2, 1)] + - x[mind(4, 3)] * y[mind(3, 1)] + x[mind(4, 4)] * y[mind(4, 1)], - x[mind(4, 1)] * y[mind(1, 2)] + x[mind(4, 2)] * y[mind(2, 2)] + - x[mind(4, 3)] * y[mind(3, 2)] + x[mind(4, 4)] * y[mind(4, 2)], - x[mind(4, 1)] * y[mind(1, 3)] + x[mind(4, 2)] * y[mind(2, 3)] + - x[mind(4, 3)] * y[mind(3, 3)] + x[mind(4, 4)] * y[mind(4, 3)], - x[mind(4, 1)] * y[mind(1, 4)] + x[mind(4, 2)] * y[mind(2, 4)] + - x[mind(4, 4)] * y[mind(3, 4)] + x[mind(4, 4)] * y[mind(4, 4)], - }; memcpy(mat, product, sizeof(product)); } -static const float transforms[][4] = { +void wlr_matrix_translate(float mat[static 9], float x, float y) { + float translate[9] = { + 1.0f, 0.0f, x, + 0.0f, 1.0f, y, + 0.0f, 0.0f, 1.0f, + }; + wlr_matrix_multiply(mat, mat, translate); +} + +void wlr_matrix_scale(float mat[static 9], float x, float y) { + float scale[9] = { + x, 0.0f, 0.0f, + 0.0f, y, 0.0f, + 0.0f, 0.0f, 1.0f, + }; + wlr_matrix_multiply(mat, mat, scale); +} + +void wlr_matrix_rotate(float mat[static 9], float rad) { + float rotate[9] = { + cos(rad), -sin(rad), 0.0f, + sin(rad), cos(rad), 0.0f, + 0.0f, 0.0f, 1.0f, + }; + wlr_matrix_multiply(mat, mat, rotate); +} + +static const float transforms[][9] = { [WL_OUTPUT_TRANSFORM_NORMAL] = { - 1.0f, 0.0f, - 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_90] = { - 0.0f, -1.0f, - 1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_180] = { - -1.0f, 0.0f, - 0.0f, -1.0f, + -1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_270] = { - 0.0f, 1.0f, - -1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_FLIPPED] = { - -1.0f, 0.0f, - 0.0f, 1.0f, + -1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_FLIPPED_90] = { - 0.0f, -1.0f, - -1.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_FLIPPED_180] = { - 1.0f, 0.0f, - 0.0f, -1.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, [WL_OUTPUT_TRANSFORM_FLIPPED_270] = { - 0.0f, 1.0f, - 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, }, }; -void wlr_matrix_transform(float mat[static 16], +void wlr_matrix_transform(float mat[static 9], enum wl_output_transform transform) { - memset(mat, 0, sizeof(*mat) * 16); - - const float *t = transforms[transform]; - - // Rotation + reflection - mat[0] = t[0]; - mat[1] = t[1]; - mat[4] = t[2]; - mat[5] = t[3]; - - // Identity - mat[10] = 1.0f; - mat[15] = 1.0f; + wlr_matrix_multiply(mat, mat, transforms[transform]); } // Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied -void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, +void wlr_matrix_texture(float mat[static 9], int32_t width, int32_t height, enum wl_output_transform transform) { - memset(mat, 0, sizeof(*mat) * 16); + memset(mat, 0, sizeof(*mat) * 9); const float *t = transforms[transform]; float x = 2.0f / width; @@ -150,62 +120,41 @@ void wlr_matrix_texture(float mat[static 16], int32_t width, int32_t height, // Rotation + reflection mat[0] = x * t[0]; mat[1] = x * t[1]; - mat[4] = y * -t[2]; - mat[5] = y * -t[3]; + mat[3] = y * -t[3]; + mat[4] = y * -t[4]; // Translation - mat[3] = -copysign(1.0f, mat[0] + mat[1]); - mat[7] = -copysign(1.0f, mat[4] + mat[5]); + mat[2] = -copysign(1.0f, mat[0] + mat[1]); + mat[5] = -copysign(1.0f, mat[3] + mat[4]); // Identity - mat[10] = 1.0f; - mat[15] = 1.0f; + mat[8] = 1.0f; } -void wlr_matrix_project_box(float mat[static 16], const struct wlr_box *box, +void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box, enum wl_output_transform transform, float rotation, - const float projection[static 16]) { + const float projection[static 9]) { int x = box->x; int y = box->y; int width = box->width; int height = box->height; - wlr_matrix_translate(mat, x, y, 0); + wlr_matrix_identity(mat); + wlr_matrix_translate(mat, x, y); if (rotation != 0) { - float translate_center[16]; - wlr_matrix_translate(translate_center, width/2, height/2, 0); - - float rotate[16]; - wlr_matrix_rotate(rotate, rotation); - - float translate_origin[16]; - wlr_matrix_translate(translate_origin, -width/2, -height/2, 0); - - wlr_matrix_mul(mat, mat, translate_center); - wlr_matrix_mul(mat, mat, rotate); - wlr_matrix_mul(mat, mat, translate_origin); + wlr_matrix_translate(mat, width/2, height/2); + wlr_matrix_rotate(mat, rotation); + wlr_matrix_translate(mat, -width/2, -height/2); } - float scale[16]; - wlr_matrix_scale(scale, width, height, 1); - - wlr_matrix_mul(mat, mat, scale); + wlr_matrix_scale(mat, width, height); if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { - float surface_translate_center[16]; - wlr_matrix_translate(surface_translate_center, 0.5, 0.5, 0); - - float surface_transform[16]; - wlr_matrix_transform(surface_transform, transform); - - float surface_translate_origin[16]; - wlr_matrix_translate(surface_translate_origin, -0.5, -0.5, 0); - - wlr_matrix_mul(mat, mat, surface_translate_center); - wlr_matrix_mul(mat, mat, surface_transform); - wlr_matrix_mul(mat, mat, surface_translate_origin); + wlr_matrix_translate(mat, 0.5, 0.5); + wlr_matrix_transform(mat, transform); + wlr_matrix_translate(mat, -0.5, -0.5); } - wlr_matrix_mul(mat, projection, mat); + wlr_matrix_multiply(mat, projection, mat); } diff --git a/types/wlr_output.c b/types/wlr_output.c index a9fb01c5..9a0edd44 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -375,7 +375,7 @@ static void output_fullscreen_surface_render(struct wlr_output *output, struct wlr_box box; output_fullscreen_surface_get_box(output, surface, &box); - float matrix[16]; + float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); wlr_matrix_project_box(matrix, &box, transform, 0, @@ -386,7 +386,7 @@ static void output_fullscreen_surface_render(struct wlr_output *output, for (int i = 0; i < nrects; ++i) { output_scissor(output, &rects[i]); wlr_renderer_clear(renderer, (float[]){0, 0, 0, 0}); - wlr_render_with_matrix(surface->renderer, surface->texture, matrix, 1.0f); + wlr_render_texture_with_matrix(surface->renderer, surface->texture, matrix, 1.0f); } wlr_renderer_scissor(renderer, NULL); @@ -435,7 +435,7 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, goto surface_damage_finish; } - float matrix[16]; + float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, cursor->output->transform_matrix); @@ -443,7 +443,7 @@ static void output_cursor_render(struct wlr_output_cursor *cursor, pixman_box32_t *rects = pixman_region32_rectangles(&surface_damage, &nrects); for (int i = 0; i < nrects; ++i) { output_scissor(cursor->output, &rects[i]); - wlr_render_with_matrix(renderer, texture, matrix, 1.0f); + wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0f); } wlr_renderer_scissor(renderer, NULL); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 04dcb141..ecab4842 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -624,20 +624,16 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, return surface; } -void wlr_surface_get_matrix(struct wlr_surface *surface, - float mat[static 16], - const float projection[static 16], - const float transform[static 16]) { +void wlr_surface_get_matrix(struct wlr_surface *surface, float mat[static 9], + const float projection[static 9], const float transform[static 9]) { int width = surface->texture->width; int height = surface->texture->height; - float scale[16]; wlr_matrix_identity(mat); - if (transform) { - wlr_matrix_mul(mat, mat, transform); + if (transform != NULL) { + wlr_matrix_multiply(mat, mat, transform); } - wlr_matrix_scale(scale, width, height, 1); - wlr_matrix_mul(mat, mat, scale); - wlr_matrix_mul(mat, projection, mat); + wlr_matrix_scale(mat, width, height); + wlr_matrix_multiply(mat, projection, mat); } bool wlr_surface_has_buffer(struct wlr_surface *surface) { From 0e253e0615469eb9293045483088f713e64e1d82 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 15:51:15 +0100 Subject: [PATCH 24/52] render/gles2: don't set inverted_y when EGL_WAYLAND_Y_INVERTED_WL is unsupported --- render/gles2/texture.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 5e84890f..775f7cdc 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -163,8 +163,10 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, (EGLint*)&tex->wlr_texture.height); EGLint inverted_y; - wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, &inverted_y); - tex->wlr_texture.inverted_y = !!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 pixel_format *pf; From 1914a1aa2b4f3c5678bbbf7d734352a6f51bec58 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 18:35:22 +0100 Subject: [PATCH 25/52] surface: drop wlr_surface_get_matrix --- include/wlr/types/wlr_surface.h | 14 -------------- types/wlr_surface.c | 12 ------------ 2 files changed, 26 deletions(-) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 2bfd1bc9..5c5b012f 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -100,20 +100,6 @@ struct wlr_renderer; struct wlr_surface *wlr_surface_create(struct wl_resource *res, struct wlr_renderer *renderer); -/** - * Gets a matrix you can pass into wlr_render_with_matrix to display this - * surface. `matrix` is the output matrix, `projection` is the wlr_output - * projection matrix, and `transform` is any additional transformations you want - * to perform on the surface (or NULL/the identity matrix if you don't). - * `transform` is used before the surface is scaled, so its geometry extends - * from 0 to 1 in both dimensions. - */ -void wlr_surface_get_matrix(struct wlr_surface *surface, - float mat[static 9], - const float projection[static 9], - const float transform[static 9]); - - /** * Set the lifetime role for this surface. Returns 0 on success or -1 if the * role cannot be set. diff --git a/types/wlr_surface.c b/types/wlr_surface.c index cf00a1e6..b3e0dcd8 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -628,18 +628,6 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, return surface; } -void wlr_surface_get_matrix(struct wlr_surface *surface, float mat[static 9], - const float projection[static 9], const float transform[static 9]) { - int width = surface->texture->width; - int height = surface->texture->height; - wlr_matrix_identity(mat); - if (transform != NULL) { - wlr_matrix_multiply(mat, mat, transform); - } - wlr_matrix_scale(mat, width, height); - wlr_matrix_multiply(mat, projection, mat); -} - bool wlr_surface_has_buffer(struct wlr_surface *surface) { return surface->texture && surface->texture->valid; } From 876f07e9f13946609047e8e32ca7918548315e1c Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 19:31:02 +0100 Subject: [PATCH 26/52] renderer: replace wlr_texture_get_matrix by wlr_render_texture --- backend/drm/drm.c | 6 ++--- examples/output-layout.c | 8 ++----- examples/rotation.c | 7 ++---- examples/touch.c | 11 ++++----- include/wlr/render.h | 41 ++++++++++------------------------ include/wlr/render/interface.h | 2 -- render/gles2/texture.c | 14 ------------ render/wlr_renderer.c | 12 ++++++++++ render/wlr_texture.c | 5 ----- 9 files changed, 34 insertions(+), 72 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index e956f280..0447d865 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -647,10 +647,8 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); - float matrix[9]; - wlr_texture_get_matrix(plane->wlr_tex, matrix, plane->matrix, 0, 0); - wlr_render_texture_with_matrix(plane->surf.renderer->wlr_rend, plane->wlr_tex, - matrix, 1.0f); + wlr_render_texture(plane->surf.renderer->wlr_rend, plane->wlr_tex, + plane->matrix, 0, 0, 1.0f); glFinish(); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); diff --git a/examples/output-layout.c b/examples/output-layout.c index 9c914137..8f506208 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -111,18 +111,14 @@ static void handle_output_frame(struct output_state *output, .width = 128, .height = 128, }; if (wlr_output_layout_intersects(sample->layout, output->output, &box)) { - float matrix[9]; - // transform global coordinates to local coordinates double local_x = sample->x_offs; double local_y = sample->y_offs; wlr_output_layout_output_coords(sample->layout, output->output, &local_x, &local_y); - wlr_texture_get_matrix(sample->cat_texture, matrix, - wlr_output->transform_matrix, local_x, local_y); - wlr_render_texture_with_matrix(sample->renderer, sample->cat_texture, - matrix, 1.0f); + wlr_render_texture(sample->renderer, sample->cat_texture, + wlr_output->transform_matrix, local_x, local_y, 1.0f); } wlr_renderer_end(sample->renderer); diff --git a/examples/rotation.c b/examples/rotation.c index 4431f60a..aaf006cf 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -46,13 +46,10 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_renderer_begin(sample->renderer, wlr_output); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); - float matrix[9]; for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { for (int x = -128 + (int)odata->x_offs; x < width; x += 128) { - wlr_texture_get_matrix(sample->cat_texture, matrix, - wlr_output->transform_matrix, x, y); - wlr_render_texture_with_matrix(sample->renderer, - sample->cat_texture, matrix, 1.0f); + wlr_render_texture(sample->renderer, sample->cat_texture, + wlr_output->transform_matrix, x, y, 1.0f); } } diff --git a/examples/touch.c b/examples/touch.c index 47bbebc2..0af8bc4a 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -45,15 +45,12 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_renderer_begin(sample->renderer, wlr_output); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); - float matrix[9]; struct touch_point *p; wl_list_for_each(p, &sample->touch_points, link) { - wlr_texture_get_matrix(sample->cat_texture, matrix, - wlr_output->transform_matrix, - (int)(p->x * width) - sample->cat_texture->width / 2, - (int)(p->y * height) - sample->cat_texture->height / 2); - wlr_render_texture_with_matrix(sample->renderer, sample->cat_texture, - matrix, 1.0f); + int x = (int)(p->x * width) - sample->cat_texture->width / 2; + int y = (int)(p->y * height) - sample->cat_texture->height / 2; + wlr_render_texture(sample->renderer, sample->cat_texture, + wlr_output->transform_matrix, x, y, 1.0f); } wlr_renderer_end(sample->renderer); diff --git a/include/wlr/render.h b/include/wlr/render.h index c3bf5c97..01d05fb1 100644 --- a/include/wlr/render.h +++ b/include/wlr/render.h @@ -25,21 +25,15 @@ void wlr_renderer_scissor(struct wlr_renderer *r, struct wlr_box *box); */ struct wlr_texture *wlr_render_texture_create(struct wlr_renderer *r); /** - * Renders the requested texture using the provided matrix. A typical texture - * rendering goes like so: - * - * struct wlr_renderer *renderer; - * struct wlr_texture *texture; - * float projection[9]; - * float matrix[9]; - * wlr_texture_get_matrix(texture, matrix, projection, 123, 321); - * wlr_render_texture_with_matrix(renderer, texture, matrix, 0.5f); - * - * This will render the texture at <123, 321> with an alpha channel of 0.5. + * Renders the requested texture. + */ +bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, + const float projection[static 9], int x, int y, float alpha); +/** + * Renders the requested texture using the provided matrix. */ bool wlr_render_texture_with_matrix(struct wlr_renderer *r, struct wlr_texture *texture, const float matrix[static 9], float alpha); - /** * Renders a solid quad in the specified color. */ @@ -95,22 +89,22 @@ struct wlr_texture { * returns. */ bool wlr_texture_upload_pixels(struct wlr_texture *tex, - enum wl_shm_format format, int stride, int width, int height, - const unsigned char *pixels); + 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); + 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); + struct wl_shm_buffer *shm); /** * Attaches the contents from the given wl_drm wl_buffer resource onto the @@ -132,18 +126,7 @@ bool wlr_texture_upload_dmabuf(struct wlr_texture *tex, * must be valid. */ 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); -/** - * Prepares a matrix with the appropriate scale for the given texture and - * multiplies it with the projection, producing a matrix that the shader can - * muptlipy vertex coordinates with to get final screen coordinates. - * - * The projection matrix is assumed to be an orthographic projection of [0, - * width) and [0, height], and the x and y coordinates provided are used as - * such. - */ -void wlr_texture_get_matrix(struct wlr_texture *texture, float mat[static 9], - const float projection[static 9], int x, int y); + int x, int y, int width, int height, struct wl_shm_buffer *shm); /** * Destroys this wlr_texture. */ diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index c8b4c8eb..1b8b7946 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -62,8 +62,6 @@ struct wlr_texture_impl { uint32_t width, uint32_t height); bool (*upload_dmabuf)(struct wlr_texture *texture, struct wl_resource *dmabuf_resource); - void (*get_matrix)(struct wlr_texture *state, float mat[static 9], - const float projection[static 9], int x, int y); void (*get_buffer_size)(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height); void (*bind)(struct wlr_texture *texture); diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 875affe2..ea05cde2 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -227,7 +227,6 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, return true; } - static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, struct wl_resource *dmabuf_resource) { struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; @@ -263,17 +262,6 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, return true; } -static void gles2_texture_get_matrix(struct wlr_texture *_texture, - float mat[static 9], const float projection[static 9], int x, int y) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - wlr_matrix_identity(mat); - wlr_matrix_translate(mat, x, y); - wlr_matrix_scale(mat, texture->wlr_texture.width, - texture->wlr_texture.height); - wlr_matrix_multiply(mat, projection, mat); -} - - 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)) { @@ -287,7 +275,6 @@ static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct 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); @@ -344,7 +331,6 @@ static struct wlr_texture_impl wlr_texture_impl = { .upload_drm = gles2_texture_upload_drm, .upload_dmabuf = gles2_texture_upload_dmabuf, .upload_eglimage = gles2_texture_upload_eglimage, - .get_matrix = gles2_texture_get_matrix, .get_buffer_size = gles2_texture_get_buffer_size, .bind = gles2_texture_bind, .destroy = gles2_texture_destroy, diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index e847fcc2..c4f91d5e 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,6 +1,7 @@ #include #include #include +#include void wlr_renderer_init(struct wlr_renderer *renderer, struct wlr_renderer_impl *impl) { @@ -35,6 +36,17 @@ 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) { + float mat[9]; + wlr_matrix_identity(mat); + wlr_matrix_translate(mat, x, y); + wlr_matrix_scale(mat, texture->width, texture->height); + wlr_matrix_multiply(mat, projection, mat); + + return wlr_render_texture_with_matrix(r, texture, mat, alpha); +} + bool wlr_render_texture_with_matrix(struct wlr_renderer *r, struct wlr_texture *texture, const float matrix[static 9], float alpha) { diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 3685185a..48f76c8e 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -58,11 +58,6 @@ bool wlr_texture_upload_dmabuf(struct wlr_texture *texture, return texture->impl->upload_dmabuf(texture, dmabuf_resource); } -void wlr_texture_get_matrix(struct wlr_texture *texture, - float mat[static 9], const float projection[static 9], int x, int y) { - texture->impl->get_matrix(texture, mat, projection, x, y); -} - 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); From 361d7c857eec82d345ed5d55971ae16da88d710e Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 09:04:06 +0100 Subject: [PATCH 27/52] xdg-shell-v6: don't leak wlr_xdg_surface_v6_configure.toplevel_state --- types/wlr_xdg_shell_v6.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index aabd9f2b..31dd306a 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -159,6 +159,16 @@ static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( } +static void xdg_surface_configure_destroy( + struct wlr_xdg_surface_v6_configure *configure) { + if (configure == NULL) { + return; + } + wl_list_remove(&configure->link); + free(configure->toplevel_state); + free(configure); +} + static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); @@ -196,6 +206,11 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { surface->popup = NULL; } + struct wlr_xdg_surface_v6_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + xdg_surface_configure_destroy(configure); + } + surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; free(surface->title); surface->title = NULL; @@ -210,12 +225,6 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) { } surface->configure_next_serial = 0; - struct wlr_xdg_surface_v6_configure *configure, *tmp; - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - wl_list_remove(&configure->link); - free(configure); - } - surface->has_next_geometry = false; memset(&surface->geometry, 0, sizeof(struct wlr_box)); memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); @@ -876,9 +885,6 @@ static void wlr_xdg_toplevel_v6_ack_configure( configure->toplevel_state->resizing; surface->toplevel->current.activated = configure->toplevel_state->activated; - - free(configure->toplevel_state); - configure->toplevel_state = NULL; } static void xdg_surface_handle_ack_configure(struct wl_client *client, @@ -897,9 +903,10 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { if (configure->serial < serial) { wl_list_remove(&configure->link); - free(configure); + xdg_surface_configure_destroy(configure); } else if (configure->serial == serial) { wl_list_remove(&configure->link); + wl_list_init(&configure->link); found = true; break; } else { @@ -927,7 +934,7 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, surface->configured = true; surface->configure_serial = serial; - free(configure); + xdg_surface_configure_destroy(configure); } static void xdg_surface_handle_set_window_geometry(struct wl_client *client, @@ -1024,16 +1031,17 @@ static void wlr_xdg_toplevel_v6_send_configure( struct wlr_xdg_surface_v6 *surface, struct wlr_xdg_surface_v6_configure *configure) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - uint32_t *s; - struct wl_array states; configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); if (configure->toplevel_state == NULL) { wlr_log(L_ERROR, "Allocation failed"); + wl_resource_post_no_memory(surface->toplevel->resource); return; } *configure->toplevel_state = surface->toplevel->pending; + uint32_t *s; + struct wl_array states; wl_array_init(&states); if (surface->toplevel->pending.maximized) { s = wl_array_add(&states, sizeof(uint32_t)); @@ -1070,7 +1078,6 @@ static void wlr_xdg_toplevel_v6_send_configure( uint32_t width = surface->toplevel->pending.width; uint32_t height = surface->toplevel->pending.height; - zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width, height, &states); From 42cc575266b3fb2bb406145d0553e375d17b038a Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 20:14:47 +0100 Subject: [PATCH 28/52] xdg-shell-v6: fix wl_list_remove called twice --- types/wlr_xdg_shell_v6.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 31dd306a..ef6045c2 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -506,8 +506,7 @@ static void xdg_popup_handle_destroy(struct wl_client *client, if (topmost != surface) { wl_resource_post_error(surface->client->resource, ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was destroyed while it was not the topmost " - "popup"); + "xdg_popup was destroyed while it was not the topmost popup"); return; } @@ -805,8 +804,8 @@ static void xdg_toplevel_handle_set_minimized(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_minimize, surface); } -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = -{ +static const struct zxdg_toplevel_v6_interface + zxdg_toplevel_v6_implementation = { .destroy = resource_handle_destroy, .set_parent = xdg_toplevel_handle_set_parent, .set_title = xdg_toplevel_handle_set_title, @@ -820,7 +819,7 @@ static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = .unset_maximized = xdg_toplevel_handle_unset_maximized, .set_fullscreen = xdg_toplevel_handle_set_fullscreen, .unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, - .set_minimized = xdg_toplevel_handle_set_minimized + .set_minimized = xdg_toplevel_handle_set_minimized, }; static void xdg_surface_resource_destroy(struct wl_resource *resource) { @@ -902,11 +901,8 @@ static void xdg_surface_handle_ack_configure(struct wl_client *client, struct wlr_xdg_surface_v6_configure *configure, *tmp; wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { if (configure->serial < serial) { - wl_list_remove(&configure->link); xdg_surface_configure_destroy(configure); } else if (configure->serial == serial) { - wl_list_remove(&configure->link); - wl_list_init(&configure->link); found = true; break; } else { From e607d0f7ee00c59354c996fc98e738c26adbca58 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 20:15:09 +0100 Subject: [PATCH 29/52] xdg-shell: add map/unmap support --- include/rootston/view.h | 2 + include/wlr/types/wlr_xdg_shell.h | 33 +- rootston/xdg_shell.c | 58 +++- types/wlr_xdg_shell.c | 520 +++++++++++++++++------------- 4 files changed, 356 insertions(+), 257 deletions(-) diff --git a/include/rootston/view.h b/include/rootston/view.h index 92d1feb5..775f3d11 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -44,6 +44,8 @@ struct roots_xdg_surface { struct wl_listener destroy; struct wl_listener new_popup; + struct wl_listener map; + struct wl_listener unmap; struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_maximize; diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 8422863c..ad0a626f 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -62,19 +62,10 @@ enum wlr_xdg_surface_role { }; struct wlr_xdg_toplevel_state { - bool maximized; - bool fullscreen; - bool resizing; - bool activated; - - uint32_t width; - uint32_t height; - - uint32_t max_width; - uint32_t max_height; - - uint32_t min_width; - uint32_t min_height; + bool maximized, fullscreen, resizing, activated; + uint32_t width, height; + uint32_t max_width, max_height; + uint32_t min_width, min_height; }; struct wlr_xdg_toplevel { @@ -90,7 +81,8 @@ struct wlr_xdg_toplevel { struct wlr_xdg_surface_configure { struct wl_list link; // wlr_xdg_surface::configure_list uint32_t serial; - struct wlr_xdg_toplevel_state state; + + struct wlr_xdg_toplevel_state *toplevel_state; }; struct wlr_xdg_surface { @@ -101,14 +93,13 @@ struct wlr_xdg_surface { enum wlr_xdg_surface_role role; union { - struct wlr_xdg_toplevel *toplevel_state; - struct wlr_xdg_popup *popup_state; + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_popup *popup; }; struct wl_list popups; // wlr_xdg_popup::link - bool configured; - bool added; + bool added, configured, mapped; uint32_t configure_serial; struct wl_event_source *configure_idle; uint32_t configure_next_serial; @@ -118,8 +109,8 @@ struct wlr_xdg_surface { char *app_id; bool has_next_geometry; - struct wlr_box *next_geometry; - struct wlr_box *geometry; + struct wlr_box next_geometry; + struct wlr_box geometry; struct wl_listener surface_destroy_listener; @@ -127,6 +118,8 @@ struct wlr_xdg_surface { struct wl_signal destroy; struct wl_signal ping_timeout; struct wl_signal new_popup; + struct wl_signal map; + struct wl_signal unmap; struct wl_signal request_maximize; struct wl_signal request_fullscreen; diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 24c57bd5..851c0045 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -60,12 +60,14 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) { assert(view->type == ROOTS_XDG_SHELL_VIEW); struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->geometry->width > 0 && surface->geometry->height > 0) { - box->width = surface->geometry->width; - box->height = surface->geometry->height; - } else { + if (surface->geometry.width > 0 && surface->geometry.height > 0) { + box->width = surface->geometry.width; + box->height = surface->geometry.height; + } else if (view->wlr_surface != NULL) { box->width = view->wlr_surface->current->width; box->height = view->wlr_surface->current->height; + } else { + box->width = box->height = 0; } } @@ -83,7 +85,7 @@ static void apply_size_constraints(struct wlr_xdg_surface *surface, *dest_width = width; *dest_height = height; - struct wlr_xdg_toplevel_state *state = &surface->toplevel_state->current; + struct wlr_xdg_toplevel_state *state = &surface->toplevel->current; if (width < state->min_width) { *dest_width = state->min_width; } else if (state->max_width > 0 && @@ -181,10 +183,13 @@ static void close(struct roots_view *view) { } static void destroy(struct roots_view *view) { + assert(view->type == ROOTS_XDG_SHELL_VIEW); struct roots_xdg_surface *roots_xdg_surface = view->roots_xdg_surface; wl_list_remove(&roots_xdg_surface->surface_commit.link); wl_list_remove(&roots_xdg_surface->destroy.link); wl_list_remove(&roots_xdg_surface->new_popup.link); + wl_list_remove(&roots_xdg_surface->map.link); + wl_list_remove(&roots_xdg_surface->unmap.link); wl_list_remove(&roots_xdg_surface->request_move.link); wl_list_remove(&roots_xdg_surface->request_resize.link); wl_list_remove(&roots_xdg_surface->request_maximize.link); @@ -231,7 +236,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) { return; } - view_maximize(view, surface->toplevel_state->next.maximized); + view_maximize(view, surface->toplevel->next.maximized); } static void handle_request_fullscreen(struct wl_listener *listener, @@ -255,6 +260,10 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct wlr_xdg_surface *surface = view->xdg_surface; + if (!surface->mapped) { + return; + } + view_apply_damage(view); struct wlr_box size; @@ -289,6 +298,26 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { popup_create(roots_xdg_surface->view, wlr_popup); } +static void handle_map(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, map); + struct roots_view *view = roots_xdg_surface->view; + + struct wlr_box box; + get_size(view, &box); + view->width = box.width; + view->height = box.height; + + view_map(view, view->xdg_surface->surface); + view_setup(view); +} + +static void handle_unmap(struct wl_listener *listener, void *data) { + struct roots_xdg_surface *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, unmap); + view_unmap(roots_xdg_surface->view); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); @@ -321,6 +350,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { &roots_surface->surface_commit); roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); + roots_surface->map.notify = handle_map; + wl_signal_add(&surface->events.map, &roots_surface->map); + roots_surface->unmap.notify = handle_unmap; + wl_signal_add(&surface->events.unmap, &roots_surface->unmap); roots_surface->request_move.notify = handle_request_move; wl_signal_add(&surface->events.request_move, &roots_surface->request_move); roots_surface->request_resize.notify = handle_request_resize; @@ -353,11 +386,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { view->destroy = destroy; roots_surface->view = view; - struct wlr_box box; - get_size(view, &box); - view->width = box.width; - view->height = box.height; - - view_map(view, surface->surface); - view_setup(view); + if (surface->toplevel->next.maximized) { + view_maximize(view, true); + } + if (surface->toplevel->next.fullscreen) { + view_set_fullscreen(view, true, NULL); + } } diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 990926cf..5b02088d 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -34,7 +34,7 @@ struct wlr_xdg_positioner { }; -static void resource_destroy(struct wl_client *client, +static void resource_handle_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } @@ -159,43 +159,37 @@ static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat( } -static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { +static void xdg_surface_configure_destroy( + struct wlr_xdg_surface_configure *configure) { + if (configure == NULL) { + return; + } + wl_list_remove(&configure->link); + free(configure->toplevel_state); + free(configure); +} + +static void xdg_surface_unmap(struct wlr_xdg_surface *surface) { + assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); + // TODO: probably need to ungrab before this event - wlr_signal_emit_safe(&surface->events.destroy, surface); - - if (surface->configure_idle) { - wl_event_source_remove(surface->configure_idle); - } - - struct wlr_xdg_surface_configure *configure, *tmp; - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { - free(configure); - } + wlr_signal_emit_safe(&surface->events.unmap, surface); if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - wl_resource_set_user_data(surface->toplevel_state->resource, NULL); - free(surface->toplevel_state); + wl_resource_set_user_data(surface->toplevel->resource, NULL); + free(surface->toplevel); + surface->toplevel = NULL; } if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - wl_resource_set_user_data(surface->popup_state->resource, NULL); + wl_resource_set_user_data(surface->popup->resource, NULL); - if (surface->popup_state->seat) { + if (surface->popup->seat) { struct wlr_xdg_popup_grab *grab = xdg_shell_popup_grab_from_seat(surface->client->shell, - surface->popup_state->seat); + surface->popup->seat); - struct wlr_xdg_surface *topmost = - xdg_popup_grab_get_topmost(grab); - - if (topmost != surface) { - wl_resource_post_error(surface->client->resource, - XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, - "xdg_popup was destroyed while it was not the topmost " - "popup."); - } - - wl_list_remove(&surface->popup_state->grab_link); + wl_list_remove(&surface->popup->grab_link); if (wl_list_empty(&grab->popups)) { if (grab->seat->pointer_state.grab == &grab->pointer_grab) { @@ -207,18 +201,46 @@ static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { } } - wl_list_remove(&surface->popup_state->link); - free(surface->popup_state); + wl_list_remove(&surface->popup->link); + free(surface->popup); + surface->popup = NULL; } + struct wlr_xdg_surface_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + xdg_surface_configure_destroy(configure); + } + + surface->role = WLR_XDG_SURFACE_ROLE_NONE; + free(surface->title); + surface->title = NULL; + free(surface->app_id); + surface->app_id = NULL; + + surface->added = surface->configured = surface->mapped = false; + surface->configure_serial = 0; + if (surface->configure_idle) { + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + } + surface->configure_next_serial = 0; + + surface->has_next_geometry = false; + memset(&surface->geometry, 0, sizeof(struct wlr_box)); + memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); +} + +static void xdg_surface_destroy(struct wlr_xdg_surface *surface) { + if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { + xdg_surface_unmap(surface); + } + + wlr_signal_emit_safe(&surface->events.destroy, surface); + wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->link); wl_list_remove(&surface->surface_destroy_listener.link); wlr_surface_set_role_committed(surface->surface, NULL, NULL); - free(surface->geometry); - free(surface->next_geometry); - free(surface->title); - free(surface->app_id); free(surface); } @@ -238,7 +260,7 @@ static void xdg_positioner_destroy(struct wl_resource *resource) { free(positioner); } -static void xdg_positioner_protocol_set_size(struct wl_client *client, +static void xdg_positioner_handle_set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_positioner *positioner = xdg_positioner_from_resource(resource); @@ -254,7 +276,7 @@ static void xdg_positioner_protocol_set_size(struct wl_client *client, positioner->size.height = height; } -static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, +static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_positioner *positioner = @@ -273,7 +295,7 @@ static void xdg_positioner_protocol_set_anchor_rect(struct wl_client *client, positioner->anchor_rect.height = height; } -static void xdg_positioner_protocol_set_anchor(struct wl_client *client, +static void xdg_positioner_handle_set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { struct wlr_xdg_positioner *positioner = xdg_positioner_from_resource(resource); @@ -288,7 +310,7 @@ static void xdg_positioner_protocol_set_anchor(struct wl_client *client, positioner->anchor = anchor; } -static void xdg_positioner_protocol_set_gravity(struct wl_client *client, +static void xdg_positioner_handle_set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { struct wlr_xdg_positioner *positioner = xdg_positioner_from_resource(resource); @@ -303,7 +325,7 @@ static void xdg_positioner_protocol_set_gravity(struct wl_client *client, positioner->gravity = gravity; } -static void xdg_positioner_protocol_set_constraint_adjustment( +static void xdg_positioner_handle_set_constraint_adjustment( struct wl_client *client, struct wl_resource *resource, uint32_t constraint_adjustment) { struct wlr_xdg_positioner *positioner = @@ -312,7 +334,7 @@ static void xdg_positioner_protocol_set_constraint_adjustment( positioner->constraint_adjustment = constraint_adjustment; } -static void xdg_positioner_protocol_set_offset(struct wl_client *client, +static void xdg_positioner_handle_set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { struct wlr_xdg_positioner *positioner = xdg_positioner_from_resource(resource); @@ -323,17 +345,17 @@ static void xdg_positioner_protocol_set_offset(struct wl_client *client, static const struct xdg_positioner_interface xdg_positioner_implementation = { - .destroy = resource_destroy, - .set_size = xdg_positioner_protocol_set_size, - .set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, - .set_anchor = xdg_positioner_protocol_set_anchor, - .set_gravity = xdg_positioner_protocol_set_gravity, + .destroy = resource_handle_destroy, + .set_size = xdg_positioner_handle_set_size, + .set_anchor_rect = xdg_positioner_handle_set_anchor_rect, + .set_anchor = xdg_positioner_handle_set_anchor, + .set_gravity = xdg_positioner_handle_set_gravity, .set_constraint_adjustment = - xdg_positioner_protocol_set_constraint_adjustment, - .set_offset = xdg_positioner_protocol_set_offset, + xdg_positioner_handle_set_constraint_adjustment, + .set_offset = xdg_positioner_handle_set_offset, }; -static void xdg_shell_create_positioner(struct wl_client *wl_client, +static void xdg_shell_handle_create_positioner(struct wl_client *wl_client, struct wl_resource *resource, uint32_t id) { struct wlr_xdg_positioner *positioner = calloc(1, sizeof(struct wlr_xdg_positioner)); @@ -458,7 +480,7 @@ static struct wlr_xdg_surface *xdg_surface_from_xdg_popup_resource( return wl_resource_get_user_data(resource); } -static void xdg_popup_protocol_grab(struct wl_client *client, +static void xdg_popup_handle_grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface *surface = @@ -466,8 +488,8 @@ static void xdg_popup_protocol_grab(struct wl_client *client, struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); - if (surface->popup_state->committed) { - wl_resource_post_error(surface->popup_state->resource, + if (surface->popup->committed) { + wl_resource_post_error(surface->popup->resource, XDG_POPUP_ERROR_INVALID_GRAB, "xdg_popup is already mapped"); return; @@ -479,10 +501,10 @@ static void xdg_popup_protocol_grab(struct wl_client *client, struct wlr_xdg_surface *topmost = xdg_popup_grab_get_topmost(popup_grab); bool parent_is_toplevel = - surface->popup_state->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; + surface->popup->parent->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; if ((topmost == NULL && !parent_is_toplevel) || - (topmost != NULL && topmost != surface->popup_state->parent)) { + (topmost != NULL && topmost != surface->popup->parent)) { wl_resource_post_error(surface->client->resource, XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, "xdg_popup was not created on the topmost popup"); @@ -490,9 +512,9 @@ static void xdg_popup_protocol_grab(struct wl_client *client, } popup_grab->client = surface->client->client; - surface->popup_state->seat = seat_client->seat; + surface->popup->seat = seat_client->seat; - wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + wl_list_insert(&popup_grab->popups, &surface->popup->grab_link); wlr_seat_pointer_start_grab(seat_client->seat, &popup_grab->pointer_grab); @@ -500,16 +522,36 @@ static void xdg_popup_protocol_grab(struct wl_client *client, &popup_grab->keyboard_grab); } +static void xdg_popup_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = + xdg_surface_from_xdg_popup_resource(resource); + struct wlr_xdg_popup_grab *grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + surface->popup->seat); + struct wlr_xdg_surface *topmost = + xdg_popup_grab_get_topmost(grab); + + if (topmost != surface) { + wl_resource_post_error(surface->client->resource, + XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP, + "xdg_popup was destroyed while it was not the topmost popup"); + return; + } + + wl_resource_destroy(resource); +} + static const struct xdg_popup_interface xdg_popup_implementation = { - .destroy = resource_destroy, - .grab = xdg_popup_protocol_grab, + .destroy = xdg_popup_handle_destroy, + .grab = xdg_popup_handle_grab, }; static void xdg_popup_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_popup_resource(resource); if (surface != NULL) { - xdg_surface_destroy(surface); + xdg_surface_unmap(surface); } } @@ -522,7 +564,7 @@ static struct wlr_xdg_surface *xdg_surface_from_resource( return wl_resource_get_user_data(resource); } -static void xdg_surface_get_popup(struct wl_client *client, +static void xdg_surface_handle_get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent_resource, struct wl_resource *positioner_resource) { @@ -545,33 +587,33 @@ static void xdg_surface_get_popup(struct wl_client *client, return; } - surface->popup_state = calloc(1, sizeof(struct wlr_xdg_popup)); - if (!surface->popup_state) { + surface->popup = calloc(1, sizeof(struct wlr_xdg_popup)); + if (!surface->popup) { wl_resource_post_no_memory(resource); return; } - surface->popup_state->resource = + surface->popup->resource = wl_resource_create(client, &xdg_popup_interface, wl_resource_get_version(resource), id); - if (surface->popup_state->resource == NULL) { - free(surface->popup_state); + if (surface->popup->resource == NULL) { + free(surface->popup); wl_resource_post_no_memory(resource); return; } surface->role = WLR_XDG_SURFACE_ROLE_POPUP; - surface->popup_state->base = surface; - surface->popup_state->parent = parent; - surface->popup_state->geometry = + surface->popup->base = surface; + surface->popup->parent = parent; + surface->popup->geometry = xdg_positioner_get_geometry(positioner, surface, parent); - wl_list_insert(&parent->popups, &surface->popup_state->link); + wl_list_insert(&parent->popups, &surface->popup->link); - wl_resource_set_implementation(surface->popup_state->resource, + wl_resource_set_implementation(surface->popup->resource, &xdg_popup_implementation, surface, xdg_popup_resource_destroy); - wlr_signal_emit_safe(&parent->events.new_popup, surface->popup_state); + wlr_signal_emit_safe(&parent->events.new_popup, surface->popup); } @@ -584,7 +626,7 @@ static struct wlr_xdg_surface *xdg_surface_from_xdg_toplevel_resource( return wl_resource_get_user_data(resource); } -static void xdg_toplevel_protocol_set_parent(struct wl_client *client, +static void xdg_toplevel_handle_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -594,10 +636,10 @@ static void xdg_toplevel_protocol_set_parent(struct wl_client *client, parent = xdg_surface_from_xdg_toplevel_resource(parent_resource); } - surface->toplevel_state->parent = parent; + surface->toplevel->parent = parent; } -static void xdg_toplevel_protocol_set_title(struct wl_client *client, +static void xdg_toplevel_handle_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -612,7 +654,7 @@ static void xdg_toplevel_protocol_set_title(struct wl_client *client, surface->title = tmp; } -static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, +static void xdg_toplevel_handle_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -627,7 +669,7 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, surface->app_id = tmp; } -static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, +static void xdg_toplevel_handle_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { struct wlr_xdg_surface *surface = @@ -636,7 +678,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { - wl_resource_post_error(surface->toplevel_state->resource, + wl_resource_post_error(surface->toplevel->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -658,7 +700,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_show_window_menu, &event); } -static void xdg_toplevel_protocol_move(struct wl_client *client, +static void xdg_toplevel_handle_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface *surface = @@ -667,7 +709,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { - wl_resource_post_error(surface->toplevel_state->resource, + wl_resource_post_error(surface->toplevel->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -687,7 +729,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_move, &event); } -static void xdg_toplevel_protocol_resize(struct wl_client *client, +static void xdg_toplevel_handle_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { struct wlr_xdg_surface *surface = @@ -696,7 +738,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, wlr_seat_client_from_resource(seat_resource); if (!surface->configured) { - wl_resource_post_error(surface->toplevel_state->resource, + wl_resource_post_error(surface->toplevel->resource, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, "surface has not been configured yet"); return; @@ -717,39 +759,39 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_resize, &event); } -static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, +static void xdg_toplevel_handle_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.max_width = width; - surface->toplevel_state->next.max_height = height; + surface->toplevel->next.max_width = width; + surface->toplevel->next.max_height = height; } -static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, +static void xdg_toplevel_handle_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.min_width = width; - surface->toplevel_state->next.min_height = height; + surface->toplevel->next.min_width = width; + surface->toplevel->next.min_height = height; } -static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, +static void xdg_toplevel_handle_set_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.maximized = true; + surface->toplevel->next.maximized = true; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } -static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, +static void xdg_toplevel_handle_unset_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.maximized = false; + surface->toplevel->next.maximized = false; wlr_signal_emit_safe(&surface->events.request_maximize, surface); } -static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -759,7 +801,7 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, output = wlr_output_from_resource(output_resource); } - surface->toplevel_state->next.fullscreen = true; + surface->toplevel->next.fullscreen = true; struct wlr_xdg_toplevel_set_fullscreen_event event = { .surface = surface, @@ -770,12 +812,12 @@ static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); } -static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, +static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); - surface->toplevel_state->next.fullscreen = false; + surface->toplevel->next.fullscreen = false; struct wlr_xdg_toplevel_set_fullscreen_event event = { .surface = surface, @@ -786,7 +828,7 @@ static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, wlr_signal_emit_safe(&surface->events.request_fullscreen, &event); } -static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, +static void xdg_toplevel_handle_set_minimized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); @@ -794,20 +836,20 @@ static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, } static const struct xdg_toplevel_interface xdg_toplevel_implementation = { - .destroy = resource_destroy, - .set_parent = xdg_toplevel_protocol_set_parent, - .set_title = xdg_toplevel_protocol_set_title, - .set_app_id = xdg_toplevel_protocol_set_app_id, - .show_window_menu = xdg_toplevel_protocol_show_window_menu, - .move = xdg_toplevel_protocol_move, - .resize = xdg_toplevel_protocol_resize, - .set_max_size = xdg_toplevel_protocol_set_max_size, - .set_min_size = xdg_toplevel_protocol_set_min_size, - .set_maximized = xdg_toplevel_protocol_set_maximized, - .unset_maximized = xdg_toplevel_protocol_unset_maximized, - .set_fullscreen = xdg_toplevel_protocol_set_fullscreen, - .unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, - .set_minimized = xdg_toplevel_protocol_set_minimized + .destroy = resource_handle_destroy, + .set_parent = xdg_toplevel_handle_set_parent, + .set_title = xdg_toplevel_handle_set_title, + .set_app_id = xdg_toplevel_handle_set_app_id, + .show_window_menu = xdg_toplevel_handle_show_window_menu, + .move = xdg_toplevel_handle_move, + .resize = xdg_toplevel_handle_resize, + .set_max_size = xdg_toplevel_handle_set_max_size, + .set_min_size = xdg_toplevel_handle_set_min_size, + .set_maximized = xdg_toplevel_handle_set_maximized, + .unset_maximized = xdg_toplevel_handle_unset_maximized, + .set_fullscreen = xdg_toplevel_handle_set_fullscreen, + .unset_fullscreen = xdg_toplevel_handle_unset_fullscreen, + .set_minimized = xdg_toplevel_handle_set_minimized, }; static void xdg_surface_resource_destroy(struct wl_resource *resource) { @@ -822,11 +864,11 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) { struct wlr_xdg_surface *surface = xdg_surface_from_xdg_toplevel_resource(resource); if (surface != NULL) { - xdg_surface_destroy(surface); + xdg_surface_unmap(surface); } } -static void xdg_surface_get_toplevel(struct wl_client *client, +static void xdg_surface_handle_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); @@ -835,24 +877,24 @@ static void xdg_surface_get_toplevel(struct wl_client *client, return; } - surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel)); - if (surface->toplevel_state == NULL) { + surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel)); + if (surface->toplevel == NULL) { wl_resource_post_no_memory(resource); return; } surface->role = WLR_XDG_SURFACE_ROLE_TOPLEVEL; - surface->toplevel_state->base = surface; + surface->toplevel->base = surface; struct wl_resource *toplevel_resource = wl_resource_create(client, &xdg_toplevel_interface, wl_resource_get_version(resource), id); if (toplevel_resource == NULL) { - free(surface->toplevel_state); + free(surface->toplevel); wl_resource_post_no_memory(resource); return; } - surface->toplevel_state->resource = toplevel_resource; + surface->toplevel->resource = toplevel_resource; wl_resource_set_implementation(toplevel_resource, &xdg_toplevel_implementation, surface, @@ -863,12 +905,19 @@ static void wlr_xdg_toplevel_ack_configure( struct wlr_xdg_surface *surface, struct wlr_xdg_surface_configure *configure) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel_state->next = configure->state; - surface->toplevel_state->pending.width = 0; - surface->toplevel_state->pending.height = 0; + assert(configure->toplevel_state != NULL); + + surface->toplevel->current.maximized = + configure->toplevel_state->maximized; + surface->toplevel->current.fullscreen = + configure->toplevel_state->fullscreen; + surface->toplevel->current.resizing = + configure->toplevel_state->resizing; + surface->toplevel->current.activated = + configure->toplevel_state->activated; } -static void xdg_surface_ack_configure(struct wl_client *client, +static void xdg_surface_handle_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); @@ -883,10 +932,8 @@ static void xdg_surface_ack_configure(struct wl_client *client, struct wlr_xdg_surface_configure *configure, *tmp; wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { if (configure->serial < serial) { - wl_list_remove(&configure->link); - free(configure); + xdg_surface_configure_destroy(configure); } else if (configure->serial == serial) { - wl_list_remove(&configure->link); found = true; break; } else { @@ -914,10 +961,10 @@ static void xdg_surface_ack_configure(struct wl_client *client, surface->configured = true; surface->configure_serial = serial; - free(configure); + xdg_surface_configure_destroy(configure); } -static void xdg_surface_set_window_geometry(struct wl_client *client, +static void xdg_surface_handle_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); @@ -930,19 +977,31 @@ static void xdg_surface_set_window_geometry(struct wl_client *client, } surface->has_next_geometry = true; - surface->next_geometry->height = height; - surface->next_geometry->width = width; - surface->next_geometry->x = x; - surface->next_geometry->y = y; + surface->next_geometry.height = height; + surface->next_geometry.width = width; + surface->next_geometry.x = x; + surface->next_geometry.y = y; +} +static void xdg_surface_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + struct wlr_xdg_surface *surface = xdg_surface_from_resource(resource); + + if (surface->role != WLR_XDG_SURFACE_ROLE_NONE) { + wlr_log(L_ERROR, "Tried to destroy an xdg_surface before its role " + "object"); + return; + } + + wl_resource_destroy(resource); } static const struct xdg_surface_interface xdg_surface_implementation = { - .destroy = resource_destroy, - .get_toplevel = xdg_surface_get_toplevel, - .get_popup = xdg_surface_get_popup, - .ack_configure = xdg_surface_ack_configure, - .set_window_geometry = xdg_surface_set_window_geometry, + .destroy = xdg_surface_handle_destroy, + .get_toplevel = xdg_surface_handle_get_toplevel, + .get_popup = xdg_surface_handle_get_popup, + .ack_configure = xdg_surface_handle_ack_configure, + .set_window_geometry = xdg_surface_handle_set_window_geometry, }; static bool wlr_xdg_surface_toplevel_state_compare( @@ -965,9 +1024,9 @@ static bool wlr_xdg_surface_toplevel_state_compare( } else { struct wlr_xdg_surface_configure *configure = wl_container_of(state->base->configure_list.prev, configure, link); - configured.state = configure->state; - configured.width = configure->state.width; - configured.height = configure->state.height; + configured.state = *configure->toplevel_state; + configured.width = configure->toplevel_state->width; + configured.height = configure->toplevel_state->height; } if (state->pending.activated != configured.state.activated) { @@ -999,13 +1058,19 @@ static void wlr_xdg_toplevel_send_configure( struct wlr_xdg_surface *surface, struct wlr_xdg_surface_configure *configure) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); + + configure->toplevel_state = malloc(sizeof(*configure->toplevel_state)); + if (configure->toplevel_state == NULL) { + wlr_log(L_ERROR, "Allocation failed"); + wl_resource_post_no_memory(surface->toplevel->resource); + return; + } + *configure->toplevel_state = surface->toplevel->pending; + uint32_t *s; struct wl_array states; - - configure->state = surface->toplevel_state->pending; - wl_array_init(&states); - if (surface->toplevel_state->pending.maximized) { + if (surface->toplevel->pending.maximized) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for maximized xdg_toplevel"); @@ -1013,7 +1078,7 @@ static void wlr_xdg_toplevel_send_configure( } *s = XDG_TOPLEVEL_STATE_MAXIMIZED; } - if (surface->toplevel_state->pending.fullscreen) { + if (surface->toplevel->pending.fullscreen) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for fullscreen xdg_toplevel"); @@ -1021,7 +1086,7 @@ static void wlr_xdg_toplevel_send_configure( } *s = XDG_TOPLEVEL_STATE_FULLSCREEN; } - if (surface->toplevel_state->pending.resizing) { + if (surface->toplevel->pending.resizing) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for resizing xdg_toplevel"); @@ -1029,7 +1094,7 @@ static void wlr_xdg_toplevel_send_configure( } *s = XDG_TOPLEVEL_STATE_RESIZING; } - if (surface->toplevel_state->pending.activated) { + if (surface->toplevel->pending.activated) { s = wl_array_add(&states, sizeof(uint32_t)); if (!s) { wlr_log(L_ERROR, "Could not allocate state for activated xdg_toplevel"); @@ -1038,23 +1103,17 @@ static void wlr_xdg_toplevel_send_configure( *s = XDG_TOPLEVEL_STATE_ACTIVATED; } - uint32_t width = surface->toplevel_state->pending.width; - uint32_t height = surface->toplevel_state->pending.height; - - if (width == 0 || height == 0) { - width = surface->geometry->width; - height = surface->geometry->height; - } - - xdg_toplevel_send_configure(surface->toplevel_state->resource, width, - height, &states); + uint32_t width = surface->toplevel->pending.width; + uint32_t height = surface->toplevel->pending.height; + xdg_toplevel_send_configure(surface->toplevel->resource, width, height, + &states); wl_array_release(&states); return; error_out: wl_array_release(&states); - wl_resource_post_no_memory(surface->toplevel_state->resource); + wl_resource_post_no_memory(surface->toplevel->resource); } static void wlr_xdg_surface_send_configure(void *user_data) { @@ -1080,11 +1139,11 @@ static void wlr_xdg_surface_send_configure(void *user_data) { wlr_xdg_toplevel_send_configure(surface, configure); break; case WLR_XDG_SURFACE_ROLE_POPUP: - xdg_popup_send_configure(surface->popup_state->resource, - surface->popup_state->geometry.x, - surface->popup_state->geometry.y, - surface->popup_state->geometry.width, - surface->popup_state->geometry.height); + xdg_popup_send_configure(surface->popup->resource, + surface->popup->geometry.x, + surface->popup->geometry.y, + surface->popup->geometry.width, + surface->popup->geometry.height); break; } @@ -1103,7 +1162,7 @@ static uint32_t wlr_xdg_surface_schedule_configure( break; case WLR_XDG_SURFACE_ROLE_TOPLEVEL: pending_same = - wlr_xdg_surface_toplevel_state_compare(surface->toplevel_state); + wlr_xdg_surface_toplevel_state_compare(surface->toplevel); break; case WLR_XDG_SURFACE_ROLE_POPUP: break; @@ -1143,29 +1202,32 @@ static void wlr_xdg_surface_toplevel_committed( struct wlr_xdg_surface *surface) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - if (!wlr_surface_has_buffer(surface->surface) - && !surface->toplevel_state->added) { + if (!surface->toplevel->added) { // on the first commit, send a configure request to tell the client it // is added wlr_xdg_surface_schedule_configure(surface); - surface->toplevel_state->added = true; + surface->toplevel->added = true; return; } - if (!wlr_surface_has_buffer(surface->surface)) { - return; - } - - surface->toplevel_state->current = surface->toplevel_state->next; + // update state that doesn't need compositor approval + surface->toplevel->current.max_width = + surface->toplevel->next.max_width; + surface->toplevel->current.min_width = + surface->toplevel->next.min_width; + surface->toplevel->current.max_height = + surface->toplevel->next.max_height; + surface->toplevel->current.min_height = + surface->toplevel->next.min_height; } static void wlr_xdg_surface_popup_committed( struct wlr_xdg_surface *surface) { assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); - if (!surface->popup_state->committed) { + if (!surface->popup->committed) { wlr_xdg_surface_schedule_configure(surface); - surface->popup_state->committed = true; + surface->popup->committed = true; } } @@ -1182,10 +1244,10 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, if (surface->has_next_geometry) { surface->has_next_geometry = false; - surface->geometry->x = surface->next_geometry->x; - surface->geometry->y = surface->next_geometry->y; - surface->geometry->width = surface->next_geometry->width; - surface->geometry->height = surface->next_geometry->height; + surface->geometry.x = surface->next_geometry.x; + surface->geometry.y = surface->next_geometry.y; + surface->geometry.width = surface->next_geometry.width; + surface->geometry.height = surface->next_geometry.height; } switch (surface->role) { @@ -1202,9 +1264,19 @@ static void handle_wlr_surface_committed(struct wlr_surface *wlr_surface, break; } - if (surface->configured && !surface->added) { + if (!surface->added) { surface->added = true; - wlr_signal_emit_safe(&surface->client->shell->events.new_surface, surface); + wlr_signal_emit_safe(&surface->client->shell->events.new_surface, + surface); + } + if (surface->configured && wlr_surface_has_buffer(surface->surface) && + !surface->mapped) { + surface->mapped = true; + wlr_signal_emit_safe(&surface->events.map, surface); + } + if (surface->configured && !wlr_surface_has_buffer(surface->surface) && + surface->mapped) { + xdg_surface_unmap(surface); } } @@ -1217,27 +1289,15 @@ static struct wlr_xdg_client *xdg_client_from_resource( return wl_resource_get_user_data(resource); } -static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, +static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *client_resource, uint32_t id, struct wl_resource *surface_resource) { struct wlr_xdg_client *client = xdg_client_from_resource(client_resource); - struct wlr_xdg_surface *surface; - if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface)))) { - wl_client_post_no_memory(wl_client); - return; - } - - if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { - free(surface); - wl_client_post_no_memory(wl_client); - return; - } - - if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { - free(surface->geometry); - free(surface); + struct wlr_xdg_surface *surface = + calloc(1, sizeof(struct wlr_xdg_surface)); + if (surface == NULL) { wl_client_post_no_memory(wl_client); return; } @@ -1249,8 +1309,6 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, &xdg_surface_interface, wl_resource_get_version(client_resource), id); if (surface->resource == NULL) { - free(surface->next_geometry); - free(surface->geometry); free(surface); wl_client_post_no_memory(wl_client); return; @@ -1258,8 +1316,6 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, if (wlr_surface_has_buffer(surface->surface)) { wl_resource_destroy(surface->resource); - free(surface->next_geometry); - free(surface->geometry); free(surface); wl_resource_post_error(surface_resource, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, @@ -1279,6 +1335,8 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.ping_timeout); wl_signal_init(&surface->events.new_popup); + wl_signal_init(&surface->events.map); + wl_signal_init(&surface->events.unmap); wl_signal_add(&surface->surface->events.destroy, &surface->surface_destroy_listener); @@ -1293,7 +1351,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, wl_list_insert(&client->surfaces, &surface->link); } -static void xdg_shell_pong(struct wl_client *wl_client, +static void xdg_shell_handle_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { struct wlr_xdg_client *client = xdg_client_from_resource(resource); @@ -1305,11 +1363,25 @@ static void xdg_shell_pong(struct wl_client *wl_client, client->ping_serial = 0; } +static void xdg_shell_handle_destroy(struct wl_client *wl_client, + struct wl_resource *resource) { + struct wlr_xdg_client *client = xdg_client_from_resource(resource); + + if (!wl_list_empty(&client->surfaces)) { + wl_resource_post_error(client->resource, + XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, + "xdg_wm_base was destroyed before children"); + return; + } + + wl_resource_destroy(resource); +} + static const struct xdg_wm_base_interface xdg_shell_impl = { - .destroy = resource_destroy, - .create_positioner = xdg_shell_create_positioner, - .get_xdg_surface = xdg_shell_get_xdg_surface, - .pong = xdg_shell_pong, + .destroy = xdg_shell_handle_destroy, + .create_positioner = xdg_shell_handle_create_positioner, + .get_xdg_surface = xdg_shell_handle_get_xdg_surface, + .pong = xdg_shell_handle_pong, }; static void wlr_xdg_client_destroy(struct wl_resource *resource) { @@ -1437,8 +1509,8 @@ void wlr_xdg_surface_ping(struct wlr_xdg_surface *surface) { uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, uint32_t width, uint32_t height) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel_state->pending.width = width; - surface->toplevel_state->pending.height = height; + surface->toplevel->pending.width = width; + surface->toplevel->pending.height = height; return wlr_xdg_surface_schedule_configure(surface); } @@ -1446,7 +1518,7 @@ uint32_t wlr_xdg_toplevel_set_size(struct wlr_xdg_surface *surface, uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, bool activated) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel_state->pending.activated = activated; + surface->toplevel->pending.activated = activated; return wlr_xdg_surface_schedule_configure(surface); } @@ -1454,7 +1526,7 @@ uint32_t wlr_xdg_toplevel_set_activated(struct wlr_xdg_surface *surface, uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, bool maximized) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel_state->pending.maximized = maximized; + surface->toplevel->pending.maximized = maximized; return wlr_xdg_surface_schedule_configure(surface); } @@ -1462,7 +1534,7 @@ uint32_t wlr_xdg_toplevel_set_maximized(struct wlr_xdg_surface *surface, uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, bool fullscreen) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel_state->pending.fullscreen = fullscreen; + surface->toplevel->pending.fullscreen = fullscreen; return wlr_xdg_surface_schedule_configure(surface); } @@ -1470,24 +1542,24 @@ uint32_t wlr_xdg_toplevel_set_fullscreen(struct wlr_xdg_surface *surface, uint32_t wlr_xdg_toplevel_set_resizing(struct wlr_xdg_surface *surface, bool resizing) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - surface->toplevel_state->pending.resizing = resizing; + surface->toplevel->pending.resizing = resizing; return wlr_xdg_surface_schedule_configure(surface); } void wlr_xdg_toplevel_send_close(struct wlr_xdg_surface *surface) { assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); - xdg_toplevel_send_close(surface->toplevel_state->resource); + xdg_toplevel_send_close(surface->toplevel->resource); } void wlr_xdg_surface_popup_get_position(struct wlr_xdg_surface *surface, double *popup_sx, double *popup_sy) { assert(surface->role == WLR_XDG_SURFACE_ROLE_POPUP); - struct wlr_xdg_surface *parent = surface->popup_state->parent; - *popup_sx = parent->geometry->x + surface->popup_state->geometry.x - - surface->geometry->x; - *popup_sy = parent->geometry->y + surface->popup_state->geometry.y - - surface->geometry->y; + struct wlr_xdg_surface *parent = surface->popup->parent; + *popup_sx = parent->geometry.x + surface->popup->geometry.x - + surface->geometry.x; + *popup_sy = parent->geometry.y + surface->popup->geometry.y - + surface->geometry.y; } struct wlr_xdg_surface *wlr_xdg_surface_popup_at( @@ -1501,30 +1573,30 @@ struct wlr_xdg_surface *wlr_xdg_surface_popup_at( struct wlr_xdg_surface *popup = popup_state->base; double _popup_sx = - surface->geometry->x + popup_state->geometry.x; + surface->geometry.x + popup_state->geometry.x; double _popup_sy = - surface->geometry->y + popup_state->geometry.y; + surface->geometry.y + popup_state->geometry.y; int popup_width = popup_state->geometry.width; int popup_height = popup_state->geometry.height; struct wlr_xdg_surface *_popup = wlr_xdg_surface_popup_at(popup, - sx - _popup_sx + popup->geometry->x, - sy - _popup_sy + popup->geometry->y, + sx - _popup_sx + popup->geometry.x, + sy - _popup_sy + popup->geometry.y, popup_sx, popup_sy); if (_popup) { - *popup_sx = *popup_sx + _popup_sx - popup->geometry->x; - *popup_sy = *popup_sy + _popup_sy - popup->geometry->y; + *popup_sx = *popup_sx + _popup_sx - popup->geometry.x; + *popup_sy = *popup_sy + _popup_sy - popup->geometry.y; return _popup; } if ((sx > _popup_sx && sx < _popup_sx + popup_width) && (sy > _popup_sy && sy < _popup_sy + popup_height)) { if (pixman_region32_contains_point(&popup->surface->current->input, - sx - _popup_sx + popup->geometry->x, - sy - _popup_sy + popup->geometry->y, NULL)) { - *popup_sx = _popup_sx - popup->geometry->x; - *popup_sy = _popup_sy - popup->geometry->y; + sx - _popup_sx + popup->geometry.x, + sy - _popup_sy + popup->geometry.y, NULL)) { + *popup_sx = _popup_sx - popup->geometry.x; + *popup_sy = _popup_sy - popup->geometry.y; return popup; } } From 7894fca22498f79f73b8f3c5853dd22a1727cd1c Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 21:26:45 +0100 Subject: [PATCH 30/52] matrix: rename wlr_matrix_texture to wlr_matrix_projection --- backend/drm/drm.c | 4 ++-- include/wlr/types/wlr_matrix.h | 4 +--- types/wlr_matrix.c | 2 +- types/wlr_output.c | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 0447d865..fd436659 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -587,8 +587,8 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, enum wl_output_transform transform = wlr_output_transform_compose( wlr_output_transform_invert(output->transform), WL_OUTPUT_TRANSFORM_FLIPPED_180); - wlr_matrix_texture(plane->matrix, plane->surf.width, plane->surf.height, - 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); diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h index 5255980a..fd060d11 100644 --- a/include/wlr/types/wlr_matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -1,7 +1,6 @@ #ifndef WLR_TYPES_WLR_MATRIX_H #define WLR_TYPES_WLR_MATRIX_H -#include #include #include @@ -13,8 +12,7 @@ void wlr_matrix_multiply(float mat[static 9], const float a[static 9], const float b[static 9]); void wlr_matrix_transform(float mat[static 9], enum wl_output_transform transform); - -void wlr_matrix_texture(float mat[static 9], int32_t width, int32_t height, +void wlr_matrix_projection(float mat[static 9], int width, int height, enum wl_output_transform transform); void wlr_matrix_project_box(float mat[static 9], const struct wlr_box *box, enum wl_output_transform transform, float rotation, diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c index 85a294d9..c5fa1340 100644 --- a/types/wlr_matrix.c +++ b/types/wlr_matrix.c @@ -109,7 +109,7 @@ void wlr_matrix_transform(float mat[static 9], } // Equivilent to glOrtho(0, width, 0, height, 1, -1) with the transform applied -void wlr_matrix_texture(float mat[static 9], int32_t width, int32_t height, +void wlr_matrix_projection(float mat[static 9], int width, int height, enum wl_output_transform transform) { memset(mat, 0, sizeof(*mat) * 9); diff --git a/types/wlr_output.c b/types/wlr_output.c index 9a0edd44..9575f071 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -139,8 +139,8 @@ void wlr_output_update_enabled(struct wlr_output *output, bool enabled) { } static void wlr_output_update_matrix(struct wlr_output *output) { - wlr_matrix_texture(output->transform_matrix, output->width, output->height, - output->transform); + wlr_matrix_projection(output->transform_matrix, output->width, + output->height, output->transform); } void wlr_output_enable(struct wlr_output *output, bool enable) { From f1cbbac636d59d22373883f6bc85f8863e01c8c5 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 21:30:31 +0100 Subject: [PATCH 31/52] render/gles2: remove matrix transposition in shaders --- render/gles2/renderer.c | 4 ++-- render/gles2/shaders.c | 28 ++-------------------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 0324ad64..a212e908 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -181,7 +181,7 @@ static bool wlr_gles2_render_texture_with_matrix( } wlr_texture_bind(texture); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_TRUE, matrix)); GL_CALL(glUniform1i(1, texture->inverted_y)); GL_CALL(glUniform1f(3, alpha)); draw_quad(); @@ -192,7 +192,7 @@ static bool wlr_gles2_render_texture_with_matrix( static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_TRUE, matrix)); GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index a64b941e..2e9386d0 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -10,20 +10,8 @@ const GLchar quad_vertex_src[] = "varying vec4 v_color;" "varying vec2 v_texcoord;" "" -"mat3 transpose(in mat3 inMatrix) {" -" vec3 i0 = inMatrix[0];" -" vec3 i1 = inMatrix[1];" -" vec3 i2 = inMatrix[2];" -" mat3 outMatrix = mat3(" -" vec3(i0.x, i1.x, i2.x)," -" vec3(i0.y, i1.y, i2.y)," -" vec3(i0.z, i1.z, i2.z)" -" );" -" return outMatrix;" -"}" -"" "void main() {" -" gl_Position = vec4(transpose(proj) * vec3(pos, 1.0), 1.0);" +" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);" " v_color = color;" " v_texcoord = texcoord;" "}"; @@ -57,20 +45,8 @@ const GLchar vertex_src[] = "attribute vec2 texcoord;" "varying vec2 v_texcoord;" "" -"mat3 transpose(in mat3 inMatrix) {" -" vec3 i0 = inMatrix[0];" -" vec3 i1 = inMatrix[1];" -" vec3 i2 = inMatrix[2];" -" mat3 outMatrix = mat3(" -" vec3(i0.x, i1.x, i2.x)," -" vec3(i0.y, i1.y, i2.y)," -" vec3(i0.z, i1.z, i2.z)" -" );" -" return outMatrix;" -"}" -"" "void main() {" -" gl_Position = vec4(transpose(proj) * vec3(pos, 1.0), 1.0);" +" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);" " if (invert_y) {" " v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);" " } else {" From 303883ce49b81438c8653991f40e72b0481e27cf Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 15 Mar 2018 21:47:20 +0100 Subject: [PATCH 32/52] rootston: properly emit view unmap event --- rootston/desktop.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rootston/desktop.c b/rootston/desktop.c index e9a9425c..78076e75 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -459,6 +459,8 @@ void view_map(struct roots_view *view, struct wlr_surface *surface) { void view_unmap(struct roots_view *view) { assert(view->wlr_surface != NULL); + wl_signal_emit(&view->events.unmap, view); + view_damage_whole(view); wl_list_remove(&view->link); From 7fd7dff26f4896bc71b7220c00e0abe1c2f6a21a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 16 Mar 2018 09:11:06 +0100 Subject: [PATCH 33/52] egl: print supported dmabuf formats Useful for debugging dmabuf related problems e.g. when a client requests a certain and we fail to support it. --- render/egl.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/render/egl.c b/render/egl.c index 55809983..d60da2ab 100644 --- a/render/egl.c +++ b/render/egl.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -101,6 +102,26 @@ static bool check_egl_ext(const char *egl_exts, const char *ext) { return false; } +static void print_dmabuf_formats(struct wlr_egl *egl) { + /* Avoid log msg if extension is not present */ + if (!egl->egl_exts.dmabuf_import_modifiers) { + return; + } + + int *formats; + int num = wlr_egl_get_dmabuf_formats(egl, &formats); + if (num < 0) { + return; + } + + char str_formats[num * 5 + 1]; + for (int i = 0; i < num; i++) { + snprintf(&str_formats[i*5], (num - i) * 5 + 1, "%.4s ", (char*)&formats[i]); + } + wlr_log(L_INFO, "Supported dmabuf buffer formats: %s", str_formats); + free(formats); +} + bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, EGLint *config_attribs, EGLint visual_id) { if (!load_glapi()) { @@ -172,6 +193,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, egl->egl_exts.dmabuf_import_modifiers = check_egl_ext(egl->egl_exts_str, "EGL_EXT_image_dma_buf_import_modifiers") && eglQueryDmaBufFormatsEXT && eglQueryDmaBufModifiersEXT; + print_dmabuf_formats(egl); return true; From a491f780b892b60aa65e17dc5dcb1752a2b78ee7 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sun, 18 Mar 2018 08:59:56 +0100 Subject: [PATCH 34/52] rootston rotation: change view->rotation sign The convetion with wlr_matrix changed and it's a good time to remove all these pesky minus signs --- rootston/cursor.c | 2 +- rootston/desktop.c | 4 ++-- rootston/output.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rootston/cursor.c b/rootston/cursor.c index aa94daeb..52439dff 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -200,7 +200,7 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, uy = cursor->offs_y - oy; int vx = cursor->cursor->x - ox, vy = cursor->cursor->y - oy; - float angle = atan2(vx*uy - vy*ux, vx*ux + vy*uy); + float angle = atan2(ux*vy - uy*vx, vx*ux + vy*uy); int steps = 12; angle = round(angle/M_PI*steps) / (steps/M_PI); view_rotate(view, cursor->view_rotation + angle); diff --git a/rootston/desktop.c b/rootston/desktop.c index 9730ca57..65d9a280 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -557,8 +557,8 @@ static bool view_at(struct roots_view *view, double lx, double ly, double ox = view_sx - (double)box.width/2, oy = view_sy - (double)box.height/2; // Rotated coordinates - double rx = cos(view->rotation)*ox - sin(view->rotation)*oy, - ry = cos(view->rotation)*oy + sin(view->rotation)*ox; + double rx = cos(view->rotation)*ox + sin(view->rotation)*oy, + ry = cos(view->rotation)*oy - sin(view->rotation)*ox; view_sx = rx + (double)box.width/2; view_sy = ry + (double)box.height/2; } diff --git a/rootston/output.c b/rootston/output.c index b8c73290..4146e3e2 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -29,8 +29,8 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, double ox = *sx - pw/2 + sw/2, oy = *sy - ph/2 + sh/2; // Rotated coordinates - double rx = cos(-rotation)*ox - sin(-rotation)*oy, - ry = cos(-rotation)*oy + sin(-rotation)*ox; + double rx = cos(rotation)*ox - sin(rotation)*oy, + ry = cos(rotation)*oy + sin(rotation)*ox; *sx = rx + pw/2 - sw/2; *sy = ry + ph/2 - sh/2; } @@ -227,7 +227,7 @@ static bool surface_intersect_output(struct wlr_surface *surface, .x = lx, .y = ly, .width = surface->current->width, .height = surface->current->height, }; - wlr_box_rotated_bounds(&layout_box, -rotation, &layout_box); + wlr_box_rotated_bounds(&layout_box, rotation, &layout_box); return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); } @@ -275,7 +275,7 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly, } struct wlr_box rotated; - wlr_box_rotated_bounds(&box, -rotation, &rotated); + wlr_box_rotated_bounds(&box, rotation, &rotated); pixman_region32_t damage; pixman_region32_init(&damage); @@ -341,7 +341,7 @@ static void render_decorations(struct roots_view *view, get_decoration_box(view, output, &box); struct wlr_box rotated; - wlr_box_rotated_bounds(&box, -view->rotation, &rotated); + wlr_box_rotated_bounds(&box, view->rotation, &rotated); pixman_region32_t damage; pixman_region32_init(&damage); @@ -616,7 +616,7 @@ static void damage_whole_surface(struct wlr_surface *surface, return; } - wlr_box_rotated_bounds(&box, -rotation, &box); + wlr_box_rotated_bounds(&box, rotation, &box); wlr_output_damage_add_box(output->damage, &box); } @@ -630,7 +630,7 @@ static void damage_whole_decoration(struct roots_view *view, struct wlr_box box; get_decoration_box(view, output, &box); - wlr_box_rotated_bounds(&box, -view->rotation, &box); + wlr_box_rotated_bounds(&box, view->rotation, &box); wlr_output_damage_add_box(output->damage, &box); } @@ -689,7 +689,7 @@ static void damage_from_surface(struct wlr_surface *surface, .width = (extents->x2 - extents->x1) * wlr_output->scale, .height = (extents->y2 - extents->y1) * wlr_output->scale, }; - wlr_box_rotated_bounds(&damage_box, -rotation, &damage_box); + wlr_box_rotated_bounds(&damage_box, rotation, &damage_box); wlr_output_damage_add_box(output->damage, &damage_box); } } From 6227da96b113f00b4b8134c10a43994716a53fef Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 18 Mar 2018 11:34:23 +0100 Subject: [PATCH 35/52] backend/drm: don't hardcode matrix --- backend/drm/renderer.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index f700dd59..97fba95a 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -178,7 +178,8 @@ static void free_eglimage(struct gbm_bo *bo, void *data) { free(tex); } -static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, struct gbm_bo *bo) { +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) { return tex->tex; @@ -231,13 +232,8 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, static const float color[] = {0.0, 0.0, 0.0, 1.0}; - static const float mat[9] = { - [0] = 2.0f, - [2] = -1.0f, - [4] = 2.0f, - [5] = -1.0f, - [8] = 1.0f, - }; + float mat[9]; + wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180); glViewport(0, 0, dest->width, dest->height); wlr_renderer_clear(dest->renderer->wlr_rend, color); @@ -246,8 +242,9 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, return wlr_drm_surface_swap_buffers(dest, NULL); } -bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm, - int32_t width, uint32_t height, uint32_t format) { +bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, + struct wlr_drm_backend *drm, int32_t width, uint32_t height, + uint32_t format) { if (!drm->parent) { return wlr_drm_surface_init(&plane->surf, &drm->renderer, width, height, format, GBM_BO_USE_SCANOUT); From 6ecb0eefcba21d923bd01fce688dbd6bd399fbae Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 19 Mar 2018 20:21:02 +0100 Subject: [PATCH 36/52] render/gles2: transpose matrices before binding them Setting glUniformMatrix3fv's transpose parameter to GL_TRUE is not allowed for OpenGL ES 2. This adds a wlr_matrix_transpose function. --- include/wlr/types/wlr_matrix.h | 5 +++-- render/gles2/renderer.c | 21 ++++++++++++++++++--- types/wlr_matrix.c | 9 +++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/include/wlr/types/wlr_matrix.h b/include/wlr/types/wlr_matrix.h index fd060d11..02111db8 100644 --- a/include/wlr/types/wlr_matrix.h +++ b/include/wlr/types/wlr_matrix.h @@ -5,11 +5,12 @@ #include void wlr_matrix_identity(float mat[static 9]); +void wlr_matrix_multiply(float mat[static 9], const float a[static 9], + const float b[static 9]); +void wlr_matrix_transpose(float mat[static 9], const float a[static 9]); void wlr_matrix_translate(float mat[static 9], float x, float y); void wlr_matrix_scale(float mat[static 9], float x, float y); void wlr_matrix_rotate(float mat[static 9], float rad); -void wlr_matrix_multiply(float mat[static 9], const float a[static 9], - const float b[static 9]); void wlr_matrix_transform(float mat[static 9], enum wl_output_transform transform); void wlr_matrix_projection(float mat[static 9], int width, int height, diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index a212e908..8d8dd17f 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -180,8 +180,13 @@ static bool wlr_gles2_render_texture_with_matrix( return false; } + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set + // to GL_FALSE + float transposition[9]; + wlr_matrix_transpose(transposition, matrix); + wlr_texture_bind(texture); - GL_CALL(glUniformMatrix3fv(0, 1, GL_TRUE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); GL_CALL(glUniform1i(1, texture->inverted_y)); GL_CALL(glUniform1f(3, alpha)); draw_quad(); @@ -191,16 +196,26 @@ static bool wlr_gles2_render_texture_with_matrix( static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set + // to GL_FALSE + float transposition[9]; + wlr_matrix_transpose(transposition, matrix); + GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_TRUE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set + // to GL_FALSE + float transposition[9]; + wlr_matrix_transpose(transposition, matrix); + GL_CALL(glUseProgram(shaders.ellipse)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_TRUE, matrix)); + GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); draw_quad(); } diff --git a/types/wlr_matrix.c b/types/wlr_matrix.c index c5fa1340..6eb47ca8 100644 --- a/types/wlr_matrix.c +++ b/types/wlr_matrix.c @@ -33,6 +33,15 @@ void wlr_matrix_multiply(float mat[static 9], const float a[static 9], memcpy(mat, product, sizeof(product)); } +void wlr_matrix_transpose(float mat[static 9], const float a[static 9]) { + float transposition[9] = { + a[0], a[3], a[6], + a[1], a[4], a[7], + a[2], a[5], a[8], + }; + memcpy(mat, transposition, sizeof(transposition)); +} + void wlr_matrix_translate(float mat[static 9], float x, float y) { float translate[9] = { 1.0f, 0.0f, x, From 8d490fdb34ad4374b3ab144f1b46296eb81ad316 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 19 Mar 2018 15:46:28 -0400 Subject: [PATCH 37/52] Write some more docs --- include/wlr/backend.h | 23 +++++++++++++++++++++++ include/wlr/backend/drm.h | 7 +++++++ include/wlr/backend/headless.h | 14 ++++++++++++++ include/wlr/backend/interface.h | 4 ++++ include/wlr/backend/libinput.h | 4 +++- include/wlr/backend/multi.h | 10 ++++++++++ 6 files changed, 61 insertions(+), 1 deletion(-) diff --git a/include/wlr/backend.h b/include/wlr/backend.h index 00dc9fdc..e3b14add 100644 --- a/include/wlr/backend.h +++ b/include/wlr/backend.h @@ -11,16 +11,39 @@ struct wlr_backend { const struct wlr_backend_impl *impl; struct { + /** Raised when destroyed, passed the wlr_backend reference */ struct wl_signal destroy; + /** Raised when new inputs are added, passed the wlr_input_device */ struct wl_signal new_input; + /** Raised when new outputs are added, passed the wlr_output */ struct wl_signal new_output; } events; }; +/** + * Automatically initializes the most suitable backend given the environment. + * Will always return a multibackend. The backend is created but not started. + * Returns NULL on failure. + */ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); +/** + * Start the backend. This may signal new_input or new_output immediately, but + * may also wait until the display's event loop begins. Returns false on + * failure. + */ bool wlr_backend_start(struct wlr_backend *backend); +/** + * Destroy the backend and clean up all of its resources. Normally called + * automatically when the wl_display is destroyed. + */ void wlr_backend_destroy(struct wlr_backend *backend); +/** + * Obtains the wlr_egl reference this backend is using. + */ struct wlr_egl *wlr_backend_get_egl(struct wlr_backend *backend); +/** + * Obtains the wlr_renderer reference this backend is using. + */ struct wlr_renderer *wlr_backend_get_renderer(struct wlr_backend *backend); uint32_t usec_to_msec(uint64_t usec); diff --git a/include/wlr/backend/drm.h b/include/wlr/backend/drm.h index 90460647..0c9e5c8b 100644 --- a/include/wlr/backend/drm.h +++ b/include/wlr/backend/drm.h @@ -6,6 +6,13 @@ #include #include +/** + * Creates a DRM backend using the specified GPU file descriptor (typically from + * a device node in /dev/dri). + * + * To slave this to another DRM backend, pass it as the parent (which _must_ be + * a DRM backend, other kinds of backends raise SIGABRT). + */ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, struct wlr_session *session, int gpu_fd, struct wlr_backend *parent); diff --git a/include/wlr/backend/headless.h b/include/wlr/backend/headless.h index 8995f7cb..ee784a0d 100644 --- a/include/wlr/backend/headless.h +++ b/include/wlr/backend/headless.h @@ -5,9 +5,23 @@ #include #include +/** + * Creates a headless backend. A headless backend has no outputs or inputs by + * default. + */ struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); +/** + * Create a new headless output backed by an in-memory EGL framebuffer. You can + * read pixels from this framebuffer via wlr_renderer_read_pixels but it is + * otherwise not displayed. + */ struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend, unsigned int width, unsigned int height); +/** + * Creates a new input device. The caller is responsible for manually raising + * any event signals on the new input device if it wants to simulate input + * events. + */ struct wlr_input_device *wlr_headless_add_input_device( struct wlr_backend *backend, enum wlr_input_device_type type); bool wlr_backend_is_headless(struct wlr_backend *backend); diff --git a/include/wlr/backend/interface.h b/include/wlr/backend/interface.h index d9212795..f03e95d9 100644 --- a/include/wlr/backend/interface.h +++ b/include/wlr/backend/interface.h @@ -12,6 +12,10 @@ struct wlr_backend_impl { struct wlr_renderer *(*get_renderer)(struct wlr_backend *backend); }; +/** + * Initializes common state on a wlr_backend and sets the implementation to the + * provided wlr_backend_impl reference. + */ void wlr_backend_init(struct wlr_backend *backend, const struct wlr_backend_impl *impl); diff --git a/include/wlr/backend/libinput.h b/include/wlr/backend/libinput.h index c7cfe894..92d31415 100644 --- a/include/wlr/backend/libinput.h +++ b/include/wlr/backend/libinput.h @@ -9,7 +9,9 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, struct wlr_session *session); -struct libinput_device *wlr_libinput_get_device_handle(struct wlr_input_device *dev); +/** Gets the underlying libinput_device handle for the given wlr_input_device */ +struct libinput_device *wlr_libinput_get_device_handle( + struct wlr_input_device *dev); bool wlr_backend_is_libinput(struct wlr_backend *backend); bool wlr_input_device_is_libinput(struct wlr_input_device *device); diff --git a/include/wlr/backend/multi.h b/include/wlr/backend/multi.h index 2dee7403..842eed67 100644 --- a/include/wlr/backend/multi.h +++ b/include/wlr/backend/multi.h @@ -4,11 +4,21 @@ #include #include +/** + * Creates a multi-backend. Multi-backends wrap an arbitrary number of backends + * and aggregate their new_output/new_input signals. + */ struct wlr_backend *wlr_multi_backend_create(struct wl_display *display); +/** + * Adds the given backend to the multi backend. This should be done before the + * new backend is started. + */ void wlr_multi_backend_add(struct wlr_backend *multi, struct wlr_backend *backend); + void wlr_multi_backend_remove(struct wlr_backend *multi, struct wlr_backend *backend); + bool wlr_backend_is_multi(struct wlr_backend *backend); struct wlr_session *wlr_multi_get_session(struct wlr_backend *base); bool wlr_multi_is_empty(struct wlr_backend *backend); From c41de2d1be5c8e814e99e3a1859cdaa885b6042d Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 19 Mar 2018 23:16:29 +0100 Subject: [PATCH 38/52] render: split render.h into wlr_renderer.h and wlr_texture.h --- backend/drm/drm.c | 2 +- backend/drm/renderer.c | 2 +- examples/idle-inhibit.c | 2 +- examples/idle.c | 6 +- examples/multi-pointer.c | 30 +++---- examples/output-layout.c | 26 +++--- examples/pointer.c | 30 +++---- examples/rotation.c | 16 ++-- examples/simple.c | 6 +- examples/tablet.c | 20 ++--- examples/touch.c | 20 ++--- include/backend/drm/renderer.h | 2 +- include/backend/wayland.h | 2 +- include/render/gles2.h | 3 +- include/rootston/server.h | 2 +- include/wlr/render.h | 135 ----------------------------- include/wlr/render/gles2.h | 2 +- include/wlr/render/interface.h | 5 +- include/wlr/render/wlr_renderer.h | 75 ++++++++++++++++ include/wlr/render/wlr_texture.h | 69 +++++++++++++++ include/wlr/types/wlr_compositor.h | 2 +- render/gles2/renderer.c | 2 +- render/gles2/texture.c | 2 +- render/wlr_renderer.c | 1 + render/wlr_texture.c | 1 + rootston/main.c | 2 +- types/wlr_linux_dmabuf.c | 1 - types/wlr_output.c | 2 +- types/wlr_screenshooter.c | 2 +- 29 files changed, 241 insertions(+), 229 deletions(-) delete mode 100644 include/wlr/render.h create mode 100644 include/wlr/render/wlr_renderer.h create mode 100644 include/wlr/render/wlr_texture.h diff --git a/backend/drm/drm.c b/backend/drm/drm.c index fd436659..344756f8 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -15,8 +15,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 97fba95a..7e330990 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -7,9 +7,9 @@ #include #include #include -#include #include #include +#include #include #include #include "backend/drm/drm.h" diff --git a/examples/idle-inhibit.c b/examples/idle-inhibit.c index b7b9c21c..c09e6507 100644 --- a/examples/idle-inhibit.c +++ b/examples/idle-inhibit.c @@ -5,8 +5,8 @@ #include #include #include -#include "xdg-shell-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" #include diff --git a/examples/idle.c b/examples/idle.c index 2b155c68..b65a81cf 100644 --- a/examples/idle.c +++ b/examples/idle.c @@ -1,11 +1,11 @@ +#include +#include #include #include #include #include -#include -#include -#include #include +#include #include #include "idle-client-protocol.h" diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index 6e56bfdc..43ccdb66 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -1,30 +1,30 @@ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 500 +#include +#include +#include #include #include -#include #include +#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include #include #include -#include -#include -#include +#include +#include #include -#include +#include #include -#include "support/shared.h" -#include "support/config.h" +#include +#include +#include +#include +#include #include "support/cat.h" +#include "support/config.h" +#include "support/shared.h" struct sample_state; diff --git a/examples/output-layout.c b/examples/output-layout.c index 8f506208..de134a71 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -1,29 +1,29 @@ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 700 +#include +#include +#include #include #include -#include #include #include +#include #include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include #include #include +#include +#include +#include +#include #include #include -#include -#include -#include "support/shared.h" -#include "support/config.h" +#include +#include #include "support/cat.h" +#include "support/config.h" +#include "support/shared.h" struct sample_state { struct example_config *config; diff --git a/examples/pointer.c b/examples/pointer.c index e80b346a..e8a0e892 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -1,30 +1,30 @@ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 500 +#include +#include +#include #include #include -#include #include +#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include #include #include -#include -#include -#include +#include +#include #include -#include +#include #include -#include "support/shared.h" -#include "support/config.h" +#include +#include +#include +#include +#include #include "support/cat.h" +#include "support/config.h" +#include "support/shared.h" struct sample_state { struct compositor_state *compositor; diff --git a/examples/rotation.c b/examples/rotation.c index aaf006cf..7f50b620 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -1,23 +1,23 @@ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 500 +#include +#include #include #include -#include #include #include +#include #include -#include #include -#include -#include -#include -#include -#include +#include #include #include +#include +#include #include +#include #include -#include +#include #include "support/shared.h" #include "support/config.h" #include "support/cat.h" diff --git a/examples/simple.c b/examples/simple.c index 90808b0f..79db4a0c 100644 --- a/examples/simple.c +++ b/examples/simple.c @@ -1,11 +1,11 @@ #define _POSIX_C_SOURCE 199309L -#include +#include +#include #include #include +#include #include -#include #include -#include #include #include #include diff --git a/examples/tablet.c b/examples/tablet.c index 521447b9..1b995003 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -1,27 +1,27 @@ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 500 +#include +#include #include #include -#include #include +#include #include -#include #include -#include -#include -#include -#include -#include +#include #include #include +#include +#include #include +#include #include -#include #include +#include #include -#include -#include "support/shared.h" +#include #include "support/cat.h" +#include "support/shared.h" struct sample_state { struct wlr_renderer *renderer; diff --git a/examples/touch.c b/examples/touch.c index 0af8bc4a..0968e82a 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -1,25 +1,25 @@ #define _POSIX_C_SOURCE 199309L #define _XOPEN_SOURCE 500 +#include +#include +#include #include #include -#include #include +#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include #include #include +#include +#include #include +#include #include -#include "support/shared.h" +#include #include "support/cat.h" +#include "support/shared.h" struct sample_state { struct wlr_renderer *renderer; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index a56a8673..73adfc27 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include struct wlr_drm_backend; struct wlr_drm_plane; diff --git a/include/backend/wayland.h b/include/backend/wayland.h index 16c8e13b..b68208af 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include struct wlr_wl_backend { diff --git a/include/render/gles2.h b/include/render/gles2.h index e015160d..e8124050 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -9,9 +9,10 @@ #include #include #include -#include #include #include +#include +#include #include extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; diff --git a/include/rootston/server.h b/include/rootston/server.h index 5f35dd90..7ab15682 100644 --- a/include/rootston/server.h +++ b/include/rootston/server.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #ifdef WLR_HAS_XWAYLAND #include diff --git a/include/wlr/render.h b/include/wlr/render.h deleted file mode 100644 index 01d05fb1..00000000 --- a/include/wlr/render.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef WLR_RENDER_H -#define WLR_RENDER_H - -#include -#include -#include -#include -#include -#include - -struct wlr_texture; -struct wlr_renderer; - -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); -void wlr_renderer_end(struct wlr_renderer *r); -void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); -/** - * Defines a scissor box. Only pixels that lie within the scissor box can be - * modified by drawing functions. Providing a NULL `box` disables the scissor - * 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. - */ -bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, - const float projection[static 9], int x, int y, float alpha); -/** - * Renders the requested texture using the provided matrix. - */ -bool wlr_render_texture_with_matrix(struct wlr_renderer *r, - struct wlr_texture *texture, const float matrix[static 9], float alpha); -/** - * Renders a solid quad in the specified color. - */ -void wlr_render_colored_quad(struct wlr_renderer *r, - const float color[static 4], const float matrix[static 9]); -/** - * Renders a solid ellipse in the specified color. - */ -void wlr_render_colored_ellipse(struct wlr_renderer *r, - const float color[static 4], const float matrix[static 9]); -/** - * Returns a list of pixel formats supported by this renderer. - */ -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. - */ -bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, - struct wl_resource *buffer); -/** - * Reads out of pixels of the currently bound surface into data. `stride` is in - * bytes. - */ -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); -/** - * Checks if a format is supported. - */ -bool wlr_renderer_format_supported(struct wlr_renderer *r, - enum wl_shm_format fmt); -/** - * Destroys this wlr_renderer. Textures must be destroyed separately. - */ -void wlr_renderer_destroy(struct wlr_renderer *renderer); - -struct wlr_texture_impl; - -struct wlr_texture { - 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. - */ -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); - -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. - */ -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); -/** - * Destroys this wlr_texture. - */ -void wlr_texture_destroy(struct wlr_texture *texture); - -#endif diff --git a/include/wlr/render/gles2.h b/include/wlr/render/gles2.h index a924a065..b3b43ab2 100644 --- a/include/wlr/render/gles2.h +++ b/include/wlr/render/gles2.h @@ -2,7 +2,7 @@ #define WLR_RENDER_GLES2_H #include -#include +#include struct wlr_egl; struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend); diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index 1b8b7946..f0307230 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -5,10 +5,11 @@ #include #include #include -#include +#include +#include #include -#include #include +#include struct wlr_renderer_impl; diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h new file mode 100644 index 00000000..d5f3cf70 --- /dev/null +++ b/include/wlr/render/wlr_renderer.h @@ -0,0 +1,75 @@ +#ifndef WLR_RENDER_WLR_RENDERER_H +#define WLR_RENDER_WLR_RENDERER_H + +#include +#include +#include +#include +#include +#include + +struct wlr_output; + +struct wlr_renderer; + +void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); +void wlr_renderer_end(struct wlr_renderer *r); +void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); +/** + * Defines a scissor box. Only pixels that lie within the scissor box can be + * modified by drawing functions. Providing a NULL `box` disables the scissor + * 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. + */ +bool wlr_render_texture(struct wlr_renderer *r, struct wlr_texture *texture, + const float projection[static 9], int x, int y, float alpha); +/** + * Renders the requested texture using the provided matrix. + */ +bool wlr_render_texture_with_matrix(struct wlr_renderer *r, + struct wlr_texture *texture, const float matrix[static 9], float alpha); +/** + * Renders a solid quad in the specified color. + */ +void wlr_render_colored_quad(struct wlr_renderer *r, + const float color[static 4], const float matrix[static 9]); +/** + * Renders a solid ellipse in the specified color. + */ +void wlr_render_colored_ellipse(struct wlr_renderer *r, + const float color[static 4], const float matrix[static 9]); +/** + * Returns a list of pixel formats supported by this renderer. + */ +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. + */ +bool wlr_renderer_buffer_is_drm(struct wlr_renderer *renderer, + struct wl_resource *buffer); +/** + * Reads out of pixels of the currently bound surface into data. `stride` is in + * bytes. + */ +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); +/** + * Checks if a format is supported. + */ +bool wlr_renderer_format_supported(struct wlr_renderer *r, + enum wl_shm_format fmt); +/** + * Destroys this wlr_renderer. Textures must be destroyed separately. + */ +void wlr_renderer_destroy(struct wlr_renderer *renderer); + +#endif diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h new file mode 100644 index 00000000..49aa93d7 --- /dev/null +++ b/include/wlr/render/wlr_texture.h @@ -0,0 +1,69 @@ +#ifndef WLR_RENDER_WLR_TEXTURE_H +#define WLR_RENDER_WLR_TEXTURE_H + +#include +#include +#include +#include + +struct wlr_texture_impl; + +struct wlr_texture { + 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. + */ +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); + +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. + */ +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); +/** + * Destroys this wlr_texture. + */ +void wlr_texture_destroy(struct wlr_texture *texture); + +#endif diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 5919b934..11bfac71 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -2,7 +2,7 @@ #define WLR_TYPES_WLR_COMPOSITOR_H #include -#include +#include struct wlr_compositor { struct wl_global *wl_global; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 8d8dd17f..55797805 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/render/gles2/texture.c b/render/gles2/texture.c index fc94ead5..c5f79ba8 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index c4f91d5e..21a7901a 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -1,6 +1,7 @@ #include #include #include +#include #include void wlr_renderer_init(struct wlr_renderer *renderer, diff --git a/render/wlr_texture.c b/render/wlr_texture.c index 48f76c8e..a5d0abde 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -1,6 +1,7 @@ #include #include #include +#include void wlr_texture_init(struct wlr_texture *texture, struct wlr_texture_impl *impl) { diff --git a/rootston/main.c b/rootston/main.c index 5450ade2..d85701ca 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include "rootston/config.h" #include "rootston/server.h" diff --git a/types/wlr_linux_dmabuf.c b/types/wlr_linux_dmabuf.c index 3b86166e..1883bc49 100644 --- a/types/wlr_linux_dmabuf.c +++ b/types/wlr_linux_dmabuf.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/types/wlr_output.c b/types/wlr_output.c index 9575f071..e30c3b78 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index e756b6aa..e1386be6 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include From b3cb5a36c7230070419afc71704800b380549a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Tue, 20 Mar 2018 13:06:53 +0100 Subject: [PATCH 39/52] gles2: allow to specify texture target type Allow to set the texture target type when generating/binding the texture. This allows us to attach the texture type to the texture so we don't have to keep the logic elsewhere. --- include/render/gles2.h | 1 + render/gles2/texture.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index e8124050..0a4fb49f 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -37,6 +37,7 @@ struct wlr_gles2_texture { GLuint tex_id; const struct pixel_format *pixel_format; EGLImageKHR image; + GLenum target; }; struct shaders { diff --git a/render/gles2/texture.c b/render/gles2/texture.c index c5f79ba8..b3035826 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -22,14 +22,16 @@ static struct pixel_format external_pixel_format = { .shader = &shaders.external }; -static void gles2_texture_ensure_texture(struct wlr_gles2_texture *texture) { +static void gles2_texture_ensure_texture(struct wlr_gles2_texture *texture, + GLenum target) { if (texture->tex_id) { return; } + texture->target = target; GL_CALL(glGenTextures(1, &texture->tex_id)); - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->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)); + GL_CALL(glBindTexture(target, texture->tex_id)); + GL_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); } static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, @@ -47,7 +49,7 @@ static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, texture->wlr_texture.format = format; texture->pixel_format = fmt; - gles2_texture_ensure_texture(texture); + gles2_texture_ensure_texture(texture, GL_TEXTURE_2D); 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, @@ -100,7 +102,7 @@ static bool gles2_texture_upload_shm(struct wlr_texture *_texture, texture->wlr_texture.format = format; texture->pixel_format = fmt; - gles2_texture_ensure_texture(texture); + gles2_texture_ensure_texture(texture, GL_TEXTURE_2D); 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)); @@ -185,9 +187,8 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, return false; } - gles2_texture_ensure_texture(tex); + gles2_texture_ensure_texture(tex, target); GL_CALL(glBindTexture(GL_TEXTURE_2D, tex->tex_id)); - EGLint attribs[] = { EGL_WAYLAND_PLANE_WL, 0, EGL_NONE }; if (tex->image) { @@ -220,7 +221,7 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, tex->wlr_texture.width = width; tex->wlr_texture.height = height; - gles2_texture_ensure_texture(tex); + gles2_texture_ensure_texture(tex, GL_TEXTURE_2D); GL_CALL(glActiveTexture(GL_TEXTURE0)); GL_CALL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id)); @@ -254,7 +255,7 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, GLenum target = GL_TEXTURE_2D; const struct pixel_format *pf = gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); - gles2_texture_ensure_texture(tex); + gles2_texture_ensure_texture(tex, target); GL_CALL(glBindTexture(target, tex->tex_id)); tex->image = wlr_egl_create_image_from_dmabuf(tex->egl, &dmabuf->attributes); GL_CALL(glActiveTexture(GL_TEXTURE0)); From 13e4ba4867c0b5ab2193728d6a4192007fe8276b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Tue, 20 Mar 2018 13:19:14 +0100 Subject: [PATCH 40/52] gles2_texture_bind: use texture's target type Hardcoding GL_TEXTURE_2D leads to rendering errors when using GL_TEXTURE_EXTERNAL_OES textures. --- render/gles2/texture.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/render/gles2/texture.c b/render/gles2/texture.c index b3035826..99f153b8 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -306,9 +306,10 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct static void gles2_texture_bind(struct wlr_texture *_texture) { struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + GL_CALL(glBindTexture(texture->target, texture->tex_id)); + GL_CALL(glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GL_CALL(glUseProgram(*texture->pixel_format->shader)); } From 2d01663b2559c6d6a121c18b9496248dce8ad1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Mon, 19 Mar 2018 15:45:34 +0100 Subject: [PATCH 41/52] gles2: Honor alpha in fragment_src_external By using the same vertex shader and adding alpha to the fragment shader for external textures we can: - use alpha blending - have wlr_gles2_render_texture_with_matrix work with the GL_TEXTURE_EXTERNAL_OES. So far this failed since we passed in alpha which was unknown by fragment_src_external --- render/gles2/renderer.c | 2 +- render/gles2/shaders.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 55797805..f525869d 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -90,7 +90,7 @@ static void init_default_shaders() { goto error; } if (glEGLImageTargetTexture2DOES) { - if (!compile_program(quad_vertex_src, fragment_src_external, + if (!compile_program(vertex_src, fragment_src_external, &shaders.external)) { goto error; } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 2e9386d0..30e12e4c 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -80,8 +80,9 @@ const GLchar fragment_src_external[] = "precision mediump float;" "varying vec2 v_texcoord;" "uniform samplerExternalOES texture0;" +"uniform float alpha;" "" "void main() {" " vec4 col = texture2D(texture0, v_texcoord);" -" gl_FragColor = vec4(col.rgb, col.a);" +" gl_FragColor = vec4(col.rgb, col.a * alpha);" "}"; From 95e86e675a7eef326958ab9047ff4ca0d0182cfc Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 20 Mar 2018 19:14:33 +0100 Subject: [PATCH 42/52] render/gles2: remove global state, use OpenGL debug extension --- include/render/gles2.h | 43 ++- include/wlr/render/interface.h | 10 +- include/wlr/render/wlr_texture.h | 2 +- render/glapi.txt | 5 + render/gles2/pixel_format.c | 8 +- render/gles2/renderer.c | 450 ++++++++++++++++++++----------- render/gles2/shaders.c | 148 +++++----- render/gles2/texture.c | 224 ++++++++------- render/wlr_renderer.c | 2 +- render/wlr_texture.c | 6 +- 10 files changed, 526 insertions(+), 372 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 0a4fb49f..9ff09065 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -17,17 +17,24 @@ extern PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; -struct pixel_format { +struct gles2_pixel_format { uint32_t wl_format; GLint gl_format, gl_type; int depth, bpp; - GLuint *shader; }; struct wlr_gles2_renderer { struct wlr_renderer wlr_renderer; struct wlr_egl *egl; + + struct { + GLuint quad; + GLuint ellipse; + GLuint tex_rgba; + GLuint tex_rgbx; + GLuint tex_ext; + } shaders; }; struct wlr_gles2_texture { @@ -35,37 +42,19 @@ struct wlr_gles2_texture { struct wlr_egl *egl; GLuint tex_id; - const struct pixel_format *pixel_format; + const struct gles2_pixel_format *pixel_format; EGLImageKHR image; GLenum target; }; -struct shaders { - bool initialized; - GLuint rgba, rgbx; - GLuint quad; - GLuint ellipse; - GLuint external; -}; - -extern struct shaders shaders; - -const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt); +const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt); struct wlr_texture *gles2_texture_create(); +struct wlr_gles2_texture *gles2_get_texture(struct wlr_texture *wlr_texture); -extern const GLchar quad_vertex_src[]; -extern const GLchar quad_fragment_src[]; -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(...) \ - _gles2_flush_errors(wlr_strip_path(__FILE__), __LINE__) - -#define GL_CALL(func) func; gles2_flush_errors() +void gles2_push_marker(const char *file, const char *func); +void gles2_pop_marker(void); +#define GLES2_DEBUG_PUSH gles2_push_marker(wlr_strip_path(__FILE__), __func__) +#define GLES2_DEBUG_POP gles2_pop_marker() #endif diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index f0307230..da0aaec9 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -14,7 +14,7 @@ struct wlr_renderer_impl; struct wlr_renderer { - struct wlr_renderer_impl *impl; + const struct wlr_renderer_impl *impl; }; struct wlr_renderer_impl { @@ -44,7 +44,7 @@ struct wlr_renderer_impl { }; void wlr_renderer_init(struct wlr_renderer *renderer, - struct wlr_renderer_impl *impl); + const struct wlr_renderer_impl *impl); struct wlr_texture_impl { bool (*upload_pixels)(struct wlr_texture *texture, @@ -65,14 +65,12 @@ struct wlr_texture_impl { struct wl_resource *dmabuf_resource); void (*get_buffer_size)(struct wlr_texture *texture, struct wl_resource *resource, int *width, int *height); - void (*bind)(struct wlr_texture *texture); void (*destroy)(struct wlr_texture *texture); }; void wlr_texture_init(struct wlr_texture *texture, - struct wlr_texture_impl *impl); -void wlr_texture_bind(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); + struct wl_resource *resource, int *width, int *height); #endif diff --git a/include/wlr/render/wlr_texture.h b/include/wlr/render/wlr_texture.h index 49aa93d7..095097e6 100644 --- a/include/wlr/render/wlr_texture.h +++ b/include/wlr/render/wlr_texture.h @@ -9,7 +9,7 @@ struct wlr_texture_impl; struct wlr_texture { - struct wlr_texture_impl *impl; + const struct wlr_texture_impl *impl; bool valid; uint32_t format; diff --git a/render/glapi.txt b/render/glapi.txt index 02ac7dd8..a8e4aaba 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -10,3 +10,8 @@ eglCreatePlatformWindowSurfaceEXT -eglSwapBuffersWithDamageKHR -eglQueryDmaBufFormatsEXT -eglQueryDmaBufModifiersEXT +-eglDebugMessageControlKHR +-glDebugMessageCallbackKHR +-glDebugMessageControlKHR +-glPopDebugGroupKHR +-glPushDebugGroupKHR diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index a544077b..7c34896c 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -6,14 +6,13 @@ * The wayland formats are little endian while the GL formats are big endian, * so WL_SHM_FORMAT_ARGB8888 is actually compatible with GL_BGRA_EXT. */ -struct pixel_format formats[] = { +struct gles2_pixel_format formats[] = { { .wl_format = WL_SHM_FORMAT_ARGB8888, .depth = 32, .bpp = 32, .gl_format = GL_BGRA_EXT, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgba }, { .wl_format = WL_SHM_FORMAT_XRGB8888, @@ -21,7 +20,6 @@ struct pixel_format formats[] = { .bpp = 32, .gl_format = GL_BGRA_EXT, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgbx }, { .wl_format = WL_SHM_FORMAT_XBGR8888, @@ -29,7 +27,6 @@ struct pixel_format formats[] = { .bpp = 32, .gl_format = GL_RGBA, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgbx }, { .wl_format = WL_SHM_FORMAT_ABGR8888, @@ -37,12 +34,11 @@ struct pixel_format formats[] = { .bpp = 32, .gl_format = GL_RGBA, .gl_type = GL_UNSIGNED_BYTE, - .shader = &shaders.rgba }, }; // TODO: more pixel formats -const struct pixel_format *gl_format_for_wl_format(enum wl_shm_format fmt) { +const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt) { for (size_t i = 0; i < sizeof(formats) / sizeof(*formats); ++i) { if (formats[i].wl_format == fmt) { return &formats[i]; diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index f525869d..14eea666 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -2,145 +2,80 @@ #include #include #include +#include #include #include #include #include -#include #include #include +#include #include #include #include "render/gles2.h" #include "glapi.h" -struct shaders shaders; +static const struct wlr_renderer_impl renderer_impl; -static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { - *shader = GL_CALL(glCreateShader(type)); - int len = strlen(src); - GL_CALL(glShaderSource(*shader, 1, &src, &len)); - GL_CALL(glCompileShader(*shader)); - GLint success; - GL_CALL(glGetShaderiv(*shader, GL_COMPILE_STATUS, &success)); - if (success == GL_FALSE) { - GLint loglen; - GL_CALL(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &loglen)); - GLchar msg[loglen]; - GL_CALL(glGetShaderInfoLog(*shader, loglen, &loglen, msg)); - wlr_log(L_ERROR, "Shader compilation failed"); - wlr_log(L_ERROR, "%s", msg); - glDeleteShader(*shader); - return false; - } - return true; +static 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; + assert(eglGetCurrentContext() == renderer->egl->context); + return renderer; } -static bool compile_program(const GLchar *vert_src, - const GLchar *frag_src, GLuint *program) { - GLuint vertex, fragment; - if (!compile_shader(GL_VERTEX_SHADER, vert_src, &vertex)) { - return false; - } - if (!compile_shader(GL_FRAGMENT_SHADER, frag_src, &fragment)) { - glDeleteShader(vertex); - return false; - } - *program = GL_CALL(glCreateProgram()); - GL_CALL(glAttachShader(*program, vertex)); - GL_CALL(glAttachShader(*program, fragment)); - GL_CALL(glLinkProgram(*program)); - GLint success; - GL_CALL(glGetProgramiv(*program, GL_LINK_STATUS, &success)); - if (success == GL_FALSE) { - GLint loglen; - GL_CALL(glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &loglen)); - GLchar msg[loglen]; - GL_CALL(glGetProgramInfoLog(*program, loglen, &loglen, msg)); - wlr_log(L_ERROR, "Program link failed"); - wlr_log(L_ERROR, "%s", msg); - glDeleteProgram(*program); - glDeleteShader(vertex); - glDeleteShader(fragment); - return false; - } - glDetachShader(*program, vertex); - glDetachShader(*program, fragment); - glDeleteShader(vertex); - glDeleteShader(fragment); - - return true; -} - -static void init_default_shaders() { - if (shaders.initialized) { - return; - } - if (!compile_program(vertex_src, fragment_src_rgba, &shaders.rgba)) { - goto error; - } - if (!compile_program(vertex_src, fragment_src_rgbx, &shaders.rgbx)) { - goto error; - } - if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) { - goto error; - } - if (!compile_program(quad_vertex_src, ellipse_fragment_src, - &shaders.ellipse)) { - goto error; - } - if (glEGLImageTargetTexture2DOES) { - if (!compile_program(vertex_src, fragment_src_external, - &shaders.external)) { - goto error; - } - } - - wlr_log(L_DEBUG, "Compiled default shaders"); - shaders.initialized = true; - return; -error: - wlr_log(L_ERROR, "Failed to set up default shaders!"); -} - -static void init_globals() { - init_default_shaders(); -} - -static void wlr_gles2_begin(struct wlr_renderer *wlr_renderer, +static void gles2_begin(struct wlr_renderer *wlr_renderer, struct wlr_output *output) { - GL_CALL(glViewport(0, 0, output->width, output->height)); + gles2_get_renderer(wlr_renderer); + + GLES2_DEBUG_PUSH; + + glViewport(0, 0, output->width, output->height); // enable transparency - GL_CALL(glEnable(GL_BLEND)); - GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // Note: maybe we should save output projection and remove some of the need + // XXX: maybe we should save output projection and remove some of the need // for users to sling matricies themselves + + GLES2_DEBUG_POP; } -static void wlr_gles2_end(struct wlr_renderer *wlr_renderer) { +static void gles2_end(struct wlr_renderer *wlr_renderer) { + gles2_get_renderer(wlr_renderer); // no-op } -static void wlr_gles2_clear(struct wlr_renderer *wlr_renderer, +static void gles2_clear(struct wlr_renderer *wlr_renderer, const float color[static 4]) { + gles2_get_renderer(wlr_renderer); + + GLES2_DEBUG_PUSH; glClearColor(color[0], color[1], color[2], color[3]); glClear(GL_COLOR_BUFFER_BIT); + GLES2_DEBUG_POP; } -static void wlr_gles2_scissor(struct wlr_renderer *wlr_renderer, +static void gles2_scissor(struct wlr_renderer *wlr_renderer, struct wlr_box *box) { + gles2_get_renderer(wlr_renderer); + + GLES2_DEBUG_PUSH; if (box != NULL) { glScissor(box->x, box->y, box->width, box->height); glEnable(GL_SCISSOR_TEST); } else { glDisable(GL_SCISSOR_TEST); } + GLES2_DEBUG_POP; } -static struct wlr_texture *wlr_gles2_texture_create( +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); @@ -160,69 +95,93 @@ static void draw_quad() { 0, 1, // bottom left }; - GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts)); - GL_CALL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord)); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord); - GL_CALL(glEnableVertexAttribArray(0)); - GL_CALL(glEnableVertexAttribArray(1)); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); - GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - GL_CALL(glDisableVertexAttribArray(0)); - GL_CALL(glDisableVertexAttribArray(1)); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); } -static bool wlr_gles2_render_texture_with_matrix( - struct wlr_renderer *wlr_renderer, struct wlr_texture *texture, +static bool gles2_render_texture_with_matrix( + struct wlr_renderer *wlr_renderer, struct wlr_texture *wlr_texture, const float matrix[static 9], float alpha) { - if (!texture || !texture->valid) { + 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; } + GLuint prog = renderer->shaders.tex_rgba; + if (texture->target == GL_TEXTURE_EXTERNAL_OES) { + prog = renderer->shaders.tex_ext; + } else if (texture->pixel_format->wl_format == WL_SHM_FORMAT_XRGB8888 || + texture->pixel_format->wl_format == WL_SHM_FORMAT_XBGR8888) { + prog = renderer->shaders.tex_rgbx; + } + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE float transposition[9]; wlr_matrix_transpose(transposition, matrix); - wlr_texture_bind(texture); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); - GL_CALL(glUniform1i(1, texture->inverted_y)); - GL_CALL(glUniform1f(3, alpha)); + 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); + glUseProgram(prog); + + glUniformMatrix3fv(0, 1, GL_FALSE, transposition); + glUniform1i(1, wlr_texture->inverted_y); + glUniform1f(3, alpha); draw_quad(); + GLES2_DEBUG_POP; return true; } -static void wlr_gles2_render_quad(struct wlr_renderer *wlr_renderer, +static void gles2_render_quad(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE float transposition[9]; wlr_matrix_transpose(transposition, matrix); - GL_CALL(glUseProgram(shaders.quad)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); - GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); + GLES2_DEBUG_PUSH; + glUseProgram(renderer->shaders.quad); + glUniformMatrix3fv(0, 1, GL_FALSE, transposition); + glUniform4f(1, color[0], color[1], color[2], color[3]); draw_quad(); + GLES2_DEBUG_POP; } -static void wlr_gles2_render_ellipse(struct wlr_renderer *wlr_renderer, +static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer, const float color[static 4], const float matrix[static 9]) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + // OpenGL ES 2 requires the glUniformMatrix3fv transpose parameter to be set // to GL_FALSE float transposition[9]; wlr_matrix_transpose(transposition, matrix); - GL_CALL(glUseProgram(shaders.ellipse)); - GL_CALL(glUniformMatrix3fv(0, 1, GL_FALSE, transposition)); - GL_CALL(glUniform4f(1, color[0], color[1], color[2], color[3])); + GLES2_DEBUG_PUSH; + glUseProgram(renderer->shaders.ellipse); + glUniformMatrix3fv(0, 1, GL_FALSE, transposition); + glUniform4f(1, color[0], color[1], color[2], color[3]); draw_quad(); + GLES2_DEBUG_POP; } -static const enum wl_shm_format *wlr_gles2_formats( +static const enum wl_shm_format *gles2_formats( struct wlr_renderer *renderer, size_t *len) { - static enum wl_shm_format formats[] = { + static const enum wl_shm_format formats[] = { WL_SHM_FORMAT_ARGB8888, WL_SHM_FORMAT_XRGB8888, WL_SHM_FORMAT_ABGR8888, @@ -232,25 +191,29 @@ static const enum wl_shm_format *wlr_gles2_formats( return formats; } -static bool wlr_gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, +static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, struct wl_resource *buffer) { - struct wlr_gles2_renderer *renderer = - (struct wlr_gles2_renderer *)wlr_renderer; + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + EGLint format; - return wlr_egl_query_buffer(renderer->egl, buffer, - EGL_TEXTURE_FORMAT, &format); + return wlr_egl_query_buffer(renderer->egl, buffer, EGL_TEXTURE_FORMAT, + &format); } -static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer, +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) { - const struct pixel_format *fmt = gl_format_for_wl_format(wl_fmt); + gles2_get_renderer(wlr_renderer); + + const struct gles2_pixel_format *fmt = gles2_format_from_wl(wl_fmt); if (fmt == NULL) { wlr_log(L_ERROR, "Cannot read pixels: unsupported pixel format"); return false; } + GLES2_DEBUG_PUSH; + // Make sure any pending drawing is finished before we try to read it glFinish(); @@ -262,38 +225,225 @@ static bool wlr_gles2_read_pixels(struct wlr_renderer *renderer, fmt->gl_type, p + i * stride + dst_x * fmt->bpp / 8); } + GLES2_DEBUG_POP; + return true; } -static bool wlr_gles2_format_supported(struct wlr_renderer *r, +static bool gles2_format_supported(struct wlr_renderer *r, enum wl_shm_format wl_fmt) { - return gl_format_for_wl_format(wl_fmt); + return gles2_format_from_wl(wl_fmt) != NULL; } -static struct wlr_renderer_impl wlr_renderer_impl = { - .begin = wlr_gles2_begin, - .end = wlr_gles2_end, - .clear = wlr_gles2_clear, - .scissor = wlr_gles2_scissor, - .texture_create = wlr_gles2_texture_create, - .render_texture_with_matrix = wlr_gles2_render_texture_with_matrix, - .render_quad = wlr_gles2_render_quad, - .render_ellipse = wlr_gles2_render_ellipse, - .formats = wlr_gles2_formats, - .buffer_is_drm = wlr_gles2_buffer_is_drm, - .read_pixels = wlr_gles2_read_pixels, - .format_supported = wlr_gles2_format_supported, +static void gles2_destroy(struct wlr_renderer *wlr_renderer) { + struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer); + + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + + GLES2_DEBUG_PUSH; + glDeleteProgram(renderer->shaders.quad); + glDeleteProgram(renderer->shaders.ellipse); + glDeleteProgram(renderer->shaders.tex_rgba); + glDeleteProgram(renderer->shaders.tex_rgbx); + glDeleteProgram(renderer->shaders.tex_ext); + GLES2_DEBUG_POP; + + if (glDebugMessageCallbackKHR) { + glDisable(GL_DEBUG_OUTPUT_KHR); + glDebugMessageCallbackKHR(NULL, NULL); + } + + free(renderer); +} + +static const struct wlr_renderer_impl renderer_impl = { + .destroy = gles2_destroy, + .begin = gles2_begin, + .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 = gles2_render_quad, + .render_ellipse = gles2_render_ellipse, + .formats = gles2_formats, + .buffer_is_drm = gles2_buffer_is_drm, + .read_pixels = gles2_read_pixels, + .format_supported = gles2_format_supported, }; +void gles2_push_marker(const char *file, const char *func) { + if (!glPushDebugGroupKHR) { + return; + } + + int len = snprintf(NULL, 0, "%s:%s", file, func) + 1; + char str[len]; + snprintf(str, len, "%s:%s", file, func); + glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str); +} + +void gles2_pop_marker(void) { + if (glPopDebugGroupKHR) { + glPopDebugGroupKHR(); + } +} + +static log_importance_t gles2_log_importance_to_wlr(GLenum type) { + switch (type) { + case GL_DEBUG_TYPE_ERROR_KHR: return L_ERROR; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR: return L_ERROR; + case GL_DEBUG_TYPE_PORTABILITY_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_PERFORMANCE_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_OTHER_KHR: return L_INFO; + case GL_DEBUG_TYPE_MARKER_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_PUSH_GROUP_KHR: return L_DEBUG; + case GL_DEBUG_TYPE_POP_GROUP_KHR: return L_DEBUG; + default: return L_INFO; + } +} + +static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, + GLsizei len, const GLchar *msg, const void *user) { + _wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg); +} + +static GLuint compile_shader(GLuint type, const GLchar *src) { + GLES2_DEBUG_PUSH; + + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + + GLint ok; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + if (ok == GL_FALSE) { + glDeleteShader(shader); + shader = 0; + } + + GLES2_DEBUG_POP; + return shader; +} + +static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) { + GLES2_DEBUG_PUSH; + + GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src); + if (!vert) { + goto error; + } + + GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src); + if (!frag) { + glDeleteShader(vert); + goto error; + } + + GLuint prog = glCreateProgram(); + glAttachShader(prog, vert); + glAttachShader(prog, frag); + glLinkProgram(prog); + + glDetachShader(prog, vert); + glDetachShader(prog, frag); + glDeleteShader(vert); + glDeleteShader(frag); + + GLint ok; + glGetProgramiv(prog, GL_LINK_STATUS, &ok); + if (ok == GL_FALSE) { + glDeleteProgram(prog); + goto error; + } + + GLES2_DEBUG_POP; + return prog; + +error: + GLES2_DEBUG_POP; + return 0; +} + +extern const GLchar quad_vertex_src[]; +extern const GLchar quad_fragment_src[]; +extern const GLchar ellipse_fragment_src[]; +extern const GLchar tex_vertex_src[]; +extern const GLchar tex_fragment_src_rgba[]; +extern const GLchar tex_fragment_src_rgbx[]; +extern const GLchar tex_fragment_src_external[]; + struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_backend *backend) { - init_globals(); - struct wlr_gles2_renderer *renderer; - if (!(renderer = calloc(1, sizeof(struct wlr_gles2_renderer)))) { + struct wlr_gles2_renderer *renderer = + calloc(1, sizeof(struct wlr_gles2_renderer)); + if (renderer == NULL) { return NULL; } - wlr_renderer_init(&renderer->wlr_renderer, &wlr_renderer_impl); + wlr_renderer_init(&renderer->wlr_renderer, &renderer_impl); renderer->egl = wlr_backend_get_egl(backend); + wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL); + + if (glDebugMessageCallbackKHR && glDebugMessageControlKHR) { + glEnable(GL_DEBUG_OUTPUT_KHR); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR); + glDebugMessageCallbackKHR(gles2_log, NULL); + + // Silence unwanted message types + glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP_KHR, + GL_DONT_CARE, 0, NULL, GL_FALSE); + glDebugMessageControlKHR(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP_KHR, + GL_DONT_CARE, 0, NULL, GL_FALSE); + } + + GLES2_DEBUG_PUSH; + + renderer->shaders.quad = link_program(quad_vertex_src, quad_fragment_src); + if (!renderer->shaders.quad) { + goto error; + } + renderer->shaders.ellipse = + link_program(quad_vertex_src, ellipse_fragment_src); + if (!renderer->shaders.ellipse) { + goto error; + } + renderer->shaders.tex_rgba = + link_program(tex_vertex_src, tex_fragment_src_rgba); + if (!renderer->shaders.tex_rgba) { + goto error; + } + renderer->shaders.tex_rgbx = + link_program(tex_vertex_src, tex_fragment_src_rgbx); + if (!renderer->shaders.tex_rgbx) { + goto error; + } + if (glEGLImageTargetTexture2DOES) { + renderer->shaders.tex_ext = + link_program(tex_vertex_src, tex_fragment_src_external); + if (!renderer->shaders.tex_ext) { + goto error; + } + } + + GLES2_DEBUG_POP; return &renderer->wlr_renderer; + +error: + glDeleteProgram(renderer->shaders.quad); + glDeleteProgram(renderer->shaders.ellipse); + glDeleteProgram(renderer->shaders.tex_rgba); + glDeleteProgram(renderer->shaders.tex_rgbx); + glDeleteProgram(renderer->shaders.tex_ext); + + GLES2_DEBUG_POP; + + if (glDebugMessageCallbackKHR) { + glDisable(GL_DEBUG_OUTPUT_KHR); + glDebugMessageCallbackKHR(NULL, NULL); + } + + free(renderer); + return NULL; } diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c index 30e12e4c..ba3bd971 100644 --- a/render/gles2/shaders.c +++ b/render/gles2/shaders.c @@ -3,86 +3,88 @@ // Colored quads const GLchar quad_vertex_src[] = -"uniform mat3 proj;" -"uniform vec4 color;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);" -" v_color = color;" -" v_texcoord = texcoord;" -"}"; +"uniform mat3 proj;\n" +"uniform vec4 color;\n" +"attribute vec2 pos;\n" +"attribute vec2 texcoord;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" +" v_color = color;\n" +" v_texcoord = texcoord;\n" +"}\n"; const GLchar quad_fragment_src[] = -"precision mediump float;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" gl_FragColor = v_color;" -"}"; +"precision mediump float;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" gl_FragColor = v_color;\n" +"}\n"; // Colored ellipses const GLchar ellipse_fragment_src[] = -"precision mediump float;" -"varying vec4 v_color;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" float l = length(v_texcoord - vec2(0.5, 0.5));" -" if (l > 0.5) discard;" -" gl_FragColor = v_color;" -"}"; +"precision mediump float;\n" +"varying vec4 v_color;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" float l = length(v_texcoord - vec2(0.5, 0.5));\n" +" if (l > 0.5) {\n" +" discard;\n" +" }\n" +" gl_FragColor = v_color;\n" +"}\n"; // Textured quads -const GLchar vertex_src[] = -"uniform mat3 proj;" -"uniform bool invert_y;" -"attribute vec2 pos;" -"attribute vec2 texcoord;" -"varying vec2 v_texcoord;" -"" -"void main() {" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);" -" if (invert_y) {" -" v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);" -" } else {" -" v_texcoord = texcoord;" -" }" -"}"; +const GLchar tex_vertex_src[] = +"uniform mat3 proj;\n" +"uniform bool invert_y;\n" +"attribute vec2 pos;\n" +"attribute vec2 texcoord;\n" +"varying vec2 v_texcoord;\n" +"\n" +"void main() {\n" +" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" +" if (invert_y) {\n" +" v_texcoord = vec2(texcoord.s, 1.0 - texcoord.t);\n" +" } else {\n" +" v_texcoord = texcoord;\n" +" }\n" +"}\n"; -const GLchar fragment_src_rgba[] = -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform sampler2D tex;" -"uniform float alpha;" -"" -"void main() {" -" gl_FragColor = alpha * texture2D(tex, v_texcoord);" -"}"; +const GLchar tex_fragment_src_rgba[] = +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform sampler2D tex;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +" gl_FragColor = alpha * texture2D(tex, v_texcoord);\n" +"}\n"; -const GLchar fragment_src_rgbx[] = -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform sampler2D tex;" -"uniform float alpha;" -"" -"void main() {" -" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;" -" gl_FragColor.a = alpha;" -"}"; +const GLchar tex_fragment_src_rgbx[] = +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform sampler2D tex;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +" gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb;\n" +" gl_FragColor.a = alpha;\n" +"}\n"; -const GLchar fragment_src_external[] = -"#extension GL_OES_EGL_image_external : require\n" -"precision mediump float;" -"varying vec2 v_texcoord;" -"uniform samplerExternalOES texture0;" -"uniform float alpha;" -"" -"void main() {" -" vec4 col = texture2D(texture0, v_texcoord);" -" gl_FragColor = vec4(col.rgb, col.a * alpha);" -"}"; +const GLchar tex_fragment_src_external[] = +"#extension GL_OES_EGL_image_external : require\n\n" +"precision mediump float;\n" +"varying vec2 v_texcoord;\n" +"uniform samplerExternalOES texture0;\n" +"uniform float alpha;\n" +"\n" +"void main() {\n" +" vec4 col = texture2D(texture0, v_texcoord);\n" +" gl_FragColor = vec4(col.rgb, col.a * alpha);\n" +"}\n"; diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 99f153b8..e21bd77f 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -13,33 +13,39 @@ #include "render/gles2.h" #include "util/signal.h" -static struct pixel_format external_pixel_format = { +static struct gles2_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_ensure_texture(struct wlr_gles2_texture *texture, +static void gles2_texture_ensure(struct wlr_gles2_texture *texture, GLenum target) { if (texture->tex_id) { return; } texture->target = target; - GL_CALL(glGenTextures(1, &texture->tex_id)); - GL_CALL(glBindTexture(target, texture->tex_id)); - GL_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GL_CALL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + 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 bool gles2_texture_upload_pixels(struct wlr_texture *_texture, +static const struct wlr_texture_impl texture_impl; + +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 *texture = (struct wlr_gles2_texture *)_texture; - assert(texture); - const struct pixel_format *fmt = gl_format_for_wl_format(format); + 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; @@ -49,44 +55,50 @@ static bool gles2_texture_upload_pixels(struct wlr_texture *_texture, texture->wlr_texture.format = format; texture->pixel_format = fmt; - gles2_texture_ensure_texture(texture, GL_TEXTURE_2D); - 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, - fmt->gl_format, fmt->gl_type, pixels)); + GLES2_DEBUG_PUSH; + gles2_texture_ensure(texture, GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); + glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, + fmt->gl_format, fmt->gl_type, pixels); + GLES2_DEBUG_POP; + texture->wlr_texture.valid = true; return true; } -static bool gles2_texture_update_pixels(struct wlr_texture *_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) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - assert(texture); + 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); + return gles2_texture_upload_pixels(&texture->wlr_texture, format, + stride, width, height, pixels); } - const struct pixel_format *fmt = texture->pixel_format; - GL_CALL(glBindTexture(GL_TEXTURE_2D, texture->tex_id)); - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); - GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, - fmt->gl_format, fmt->gl_type, pixels)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + const struct gles2_pixel_format *fmt = texture->pixel_format; + GLES2_DEBUG_PUSH; + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, x); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y); + glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, fmt->gl_format, + fmt->gl_type, pixels); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); + GLES2_DEBUG_POP; return true; } -static bool gles2_texture_upload_shm(struct wlr_texture *_texture, +static bool gles2_texture_upload_shm(struct wlr_texture *wlr_texture, uint32_t format, struct wl_shm_buffer *buffer) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - const struct pixel_format *fmt = gl_format_for_wl_format(format); + 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); @@ -102,23 +114,26 @@ static bool gles2_texture_upload_shm(struct wlr_texture *_texture, texture->wlr_texture.format = format; texture->pixel_format = fmt; - gles2_texture_ensure_texture(texture, GL_TEXTURE_2D); - 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)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, fmt->gl_format, width, height, 0, - fmt->gl_format, fmt->gl_type, pixels)); + 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 *_texture, +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 = (struct wlr_gles2_texture *)_texture; + 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); @@ -127,28 +142,30 @@ static bool gles2_texture_update_shm(struct wlr_texture *_texture, /* || unpack not supported */) { return gles2_texture_upload_shm(&texture->wlr_texture, format, buffer); } - const struct pixel_format *fmt = texture->pixel_format; + 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); - 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, x)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, y)); - GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, - fmt->gl_format, fmt->gl_type, pixels)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); - GL_CALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + 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 *_tex, +static bool gles2_texture_upload_drm(struct wlr_texture *wlr_texture, struct wl_resource *buf) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; + struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); if (!glEGLImageTargetTexture2DOES) { return false; } @@ -160,9 +177,9 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, } wlr_egl_query_buffer(tex->egl, buf, EGL_WIDTH, - (EGLint*)&tex->wlr_texture.width); + (EGLint*)&tex->wlr_texture.width); wlr_egl_query_buffer(tex->egl, buf, EGL_HEIGHT, - (EGLint*)&tex->wlr_texture.height); + (EGLint*)&tex->wlr_texture.height); EGLint inverted_y; if (wlr_egl_query_buffer(tex->egl, buf, EGL_WAYLAND_Y_INVERTED_WL, @@ -171,12 +188,12 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, } GLenum target; - const struct pixel_format *pf; + const struct gles2_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); + pf = gles2_format_from_wl(WL_SHM_FORMAT_ARGB8888); break; case EGL_TEXTURE_EXTERNAL_WL: target = GL_TEXTURE_EXTERNAL_OES; @@ -187,8 +204,11 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, return false; } - gles2_texture_ensure_texture(tex, target); - GL_CALL(glBindTexture(GL_TEXTURE_2D, tex->tex_id)); + 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) { @@ -202,18 +222,20 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, return false; } - GL_CALL(glActiveTexture(GL_TEXTURE0)); - GL_CALL(glBindTexture(target, tex->tex_id)); - GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); + 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_tex, +static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_texture, EGLImageKHR image, uint32_t width, uint32_t height) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)wlr_tex; + struct wlr_gles2_texture *tex = gles2_get_texture(wlr_texture); tex->image = image; tex->pixel_format = &external_pixel_format; @@ -221,20 +243,21 @@ static bool gles2_texture_upload_eglimage(struct wlr_texture *wlr_tex, tex->wlr_texture.width = width; tex->wlr_texture.height = height; - gles2_texture_ensure_texture(tex, GL_TEXTURE_2D); - - GL_CALL(glActiveTexture(GL_TEXTURE0)); - GL_CALL(glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex->tex_id)); - GL_CALL(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, tex->image)); + 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 *_tex, +static bool gles2_texture_upload_dmabuf(struct wlr_texture *wlr_texture, struct wl_resource *dmabuf_resource) { - struct wlr_gles2_texture *tex = (struct wlr_gles2_texture *)_tex; - struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_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"); @@ -249,17 +272,19 @@ static bool gles2_texture_upload_dmabuf(struct wlr_texture *_tex, } if (wlr_dmabuf_buffer_has_inverted_y(dmabuf)) { - _tex->inverted_y = true; + wlr_texture->inverted_y = true; } GLenum target = GL_TEXTURE_2D; - const struct pixel_format *pf = - gl_format_for_wl_format(WL_SHM_FORMAT_ARGB8888); - gles2_texture_ensure_texture(tex, target); - GL_CALL(glBindTexture(target, tex->tex_id)); + const struct gles2_pixel_format *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); - GL_CALL(glActiveTexture(GL_TEXTURE0)); - GL_CALL(glEGLImageTargetTexture2DOES(target, tex->image)); + glActiveTexture(GL_TEXTURE0); + glEGLImageTargetTexture2DOES(target, tex->image); + GLES2_DEBUG_POP; tex->pixel_format = pf; tex->wlr_texture.valid = true; return true; @@ -271,15 +296,15 @@ static bool gles2_texture_get_dmabuf_size(struct wlr_texture *texture, struct return false; } - struct wlr_dmabuf_buffer *dmabuf = wlr_dmabuf_buffer_from_buffer_resource( - resource); + 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) { +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; @@ -288,14 +313,13 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct } if (!wlr_egl_query_buffer(tex->egl, resource, EGL_WIDTH, (EGLint*)width)) { - if (!gles2_texture_get_dmabuf_size(texture, resource, - width, height)) { + 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); + wlr_egl_query_buffer(tex->egl, resource, EGL_HEIGHT, (EGLint*)height); return; } @@ -304,20 +328,15 @@ static void gles2_texture_get_buffer_size(struct wlr_texture *texture, struct *height = wl_shm_buffer_get_height(buffer); } -static void gles2_texture_bind(struct wlr_texture *_texture) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; +static void gles2_texture_destroy(struct wlr_texture *wlr_texture) { + struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture); - GL_CALL(glBindTexture(texture->target, texture->tex_id)); - GL_CALL(glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GL_CALL(glUseProgram(*texture->pixel_format->shader)); -} - -static void gles2_texture_destroy(struct wlr_texture *_texture) { - struct wlr_gles2_texture *texture = (struct wlr_gles2_texture *)_texture; - wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, &texture->wlr_texture); + wlr_signal_emit_safe(&texture->wlr_texture.destroy_signal, + &texture->wlr_texture); if (texture->tex_id) { - GL_CALL(glDeleteTextures(1, &texture->tex_id)); + GLES2_DEBUG_PUSH; + glDeleteTextures(1, &texture->tex_id); + GLES2_DEBUG_POP; } if (texture->image) { @@ -327,7 +346,7 @@ static void gles2_texture_destroy(struct wlr_texture *_texture) { free(texture); } -static struct wlr_texture_impl wlr_texture_impl = { +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, @@ -336,7 +355,6 @@ static struct wlr_texture_impl wlr_texture_impl = { .upload_dmabuf = gles2_texture_upload_dmabuf, .upload_eglimage = gles2_texture_upload_eglimage, .get_buffer_size = gles2_texture_get_buffer_size, - .bind = gles2_texture_bind, .destroy = gles2_texture_destroy, }; @@ -345,7 +363,7 @@ struct wlr_texture *gles2_texture_create(struct wlr_egl *egl) { if (!(texture = calloc(1, sizeof(struct wlr_gles2_texture)))) { return NULL; } - wlr_texture_init(&texture->wlr_texture, &wlr_texture_impl); + wlr_texture_init(&texture->wlr_texture, &texture_impl); texture->egl = egl; return &texture->wlr_texture; } diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 21a7901a..79e0b5d5 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -5,7 +5,7 @@ #include void wlr_renderer_init(struct wlr_renderer *renderer, - struct wlr_renderer_impl *impl) { + const struct wlr_renderer_impl *impl) { renderer->impl = impl; } diff --git a/render/wlr_texture.c b/render/wlr_texture.c index a5d0abde..33c91822 100644 --- a/render/wlr_texture.c +++ b/render/wlr_texture.c @@ -4,7 +4,7 @@ #include void wlr_texture_init(struct wlr_texture *texture, - struct wlr_texture_impl *impl) { + const struct wlr_texture_impl *impl) { texture->impl = impl; wl_signal_init(&texture->destroy_signal); } @@ -17,10 +17,6 @@ void wlr_texture_destroy(struct wlr_texture *texture) { } } -void wlr_texture_bind(struct wlr_texture *texture) { - texture->impl->bind(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, From 3581573bdcbe3c905eae83af53cccbcdd52edad2 Mon Sep 17 00:00:00 2001 From: emersion Date: Tue, 20 Mar 2018 23:10:42 +0100 Subject: [PATCH 43/52] render/gles2: make wlr_renderer_begin take viewport size This allows raw GL calls outside wlr_renderer to be removed. --- backend/drm/drm.c | 13 ++++++------- backend/drm/renderer.c | 23 +++++++++++------------ backend/headless/output.c | 14 ++++++-------- backend/wayland/output.c | 21 ++++++++++----------- examples/output-layout.c | 2 +- examples/rotation.c | 2 +- examples/tablet.c | 2 +- examples/touch.c | 2 +- include/wlr/render/interface.h | 3 ++- include/wlr/render/wlr_renderer.h | 2 +- render/gles2/renderer.c | 6 +++--- render/wlr_renderer.c | 4 ++-- rootston/output.c | 2 +- wlroots.syms | 2 +- 14 files changed, 47 insertions(+), 51 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 344756f8..345c0dd8 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -643,14 +643,13 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); - glViewport(0, 0, plane->surf.width, plane->surf.height); - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; + 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_renderer_end(rend); - wlr_render_texture(plane->surf.renderer->wlr_rend, plane->wlr_tex, - plane->matrix, 0, 0, 1.0f); - - glFinish(); + // TODO: remove these raw GL calls glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bo_data); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7e330990..3b9aaded 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -107,9 +106,6 @@ void wlr_drm_surface_finish(struct wlr_drm_surface *surf) { return; } - eglMakeCurrent(surf->renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - if (surf->front) { gbm_surface_release_buffer(surf->gbm, surf->front); } @@ -151,9 +147,10 @@ struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) { } wlr_drm_surface_make_current(surf, NULL); - glViewport(0, 0, surf->width, surf->height); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + struct wlr_renderer *renderer = surf->renderer->wlr_rend; + wlr_renderer_begin(renderer, surf->width, surf->height); + wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); + wlr_renderer_end(renderer); return wlr_drm_surface_swap_buffers(surf, NULL); } @@ -185,6 +182,8 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, return tex->tex; } + // TODO: use wlr_texture_upload_dmabuf instead + tex = malloc(sizeof(*tex)); if (!tex) { wlr_log_errno(L_ERROR, "Allocation failed"); @@ -230,14 +229,14 @@ struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); assert(tex); - static const float color[] = {0.0, 0.0, 0.0, 1.0}; - float mat[9]; wlr_matrix_projection(mat, 1, 1, WL_OUTPUT_TRANSFORM_FLIPPED_180); - glViewport(0, 0, dest->width, dest->height); - wlr_renderer_clear(dest->renderer->wlr_rend, color); - wlr_render_texture_with_matrix(dest->renderer->wlr_rend, tex, mat, 1.0f); + struct wlr_renderer *renderer = dest->renderer->wlr_rend; + wlr_renderer_begin(renderer, dest->width, dest->height); + wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); + wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); + wlr_renderer_end(renderer); return wlr_drm_surface_swap_buffers(dest, NULL); } diff --git a/backend/headless/output.c b/backend/headless/output.c index 6ce8fc35..4746d2f2 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -1,8 +1,8 @@ #include #include -#include #include #include +#include #include #include "backend/headless.h" #include "util/signal.h" @@ -120,16 +120,14 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, snprintf(wlr_output->name, sizeof(wlr_output->name), "HEADLESS-%d", wl_list_length(&backend->outputs) + 1); - if (!eglMakeCurrent(output->backend->egl.display, - output->egl_surface, output->egl_surface, - output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, + NULL)) { goto error; } - glViewport(0, 0, wlr_output->width, wlr_output->height); - glClearColor(1.0, 1.0, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); + wlr_renderer_end(backend->renderer); struct wl_event_loop *ev = wl_display_get_event_loop(backend->display); output->frame_timer = wl_event_loop_add_timer(ev, signal_frame, output); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index fc40dea0..d528c888 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -9,6 +8,7 @@ #include #include #include +#include #include #include "backend/wayland.h" #include "util/signal.h" @@ -313,27 +313,26 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { output->egl_window = wl_egl_window_create(output->surface, wlr_output->width, wlr_output->height); - output->egl_surface = wlr_egl_create_surface(&backend->egl, output->egl_window); + output->egl_surface = wlr_egl_create_surface(&backend->egl, + output->egl_window); wl_display_roundtrip(output->backend->remote_display); // start rendering loop per callbacks by rendering first frame - if (!eglMakeCurrent(output->backend->egl.display, - output->egl_surface, output->egl_surface, - output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + if (!wlr_egl_make_current(&output->backend->egl, output->egl_surface, + NULL)) { goto error; } - glViewport(0, 0, wlr_output->width, wlr_output->height); - glClearColor(1.0, 1.0, 1.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); + wlr_renderer_begin(backend->renderer, wlr_output->width, wlr_output->height); + wlr_renderer_clear(backend->renderer, (float[]){ 1.0, 1.0, 1.0, 1.0 }); + wlr_renderer_end(backend->renderer); output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &frame_listener, output); - if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { - wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + if (!wlr_egl_swap_buffers(&output->backend->egl, output->egl_surface, + NULL)) { goto error; } diff --git a/examples/output-layout.c b/examples/output-layout.c index de134a71..45d896b0 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -101,7 +101,7 @@ static void handle_output_frame(struct output_state *output, struct wlr_output *wlr_output = output->output; wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); animate_cat(sample, output->output); diff --git a/examples/rotation.c b/examples/rotation.c index 7f50b620..cbff09a1 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -43,7 +43,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_effective_resolution(wlr_output, &width, &height); wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { diff --git a/examples/tablet.c b/examples/tablet.c index 1b995003..65c559cb 100644 --- a/examples/tablet.c +++ b/examples/tablet.c @@ -46,7 +46,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_effective_resolution(wlr_output, &width, &height); wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); float matrix[9]; diff --git a/examples/touch.c b/examples/touch.c index 0968e82a..f9c496cf 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -42,7 +42,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_effective_resolution(wlr_output, &width, &height); wlr_output_make_current(wlr_output, NULL); - wlr_renderer_begin(sample->renderer, wlr_output); + wlr_renderer_begin(sample->renderer, wlr_output->width, wlr_output->height); wlr_renderer_clear(sample->renderer, (float[]){0.25f, 0.25f, 0.25f, 1}); struct touch_point *p; diff --git a/include/wlr/render/interface.h b/include/wlr/render/interface.h index da0aaec9..7f25c0ff 100644 --- a/include/wlr/render/interface.h +++ b/include/wlr/render/interface.h @@ -18,7 +18,8 @@ struct wlr_renderer { }; struct wlr_renderer_impl { - void (*begin)(struct wlr_renderer *renderer, struct wlr_output *output); + void (*begin)(struct wlr_renderer *renderer, uint32_t width, + uint32_t height); 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); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index d5f3cf70..6f0d2ecc 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -12,7 +12,7 @@ struct wlr_output; struct wlr_renderer; -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *output); +void wlr_renderer_begin(struct wlr_renderer *r, int width, int height); void wlr_renderer_end(struct wlr_renderer *r); void wlr_renderer_clear(struct wlr_renderer *r, const float color[static 4]); /** diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 14eea666..6b046bc4 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -26,13 +26,13 @@ static struct wlr_gles2_renderer *gles2_get_renderer( return renderer; } -static void gles2_begin(struct wlr_renderer *wlr_renderer, - struct wlr_output *output) { +static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width, + uint32_t height) { gles2_get_renderer(wlr_renderer); GLES2_DEBUG_PUSH; - glViewport(0, 0, output->width, output->height); + glViewport(0, 0, width, height); // enable transparency glEnable(GL_BLEND); diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 79e0b5d5..622aa1dd 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -17,8 +17,8 @@ void wlr_renderer_destroy(struct wlr_renderer *r) { } } -void wlr_renderer_begin(struct wlr_renderer *r, struct wlr_output *o) { - r->impl->begin(r, o); +void wlr_renderer_begin(struct wlr_renderer *r, int width, int height) { + r->impl->begin(r, width, height); } void wlr_renderer_end(struct wlr_renderer *r) { diff --git a/rootston/output.c b/rootston/output.c index 4146e3e2..1de27bad 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -479,7 +479,7 @@ static void render_output(struct roots_output *output) { goto damage_finish; } - wlr_renderer_begin(renderer, wlr_output); + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); if (!pixman_region32_not_empty(&damage)) { // Output isn't damaged but needs buffer swap diff --git a/wlroots.syms b/wlroots.syms index 3f45e045..cb030a6d 100644 --- a/wlroots.syms +++ b/wlroots.syms @@ -15,8 +15,8 @@ WLROOTS_0_0_0 { wlr_drm_get_connector_props; wlr_drm_get_crtc_props; wlr_drm_get_plane_props; - wlr_drm_get_prop; wlr_drm_get_prop_blob; + wlr_drm_get_prop; wlr_drm_plane_surfaces_init; wlr_drm_renderer_finish; wlr_drm_renderer_init; From cc5ef1d2ffab1d7c0caaf1aa606637791ddf5ada Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 21 Mar 2018 08:50:59 +0100 Subject: [PATCH 44/52] render/gles2: move list of supported WL formats to pixel_format.c --- include/render/gles2.h | 2 ++ render/gles2/pixel_format.c | 19 ++++++++++++++++++- render/gles2/renderer.c | 15 ++++----------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/include/render/gles2.h b/include/render/gles2.h index 9ff09065..43a8d648 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -21,6 +21,7 @@ struct gles2_pixel_format { uint32_t wl_format; GLint gl_format, gl_type; int depth, bpp; + bool has_alpha; }; struct wlr_gles2_renderer { @@ -48,6 +49,7 @@ struct wlr_gles2_texture { }; 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); diff --git a/render/gles2/pixel_format.c b/render/gles2/pixel_format.c index 7c34896c..89ba762f 100644 --- a/render/gles2/pixel_format.c +++ b/render/gles2/pixel_format.c @@ -6,13 +6,14 @@ * The wayland formats are little endian while the GL formats are big endian, * so WL_SHM_FORMAT_ARGB8888 is actually compatible with GL_BGRA_EXT. */ -struct gles2_pixel_format formats[] = { +static const struct gles2_pixel_format formats[] = { { .wl_format = WL_SHM_FORMAT_ARGB8888, .depth = 32, .bpp = 32, .gl_format = GL_BGRA_EXT, .gl_type = GL_UNSIGNED_BYTE, + .has_alpha = true, }, { .wl_format = WL_SHM_FORMAT_XRGB8888, @@ -20,6 +21,7 @@ struct gles2_pixel_format formats[] = { .bpp = 32, .gl_format = GL_BGRA_EXT, .gl_type = GL_UNSIGNED_BYTE, + .has_alpha = false, }, { .wl_format = WL_SHM_FORMAT_XBGR8888, @@ -27,6 +29,7 @@ struct gles2_pixel_format formats[] = { .bpp = 32, .gl_format = GL_RGBA, .gl_type = GL_UNSIGNED_BYTE, + .has_alpha = false, }, { .wl_format = WL_SHM_FORMAT_ABGR8888, @@ -34,8 +37,17 @@ struct gles2_pixel_format formats[] = { .bpp = 32, .gl_format = GL_RGBA, .gl_type = GL_UNSIGNED_BYTE, + .has_alpha = true, }, }; + +static const enum wl_shm_format wl_formats[] = { + WL_SHM_FORMAT_ARGB8888, + WL_SHM_FORMAT_XRGB8888, + WL_SHM_FORMAT_ABGR8888, + WL_SHM_FORMAT_XBGR8888, +}; + // TODO: more pixel formats const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt) { @@ -46,3 +58,8 @@ const struct gles2_pixel_format *gles2_format_from_wl(enum wl_shm_format fmt) { } return NULL; } + +const enum wl_shm_format *gles2_formats(size_t *len) { + *len = sizeof(wl_formats) / sizeof(wl_formats[0]); + return wl_formats; +} diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 6b046bc4..2d05932c 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -179,16 +179,9 @@ static void gles2_render_ellipse(struct wlr_renderer *wlr_renderer, GLES2_DEBUG_POP; } -static const enum wl_shm_format *gles2_formats( - struct wlr_renderer *renderer, size_t *len) { - static const enum wl_shm_format formats[] = { - WL_SHM_FORMAT_ARGB8888, - WL_SHM_FORMAT_XRGB8888, - WL_SHM_FORMAT_ABGR8888, - WL_SHM_FORMAT_XBGR8888, - }; - *len = sizeof(formats) / sizeof(formats[0]); - return formats; +static const enum wl_shm_format *gles2_renderer_formats( + struct wlr_renderer *wlr_renderer, size_t *len) { + return gles2_formats(len); } static bool gles2_buffer_is_drm(struct wlr_renderer *wlr_renderer, @@ -266,7 +259,7 @@ static const struct wlr_renderer_impl renderer_impl = { .render_texture_with_matrix = gles2_render_texture_with_matrix, .render_quad = gles2_render_quad, .render_ellipse = gles2_render_ellipse, - .formats = gles2_formats, + .formats = gles2_renderer_formats, .buffer_is_drm = gles2_buffer_is_drm, .read_pixels = gles2_read_pixels, .format_supported = gles2_format_supported, From 8207f0f081d6b0e1c493366614be836c392c34fd Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 21 Mar 2018 08:53:36 +0100 Subject: [PATCH 45/52] render/gles2: use gles2_pixel_format::has_alpha for shader selection --- render/gles2/renderer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index 2d05932c..9403c0ed 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -120,8 +120,7 @@ static bool gles2_render_texture_with_matrix( GLuint prog = renderer->shaders.tex_rgba; if (texture->target == GL_TEXTURE_EXTERNAL_OES) { prog = renderer->shaders.tex_ext; - } else if (texture->pixel_format->wl_format == WL_SHM_FORMAT_XRGB8888 || - texture->pixel_format->wl_format == WL_SHM_FORMAT_XBGR8888) { + } else if (!texture->pixel_format->has_alpha) { prog = renderer->shaders.tex_rgbx; } From b1f93bc5cc6eee4fd15b16bdc0337d665e83a040 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 21 Mar 2018 10:42:43 +0100 Subject: [PATCH 46/52] render/egl: use EGL_KHR_debug --- backend/drm/backend.c | 2 +- backend/drm/renderer.c | 2 +- backend/headless/output.c | 4 +- backend/wayland/output.c | 4 +- include/wlr/render/egl.h | 5 --- render/egl.c | 87 ++++++++++++++++++--------------------- render/glapi.txt | 1 + render/gles2/texture.c | 2 +- 8 files changed, 49 insertions(+), 58 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 75b44210..43a8d017 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -173,7 +173,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, } if (!wlr_egl_bind_display(&drm->renderer.egl, display)) { - wlr_log(L_INFO, "Failed to bind egl/wl display: %s", egl_error()); + wlr_log(L_INFO, "Failed to bind egl/wl display"); } drm->display_destroy.notify = handle_display_destroy; diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 7e330990..528cd26c 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -211,7 +211,7 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, 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: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL image"); abort(); } diff --git a/backend/headless/output.c b/backend/headless/output.c index 6ce8fc35..fc275eaf 100644 --- a/backend/headless/output.c +++ b/backend/headless/output.c @@ -13,7 +13,7 @@ static EGLSurface egl_create_surface(struct wlr_egl *egl, unsigned int width, EGLSurface surf = eglCreatePbufferSurface(egl->display, egl->config, attribs); if (surf == EGL_NO_SURFACE) { - wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL surface"); return EGL_NO_SURFACE; } return surf; @@ -123,7 +123,7 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend, if (!eglMakeCurrent(output->backend->egl.display, output->egl_surface, output->egl_surface, output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + wlr_log(L_ERROR, "eglMakeCurrent failed"); goto error; } diff --git a/backend/wayland/output.c b/backend/wayland/output.c index fc40dea0..6becceb7 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -321,7 +321,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { if (!eglMakeCurrent(output->backend->egl.display, output->egl_surface, output->egl_surface, output->backend->egl.context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + wlr_log(L_ERROR, "eglMakeCurrent failed"); goto error; } @@ -333,7 +333,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { wl_callback_add_listener(output->frame_callback, &frame_listener, output); if (!eglSwapBuffers(output->backend->egl.display, output->egl_surface)) { - wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + wlr_log(L_ERROR, "eglSwapBuffers failed"); goto error; } diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index f05a9837..aa429e8e 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -94,11 +94,6 @@ int wlr_egl_get_dmabuf_modifiers(struct wlr_egl *egl, int format, */ bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImageKHR image); -/** - * Returns a string for the last error ocurred with egl. - */ -const char *egl_error(void); - bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface, int *buffer_age); diff --git a/render/egl.c b/render/egl.c index d60da2ab..b1bd4884 100644 --- a/render/egl.c +++ b/render/egl.c @@ -12,43 +12,6 @@ // 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 -const char *egl_error(void) { - switch (eglGetError()) { - case EGL_SUCCESS: - return "Success"; - case EGL_NOT_INITIALIZED: - return "Not initialized"; - case EGL_BAD_ACCESS: - return "Bad access"; - case EGL_BAD_ALLOC: - return "Bad alloc"; - case EGL_BAD_ATTRIBUTE: - return "Bad attribute"; - case EGL_BAD_CONTEXT: - return "Bad Context"; - case EGL_BAD_CONFIG: - return "Bad Config"; - case EGL_BAD_CURRENT_SURFACE: - return "Bad current surface"; - case EGL_BAD_DISPLAY: - return "Bad display"; - case EGL_BAD_SURFACE: - return "Bad surface"; - case EGL_BAD_MATCH: - return "Bad match"; - case EGL_BAD_PARAMETER: - return "Bad parameter"; - case EGL_BAD_NATIVE_PIXMAP: - return "Bad native pixmap"; - case EGL_BAD_NATIVE_WINDOW: - return "Bad native window"; - case EGL_CONTEXT_LOST: - return "Context lost"; - default: - return "Unknown"; - } -} - static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out, EGLint visual_id) { EGLint count = 0, matched = 0, ret; @@ -84,6 +47,21 @@ static bool egl_get_config(EGLDisplay disp, EGLint *attribs, EGLConfig *out, return false; } +static log_importance_t egl_log_importance_to_wlr(EGLint type) { + switch (type) { + case EGL_DEBUG_MSG_CRITICAL_KHR: return L_ERROR; + case EGL_DEBUG_MSG_ERROR_KHR: return L_ERROR; + case EGL_DEBUG_MSG_WARN_KHR: return L_ERROR; + case EGL_DEBUG_MSG_INFO_KHR: return L_INFO; + default: return L_INFO; + } +} + +static void egl_log(EGLenum error, const char *command, EGLint msg_type, + EGLLabelKHR thread, EGLLabelKHR obj, const char *msg) { + _wlr_log(egl_log_importance_to_wlr(msg_type), "[EGL] %s: %s", command, msg); +} + static bool check_egl_ext(const char *egl_exts, const char *ext) { size_t extlen = strlen(ext); const char *end = egl_exts + strlen(egl_exts); @@ -128,8 +106,19 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, return false; } + if (eglDebugMessageControlKHR) { + static const EGLAttrib debug_attribs[] = { + EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, + EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, + EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, + EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, + EGL_NONE, + }; + eglDebugMessageControlKHR(egl_log, debug_attribs); + } + if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) { - wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API: %s", egl_error()); + wlr_log(L_ERROR, "Failed to bind to the OpenGL ES API"); goto error; } @@ -140,13 +129,13 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL); } if (egl->display == EGL_NO_DISPLAY) { - wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL display"); goto error; } EGLint major, minor; if (eglInitialize(egl->display, &major, &minor) == EGL_FALSE) { - wlr_log(L_ERROR, "Failed to initialize EGL: %s", egl_error()); + wlr_log(L_ERROR, "Failed to initialize EGL"); goto error; } @@ -161,7 +150,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, EGL_NO_CONTEXT, attribs); if (egl->context == EGL_NO_CONTEXT) { - wlr_log(L_ERROR, "Failed to create EGL context: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL context"); goto error; } @@ -199,12 +188,18 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, void *remote_display, error: eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(egl->display); + if (egl->display) { + eglTerminate(egl->display); + } eglReleaseThread(); return false; } void wlr_egl_finish(struct wlr_egl *egl) { + if (egl == NULL) { + return; + } + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (egl->wl_display && eglUnbindWaylandDisplayWL) { eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); @@ -259,7 +254,7 @@ EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { EGLSurface surf = eglCreatePlatformWindowSurfaceEXT(egl->display, egl->config, window, NULL); if (surf == EGL_NO_SURFACE) { - wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); + wlr_log(L_ERROR, "Failed to create EGL surface"); return EGL_NO_SURFACE; } return surf; @@ -274,7 +269,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { EGLBoolean ok = eglQuerySurface(egl->display, surface, EGL_BUFFER_AGE_EXT, &buffer_age); if (!ok) { - wlr_log(L_ERROR, "Failed to get EGL surface buffer age: %s", egl_error()); + wlr_log(L_ERROR, "Failed to get EGL surface buffer age"); return -1; } @@ -284,7 +279,7 @@ int wlr_egl_get_buffer_age(struct wlr_egl *egl, EGLSurface surface) { bool wlr_egl_make_current(struct wlr_egl *egl, EGLSurface surface, int *buffer_age) { if (!eglMakeCurrent(egl->display, surface, surface, egl->context)) { - wlr_log(L_ERROR, "eglMakeCurrent failed: %s", egl_error()); + wlr_log(L_ERROR, "eglMakeCurrent failed"); return false; } @@ -322,7 +317,7 @@ bool wlr_egl_swap_buffers(struct wlr_egl *egl, EGLSurface surface, } if (!ret) { - wlr_log(L_ERROR, "eglSwapBuffers failed: %s", egl_error()); + wlr_log(L_ERROR, "eglSwapBuffers failed"); return false; } return true; diff --git a/render/glapi.txt b/render/glapi.txt index 02ac7dd8..2077d1c3 100644 --- a/render/glapi.txt +++ b/render/glapi.txt @@ -10,3 +10,4 @@ eglCreatePlatformWindowSurfaceEXT -eglSwapBuffersWithDamageKHR -eglQueryDmaBufFormatsEXT -eglQueryDmaBufModifiersEXT +-eglDebugMessageControlKHR diff --git a/render/gles2/texture.c b/render/gles2/texture.c index 99f153b8..8da40032 100644 --- a/render/gles2/texture.c +++ b/render/gles2/texture.c @@ -198,7 +198,7 @@ static bool gles2_texture_upload_drm(struct wlr_texture *_tex, 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: %s", egl_error()); + wlr_log(L_ERROR, "failed to create EGL image"); return false; } From 60bfe0a6aad6bc415f84a52326c9a0851fc647c0 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 21 Mar 2018 11:34:08 +0100 Subject: [PATCH 47/52] backend/drm: remove remaining raw GL call This makes the hardware cursor code a less efficient. Can be fixed with a GLES3 renderer. --- backend/drm/drm.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 345c0dd8..524e80bb 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -582,11 +582,8 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, return false; } - // OpenGL will read the pixels out upside down, - // so we need to flip the image vertically - enum wl_output_transform transform = wlr_output_transform_compose( - wlr_output_transform_invert(output->transform), - WL_OUTPUT_TRANSFORM_FLIPPED_180); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); wlr_matrix_projection(plane->matrix, plane->surf.width, plane->surf.height, transform); @@ -649,11 +646,8 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output, wlr_render_texture(rend, plane->wlr_tex, plane->matrix, 0, 0, 1.0f); wlr_renderer_end(rend); - // TODO: remove these raw GL calls - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); - glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, - GL_UNSIGNED_BYTE, bo_data); - glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); + wlr_renderer_read_pixels(rend, WL_SHM_FORMAT_ARGB8888, bo_stride, + plane->surf.width, plane->surf.height, 0, 0, 0, 0, bo_data); wlr_drm_surface_swap_buffers(&plane->surf, NULL); From de955a0f63e17e259b7966bf7c32d605f96d52cc Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sat, 30 Dec 2017 17:16:00 +0100 Subject: [PATCH 48/52] xdg_popup_grab: add listener on seat destroy --- include/wlr/types/wlr_xdg_shell.h | 1 + include/wlr/types/wlr_xdg_shell_v6.h | 1 + types/wlr_xdg_shell.c | 21 +++++++++++++++++++++ types/wlr_xdg_shell_v6.c | 21 +++++++++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index ad0a626f..a5fa093b 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -53,6 +53,7 @@ struct wlr_xdg_popup_grab { struct wlr_seat *seat; struct wl_list popups; struct wl_list link; // wlr_xdg_shell::popup_grabs + struct wl_listener seat_destroy; }; enum wlr_xdg_surface_role { diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index d8503d28..a1bdac1b 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -53,6 +53,7 @@ struct wlr_xdg_popup_grab_v6 { struct wlr_seat *seat; struct wl_list popups; struct wl_list link; // wlr_xdg_shell_v6::popup_grabs + struct wl_listener seat_destroy; }; enum wlr_xdg_surface_v6_role { diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 5b02088d..f01d81a5 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -131,6 +131,24 @@ static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { .cancel = xdg_keyboard_grab_cancel, }; +static void xdg_surface_destroy(struct wlr_xdg_surface *surface); + +static void wlr_xdg_popup_grab_handle_seat_destroy( + struct wl_listener *listener, void *data) { + struct wlr_xdg_popup_grab *xdg_grab = + wl_container_of(listener, xdg_grab, seat_destroy); + + wl_list_remove(&xdg_grab->seat_destroy.link); + + struct wlr_xdg_popup *popup, *next; + wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { + xdg_surface_destroy(popup->base); + } + + wl_list_remove(&xdg_grab->link); + free(xdg_grab); +} + static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell *shell, struct wlr_seat *seat) { struct wlr_xdg_popup_grab *xdg_grab; @@ -155,6 +173,9 @@ static struct wlr_xdg_popup_grab *xdg_shell_popup_grab_from_seat( wl_list_insert(&shell->popup_grabs, &xdg_grab->link); xdg_grab->seat = seat; + xdg_grab->seat_destroy.notify = wlr_xdg_popup_grab_handle_seat_destroy; + wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy); + return xdg_grab; } diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index a0c74e6f..2aaa607b 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -131,6 +131,24 @@ static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { .cancel = xdg_keyboard_grab_cancel, }; +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface); + +static void wlr_xdg_popup_grab_handle_seat_destroy( + struct wl_listener *listener, void *data) { + struct wlr_xdg_popup_grab_v6 *xdg_grab = + wl_container_of(listener, xdg_grab, seat_destroy); + + wl_list_remove(&xdg_grab->seat_destroy.link); + + struct wlr_xdg_popup_v6 *popup, *next; + wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) { + xdg_surface_destroy(popup->base); + } + + wl_list_remove(&xdg_grab->link); + free(xdg_grab); +} + static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) { struct wlr_xdg_popup_grab_v6 *xdg_grab; @@ -155,6 +173,9 @@ static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( wl_list_insert(&shell->popup_grabs, &xdg_grab->link); xdg_grab->seat = seat; + xdg_grab->seat_destroy.notify = wlr_xdg_popup_grab_handle_seat_destroy; + wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy); + return xdg_grab; } From d9a3c6694281fae6f720f91230e8ec27df8fd82b Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sat, 17 Mar 2018 17:04:51 +0100 Subject: [PATCH 49/52] rootston/output: fix leak in damage_from_surface --- rootston/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/rootston/output.c b/rootston/output.c index 4146e3e2..22c0d7ed 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -680,6 +680,7 @@ static void damage_from_surface(struct wlr_surface *surface, } pixman_region32_translate(&damage, box.x, box.y); wlr_output_damage_add(output->damage, &damage); + pixman_region32_fini(&damage); } else { pixman_box32_t *extents = pixman_region32_extents(&surface->current->surface_damage); From b0c2bbebd1c4c50173a01175d049842b79ee7e1b Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sat, 17 Mar 2018 17:06:03 +0100 Subject: [PATCH 50/52] x11 backend: fix various leaks - xcb_query_pointer_reply return value needs to be freed - call XCloseDisplay - remove wl event_source --- backend/x11/backend.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/x11/backend.c b/backend/x11/backend.c index cb29e518..dd2c0a6e 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -143,6 +143,7 @@ static bool handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *e }; wlr_signal_emit_safe(&x11->pointer.events.motion_absolute, &abs); + free(pointer); break; } case XCB_CLIENT_MESSAGE: { @@ -317,12 +318,20 @@ static void wlr_x11_backend_destroy(struct wlr_backend *backend) { wlr_signal_emit_safe(&backend->events.destroy, backend); + if (x11->event_source) { + wl_event_source_remove(x11->event_source); + } wl_list_remove(&x11->display_destroy.link); wl_event_source_remove(x11->frame_timer); wlr_egl_finish(&x11->egl); - xcb_disconnect(x11->xcb_conn); + if (x11->xcb_conn) { + xcb_disconnect(x11->xcb_conn); + } + if (x11->xlib_conn) { + XCloseDisplay(x11->xlib_conn); + } free(x11); } From d5e14ab2470032a5f8152c685415724a4734b492 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Sat, 17 Mar 2018 17:11:43 +0100 Subject: [PATCH 51/52] wayland backend: fix use-after free on output destroy ==12021==ERROR: AddressSanitizer: heap-use-after-free on address 0x617000015698 at pc 0x7f1a9abe1c09 bp 0x7ffe9068f6b0 sp 0x7ffe9068f6a0 WRITE of size 4 at 0x617000015698 thread T0 #0 0x7f1a9abe1c08 in pointer_handle_leave ../backend/wayland/wl_seat.c:40 #1 0x7f1a96ae7d1d in ffi_call_unix64 (/lib64/libffi.so.6+0x5d1d) #2 0x7f1a96ae768e in ffi_call (/lib64/libffi.so.6+0x568e) #3 0x7f1a988e0d8a (/lib64/libwayland-client.so.0+0x8d8a) #4 0x7f1a988dd927 (/lib64/libwayland-client.so.0+0x5927) #5 0x7f1a988debe3 in wl_display_dispatch_queue_pending (/lib64/libwayland-client.so.0+0x6be3) #6 0x7f1a9abdd6d6 in dispatch_events ../backend/wayland/backend.c:28 #7 0x7f1a9a968c11 in wl_event_loop_dispatch (/lib64/libwayland-server.so.0+0x9c11) #8 0x7f1a9a967449 in wl_display_run (/lib64/libwayland-server.so.0+0x8449) #9 0x418dff in main ../rootston/main.c:81 #10 0x7f1a99b5ef29 in __libc_start_main (/lib64/libc.so.6+0x20f29) #11 0x4057c9 in _start (/home/shared/wayland/wlroots/build/rootston/rootston+0x4057c9) 0x617000015698 is located 664 bytes inside of 696-byte region [0x617000015400,0x6170000156b8) freed by thread T0 here: #0 0x7f1a9af754b8 in __interceptor_free (/lib64/libasan.so.4+0xde4b8) #1 0x7f1a9abe01ee in wlr_wl_output_destroy ../backend/wayland/output.c:194 #2 0x7f1a9ac12918 in wlr_output_destroy ../types/wlr_output.c:299 #3 0x7f1a9abe061b in xdg_toplevel_handle_close ../backend/wayland/output.c:255 #4 0x7f1a96ae7d1d in ffi_call_unix64 (/lib64/libffi.so.6+0x5d1d) #5 0x7f1a96ae768e in ffi_call (/lib64/libffi.so.6+0x568e) #6 0x7f1a988e0d8a (/lib64/libwayland-client.so.0+0x8d8a) #7 0x7f1a988dd927 (/lib64/libwayland-client.so.0+0x5927) #8 0x7f1a988debe3 in wl_display_dispatch_queue_pending (/lib64/libwayland-client.so.0+0x6be3) #9 0x7f1a9abdd6d6 in dispatch_events ../backend/wayland/backend.c:28 #10 0x7f1a9a968c11 in wl_event_loop_dispatch (/lib64/libwayland-server.so.0+0x9c11) #11 0x7f1a9a967449 in wl_display_run (/lib64/libwayland-server.so.0+0x8449) #12 0x418dff in main ../rootston/main.c:81 #13 0x7f1a99b5ef29 in __libc_start_main (/lib64/libc.so.6+0x20f29) #14 0x4057c9 in _start (/home/shared/wayland/wlroots/build/rootston/rootston+0x4057c9) previously allocated by thread T0 here: #0 0x7f1a9af75a38 in __interceptor_calloc (/lib64/libasan.so.4+0xdea38) #1 0x7f1a9abe0703 in wlr_wl_output_create ../backend/wayland/output.c:272 #2 0x7f1a9abdd8eb in wlr_wl_backend_start ../backend/wayland/backend.c:55 #3 0x7f1a9abbeb49 in wlr_backend_start ../backend/backend.c:28 #4 0x7f1a9abd8ce1 in multi_backend_start ../backend/multi/backend.c:24 #5 0x7f1a9abbeb49 in wlr_backend_start ../backend/backend.c:28 #6 0x418c32 in main ../rootston/main.c:58 #7 0x7f1a99b5ef29 in __libc_start_main (/lib64/libc.so.6+0x20f29) #8 0x4057c9 in _start (/home/shared/wayland/wlroots/build/rootston/rootston+0x4057c9) --- backend/wayland/wl_seat.c | 17 ++++++++++++++++- include/backend/wayland.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index 841e693d..6ca59130 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -26,6 +26,11 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, // GNOME sends a pointer enter when the surface is being destroyed return; } + if (wlr_wl_pointer->current_output) { + wl_list_remove(&wlr_wl_pointer->output_destroy_listener.link); + } + wl_signal_add(&output->wlr_output.events.destroy, + &wlr_wl_pointer->output_destroy_listener); wlr_wl_pointer->current_output = output; output->enter_serial = serial; wlr_wl_output_update_cursor(output); @@ -49,7 +54,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_pointer *wlr_wl_pointer = (struct wlr_wl_pointer *)dev->pointer; if (!wlr_wl_pointer->current_output) { - wlr_log(L_ERROR, "pointer motion event without current output"); + wlr_log(L_DEBUG, "pointer motion event without current output"); return; } @@ -231,6 +236,14 @@ static struct wlr_input_device *allocate_device(struct wlr_wl_backend *backend, return wlr_device; } +static void wlr_wl_pointer_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_wl_pointer *wlr_wl_pointer = + wl_container_of(listener, wlr_wl_pointer, output_destroy_listener); + wlr_wl_pointer->current_output = NULL; + wl_list_remove(&wlr_wl_pointer->output_destroy_listener.link); +} + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct wlr_wl_backend *backend = data; @@ -243,6 +256,8 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wlr_log(L_ERROR, "Unable to allocate wlr_wl_pointer"); return; } + wlr_wl_pointer->output_destroy_listener.notify = + wlr_wl_pointer_handle_output_destroy; struct wlr_input_device *wlr_device; if (!(wlr_device = allocate_device(backend, WLR_INPUT_DEVICE_POINTER))) { diff --git a/include/backend/wayland.h b/include/backend/wayland.h index b68208af..00b6ae89 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -71,6 +71,7 @@ struct wlr_wl_pointer { struct wlr_pointer wlr_pointer; enum wlr_axis_source axis_source; struct wlr_wl_backend_output *current_output; + struct wl_listener output_destroy_listener; }; void wlr_wl_registry_poll(struct wlr_wl_backend *backend); From e86cd4dc33e495c2e5cacd319ba75984ea19a868 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 22 Mar 2018 19:57:11 +0100 Subject: [PATCH 52/52] wlr_pointer: fix potential null deref if pointer is null here we'd access pointer->events... anyway --- types/wlr_pointer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/types/wlr_pointer.c b/types/wlr_pointer.c index bc9efd8c..9d5dc08c 100644 --- a/types/wlr_pointer.c +++ b/types/wlr_pointer.c @@ -14,7 +14,10 @@ void wlr_pointer_init(struct wlr_pointer *pointer, } void wlr_pointer_destroy(struct wlr_pointer *pointer) { - if (pointer && pointer->impl && pointer->impl->destroy) { + if (!pointer) { + return; + } + if (pointer->impl && pointer->impl->destroy) { pointer->impl->destroy(pointer); } else { wl_list_remove(&pointer->events.motion.listener_list);