~sircmpwn/sedna

2b3371ef8b5ab7ea4282048bf502db961293f9bf — Simon Ser 2 months ago eab7871
Render using wlr_scene

sedna is pretty young, so it's a good candidate to adopt the new
wlr_scene API [1] without too many changes. For now only rendering is
offloaded to wlr_scene, because wlr_scene doesn't support anything else.
In the future, more features will be delegated (frame scheduling &
events handling, presentation-time, hardware planes management, etc).

[1]: https://github.com/swaywm/wlroots/pull/1966
5 files changed, 93 insertions(+), 45 deletions(-)

M include/server.h
M include/view.h
M src/main.c
M src/output.c
M src/view.c
M include/server.h => include/server.h +5 -0
@@ 4,6 4,7 @@
#include <wlr/backend.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_xdg_shell.h>
#include "input.h"


@@ 13,6 14,7 @@ struct sedna_server {
	struct wlr_backend *backend;
	struct wlr_renderer *renderer;
	struct wlr_output_layout *output_layout;
	struct wlr_scene *scene;

	struct wl_list outputs;
	struct wl_listener new_output;


@@ 21,6 23,9 @@ struct sedna_server {

	struct wl_list views;

	struct wlr_compositor *compositor;
	struct wl_listener compositor_new_surface;

	struct wlr_xdg_shell *xdg_shell;
	struct wl_listener xdg_shell_new_surface;
};

M include/view.h => include/view.h +10 -0
@@ 5,6 5,7 @@
#include <stdint.h>
#include <wayland-server.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_scene.h>
#if HAVE_XWAYLAND
#include <wlr/xwayland.h>
#endif


@@ 17,6 18,13 @@
struct sedna_server;
struct sedna_view;

struct sedna_surface {
	struct wlr_surface *wlr_surface;
	struct wlr_scene_surface *scene_surface;

	struct wl_listener destroy;
};

enum sedna_view_type {
	SEDNA_VIEW_XDG_TOPLEVEL,
#if HAVE_XWAYLAND


@@ 103,4 111,6 @@ void sedna_view_close(struct sedna_view *view);

void sedna_view_destroy(struct sedna_view *view);

void sedna_compositor_init(struct sedna_server *server);

#endif

M src/main.c => src/main.c +4 -1
@@ 13,6 13,7 @@
#include "input.h"
#include "output.h"
#include "server.h"
#include "view.h"
#include "xdg-shell.h"

int


@@ 41,7 42,8 @@ main(int argc, char *argv[])

	wl_list_init(&server.views);

	wlr_compositor_create(server.wl_display, server.renderer);
	server.scene = wlr_scene_create();

	/* TODO: Rig up data device listeners */
	wlr_data_device_manager_create(server.wl_display);



@@ 54,6 56,7 @@ main(int argc, char *argv[])
	/* Order-sensitive */
	sedna_outputs_init(&server);
	sedna_seat_init(&server, &server.seat);
	sedna_compositor_init(&server);
	sedna_xdg_shell_init(&server);

	const char *socket = wl_display_add_socket_auto(server.wl_display);

M src/output.c => src/output.c +37 -44
@@ 10,48 10,40 @@
#include "server.h"
#include "view.h"

struct render_context {
	struct wlr_output *output;
	struct wlr_renderer *renderer;
	struct sedna_view *view;
	struct timespec *when;
};
static void
send_frame_done_iterator(struct wlr_surface *surface, int x, int y, void *data)
{
	struct timespec *when = data;
	wlr_surface_send_frame_done(surface, when);
}

static void
render_surface(struct wlr_surface *surface,
setup_surface_iterator(struct wlr_surface *wlr_surface,
		int sx, int sy, void *data)
{
	struct render_context *context = data;
	struct sedna_view *view = context->view;
	struct wlr_output *output = context->output;
	struct sedna_view *view = data;
	struct sedna_surface *surface = wlr_surface->data;
	struct sedna_server *server = view->server;

	struct wlr_texture *texture = wlr_surface_get_texture(surface);
	if (texture == NULL) {
	if (wlr_surface_is_subsurface(surface->wlr_surface)) {
		return;
	}

	double ox = 0, oy = 0;
	wlr_output_layout_output_coords(
			view->server->output_layout, output, &ox, &oy);
	ox += view->x + sx, oy += view->y + sy;

	/* TODO: Full HiDPI support */
	struct wlr_box box = {
		.x = ox * output->scale,
		.y = oy * output->scale,
		.width = surface->current.width * output->scale,
		.height = surface->current.height * output->scale,
	};

	float matrix[9];
	enum wl_output_transform transform =
		wlr_output_transform_invert(surface->current.transform);
	wlr_matrix_project_box(matrix, &box, transform, 0,
		output->transform_matrix);

	wlr_render_texture_with_matrix(context->renderer, texture, matrix, 1);

	wlr_surface_send_frame_done(surface, context->when);
	if (!view->mapped) {
		if (surface->scene_surface != NULL) {
			wlr_scene_node_destroy(&surface->scene_surface->node);
			surface->scene_surface = NULL;
		}
		return;
	}

	if (surface->scene_surface == NULL) {
		surface->scene_surface = wlr_scene_surface_create(
			&server->scene->node, surface->wlr_surface);
	}

	wlr_scene_node_move(&surface->scene_surface->node,
		view->x + sx, view->y + sy);
}

static void


@@ 78,20 70,21 @@ output_frame_notify(struct wl_listener *listener, void *data)

	struct sedna_view *view;
	wl_list_for_each_reverse(view, &server->views, link) {
		if (!view->mapped) {
			continue;
		}
		struct render_context context = {
			.output = output->wlr_output,
			.view = view,
			.renderer = renderer,
			.when = &now,
		};
		sedna_view_for_each_surface(view, render_surface, &context);
		sedna_view_for_each_surface(view, setup_surface_iterator, view);
	}
	wlr_scene_node_commit(&server->scene->node);

	double ox = 0, oy = 0;
	wlr_output_layout_output_coords(server->output_layout,
		output->wlr_output, &ox, &oy);

	wlr_scene_render(server->scene, output->wlr_output, ox, oy, NULL);

	wlr_renderer_end(renderer);
	wlr_output_commit(output->wlr_output);

	wlr_scene_node_for_each_surface(&server->scene->node,
		send_frame_done_iterator, &now);
}

static struct sedna_output *

M src/view.c => src/view.c +37 -0
@@ 1,3 1,4 @@
#include <stdlib.h>
#include <wayland-server.h>
#include "server.h"
#include "view.h"


@@ 94,3 95,39 @@ sedna_view_init(struct sedna_view *view,
	view->impl = impl;
	wl_list_insert(&server->views, &view->link);
}

static void
surface_handle_destroy(struct wl_listener *listener, void *data)
{
	struct sedna_surface *surface =
		wl_container_of(listener, surface, destroy);
	wl_list_remove(&surface->destroy.link);
	free(surface);
}

static void
handle_new_surface(struct wl_listener *listener, void *data)
{
	struct sedna_server *server =
		wl_container_of(listener, server, compositor_new_surface);
	struct wlr_surface *wlr_surface = data;

	struct sedna_surface *surface = calloc(1, sizeof(struct sedna_surface));
	surface->wlr_surface = wlr_surface;

	surface->destroy.notify = surface_handle_destroy;
	wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);

	wlr_surface->data = surface;
}

void
sedna_compositor_init(struct sedna_server *server)
{
	server->compositor =
		wlr_compositor_create(server->wl_display, server->renderer);

	server->compositor_new_surface.notify = handle_new_surface;
	wl_signal_add(&server->compositor->events.new_surface,
		&server->compositor_new_surface);
}