aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-04-29 23:28:39 +0300
committerDrew DeVault <sir@cmpwn.com>2019-06-07 09:06:11 -0400
commit67cd84de450fb30e82beaa9f2e0dbb795d9eca98 (patch)
tree54ed473044a5fee55a1d71f156abeb0f623cb2e3
parentd1766547bd3d7f150b5ddca405b9b6259e546f52 (diff)
rootston: add support for direct scan-out
-rw-r--r--rootston/render.c104
1 files changed, 97 insertions, 7 deletions
diff --git a/rootston/render.c b/rootston/render.c
index 712e47c0..3b242b88 100644
--- a/rootston/render.c
+++ b/rootston/render.c
@@ -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);
}