diff --git a/rootston/render.c b/rootston/render.c index 873a445680..88665d3326 100644 --- a/rootston/render.c +++ b/rootston/render.c @@ -177,6 +177,74 @@ 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 + + if (view->wlr_surface->buffer == NULL) { + return false; + } + + // TODO: don't rely on the resource + struct wl_resource *buffer_resource = view->wlr_surface->buffer->resource; + if (!wlr_dmabuf_v1_resource_is_buffer(buffer_resource)) { + return false; + } + struct wlr_dmabuf_v1_buffer *dmabuf_buffer = + wlr_dmabuf_v1_buffer_from_buffer_resource(buffer_resource); + + return wlr_output_set_dmabuf(wlr_output, &dmabuf_buffer->attributes); +} + static void surface_send_frame_done_iterator(struct roots_output *output, struct wlr_surface *surface, struct wlr_box *box, float rotation, void *data) { @@ -220,6 +288,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_swap; @@ -257,29 +341,9 @@ void output_render(struct roots_output *output) { 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; - - // TODO: check this is the only surface on screen - // TODO: don't rely on the resource - struct wl_resource *buffer_resource = - output->fullscreen_view->wlr_surface->buffer->resource; - if (wlr_dmabuf_v1_resource_is_buffer(buffer_resource)) { - wlr_log(WLR_ERROR, "YES it's a dmabuf"); - struct wlr_dmabuf_v1_buffer *dmabuf_buffer = - wlr_dmabuf_v1_buffer_from_buffer_resource(buffer_resource); - if (wlr_output_set_dmabuf(wlr_output, &dmabuf_buffer->attributes)) { - wlr_log(WLR_ERROR, "YES scanned out!"); - goto damage_finish; - } - } - render_view(output, view, &data); // During normal rendering the xwayland window tree isn't traversed @@ -295,12 +359,19 @@ void output_render(struct roots_output *output) { } #endif } else { + // Render background and bottom layers under views + render_layer(output, &damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(output, &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, &damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } @@ -334,6 +405,7 @@ void output_render(struct roots_output *output) { damage_finish: pixman_region32_fini(&damage); +send_frame_done: // Send frame done events to all surfaces output_for_each_surface(output, surface_send_frame_done_iterator, &now);