aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_scene.h13
-rw-r--r--types/scene/wlr_scene.c82
2 files changed, 95 insertions, 0 deletions
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 19924090..b6f0d217 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -38,6 +38,7 @@ struct wlr_scene_node;
struct wlr_scene_buffer;
struct wlr_presentation;
+struct wlr_linux_dmabuf_v1;
typedef bool (*wlr_scene_buffer_point_accepts_input_func_t)(
struct wlr_scene_buffer *buffer, int sx, int sy);
@@ -95,10 +96,12 @@ struct wlr_scene {
// May be NULL
struct wlr_presentation *presentation;
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
// private state
struct wl_listener presentation_destroy;
+ struct wl_listener linux_dmabuf_v1_destroy;
enum wlr_scene_debug_damage_option debug_damage_option;
bool direct_scanout;
@@ -169,6 +172,7 @@ struct wlr_scene_buffer {
int dst_width, dst_height;
enum wl_output_transform transform;
pixman_region32_t opaque_region;
+ struct wlr_linux_dmabuf_feedback_v1_init_options prev_feedback_options;
};
/** A viewport for an output in the scene-graph */
@@ -288,6 +292,15 @@ void wlr_scene_set_presentation(struct wlr_scene *scene,
struct wlr_presentation *presentation);
/**
+ * Handles linux_dmabuf_v1 feedback for all surfaces in the scene.
+ *
+ * Asserts that a struct wlr_linux_dmabuf_v1 hasn't already been set for the scene.
+ */
+void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1);
+
+
+/**
* Add a node displaying nothing but its children.
*/
struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent);
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index 9b9224b1..45a00429 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -7,6 +7,7 @@
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_matrix.h>
+#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
@@ -120,6 +121,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
}
wl_list_remove(&scene->presentation_destroy.link);
+ wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
} else {
assert(node->parent);
}
@@ -153,6 +155,7 @@ struct wlr_scene *wlr_scene_create(void) {
wl_list_init(&scene->outputs);
wl_list_init(&scene->presentation_destroy.link);
+ wl_list_init(&scene->linux_dmabuf_v1_destroy.link);
const char *debug_damage_options[] = {
"none",
@@ -307,6 +310,7 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
uint32_t largest_overlap = 0;
+ struct wlr_scene_output *old_primary_output = scene_buffer->primary_output;
scene_buffer->primary_output = NULL;
size_t count = 0;
@@ -354,6 +358,11 @@ static void update_node_update_outputs(struct wlr_scene_node *node,
pixman_region32_fini(&intersection);
}
+ if (old_primary_output != scene_buffer->primary_output) {
+ memset(&scene_buffer->prev_feedback_options, 0,
+ sizeof(scene_buffer->prev_feedback_options));
+ }
+
uint64_t old_active = scene_buffer->active_outputs;
scene_buffer->active_outputs = active_outputs;
@@ -1171,6 +1180,23 @@ void wlr_scene_set_presentation(struct wlr_scene *scene,
wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy);
}
+static void scene_handle_linux_dmabuf_v1_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_scene *scene =
+ wl_container_of(listener, scene, linux_dmabuf_v1_destroy);
+ wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
+ wl_list_init(&scene->linux_dmabuf_v1_destroy.link);
+ scene->linux_dmabuf_v1 = NULL;
+}
+
+void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1) {
+ assert(scene->linux_dmabuf_v1 == NULL);
+ scene->linux_dmabuf_v1 = linux_dmabuf_v1;
+ scene->linux_dmabuf_v1_destroy.notify = scene_handle_linux_dmabuf_v1_destroy;
+ wl_signal_add(&linux_dmabuf_v1->events.destroy, &scene->linux_dmabuf_v1_destroy);
+}
+
static void scene_output_handle_destroy(struct wlr_addon *addon) {
struct wlr_scene_output *scene_output =
wl_container_of(addon, scene_output, addon);
@@ -1414,6 +1440,37 @@ static void get_frame_damage(struct wlr_scene_output *scene_output, pixman_regio
transform, tr_width, tr_height);
}
+static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
+ struct wlr_scene_buffer *scene_buffer,
+ const struct wlr_linux_dmabuf_feedback_v1_init_options *options) {
+ if (!scene->linux_dmabuf_v1) {
+ return;
+ }
+
+ struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(scene_buffer);
+ if (!surface) {
+ return;
+ }
+
+ // compare to the previous options so that we don't send
+ // duplicate feedback events.
+ if (memcmp(options, &scene_buffer->prev_feedback_options, sizeof(*options)) == 0) {
+ return;
+ }
+
+ scene_buffer->prev_feedback_options = *options;
+
+ struct wlr_linux_dmabuf_feedback_v1 feedback = {0};
+ if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, options)) {
+ return;
+ }
+
+ wlr_linux_dmabuf_v1_set_surface_feedback(scene->linux_dmabuf_v1,
+ surface->surface, &feedback);
+
+ wlr_linux_dmabuf_feedback_v1_finish(&feedback);
+}
+
static bool scene_buffer_can_consider_direct_scanout(struct wlr_scene_buffer *buffer,
const struct wlr_scene_output *scene_output) {
struct wlr_scene_node *node = &buffer->node;
@@ -1517,6 +1574,8 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *);
struct wlr_scene_node **list_data = list_con.render_list->data;
+ bool sent_direct_scanout_feedback = false;
+
// if there is only one thing to render let's see if that thing can be
// directly scanned out
bool scanout = false;
@@ -1527,6 +1586,16 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
if (scene_buffer_can_consider_direct_scanout(buffer, scene_output)) {
+ if (buffer->primary_output == scene_output) {
+ struct wlr_linux_dmabuf_feedback_v1_init_options options = {
+ .main_renderer = output->renderer,
+ .scanout_primary_output = output,
+ };
+
+ scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options);
+ sent_direct_scanout_feedback = true;
+ }
+
scanout = scene_buffer_try_direct_scanout(buffer, scene_output);
}
}
@@ -1667,6 +1736,19 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
for (int i = list_len - 1; i >= 0; i--) {
struct wlr_scene_node *node = list_data[i];
scene_node_render(node, scene_output, &damage);
+
+ if (node->type == WLR_SCENE_NODE_BUFFER) {
+ struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
+
+ if (buffer->primary_output == scene_output && !sent_direct_scanout_feedback) {
+ struct wlr_linux_dmabuf_feedback_v1_init_options options = {
+ .main_renderer = output->renderer,
+ .scanout_primary_output = NULL,
+ };
+
+ scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options);
+ }
+ }
}
wlr_renderer_scissor(renderer, NULL);