mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-12-22 18:09:49 +01:00
wlr_scene: Add dmabuf_feedback helper
This commit is contained in:
parent
4ddc20e14c
commit
3ef9f91283
2 changed files with 95 additions and 0 deletions
|
@ -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 */
|
||||
|
@ -287,6 +291,15 @@ struct wlr_scene *wlr_scene_create(void);
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue