rootston: add support for direct scan-out

This commit is contained in:
Simon Ser 2019-04-29 23:28:39 +03:00 committed by Drew DeVault
parent d1766547bd
commit 67cd84de45
1 changed files with 97 additions and 7 deletions

View File

@ -6,6 +6,8 @@
#include <wlr/config.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/util/log.h>
#include <wlr/util/region.h>
#include "rootston/layers.h"
@ -175,6 +177,76 @@ static void render_drag_icons(struct roots_output *output,
render_surface_iterator, &data);
}
static void count_surface_iterator(struct roots_output *output,
struct wlr_surface *surface, struct wlr_box *_box, float rotation,
void *data) {
size_t *n = data;
n++;
}
static bool scan_out_fullscreen_view(struct roots_output *output) {
struct wlr_output *wlr_output = output->wlr_output;
struct roots_desktop *desktop = output->desktop;
struct roots_seat *seat;
wl_list_for_each(seat, &desktop->server->input->seats, link) {
struct roots_drag_icon *drag_icon = seat->drag_icon;
if (drag_icon && drag_icon->wlr_drag_icon->mapped) {
return false;
}
}
if (!wl_list_empty(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) {
return false;
}
struct wlr_output_cursor *cursor;
wl_list_for_each(cursor, &wlr_output->cursors, link) {
if (cursor->enabled && cursor->visible &&
wlr_output->hardware_cursor != cursor) {
return false;
}
}
struct roots_view *view = output->fullscreen_view;
assert(view != NULL);
if (view->wlr_surface == NULL) {
return false;
}
size_t n_surfaces = 0;
output_view_for_each_surface(output, view,
count_surface_iterator, &n_surfaces);
if (n_surfaces > 1) {
return false;
}
#if WLR_HAS_XWAYLAND
if (view->type == ROOTS_XWAYLAND_VIEW) {
struct roots_xwayland_surface *xwayland_surface =
roots_xwayland_surface_from_view(view);
if (!wl_list_empty(&xwayland_surface->xwayland_surface->children)) {
return false;
}
}
#endif
struct wlr_surface *surface = view->wlr_surface;
if (surface->buffer == NULL) {
return false;
}
if ((float)surface->current.scale != wlr_output->scale ||
surface->current.transform != wlr_output->transform) {
return false;
}
if (!wlr_output_attach_buffer(wlr_output, surface->buffer)) {
return false;
}
return wlr_output_commit(wlr_output);
}
static void surface_send_frame_done_iterator(struct roots_output *output,
struct wlr_surface *surface, struct wlr_box *box, float rotation,
void *data) {
@ -218,6 +290,22 @@ void output_render(struct roots_output *output) {
// Fullscreen views are rendered on a black background
clear_color[0] = clear_color[1] = clear_color[2] = 0;
// Check if we can scan-out the fullscreen view
static bool last_scanned_out = false;
bool scanned_out = scan_out_fullscreen_view(output);
if (scanned_out && !last_scanned_out) {
wlr_log(WLR_DEBUG, "Scanning out fullscreen view");
}
if (last_scanned_out && !scanned_out) {
wlr_log(WLR_DEBUG, "Stopping fullscreen view scan out");
}
last_scanned_out = scanned_out;
if (scanned_out) {
goto send_frame_done;
}
}
bool needs_frame;
@ -256,15 +344,9 @@ void output_render(struct roots_output *output) {
wlr_renderer_clear(renderer, clear_color);
}
render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
render_layer(output, &buffer_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
@ -280,12 +362,19 @@ void output_render(struct roots_output *output) {
}
#endif
} else {
// Render background and bottom layers under views
render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
// 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 top layer above views
render_layer(output, &buffer_damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
}
@ -327,6 +416,7 @@ renderer_end:
buffer_damage_finish:
pixman_region32_fini(&buffer_damage);
send_frame_done:
// Send frame done events to all surfaces
output_for_each_surface(output, surface_send_frame_done_iterator, &now);
}