mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-19 06:47:02 -04:00
Merge branch 'wlr_raster' into 'master'
Introduce wlr_raster See merge request wlroots/wlroots!3634
This commit is contained in:
commit
48482c471b
10 changed files with 655 additions and 164 deletions
|
|
@ -19,6 +19,7 @@ void wlr_buffer_init(struct wlr_buffer *buffer,
|
|||
};
|
||||
wl_signal_init(&buffer->events.destroy);
|
||||
wl_signal_init(&buffer->events.release);
|
||||
wl_signal_init(&buffer->events.prerelease);
|
||||
wlr_addon_set_init(&buffer->addons);
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +59,10 @@ void wlr_buffer_unlock(struct wlr_buffer *buffer) {
|
|||
assert(buffer->n_locks > 0);
|
||||
buffer->n_locks--;
|
||||
|
||||
if (buffer->n_locks == 0) {
|
||||
wl_signal_emit_mutable(&buffer->events.prerelease, NULL);
|
||||
}
|
||||
|
||||
if (buffer->n_locks == 0) {
|
||||
wl_signal_emit_mutable(&buffer->events.release, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ wlr_files += files(
|
|||
'wlr_presentation_time.c',
|
||||
'wlr_primary_selection_v1.c',
|
||||
'wlr_primary_selection.c',
|
||||
'wlr_raster.c',
|
||||
'wlr_region.c',
|
||||
'wlr_relative_pointer_v1.c',
|
||||
'wlr_screencopy_v1.c',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
|
||||
#include <wlr/types/wlr_presentation_time.h>
|
||||
#include <wlr/types/wlr_raster.h>
|
||||
#include <wlr/util/transform.h>
|
||||
#include "types/wlr_scene.h"
|
||||
|
||||
|
|
@ -76,28 +77,6 @@ static void scene_surface_handle_surface_destroy(
|
|||
wlr_scene_node_destroy(&surface->buffer->node);
|
||||
}
|
||||
|
||||
// This is used for wlr_scene where it unconditionally locks buffers preventing
|
||||
// reuse of the existing texture for shm clients. With the usage pattern of
|
||||
// wlr_scene surface handling, we can mark its locked buffer as safe
|
||||
// for mutation.
|
||||
static void client_buffer_mark_next_can_damage(struct wlr_client_buffer *buffer) {
|
||||
buffer->n_ignore_locks++;
|
||||
}
|
||||
|
||||
static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buffer) {
|
||||
if (!scene_buffer->buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_client_buffer *buffer = wlr_client_buffer_get(scene_buffer->buffer);
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(buffer->n_ignore_locks > 0);
|
||||
buffer->n_ignore_locks--;
|
||||
}
|
||||
|
||||
static int min(int a, int b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
|
@ -160,38 +139,23 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) {
|
|||
wlr_scene_buffer_set_transform(scene_buffer, state->transform);
|
||||
wlr_scene_buffer_set_opacity(scene_buffer, opacity);
|
||||
|
||||
scene_buffer_unmark_client_buffer(scene_buffer);
|
||||
|
||||
if (surface->buffer) {
|
||||
client_buffer_mark_next_can_damage(surface->buffer);
|
||||
struct wlr_raster *raster = wlr_raster_from_surface(surface);
|
||||
if (raster) {
|
||||
wlr_scene_buffer_set_raster_with_damage(scene_buffer,
|
||||
raster, &surface->buffer_damage);
|
||||
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
||||
|
||||
struct wlr_drm_syncobj_timeline *wait_timeline = NULL;
|
||||
uint64_t wait_point = 0;
|
||||
if (syncobj_surface_state != NULL) {
|
||||
wait_timeline = syncobj_surface_state->acquire_timeline;
|
||||
wait_point = syncobj_surface_state->acquire_point;
|
||||
}
|
||||
|
||||
struct wlr_scene_buffer_set_buffer_options options = {
|
||||
.damage = &surface->buffer_damage,
|
||||
.wait_timeline = wait_timeline,
|
||||
.wait_point = wait_point,
|
||||
};
|
||||
wlr_scene_buffer_set_buffer_with_options(scene_buffer,
|
||||
&surface->buffer->base, &options);
|
||||
|
||||
if (syncobj_surface_state != NULL &&
|
||||
if (syncobj_surface_state != NULL && raster->buffer &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
&surface->buffer->base);
|
||||
raster->buffer);
|
||||
}
|
||||
} else {
|
||||
wlr_scene_buffer_set_buffer(scene_buffer, NULL);
|
||||
}
|
||||
|
||||
wlr_raster_unlock(raster);
|
||||
pixman_region32_fini(&opaque);
|
||||
}
|
||||
|
||||
|
|
@ -231,8 +195,6 @@ static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buff
|
|||
static void surface_addon_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon);
|
||||
|
||||
scene_buffer_unmark_client_buffer(surface->buffer);
|
||||
|
||||
wlr_addon_finish(&surface->addon);
|
||||
|
||||
wl_list_remove(&surface->outputs_update.link);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
#include <wlr/types/wlr_linux_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_presentation_time.h>
|
||||
#include <wlr/types/wlr_raster.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/util/region.h>
|
||||
|
|
@ -91,8 +92,6 @@ struct highlight_region {
|
|||
|
||||
static void scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_buffer *buffer);
|
||||
static void scene_buffer_set_texture(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_texture *texture);
|
||||
|
||||
void wlr_scene_node_destroy(struct wlr_scene_node *node) {
|
||||
if (node == NULL) {
|
||||
|
|
@ -123,9 +122,8 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
|
|||
}
|
||||
|
||||
scene_buffer_set_buffer(scene_buffer, NULL);
|
||||
scene_buffer_set_texture(scene_buffer, NULL);
|
||||
wlr_raster_unlock(scene_buffer->raster);
|
||||
pixman_region32_fini(&scene_buffer->opaque_region);
|
||||
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
||||
} else if (node->type == WLR_SCENE_NODE_TREE) {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
|
||||
|
|
@ -259,7 +257,7 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
|
|||
} else if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
||||
|
||||
if (!scene_buffer->buffer) {
|
||||
if (!scene_buffer->raster) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +265,7 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!scene_buffer->buffer_is_opaque) {
|
||||
if (!scene_buffer->raster->opaque) {
|
||||
pixman_region32_copy(opaque, &scene_buffer->opaque_region);
|
||||
pixman_region32_intersect_rect(opaque, opaque, 0, 0, width, height);
|
||||
pixman_region32_translate(opaque, x, y);
|
||||
|
|
@ -760,57 +758,17 @@ static void scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
|
|||
if (scene_buffer->own_buffer) {
|
||||
wlr_buffer_unlock(scene_buffer->buffer);
|
||||
}
|
||||
scene_buffer->buffer = NULL;
|
||||
scene_buffer->buffer = buffer;
|
||||
scene_buffer->own_buffer = false;
|
||||
scene_buffer->buffer_width = scene_buffer->buffer_height = 0;
|
||||
scene_buffer->buffer_is_opaque = false;
|
||||
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
scene_buffer->own_buffer = true;
|
||||
scene_buffer->buffer = wlr_buffer_lock(buffer);
|
||||
scene_buffer->buffer_width = buffer->width;
|
||||
scene_buffer->buffer_height = buffer->height;
|
||||
scene_buffer->buffer_is_opaque = buffer_is_opaque(buffer);
|
||||
|
||||
scene_buffer->buffer_release.notify = scene_buffer_handle_buffer_release;
|
||||
wl_signal_add(&buffer->events.release, &scene_buffer->buffer_release);
|
||||
}
|
||||
|
||||
static void scene_buffer_handle_renderer_destroy(struct wl_listener *listener,
|
||||
void *data) {
|
||||
struct wlr_scene_buffer *scene_buffer = wl_container_of(listener, scene_buffer, renderer_destroy);
|
||||
scene_buffer_set_texture(scene_buffer, NULL);
|
||||
}
|
||||
|
||||
static void scene_buffer_set_texture(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_texture *texture) {
|
||||
wl_list_remove(&scene_buffer->renderer_destroy.link);
|
||||
wlr_texture_destroy(scene_buffer->texture);
|
||||
scene_buffer->texture = texture;
|
||||
|
||||
if (texture != NULL) {
|
||||
scene_buffer->renderer_destroy.notify = scene_buffer_handle_renderer_destroy;
|
||||
wl_signal_add(&texture->renderer->events.destroy, &scene_buffer->renderer_destroy);
|
||||
} else {
|
||||
wl_list_init(&scene_buffer->renderer_destroy.link);
|
||||
}
|
||||
}
|
||||
|
||||
static void scene_buffer_set_wait_timeline(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_drm_syncobj_timeline *timeline, uint64_t point) {
|
||||
wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
|
||||
if (timeline != NULL) {
|
||||
scene_buffer->wait_timeline = wlr_drm_syncobj_timeline_ref(timeline);
|
||||
scene_buffer->wait_point = point;
|
||||
} else {
|
||||
scene_buffer->wait_timeline = NULL;
|
||||
scene_buffer->wait_point = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
|
||||
struct wlr_buffer *buffer) {
|
||||
struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer));
|
||||
|
|
@ -829,8 +787,14 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
|
|||
wl_list_init(&scene_buffer->buffer_release.link);
|
||||
wl_list_init(&scene_buffer->renderer_destroy.link);
|
||||
scene_buffer->opacity = 1;
|
||||
|
||||
scene_buffer_set_buffer(scene_buffer, buffer);
|
||||
|
||||
if (buffer) {
|
||||
scene_buffer->raster = wlr_raster_create(buffer, NULL);
|
||||
wlr_buffer_lock(buffer);
|
||||
scene_buffer->own_buffer = true;
|
||||
}
|
||||
|
||||
scene_node_update(&scene_buffer->node, NULL);
|
||||
|
||||
return scene_buffer;
|
||||
|
|
@ -843,32 +807,47 @@ void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buf
|
|||
options = &default_options;
|
||||
}
|
||||
|
||||
// specifying a region for a NULL buffer doesn't make sense. We need to know
|
||||
// about the buffer to scale the buffer local coordinates down to scene
|
||||
struct wlr_raster *raster = NULL;
|
||||
if (buffer) {
|
||||
raster = wlr_raster_create(buffer, &(struct wlr_raster_create_options) {
|
||||
.wait_timeline = options->wait_timeline,
|
||||
.wait_point = options->wait_point,
|
||||
});
|
||||
}
|
||||
|
||||
wlr_scene_buffer_set_raster_with_damage(scene_buffer, raster, options->damage);
|
||||
|
||||
if (raster) {
|
||||
wlr_buffer_lock(buffer);
|
||||
scene_buffer->own_buffer = true;
|
||||
}
|
||||
|
||||
wlr_raster_unlock(raster);
|
||||
}
|
||||
|
||||
void wlr_scene_buffer_set_raster_with_damage(struct wlr_scene_buffer *scene_buffer,
|
||||
struct wlr_raster *raster, const pixman_region32_t *damage) {
|
||||
// specifying a region for a NULL raster doesn't make sense. We need to know
|
||||
// about the raster to scale the raster local coordinates down to scene
|
||||
// coordinates.
|
||||
assert(buffer || !options->damage);
|
||||
assert(raster || !damage);
|
||||
|
||||
bool mapped = buffer != NULL;
|
||||
bool prev_mapped = scene_buffer->buffer != NULL || scene_buffer->texture != NULL;
|
||||
|
||||
if (!mapped && !prev_mapped) {
|
||||
// unmapping already unmapped buffer - noop
|
||||
if (raster == scene_buffer->raster) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if this node used to not be mapped or its previous displayed
|
||||
// buffer region will be different from what the new buffer would
|
||||
// produce we need to update the node.
|
||||
bool update = mapped != prev_mapped;
|
||||
if (buffer != NULL && scene_buffer->dst_width == 0 && scene_buffer->dst_height == 0) {
|
||||
update = update || scene_buffer->buffer_width != buffer->width ||
|
||||
scene_buffer->buffer_height != buffer->height;
|
||||
bool update = !raster != !scene_buffer->raster;
|
||||
if (raster != NULL && scene_buffer->dst_width == 0 && scene_buffer->dst_height == 0) {
|
||||
update = update || scene_buffer->raster->width != raster->width ||
|
||||
scene_buffer->raster->height != raster->height;
|
||||
}
|
||||
|
||||
scene_buffer_set_buffer(scene_buffer, buffer);
|
||||
scene_buffer_set_texture(scene_buffer, NULL);
|
||||
scene_buffer_set_wait_timeline(scene_buffer,
|
||||
options->wait_timeline, options->wait_point);
|
||||
wlr_raster_unlock(scene_buffer->raster);
|
||||
scene_buffer_set_buffer(scene_buffer, raster ? raster->buffer : NULL);
|
||||
scene_buffer->raster = raster ? wlr_raster_lock(raster) : NULL;
|
||||
|
||||
if (update) {
|
||||
scene_node_update(&scene_buffer->node, NULL);
|
||||
|
|
@ -883,8 +862,7 @@ void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buf
|
|||
}
|
||||
|
||||
pixman_region32_t fallback_damage;
|
||||
pixman_region32_init_rect(&fallback_damage, 0, 0, buffer->width, buffer->height);
|
||||
const pixman_region32_t *damage = options->damage;
|
||||
pixman_region32_init_rect(&fallback_damage, 0, 0, raster->width, raster->height);
|
||||
if (!damage) {
|
||||
damage = &fallback_damage;
|
||||
}
|
||||
|
|
@ -893,26 +871,26 @@ void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buf
|
|||
if (wlr_fbox_empty(&box)) {
|
||||
box.x = 0;
|
||||
box.y = 0;
|
||||
box.width = buffer->width;
|
||||
box.height = buffer->height;
|
||||
box.width = raster->width;
|
||||
box.height = raster->height;
|
||||
}
|
||||
|
||||
wlr_fbox_transform(&box, &box, scene_buffer->transform,
|
||||
buffer->width, buffer->height);
|
||||
raster->width, raster->height);
|
||||
|
||||
float scale_x, scale_y;
|
||||
if (scene_buffer->dst_width || scene_buffer->dst_height) {
|
||||
scale_x = scene_buffer->dst_width / box.width;
|
||||
scale_y = scene_buffer->dst_height / box.height;
|
||||
} else {
|
||||
scale_x = buffer->width / box.width;
|
||||
scale_y = buffer->height / box.height;
|
||||
scale_x = raster->width / box.width;
|
||||
scale_y = raster->height / box.height;
|
||||
}
|
||||
|
||||
pixman_region32_t trans_damage;
|
||||
pixman_region32_init(&trans_damage);
|
||||
wlr_region_transform(&trans_damage, damage,
|
||||
scene_buffer->transform, buffer->width, buffer->height);
|
||||
scene_buffer->transform, raster->width, raster->height);
|
||||
pixman_region32_intersect_rect(&trans_damage, &trans_damage,
|
||||
box.x, box.y, box.width, box.height);
|
||||
pixman_region32_translate(&trans_damage, -box.x, -box.y);
|
||||
|
|
@ -1063,28 +1041,6 @@ void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
|
|||
scene_node_update(&scene_buffer->node, NULL);
|
||||
}
|
||||
|
||||
static struct wlr_texture *scene_buffer_get_texture(
|
||||
struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) {
|
||||
if (scene_buffer->buffer == NULL || scene_buffer->texture != NULL) {
|
||||
return scene_buffer->texture;
|
||||
}
|
||||
|
||||
struct wlr_client_buffer *client_buffer =
|
||||
wlr_client_buffer_get(scene_buffer->buffer);
|
||||
if (client_buffer != NULL) {
|
||||
return client_buffer->texture;
|
||||
}
|
||||
|
||||
struct wlr_texture *texture =
|
||||
wlr_texture_from_buffer(renderer, scene_buffer->buffer);
|
||||
if (texture != NULL && scene_buffer->own_buffer) {
|
||||
scene_buffer->own_buffer = false;
|
||||
wlr_buffer_unlock(scene_buffer->buffer);
|
||||
}
|
||||
scene_buffer_set_texture(scene_buffer, texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
static void scene_node_get_size(struct wlr_scene_node *node,
|
||||
int *width, int *height) {
|
||||
*width = 0;
|
||||
|
|
@ -1103,9 +1059,9 @@ static void scene_node_get_size(struct wlr_scene_node *node,
|
|||
if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) {
|
||||
*width = scene_buffer->dst_width;
|
||||
*height = scene_buffer->dst_height;
|
||||
} else {
|
||||
*width = scene_buffer->buffer_width;
|
||||
*height = scene_buffer->buffer_height;
|
||||
} else if (scene_buffer->raster) {
|
||||
*width = scene_buffer->raster->width;
|
||||
*height = scene_buffer->raster->height;
|
||||
wlr_output_transform_coords(scene_buffer->transform, width, height);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1374,8 +1330,12 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
case WLR_SCENE_NODE_BUFFER:;
|
||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
||||
|
||||
struct wlr_texture *texture = scene_buffer_get_texture(scene_buffer,
|
||||
data->output->output->renderer);
|
||||
struct wlr_texture *texture = NULL;
|
||||
if (scene_buffer->raster) {
|
||||
texture = wlr_raster_obtain_texture(scene_buffer->raster,
|
||||
data->output->output->renderer);
|
||||
}
|
||||
|
||||
if (texture == NULL) {
|
||||
scene_output_damage(data->output, &render_region);
|
||||
break;
|
||||
|
|
@ -1396,8 +1356,8 @@ static void scene_entry_render(struct render_list_entry *entry, const struct ren
|
|||
.blend_mode = !data->output->scene->calculate_visibility ||
|
||||
pixman_region32_not_empty(&opaque) ?
|
||||
WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
|
||||
.wait_timeline = scene_buffer->wait_timeline,
|
||||
.wait_point = scene_buffer->wait_point,
|
||||
.wait_timeline = scene_buffer->raster->wait_timeline,
|
||||
.wait_point = scene_buffer->raster->wait_point,
|
||||
});
|
||||
|
||||
struct wlr_scene_output_sample_event sample_event = {
|
||||
|
|
@ -1708,7 +1668,7 @@ static bool scene_node_invisible(struct wlr_scene_node *node) {
|
|||
} else if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
|
||||
|
||||
return buffer->buffer == NULL && buffer->texture == NULL;
|
||||
return buffer->raster == NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -1831,8 +1791,8 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry,
|
|||
return false;
|
||||
}
|
||||
|
||||
int default_width = buffer->buffer->width;
|
||||
int default_height = buffer->buffer->height;
|
||||
int default_width = buffer->raster->width;
|
||||
int default_height = buffer->raster->height;
|
||||
wlr_output_transform_coords(buffer->transform, &default_width, &default_height);
|
||||
struct wlr_fbox default_box = {
|
||||
.width = default_width,
|
||||
|
|
@ -1872,8 +1832,9 @@ static bool scene_entry_try_direct_scanout(struct render_list_entry *entry,
|
|||
}
|
||||
|
||||
wlr_output_state_set_buffer(&pending, buffer->buffer);
|
||||
if (buffer->wait_timeline != NULL) {
|
||||
wlr_output_state_set_wait_timeline(&pending, buffer->wait_timeline, buffer->wait_point);
|
||||
if (buffer->raster->wait_timeline != NULL) {
|
||||
wlr_output_state_set_wait_timeline(&pending,
|
||||
buffer->raster->wait_timeline, buffer->raster->wait_point);
|
||||
}
|
||||
|
||||
if (!wlr_output_test_state(scene_output->output, &pending)) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include <wlr/types/wlr_raster.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/util/box.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
|
@ -539,7 +540,12 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
|
|||
} else if (cur->state->surface != NULL) {
|
||||
struct wlr_surface *surface = cur->state->surface;
|
||||
|
||||
struct wlr_texture *texture = wlr_surface_get_texture(surface);
|
||||
struct wlr_texture *texture = NULL;
|
||||
struct wlr_raster *raster = wlr_raster_from_surface(surface);
|
||||
if (raster) {
|
||||
texture = wlr_raster_obtain_texture(raster, output_cursor->output_cursor->output->renderer);
|
||||
}
|
||||
|
||||
int32_t hotspot_x = cur->state->surface_hotspot.x;
|
||||
int32_t hotspot_y = cur->state->surface_hotspot.y;
|
||||
|
||||
|
|
@ -561,12 +567,14 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_
|
|||
&src_box, dst_width, dst_height, surface->current.transform,
|
||||
hotspot_x, hotspot_y, wait_timeline, wait_point);
|
||||
|
||||
if (syncobj_surface_state != NULL && surface->buffer != NULL &&
|
||||
if (syncobj_surface_state != NULL && raster && raster->buffer != NULL &&
|
||||
(surface->current.committed & WLR_SURFACE_STATE_BUFFER)) {
|
||||
wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer(syncobj_surface_state,
|
||||
&surface->buffer->base);
|
||||
raster->buffer);
|
||||
}
|
||||
|
||||
wlr_raster_unlock(raster);
|
||||
|
||||
if (output_cursor->output_cursor->visible) {
|
||||
wlr_surface_send_enter(surface, output);
|
||||
} else {
|
||||
|
|
|
|||
392
types/wlr_raster.c
Normal file
392
types/wlr_raster.c
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
#include <assert.h>
|
||||
#include <pixman.h>
|
||||
#include <wlr/types/wlr_buffer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
|
||||
#include <wlr/types/wlr_raster.h>
|
||||
#include <wlr/render/drm_syncobj.h>
|
||||
#include <wlr/render/wlr_texture.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/addon.h>
|
||||
#include "types/wlr_buffer.h"
|
||||
|
||||
static void raster_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||
struct wlr_raster *raster = wl_container_of(listener, raster, buffer_release);
|
||||
raster->buffer = NULL;
|
||||
wl_list_remove(&raster->buffer_release.link);
|
||||
wl_list_init(&raster->buffer_release.link);
|
||||
}
|
||||
|
||||
struct wlr_raster *wlr_raster_create(struct wlr_buffer *buffer,
|
||||
const struct wlr_raster_create_options *options) {
|
||||
struct wlr_raster *raster = calloc(1, sizeof(*raster));
|
||||
if (!raster) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wl_signal_init(&raster->events.destroy);
|
||||
|
||||
assert(buffer);
|
||||
raster->opaque = buffer_is_opaque(buffer);
|
||||
raster->width = buffer->width;
|
||||
raster->height = buffer->height;
|
||||
raster->buffer = buffer;
|
||||
|
||||
raster->n_locks = 1;
|
||||
|
||||
raster->buffer_release.notify = raster_handle_buffer_release;
|
||||
wl_signal_add(&raster->buffer->events.release, &raster->buffer_release);
|
||||
|
||||
if (options && options->wait_timeline) {
|
||||
raster->wait_timeline = wlr_drm_syncobj_timeline_ref(options->wait_timeline);
|
||||
raster->wait_point = options->wait_point;
|
||||
}
|
||||
|
||||
return raster;
|
||||
}
|
||||
|
||||
static void raster_consider_destroy(struct wlr_raster *raster) {
|
||||
if (raster->n_locks > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wl_signal_emit_mutable(&raster->events.destroy, NULL);
|
||||
|
||||
if (raster->texture) {
|
||||
wl_list_remove(&raster->renderer_destroy.link);
|
||||
wlr_texture_destroy(raster->texture);
|
||||
}
|
||||
|
||||
wl_list_remove(&raster->buffer_release.link);
|
||||
wlr_drm_syncobj_timeline_unref(raster->wait_timeline);
|
||||
free(raster);
|
||||
}
|
||||
|
||||
struct wlr_raster *wlr_raster_lock(struct wlr_raster *raster) {
|
||||
raster->n_locks++;
|
||||
return raster;
|
||||
}
|
||||
|
||||
void wlr_raster_unlock(struct wlr_raster *raster) {
|
||||
if (!raster) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(raster->n_locks > 0);
|
||||
|
||||
raster->n_locks--;
|
||||
raster_consider_destroy(raster);
|
||||
}
|
||||
|
||||
static void raster_detach(struct wlr_raster *raster, struct wlr_texture *texture) {
|
||||
assert(texture);
|
||||
assert(raster->texture == texture);
|
||||
|
||||
wl_list_remove(&raster->renderer_destroy.link);
|
||||
raster->texture = NULL;
|
||||
}
|
||||
|
||||
static void handle_renderer_destroy(struct wl_listener *listener, void *data) {
|
||||
struct wlr_raster *raster = wl_container_of(listener, raster, renderer_destroy);
|
||||
raster_detach(raster, raster->texture);
|
||||
}
|
||||
|
||||
static void raster_attach(struct wlr_raster *raster, struct wlr_texture *texture) {
|
||||
assert(texture->width == raster->width && texture->height == raster->height);
|
||||
assert(!raster->texture);
|
||||
|
||||
raster->renderer_destroy.notify = handle_renderer_destroy;
|
||||
wl_signal_add(&texture->renderer->events.destroy, &raster->renderer_destroy);
|
||||
|
||||
raster->texture = texture;
|
||||
}
|
||||
|
||||
struct wlr_texture *wlr_raster_obtain_texture(struct wlr_raster *raster,
|
||||
struct wlr_renderer *renderer) {
|
||||
if (raster->texture) {
|
||||
assert(raster->texture->renderer == renderer);
|
||||
return raster->texture;
|
||||
}
|
||||
|
||||
assert(raster->buffer);
|
||||
|
||||
struct wlr_client_buffer *client_buffer =
|
||||
wlr_client_buffer_get(raster->buffer);
|
||||
if (client_buffer != NULL) {
|
||||
return client_buffer->texture;
|
||||
}
|
||||
|
||||
struct wlr_texture *texture = wlr_texture_from_buffer(renderer, raster->buffer);
|
||||
if (texture) {
|
||||
raster_attach(raster, texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
struct raster_update_state {
|
||||
struct wlr_buffer *buffer;
|
||||
pixman_region32_t damage;
|
||||
|
||||
struct wlr_raster *new_raster;
|
||||
struct wlr_raster *old_raster;
|
||||
|
||||
struct wl_listener old_raster_destroy;
|
||||
struct wl_listener new_raster_destroy;
|
||||
struct wl_listener buffer_release;
|
||||
};
|
||||
|
||||
static void destroy_raster_update_state(struct raster_update_state *state) {
|
||||
wl_list_remove(&state->old_raster_destroy.link);
|
||||
wl_list_remove(&state->new_raster_destroy.link);
|
||||
wl_list_remove(&state->buffer_release.link);
|
||||
pixman_region32_fini(&state->damage);
|
||||
free(state);
|
||||
}
|
||||
|
||||
static void raster_update_handle_new_raster_destroy(struct wl_listener *listener, void *data) {
|
||||
struct raster_update_state *state = wl_container_of(listener, state, new_raster_destroy);
|
||||
destroy_raster_update_state(state);
|
||||
}
|
||||
|
||||
static void raster_update_handle_old_raster_destroy(struct wl_listener *listener, void *data) {
|
||||
struct raster_update_state *state = wl_container_of(listener, state, old_raster_destroy);
|
||||
|
||||
// if the new raster already has a texture, there's nothing we can do to help.
|
||||
if (state->new_raster->texture) {
|
||||
assert(state->new_raster->texture->renderer == state->old_raster->texture->renderer);
|
||||
destroy_raster_update_state(state);
|
||||
return;
|
||||
}
|
||||
|
||||
struct wlr_texture *texture = state->old_raster->texture;
|
||||
if (!texture) {
|
||||
destroy_raster_update_state(state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wlr_texture_update_from_buffer(texture, state->buffer, &state->damage)) {
|
||||
raster_detach(state->old_raster, texture);
|
||||
raster_attach(state->new_raster, texture);
|
||||
}
|
||||
|
||||
destroy_raster_update_state(state);
|
||||
}
|
||||
|
||||
static void raster_update_handle_buffer_release(struct wl_listener *listener, void *data) {
|
||||
struct raster_update_state *state = wl_container_of(listener, state, buffer_release);
|
||||
destroy_raster_update_state(state);
|
||||
}
|
||||
|
||||
static struct wlr_raster *raster_update(struct wlr_raster *raster,
|
||||
struct wlr_buffer *buffer, const pixman_region32_t *damage,
|
||||
const struct wlr_raster_create_options *options) {
|
||||
struct raster_update_state *state = calloc(1, sizeof(*state));
|
||||
if (!state) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_raster *new_raster = wlr_raster_create(buffer, options);
|
||||
if (!new_raster) {
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state->old_raster_destroy.notify = raster_update_handle_old_raster_destroy;
|
||||
wl_signal_add(&raster->events.destroy, &state->old_raster_destroy);
|
||||
state->new_raster_destroy.notify = raster_update_handle_new_raster_destroy;
|
||||
wl_signal_add(&new_raster->events.destroy, &state->new_raster_destroy);
|
||||
state->buffer_release.notify = raster_update_handle_buffer_release;
|
||||
wl_signal_add(&buffer->events.release, &state->buffer_release);
|
||||
|
||||
state->new_raster = new_raster;
|
||||
state->old_raster = raster;
|
||||
state->buffer = buffer;
|
||||
|
||||
pixman_region32_init(&state->damage);
|
||||
pixman_region32_copy(&state->damage, damage);
|
||||
|
||||
return new_raster;
|
||||
}
|
||||
|
||||
struct surface_raster {
|
||||
struct wlr_raster *raster;
|
||||
struct wlr_surface *surface;
|
||||
|
||||
struct wlr_addon addon;
|
||||
|
||||
struct wl_listener buffer_prerelease;
|
||||
|
||||
bool locking_buffer;
|
||||
};
|
||||
|
||||
static void surface_raster_drop_raster(struct surface_raster *surface_raster) {
|
||||
if (surface_raster->locking_buffer) {
|
||||
wlr_buffer_unlock(surface_raster->raster->buffer);
|
||||
surface_raster->locking_buffer = false;
|
||||
}
|
||||
|
||||
wlr_raster_unlock(surface_raster->raster);
|
||||
surface_raster->raster = NULL;
|
||||
}
|
||||
|
||||
static void surface_raster_destroy(struct surface_raster *surface_raster) {
|
||||
surface_raster_drop_raster(surface_raster);
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wlr_addon_finish(&surface_raster->addon);
|
||||
free(surface_raster);
|
||||
}
|
||||
|
||||
static void surface_raster_handle_addon_destroy(struct wlr_addon *addon) {
|
||||
struct surface_raster *surface_raster = wl_container_of(addon, surface_raster, addon);
|
||||
surface_raster_destroy(surface_raster);
|
||||
}
|
||||
|
||||
static void surface_raster_handle_buffer_prerelease(struct wl_listener *listener, void *data) {
|
||||
struct surface_raster *surface_raster =
|
||||
wl_container_of(listener, surface_raster, buffer_prerelease);
|
||||
struct wlr_raster *raster = surface_raster->raster;
|
||||
|
||||
struct wlr_surface_output *output;
|
||||
wl_list_for_each(output, &surface_raster->surface->current_outputs, link) {
|
||||
wlr_raster_obtain_texture(raster, output->output->renderer);
|
||||
}
|
||||
|
||||
// if there was a failed texture upload, keep on locking the buffer
|
||||
if (!raster->texture) {
|
||||
wlr_buffer_lock(raster->buffer);
|
||||
surface_raster->locking_buffer = true;
|
||||
}
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wl_list_init(&surface_raster->buffer_prerelease.link);
|
||||
}
|
||||
|
||||
const struct wlr_addon_interface surface_raster_addon_impl = {
|
||||
.name = "wlr_raster_surface",
|
||||
.destroy = surface_raster_handle_addon_destroy,
|
||||
};
|
||||
|
||||
static struct surface_raster *get_surface_raster(struct wlr_surface *surface) {
|
||||
struct wlr_addon *addon = wlr_addon_find(&surface->addons, NULL,
|
||||
&surface_raster_addon_impl);
|
||||
if (!addon) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct surface_raster *surface_raster = wl_container_of(addon, surface_raster, addon);
|
||||
return surface_raster;
|
||||
}
|
||||
|
||||
// Because wlr_raster doesn't lock the buffer itself, we need something extra
|
||||
// to keep client buffer locked when operating in legacy mode.
|
||||
struct client_buffer_compat {
|
||||
struct wlr_client_buffer *buffer;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
static void client_buffer_compat_raster_destroy(struct wl_listener *listener, void *data) {
|
||||
struct client_buffer_compat *compat = wl_container_of(listener, compat, destroy);
|
||||
|
||||
wlr_buffer_unlock(&compat->buffer->base);
|
||||
wl_list_remove(&compat->destroy.link);
|
||||
free(compat);
|
||||
}
|
||||
|
||||
struct wlr_raster *wlr_raster_from_surface(struct wlr_surface *surface) {
|
||||
struct wlr_linux_drm_syncobj_surface_v1_state *syncobj_surface_state =
|
||||
wlr_linux_drm_syncobj_v1_get_surface_state(surface);
|
||||
|
||||
struct wlr_raster_create_options options = {0};
|
||||
if (syncobj_surface_state) {
|
||||
options.wait_timeline = syncobj_surface_state->acquire_timeline;
|
||||
options.wait_point = syncobj_surface_state->acquire_point;
|
||||
}
|
||||
|
||||
if (surface->compositor->renderer) {
|
||||
// use legacy wlr_client_buffer
|
||||
if (!surface->buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct client_buffer_compat *compat = calloc(1, sizeof(*compat));
|
||||
if (!compat) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_raster *raster = wlr_raster_create(&surface->buffer->base, &options);
|
||||
if (!raster) {
|
||||
free(compat);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
compat->destroy.notify = client_buffer_compat_raster_destroy;
|
||||
wl_signal_add(&raster->events.destroy, &compat->destroy);
|
||||
|
||||
compat->buffer = surface->buffer;
|
||||
wlr_buffer_lock(&surface->buffer->base);
|
||||
|
||||
return raster;
|
||||
}
|
||||
|
||||
struct surface_raster *surface_raster = get_surface_raster(surface);
|
||||
if (!surface_raster) {
|
||||
surface_raster = calloc(1, sizeof(*surface_raster));
|
||||
if (!surface_raster) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface_raster->surface = surface;
|
||||
|
||||
wlr_addon_init(&surface_raster->addon, &surface->addons, NULL,
|
||||
&surface_raster_addon_impl);
|
||||
|
||||
surface_raster->buffer_prerelease.notify = surface_raster_handle_buffer_prerelease;
|
||||
wl_list_init(&surface_raster->buffer_prerelease.link);
|
||||
}
|
||||
|
||||
if (!surface->current.buffer) {
|
||||
// surface is mapped but it hasn't committed a new buffer. We need to keep
|
||||
// using the old one
|
||||
if (wlr_surface_has_buffer(surface)) {
|
||||
if (surface_raster->raster) {
|
||||
return wlr_raster_lock(surface_raster->raster);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wl_list_init(&surface_raster->buffer_prerelease.link);
|
||||
|
||||
surface_raster_drop_raster(surface_raster);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wlr_raster *raster;
|
||||
if (surface_raster->raster) {
|
||||
// make sure we haven't already seen this buffer
|
||||
if (surface_raster->raster->buffer == surface->current.buffer) {
|
||||
return wlr_raster_lock(surface_raster->raster);
|
||||
}
|
||||
|
||||
raster = raster_update(surface_raster->raster,
|
||||
surface->current.buffer, &surface->buffer_damage, &options);
|
||||
} else {
|
||||
raster = wlr_raster_create(surface->current.buffer, &options);
|
||||
}
|
||||
|
||||
if (!raster) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface_raster_drop_raster(surface_raster);
|
||||
surface_raster->raster = wlr_raster_lock(raster);
|
||||
|
||||
wl_list_remove(&surface_raster->buffer_prerelease.link);
|
||||
wl_signal_add(&surface->current.buffer->events.prerelease, &surface_raster->buffer_prerelease);
|
||||
|
||||
return raster;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue