mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-27 23:49:04 +00:00
worker: move display_channel_draw
Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
parent
30e0aabace
commit
b61bd286bc
@ -1261,3 +1261,159 @@ void drawable_draw(DisplayChannel *display, Drawable *drawable)
|
||||
spice_warning("invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
static void surface_update_dest(RedSurface *surface, const SpiceRect *area)
|
||||
{
|
||||
SpiceCanvas *canvas = surface->context.canvas;
|
||||
int stride = surface->context.stride;
|
||||
uint8_t *line_0 = surface->context.line_0;
|
||||
|
||||
if (surface->context.canvas_draws_on_surface)
|
||||
return;
|
||||
|
||||
int h = area->bottom - area->top;
|
||||
if (h == 0)
|
||||
return;
|
||||
|
||||
spice_return_if_fail(stride < 0);
|
||||
|
||||
uint8_t *dest = line_0 + (area->top * stride) + area->left * sizeof(uint32_t);
|
||||
dest += (h - 1) * stride;
|
||||
canvas->ops->read_bits(canvas, dest, -stride, area);
|
||||
}
|
||||
|
||||
/*
|
||||
* Renders drawables for updating the requested area, but only drawables that are older
|
||||
* than 'last' (exclusive).
|
||||
* FIXME: merge with display_channel_draw()?
|
||||
*/
|
||||
void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
|
||||
Drawable *last)
|
||||
{
|
||||
RedSurface *surface;
|
||||
Drawable *surface_last = NULL;
|
||||
Ring *ring;
|
||||
RingItem *ring_item;
|
||||
Drawable *now;
|
||||
QRegion rgn;
|
||||
|
||||
spice_assert(last);
|
||||
spice_assert(ring_item_is_linked(&last->list_link));
|
||||
|
||||
surface = &display->surfaces[surface_id];
|
||||
|
||||
if (surface_id != last->surface_id) {
|
||||
// find the nearest older drawable from the appropriate surface
|
||||
ring = &display->current_list;
|
||||
ring_item = &last->list_link;
|
||||
while ((ring_item = ring_next(ring, ring_item))) {
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
|
||||
if (now->surface_id == surface_id) {
|
||||
surface_last = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ring_item = ring_next(&surface->current_list, &last->surface_list_link);
|
||||
if (ring_item) {
|
||||
surface_last = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
}
|
||||
}
|
||||
|
||||
if (!surface_last) {
|
||||
return;
|
||||
}
|
||||
|
||||
ring = &surface->current_list;
|
||||
ring_item = &surface_last->surface_list_link;
|
||||
|
||||
region_init(&rgn);
|
||||
region_add(&rgn, area);
|
||||
|
||||
// find the first older drawable that intersects with the area
|
||||
do {
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
if (region_intersects(&rgn, &now->tree_item.base.rgn)) {
|
||||
surface_last = now;
|
||||
break;
|
||||
}
|
||||
} while ((ring_item = ring_next(ring, ring_item)));
|
||||
|
||||
region_destroy(&rgn);
|
||||
|
||||
if (!surface_last) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Container *container;
|
||||
|
||||
ring_item = ring_get_tail(&surface->current_list);
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
now->refs++;
|
||||
container = now->tree_item.base.container;
|
||||
current_remove_drawable(display, now);
|
||||
container_cleanup(container);
|
||||
/* drawable_draw may call display_channel_draw for the surfaces 'now' depends on. Notice,
|
||||
that it is valid to call display_channel_draw in this case and not display_channel_draw_till:
|
||||
It is impossible that there was newer item then 'last' in one of the surfaces
|
||||
that display_channel_draw is called for, Otherwise, 'now' would have already been rendered.
|
||||
See the call for red_handle_depends_on_target_surface in red_process_draw */
|
||||
drawable_draw(display, now);
|
||||
display_channel_drawable_unref(display, now);
|
||||
} while (now != surface_last);
|
||||
surface_update_dest(surface, area);
|
||||
}
|
||||
|
||||
void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int surface_id)
|
||||
{
|
||||
RedSurface *surface;
|
||||
Ring *ring;
|
||||
RingItem *ring_item;
|
||||
QRegion rgn;
|
||||
Drawable *last;
|
||||
Drawable *now;
|
||||
spice_debug("surface %d: area ==>", surface_id);
|
||||
rect_debug(area);
|
||||
|
||||
spice_return_if_fail(surface_id >= 0 && surface_id < NUM_SURFACES);
|
||||
spice_return_if_fail(area);
|
||||
spice_return_if_fail(area->left >= 0 && area->top >= 0 &&
|
||||
area->left < area->right && area->top < area->bottom);
|
||||
|
||||
surface = &display->surfaces[surface_id];
|
||||
|
||||
last = NULL;
|
||||
ring = &surface->current_list;
|
||||
ring_item = ring;
|
||||
|
||||
region_init(&rgn);
|
||||
region_add(&rgn, area);
|
||||
while ((ring_item = ring_next(ring, ring_item))) {
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
if (region_intersects(&rgn, &now->tree_item.base.rgn)) {
|
||||
last = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
region_destroy(&rgn);
|
||||
|
||||
if (!last) {
|
||||
surface_update_dest(surface, area);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Container *container;
|
||||
|
||||
ring_item = ring_get_tail(&surface->current_list);
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
now->refs++;
|
||||
container = now->tree_item.base.container;
|
||||
current_remove_drawable(display, now);
|
||||
container_cleanup(container);
|
||||
drawable_draw(display, now);
|
||||
display_channel_drawable_unref(display, now);
|
||||
} while (now != last);
|
||||
surface_update_dest(surface, area);
|
||||
}
|
||||
|
||||
@ -936,161 +936,6 @@ static void image_surface_init(DisplayChannel *display)
|
||||
display->image_surfaces.ops = &image_surfaces_ops;
|
||||
}
|
||||
|
||||
static void surface_update_dest(RedSurface *surface, const SpiceRect *area)
|
||||
{
|
||||
SpiceCanvas *canvas = surface->context.canvas;
|
||||
int stride = surface->context.stride;
|
||||
uint8_t *line_0 = surface->context.line_0;
|
||||
|
||||
if (surface->context.canvas_draws_on_surface)
|
||||
return;
|
||||
|
||||
int h = area->bottom - area->top;
|
||||
if (h == 0)
|
||||
return;
|
||||
|
||||
spice_return_if_fail(stride < 0);
|
||||
|
||||
uint8_t *dest = line_0 + (area->top * stride) + area->left * sizeof(uint32_t);
|
||||
dest += (h - 1) * stride;
|
||||
canvas->ops->read_bits(canvas, dest, -stride, area);
|
||||
}
|
||||
|
||||
/*
|
||||
Renders drawables for updating the requested area, but only drawables that are older
|
||||
than 'last' (exclusive).
|
||||
*/
|
||||
void display_channel_draw_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
|
||||
Drawable *last)
|
||||
{
|
||||
RedSurface *surface;
|
||||
Drawable *surface_last = NULL;
|
||||
Ring *ring;
|
||||
RingItem *ring_item;
|
||||
Drawable *now;
|
||||
QRegion rgn;
|
||||
|
||||
spice_assert(last);
|
||||
spice_assert(ring_item_is_linked(&last->list_link));
|
||||
|
||||
surface = &display->surfaces[surface_id];
|
||||
|
||||
if (surface_id != last->surface_id) {
|
||||
// find the nearest older drawable from the appropriate surface
|
||||
ring = &display->current_list;
|
||||
ring_item = &last->list_link;
|
||||
while ((ring_item = ring_next(ring, ring_item))) {
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
|
||||
if (now->surface_id == surface_id) {
|
||||
surface_last = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ring_item = ring_next(&surface->current_list, &last->surface_list_link);
|
||||
if (ring_item) {
|
||||
surface_last = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
}
|
||||
}
|
||||
|
||||
if (!surface_last) {
|
||||
return;
|
||||
}
|
||||
|
||||
ring = &surface->current_list;
|
||||
ring_item = &surface_last->surface_list_link;
|
||||
|
||||
region_init(&rgn);
|
||||
region_add(&rgn, area);
|
||||
|
||||
// find the first older drawable that intersects with the area
|
||||
do {
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
if (region_intersects(&rgn, &now->tree_item.base.rgn)) {
|
||||
surface_last = now;
|
||||
break;
|
||||
}
|
||||
} while ((ring_item = ring_next(ring, ring_item)));
|
||||
|
||||
region_destroy(&rgn);
|
||||
|
||||
if (!surface_last) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Container *container;
|
||||
|
||||
ring_item = ring_get_tail(&surface->current_list);
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
now->refs++;
|
||||
container = now->tree_item.base.container;
|
||||
current_remove_drawable(display, now);
|
||||
container_cleanup(container);
|
||||
/* drawable_draw may call display_channel_draw for the surfaces 'now' depends on. Notice,
|
||||
that it is valid to call display_channel_draw in this case and not display_channel_draw_till:
|
||||
It is impossible that there was newer item then 'last' in one of the surfaces
|
||||
that display_channel_draw is called for, Otherwise, 'now' would have already been rendered.
|
||||
See the call for red_handle_depends_on_target_surface in red_process_draw */
|
||||
drawable_draw(display, now);
|
||||
display_channel_drawable_unref(display, now);
|
||||
} while (now != surface_last);
|
||||
surface_update_dest(surface, area);
|
||||
}
|
||||
|
||||
void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int surface_id)
|
||||
{
|
||||
RedSurface *surface;
|
||||
Ring *ring;
|
||||
RingItem *ring_item;
|
||||
QRegion rgn;
|
||||
Drawable *last;
|
||||
Drawable *now;
|
||||
spice_debug("surface %d: area ==>", surface_id);
|
||||
rect_debug(area);
|
||||
|
||||
spice_return_if_fail(surface_id >= 0 && surface_id < NUM_SURFACES);
|
||||
spice_return_if_fail(area);
|
||||
spice_return_if_fail(area->left >= 0 && area->top >= 0 &&
|
||||
area->left < area->right && area->top < area->bottom);
|
||||
|
||||
surface = &display->surfaces[surface_id];
|
||||
|
||||
last = NULL;
|
||||
ring = &surface->current_list;
|
||||
ring_item = ring;
|
||||
|
||||
region_init(&rgn);
|
||||
region_add(&rgn, area);
|
||||
while ((ring_item = ring_next(ring, ring_item))) {
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
if (region_intersects(&rgn, &now->tree_item.base.rgn)) {
|
||||
last = now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
region_destroy(&rgn);
|
||||
|
||||
if (!last) {
|
||||
surface_update_dest(surface, area);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Container *container;
|
||||
|
||||
ring_item = ring_get_tail(&surface->current_list);
|
||||
now = SPICE_CONTAINEROF(ring_item, Drawable, surface_list_link);
|
||||
now->refs++;
|
||||
container = now->tree_item.base.container;
|
||||
current_remove_drawable(display, now);
|
||||
container_cleanup(container);
|
||||
drawable_draw(display, now);
|
||||
display_channel_drawable_unref(display, now);
|
||||
} while (now != last);
|
||||
surface_update_dest(surface, area);
|
||||
}
|
||||
|
||||
static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
|
||||
{
|
||||
QXLCommandExt ext_cmd;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user