diff --git a/include/rootston/output.h b/include/rootston/output.h index c0022d1a..89fe1d82 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -5,6 +5,11 @@ #include #include +/** + * Damage tracking requires to keep track of previous frames' damage. To allow + * damage tracking to work with triple buffering, an history of two frames is + * required. + */ #define ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN 2 struct roots_desktop; @@ -20,6 +25,7 @@ struct roots_output { pixman_region32_t damage; bool frame_pending; + // circular queue for previous damage pixman_region32_t previous_damage[ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN]; size_t previous_damage_idx; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index 3267a608..91429123 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -33,8 +33,6 @@ struct wlr_output_cursor { struct wl_listener surface_destroy; }; -#define WLR_OUTPUT_PREVIOUS_DAMAGE_COUNT 2 - struct wlr_output_impl; struct wlr_output { @@ -51,21 +49,21 @@ struct wlr_output { char serial[16]; int32_t phys_width, phys_height; // mm + // Note: some backends may have zero modes + struct wl_list modes; + struct wlr_output_mode *current_mode; + int32_t width, height; + int32_t refresh; // mHz, may be zero + bool enabled; float scale; enum wl_output_subpixel subpixel; enum wl_output_transform transform; bool needs_swap; - pixman_region32_t damage; + pixman_region32_t damage; // damage for cursors and fullscreen surface float transform_matrix[16]; - // Note: some backends may have zero modes - struct wl_list modes; - struct wlr_output_mode *current_mode; - int32_t width, height; - int32_t refresh; // mHz - struct { struct wl_signal frame; struct wl_signal needs_swap; @@ -107,16 +105,18 @@ void wlr_output_destroy(struct wlr_output *output); void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); /** - * Makes the output GL context current. + * Makes the output rendering context current. * * `buffer_age` is set to the drawing buffer age in number of frames or -1 if - * unknown. + * unknown. This is useful for damage tracking. */ bool wlr_output_make_current(struct wlr_output *output, int *buffer_age); /** * Swaps the output buffers. If the time of the frame isn't known, set `when` to * NULL. If the compositor doesn't support damage tracking, set `damage` to * NULL. + * + * Swapping buffers schedules a `frame` event. */ bool wlr_output_swap_buffers(struct wlr_output *output, struct timespec *when, pixman_region32_t *damage); @@ -126,6 +126,7 @@ uint32_t wlr_output_get_gamma_size(struct wlr_output *output); void wlr_output_set_fullscreen_surface(struct wlr_output *output, struct wlr_surface *surface); + struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output); /** * Sets the cursor image. The image must be already scaled for the output. diff --git a/rootston/output.c b/rootston/output.c index 13e78082..f8da9c77 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -31,6 +31,10 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, } } +/** + * Checks whether a surface at (lx, ly) intersects an output. Sets `box` to the + * surface box in the output, in output-local coordinates. + */ static bool surface_intersect_output(struct wlr_surface *surface, struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, double lx, double ly, struct wlr_box *box) { @@ -138,10 +142,8 @@ render_subsurfaces:; struct wlr_surface_state *state = subsurface->surface->current; double sx = state->subsurface_position.x; double sy = state->subsurface_position.y; - double sw = state->buffer_width / state->scale; - double sh = state->buffer_height / state->scale; - rotate_child_position(&sx, &sy, sw, sh, surface->current->width, - surface->current->height, rotation); + rotate_child_position(&sx, &sy, state->width, state->height, + surface->current->width, surface->current->height, rotation); render_surface(subsurface->surface, output, when, damage, lx + sx, ly + sy, rotation); @@ -297,6 +299,7 @@ static void render_output(struct roots_output *output) { int buffer_age = -1; wlr_output_make_current(wlr_output, &buffer_age); + // Check if we can use damage tracking pixman_region32_t damage; pixman_region32_init(&damage); if (buffer_age <= 0 || buffer_age - 1 > ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN) { @@ -306,8 +309,9 @@ static void render_output(struct roots_output *output) { } else { pixman_region32_copy(&damage, &output->damage); + // Accumulate damage from old buffers size_t idx = output->previous_damage_idx; - for (int i = 0; i < buffer_age - 1; i++) { + for (int i = 0; i < buffer_age - 1; ++i) { int j = (idx + i) % ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; pixman_region32_union(&damage, &damage, &output->previous_damage[j]); } @@ -362,11 +366,13 @@ static void render_output(struct roots_output *output) { goto renderer_end; } + // Render all views struct roots_view *view; wl_list_for_each_reverse(view, &desktop->views, link) { render_view(view, output, &now, &damage); } + // Render drag icons struct wlr_drag_icon *drag_icon = NULL; struct roots_seat *seat = NULL; wl_list_for_each(seat, &server->input->seats, link) { @@ -398,6 +404,7 @@ renderer_end: wlr_renderer_end(server->renderer); wlr_output_swap_buffers(wlr_output, &now, &damage); output->frame_pending = true; + // same as decrementing, but works on unsigned integers output->previous_damage_idx += ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN - 1; output->previous_damage_idx %= ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN; pixman_region32_copy(&output->previous_damage[output->previous_damage_idx], @@ -421,6 +428,7 @@ static void handle_idle_render(void *data) { static void schedule_render(struct roots_output *output) { if (!output->frame_pending) { + // TODO: ask the backend to send a frame event when appropriate instead struct wl_event_loop *ev = wl_display_get_event_loop(output->desktop->server->wl_display); wl_event_loop_add_idle(ev, handle_idle_render, output); @@ -480,6 +488,7 @@ static void output_damage_from_surface(struct roots_output *output, return; } + // TODO: output scale, output transform support pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_copy(&damage, &surface->current->surface_damage);