diff options
Diffstat (limited to 'rootston')
| -rw-r--r-- | rootston/meson.build | 1 | ||||
| -rw-r--r-- | rootston/output.c | 322 | ||||
| -rw-r--r-- | rootston/render.c | 324 | 
3 files changed, 330 insertions, 317 deletions
| diff --git a/rootston/meson.build b/rootston/meson.build index 6a4fbe76..c2f9a250 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -9,6 +9,7 @@ sources = [  	'layer_shell.c',  	'main.c',  	'output.c', +	'render.c',  	'seat.c',  	'switch.c',  	'text_input.c', diff --git a/rootston/output.c b/rootston/output.c index 595b401a..a6cdc25d 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -6,7 +6,6 @@  #include <wlr/backend/drm.h>  #include <wlr/config.h>  #include <wlr/types/wlr_compositor.h> -#include <wlr/types/wlr_matrix.h>  #include <wlr/types/wlr_output_layout.h>  #include <wlr/types/wlr_presentation_time.h>  #include <wlr/types/wlr_wl_shell.h> @@ -14,6 +13,7 @@  #include <wlr/types/wlr_xdg_shell.h>  #include <wlr/util/log.h>  #include <wlr/util/region.h> +#include <wlr/xwayland.h>  #include "rootston/config.h"  #include "rootston/layers.h"  #include "rootston/output.h" @@ -137,7 +137,7 @@ void output_view_for_each_surface(struct roots_output *output,  }  #if WLR_HAS_XWAYLAND -static void output_xwayland_children_for_each_surface( +void output_xwayland_children_for_each_surface(  		struct roots_output *output, struct wlr_xwayland_surface *surface,  		roots_surface_iterator_func_t iterator, void *user_data) {  	struct wlr_xwayland_surface *child; @@ -218,105 +218,18 @@ void output_for_each_surface(struct roots_output *output,  	}  } - -struct render_data { -	pixman_region32_t *damage; -	float alpha; -}; - -static void scissor_output(struct wlr_output *wlr_output, -		pixman_box32_t *rect) { -	struct wlr_renderer *renderer = -		wlr_backend_get_renderer(wlr_output->backend); -	assert(renderer); - -	struct wlr_box box = { -		.x = rect->x1, -		.y = rect->y1, -		.width = rect->x2 - rect->x1, -		.height = rect->y2 - rect->y1, -	}; - -	int ow, oh; -	wlr_output_transformed_resolution(wlr_output, &ow, &oh); - -	enum wl_output_transform transform = -		wlr_output_transform_invert(wlr_output->transform); -	wlr_box_transform(&box, &box, transform, ow, oh); - -	wlr_renderer_scissor(renderer, &box); -} -  static int scale_length(int length, int offset, float scale) {  	return round((offset + length) * scale) - round(offset * scale);  } -static void scale_box(struct wlr_box *box, float scale) { +void scale_box(struct wlr_box *box, float scale) {  	box->width = scale_length(box->width, box->x, scale);  	box->height = scale_length(box->height, box->y, scale);  	box->x = round(box->x * scale);  	box->y = round(box->y * scale);  } -static void render_texture(struct wlr_output *wlr_output, -		pixman_region32_t *output_damage, struct wlr_texture *texture, -		const struct wlr_box *box, const float matrix[static 9], -		float rotation, float alpha) { -	struct wlr_renderer *renderer = -		wlr_backend_get_renderer(wlr_output->backend); -	assert(renderer); - -	struct wlr_box rotated; -	wlr_box_rotated_bounds(&rotated, box, rotation); - -	pixman_region32_t damage; -	pixman_region32_init(&damage); -	pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, -		rotated.width, rotated.height); -	pixman_region32_intersect(&damage, &damage, output_damage); -	bool damaged = pixman_region32_not_empty(&damage); -	if (!damaged) { -		goto damage_finish; -	} - -	int nrects; -	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); -	for (int i = 0; i < nrects; ++i) { -		scissor_output(wlr_output, &rects[i]); -		wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); -	} - -damage_finish: -	pixman_region32_fini(&damage); -} - -static void render_surface_iterator(struct roots_output *output, -		struct wlr_surface *surface, struct wlr_box *_box, float rotation, -		void *_data) { -	struct render_data *data = _data; -	struct wlr_output *wlr_output = output->wlr_output; -	pixman_region32_t *output_damage = data->damage; -	float alpha = data->alpha; - -	struct wlr_texture *texture = wlr_surface_get_texture(surface); -	if (!texture) { -		return; -	} - -	struct wlr_box box = *_box; -	scale_box(&box, wlr_output->scale); - -	float matrix[9]; -	enum wl_output_transform transform = -		wlr_output_transform_invert(surface->current.transform); -	wlr_matrix_project_box(matrix, &box, transform, rotation, -		wlr_output->transform_matrix); - -	render_texture(wlr_output, output_damage, -		texture, &box, matrix, rotation, alpha); -} - -static void get_decoration_box(struct roots_view *view, +void get_decoration_box(struct roots_view *view,  		struct roots_output *output, struct wlr_box *box) {  	struct wlr_output *wlr_output = output->wlr_output; @@ -338,231 +251,6 @@ static void get_decoration_box(struct roots_view *view,  	box->height = deco_box.height * wlr_output->scale;  } -static void render_decorations(struct roots_output *output, -		struct roots_view *view, struct render_data *data) { -	if (!view->decorated || view->wlr_surface == NULL) { -		return; -	} - -	struct wlr_renderer *renderer = -		wlr_backend_get_renderer(output->wlr_output->backend); -	assert(renderer); - -	struct wlr_box box; -	get_decoration_box(view, output, &box); - -	struct wlr_box rotated; -	wlr_box_rotated_bounds(&rotated, &box, view->rotation); - -	pixman_region32_t damage; -	pixman_region32_init(&damage); -	pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, -		rotated.width, rotated.height); -	pixman_region32_intersect(&damage, &damage, data->damage); -	bool damaged = pixman_region32_not_empty(&damage); -	if (!damaged) { -		goto damage_finish; -	} - -	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 }; - -	int nrects; -	pixman_box32_t *rects = -		pixman_region32_rectangles(&damage, &nrects); -	for (int i = 0; i < nrects; ++i) { -		scissor_output(output->wlr_output, &rects[i]); -		wlr_render_quad_with_matrix(renderer, color, matrix); -	} - -damage_finish: -	pixman_region32_fini(&damage); -} - -static void render_view(struct roots_output *output, struct roots_view *view, -		struct render_data *data) { -	// Do not render views fullscreened on other outputs -	if (view->fullscreen_output != NULL && view->fullscreen_output != output) { -		return; -	} - -	data->alpha = view->alpha; -	if (view->fullscreen_output == NULL) { -		render_decorations(output, view, data); -	} -	output_view_for_each_surface(output, view, render_surface_iterator, data); -} - -static void render_layer(struct roots_output *output, -		pixman_region32_t *damage, struct wl_list *layer_surfaces) { -	struct render_data data = { -		.damage = damage, -		.alpha = 1.0f, -	}; -	output_layer_for_each_surface(output, layer_surfaces, -		render_surface_iterator, &data); -} - -static void render_drag_icons(struct roots_output *output, -		pixman_region32_t *damage, struct roots_input *input) { -	struct render_data data = { -		.damage = damage, -		.alpha = 1.0f, -	}; -	output_drag_icons_for_each_surface(output, input, -		render_surface_iterator, &data); -} - -static void surface_send_frame_done_iterator(struct roots_output *output, -		struct wlr_surface *surface, struct wlr_box *box, float rotation, -		void *data) { -	struct timespec *when = data; -	wlr_surface_send_frame_done(surface, when); -} - -static void render_output(struct roots_output *output) { -	struct wlr_output *wlr_output = output->wlr_output; -	struct roots_desktop *desktop = output->desktop; -	struct roots_server *server = desktop->server; -	struct wlr_renderer *renderer = -		wlr_backend_get_renderer(wlr_output->backend); -	assert(renderer); - -	if (!wlr_output->enabled) { -		return; -	} - -	struct timespec now; -	clock_gettime(CLOCK_MONOTONIC, &now); - -	float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; - -	const struct wlr_box *output_box = -		wlr_output_layout_get_box(desktop->layout, wlr_output); - -	// Check if we can delegate the fullscreen surface to the output -	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 -		struct wlr_box view_box; -		view_get_box(view, &view_box); -		double view_x = (double)(output_box->width - view_box.width) / 2 + -			output_box->x; -		double view_y = (double)(output_box->height - view_box.height) / 2 + -			output_box->y; -		view_move(view, view_x, view_y); - -		// Fullscreen views are rendered on a black background -		clear_color[0] = clear_color[1] = clear_color[2] = 0; -	} - -	bool needs_swap; -	pixman_region32_t damage; -	pixman_region32_init(&damage); -	if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) { -		return; -	} - -	struct render_data data = { -		.damage = &damage, -		.alpha = 1.0, -	}; - -	if (!needs_swap) { -		// Output doesn't need swap and isn't damaged, skip rendering completely -		goto damage_finish; -	} - -	wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - -	if (!pixman_region32_not_empty(&damage)) { -		// Output isn't damaged but needs buffer swap -		goto renderer_end; -	} - -	if (server->config->debug_damage_tracking) { -		wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); -	} - -	int nrects; -	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); -	for (int i = 0; i < nrects; ++i) { -		scissor_output(output->wlr_output, &rects[i]); -		wlr_renderer_clear(renderer, clear_color); -	} - -	render_layer(output, &damage, -		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); -	render_layer(output, &damage, -		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - -	// If a view is fullscreen on this output, render it -	if (output->fullscreen_view != NULL) { -		struct roots_view *view = output->fullscreen_view; - -		render_view(output, view, &data); - -		// During normal rendering the xwayland window tree isn't traversed -		// because all windows are rendered. Here we only want to render -		// the fullscreen window's children so we have to traverse the tree. -#if WLR_HAS_XWAYLAND -		if (view->type == ROOTS_XWAYLAND_VIEW) { -			struct roots_xwayland_surface *xwayland_surface = -				roots_xwayland_surface_from_view(view); -			output_xwayland_children_for_each_surface(output, -				xwayland_surface->xwayland_surface, -				render_surface_iterator, &data); -		} -#endif -	} else { -		// Render all views -		struct roots_view *view; -		wl_list_for_each_reverse(view, &desktop->views, link) { -			render_view(output, view, &data); -		} -		// Render top layer above shell views -		render_layer(output, &damage, -			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); -	} - -	render_drag_icons(output, &damage, server->input); - -	render_layer(output, &damage, -		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - -renderer_end: -	wlr_output_render_software_cursors(wlr_output, &damage); -	wlr_renderer_scissor(renderer, NULL); -	wlr_renderer_end(renderer); - -	int width, height; -	wlr_output_transformed_resolution(wlr_output, &width, &height); - -	if (server->config->debug_damage_tracking) { -		pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); -	} - -	enum wl_output_transform transform = -		wlr_output_transform_invert(wlr_output->transform); -	wlr_region_transform(&damage, &damage, transform, width, height); - -	if (!wlr_output_damage_swap_buffers(output->damage, &now, &damage)) { -		goto damage_finish; -	} -	output->last_frame = desktop->last_frame = now; - -damage_finish: -	pixman_region32_fini(&damage); - -	// Send frame done events to all surfaces -	output_for_each_surface(output, surface_send_frame_done_iterator, -		&now); -} -  void output_damage_whole(struct roots_output *output) {  	wlr_output_damage_add_whole(output->damage);  } @@ -743,7 +431,7 @@ static void output_damage_handle_frame(struct wl_listener *listener,  		void *data) {  	struct roots_output *output =  		wl_container_of(listener, output, damage_frame); -	render_output(output); +	output_render(output);  }  static void output_damage_handle_destroy(struct wl_listener *listener, diff --git a/rootston/render.c b/rootston/render.c new file mode 100644 index 00000000..988f8de0 --- /dev/null +++ b/rootston/render.c @@ -0,0 +1,324 @@ +#define _POSIX_C_SOURCE 200809L +#include <assert.h> +#include <stdbool.h> +#include <stdlib.h> +#include <time.h> +#include <wlr/config.h> +#include <wlr/types/wlr_compositor.h> +#include <wlr/types/wlr_matrix.h> +#include <wlr/util/log.h> +#include <wlr/util/region.h> +#include "rootston/layers.h" +#include "rootston/output.h" +#include "rootston/server.h" + +struct render_data { +	pixman_region32_t *damage; +	float alpha; +}; + +static void scissor_output(struct wlr_output *wlr_output, +		pixman_box32_t *rect) { +	struct wlr_renderer *renderer = +		wlr_backend_get_renderer(wlr_output->backend); +	assert(renderer); + +	struct wlr_box box = { +		.x = rect->x1, +		.y = rect->y1, +		.width = rect->x2 - rect->x1, +		.height = rect->y2 - rect->y1, +	}; + +	int ow, oh; +	wlr_output_transformed_resolution(wlr_output, &ow, &oh); + +	enum wl_output_transform transform = +		wlr_output_transform_invert(wlr_output->transform); +	wlr_box_transform(&box, &box, transform, ow, oh); + +	wlr_renderer_scissor(renderer, &box); +} + +static void render_texture(struct wlr_output *wlr_output, +		pixman_region32_t *output_damage, struct wlr_texture *texture, +		const struct wlr_box *box, const float matrix[static 9], +		float rotation, float alpha) { +	struct wlr_renderer *renderer = +		wlr_backend_get_renderer(wlr_output->backend); +	assert(renderer); + +	struct wlr_box rotated; +	wlr_box_rotated_bounds(&rotated, box, rotation); + +	pixman_region32_t damage; +	pixman_region32_init(&damage); +	pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, +		rotated.width, rotated.height); +	pixman_region32_intersect(&damage, &damage, output_damage); +	bool damaged = pixman_region32_not_empty(&damage); +	if (!damaged) { +		goto damage_finish; +	} + +	int nrects; +	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); +	for (int i = 0; i < nrects; ++i) { +		scissor_output(wlr_output, &rects[i]); +		wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); +	} + +damage_finish: +	pixman_region32_fini(&damage); +} + +static void render_surface_iterator(struct roots_output *output, +		struct wlr_surface *surface, struct wlr_box *_box, float rotation, +		void *_data) { +	struct render_data *data = _data; +	struct wlr_output *wlr_output = output->wlr_output; +	pixman_region32_t *output_damage = data->damage; +	float alpha = data->alpha; + +	struct wlr_texture *texture = wlr_surface_get_texture(surface); +	if (!texture) { +		return; +	} + +	struct wlr_box box = *_box; +	scale_box(&box, wlr_output->scale); + +	float matrix[9]; +	enum wl_output_transform transform = +		wlr_output_transform_invert(surface->current.transform); +	wlr_matrix_project_box(matrix, &box, transform, rotation, +		wlr_output->transform_matrix); + +	render_texture(wlr_output, output_damage, +		texture, &box, matrix, rotation, alpha); +} + +static void render_decorations(struct roots_output *output, +		struct roots_view *view, struct render_data *data) { +	if (!view->decorated || view->wlr_surface == NULL) { +		return; +	} + +	struct wlr_renderer *renderer = +		wlr_backend_get_renderer(output->wlr_output->backend); +	assert(renderer); + +	struct wlr_box box; +	get_decoration_box(view, output, &box); + +	struct wlr_box rotated; +	wlr_box_rotated_bounds(&rotated, &box, view->rotation); + +	pixman_region32_t damage; +	pixman_region32_init(&damage); +	pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, +		rotated.width, rotated.height); +	pixman_region32_intersect(&damage, &damage, data->damage); +	bool damaged = pixman_region32_not_empty(&damage); +	if (!damaged) { +		goto damage_finish; +	} + +	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 }; + +	int nrects; +	pixman_box32_t *rects = +		pixman_region32_rectangles(&damage, &nrects); +	for (int i = 0; i < nrects; ++i) { +		scissor_output(output->wlr_output, &rects[i]); +		wlr_render_quad_with_matrix(renderer, color, matrix); +	} + +damage_finish: +	pixman_region32_fini(&damage); +} + +static void render_view(struct roots_output *output, struct roots_view *view, +		struct render_data *data) { +	// Do not render views fullscreened on other outputs +	if (view->fullscreen_output != NULL && view->fullscreen_output != output) { +		return; +	} + +	data->alpha = view->alpha; +	if (view->fullscreen_output == NULL) { +		render_decorations(output, view, data); +	} +	output_view_for_each_surface(output, view, render_surface_iterator, data); +} + +static void render_layer(struct roots_output *output, +		pixman_region32_t *damage, struct wl_list *layer_surfaces) { +	struct render_data data = { +		.damage = damage, +		.alpha = 1.0f, +	}; +	output_layer_for_each_surface(output, layer_surfaces, +		render_surface_iterator, &data); +} + +static void render_drag_icons(struct roots_output *output, +		pixman_region32_t *damage, struct roots_input *input) { +	struct render_data data = { +		.damage = damage, +		.alpha = 1.0f, +	}; +	output_drag_icons_for_each_surface(output, input, +		render_surface_iterator, &data); +} + +static void surface_send_frame_done_iterator(struct roots_output *output, +		struct wlr_surface *surface, struct wlr_box *box, float rotation, +		void *data) { +	struct timespec *when = data; +	wlr_surface_send_frame_done(surface, when); +} + +void output_render(struct roots_output *output) { +	struct wlr_output *wlr_output = output->wlr_output; +	struct roots_desktop *desktop = output->desktop; +	struct roots_server *server = desktop->server; +	struct wlr_renderer *renderer = +		wlr_backend_get_renderer(wlr_output->backend); +	assert(renderer); + +	if (!wlr_output->enabled) { +		return; +	} + +	struct timespec now; +	clock_gettime(CLOCK_MONOTONIC, &now); + +	float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + +	const struct wlr_box *output_box = +		wlr_output_layout_get_box(desktop->layout, wlr_output); + +	// Check if we can delegate the fullscreen surface to the output +	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 +		struct wlr_box view_box; +		view_get_box(view, &view_box); +		double view_x = (double)(output_box->width - view_box.width) / 2 + +			output_box->x; +		double view_y = (double)(output_box->height - view_box.height) / 2 + +			output_box->y; +		view_move(view, view_x, view_y); + +		// Fullscreen views are rendered on a black background +		clear_color[0] = clear_color[1] = clear_color[2] = 0; +	} + +	bool needs_swap; +	pixman_region32_t damage; +	pixman_region32_init(&damage); +	if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) { +		return; +	} + +	struct render_data data = { +		.damage = &damage, +		.alpha = 1.0, +	}; + +	if (!needs_swap) { +		// Output doesn't need swap and isn't damaged, skip rendering completely +		goto damage_finish; +	} + +	wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + +	if (!pixman_region32_not_empty(&damage)) { +		// Output isn't damaged but needs buffer swap +		goto renderer_end; +	} + +	if (server->config->debug_damage_tracking) { +		wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); +	} + +	int nrects; +	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); +	for (int i = 0; i < nrects; ++i) { +		scissor_output(output->wlr_output, &rects[i]); +		wlr_renderer_clear(renderer, clear_color); +	} + +	render_layer(output, &damage, +		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); +	render_layer(output, &damage, +		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + +	// If a view is fullscreen on this output, render it +	if (output->fullscreen_view != NULL) { +		struct roots_view *view = output->fullscreen_view; + +		render_view(output, view, &data); + +		// During normal rendering the xwayland window tree isn't traversed +		// because all windows are rendered. Here we only want to render +		// the fullscreen window's children so we have to traverse the tree. +#if WLR_HAS_XWAYLAND +		if (view->type == ROOTS_XWAYLAND_VIEW) { +			struct roots_xwayland_surface *xwayland_surface = +				roots_xwayland_surface_from_view(view); +			output_xwayland_children_for_each_surface(output, +				xwayland_surface->xwayland_surface, +				render_surface_iterator, &data); +		} +#endif +	} else { +		// Render all views +		struct roots_view *view; +		wl_list_for_each_reverse(view, &desktop->views, link) { +			render_view(output, view, &data); +		} +		// Render top layer above shell views +		render_layer(output, &damage, +			&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); +	} + +	render_drag_icons(output, &damage, server->input); + +	render_layer(output, &damage, +		&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + +renderer_end: +	wlr_output_render_software_cursors(wlr_output, &damage); +	wlr_renderer_scissor(renderer, NULL); +	wlr_renderer_end(renderer); + +	int width, height; +	wlr_output_transformed_resolution(wlr_output, &width, &height); + +	if (server->config->debug_damage_tracking) { +		pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); +	} + +	enum wl_output_transform transform = +		wlr_output_transform_invert(wlr_output->transform); +	wlr_region_transform(&damage, &damage, transform, width, height); + +	if (!wlr_output_damage_swap_buffers(output->damage, &now, &damage)) { +		goto damage_finish; +	} +	output->last_frame = desktop->last_frame = now; + +damage_finish: +	pixman_region32_fini(&damage); + +	// Send frame done events to all surfaces +	output_for_each_surface(output, surface_send_frame_done_iterator, +		&now); +} | 
