rootston: add support for direct scan-out
This commit is contained in:
parent
d1766547bd
commit
67cd84de45
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue