mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-08-10 03:47:35 +00:00
worker: move destroy_surface() familly
Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
parent
9c828e8553
commit
0ebb539f48
80
server/dcc.c
80
server/dcc.c
@ -22,6 +22,8 @@
|
||||
#include "dcc.h"
|
||||
#include "display-channel.h"
|
||||
|
||||
#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
|
||||
|
||||
static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
|
||||
uint32_t surface_id, uint32_t width,
|
||||
uint32_t height, uint32_t format, uint32_t flags)
|
||||
@ -41,6 +43,84 @@ static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
|
||||
return create;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return: TRUE if wait_if_used == FALSE, or otherwise, if all of the pipe items that
|
||||
* are related to the surface have been cleared (or sent) from the pipe.
|
||||
*/
|
||||
int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id,
|
||||
int wait_if_used)
|
||||
{
|
||||
Ring *ring;
|
||||
PipeItem *item;
|
||||
int x;
|
||||
RedChannelClient *rcc;
|
||||
|
||||
spice_return_val_if_fail(dcc != NULL, TRUE);
|
||||
/* removing the newest drawables that their destination is surface_id and
|
||||
no other drawable depends on them */
|
||||
|
||||
rcc = RED_CHANNEL_CLIENT(dcc);
|
||||
ring = &rcc->pipe;
|
||||
item = (PipeItem *) ring;
|
||||
while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
|
||||
Drawable *drawable;
|
||||
DrawablePipeItem *dpi = NULL;
|
||||
int depend_found = FALSE;
|
||||
|
||||
if (item->type == PIPE_ITEM_TYPE_DRAW) {
|
||||
dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
|
||||
drawable = dpi->drawable;
|
||||
} else if (item->type == PIPE_ITEM_TYPE_UPGRADE) {
|
||||
drawable = ((UpgradeItem *)item)->drawable;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drawable->surface_id == surface_id) {
|
||||
PipeItem *tmp_item = item;
|
||||
item = (PipeItem *)ring_prev(ring, (RingItem *)item);
|
||||
red_channel_client_pipe_remove_and_release(rcc, tmp_item);
|
||||
if (!item) {
|
||||
item = (PipeItem *)ring;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = 0; x < 3; ++x) {
|
||||
if (drawable->surface_deps[x] == surface_id) {
|
||||
depend_found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (depend_found) {
|
||||
spice_debug("surface %d dependent item found %p, %p", surface_id, drawable, item);
|
||||
if (wait_if_used) {
|
||||
break;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_if_used) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (item) {
|
||||
return red_channel_client_wait_pipe_item_sent(RED_CHANNEL_CLIENT(dcc), item,
|
||||
DISPLAY_CLIENT_TIMEOUT);
|
||||
} else {
|
||||
/*
|
||||
* in case that the pipe didn't contain any item that is dependent on the surface, but
|
||||
* there is one during sending. Use a shorter timeout, since it is just one item
|
||||
*/
|
||||
return red_channel_client_wait_outgoing_item(RED_CHANNEL_CLIENT(dcc),
|
||||
DISPLAY_CLIENT_SHORT_TIMEOUT);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
|
||||
{
|
||||
DisplayChannel *display;
|
||||
|
||||
@ -201,6 +201,8 @@ void dcc_release_item (DisplayCha
|
||||
int item_pushed);
|
||||
void dcc_send_item (DisplayChannelClient *dcc,
|
||||
PipeItem *item);
|
||||
int dcc_clear_surface_drawables_from_pipe (DisplayChannelClient *dcc,
|
||||
int surface_id, int force);
|
||||
|
||||
typedef struct compress_send_data_t {
|
||||
void* comp_buf;
|
||||
|
||||
@ -1419,6 +1419,73 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su
|
||||
surface_update_dest(surface, area);
|
||||
}
|
||||
|
||||
static void clear_surface_drawables_from_pipes(DisplayChannel *display, int surface_id,
|
||||
int wait_if_used)
|
||||
{
|
||||
RingItem *item, *next;
|
||||
DisplayChannelClient *dcc;
|
||||
|
||||
FOREACH_DCC(display, item, next, dcc) {
|
||||
if (!dcc_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used)) {
|
||||
red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: cleanup/refactor destroy functions */
|
||||
void display_channel_destroy_surface(DisplayChannel *display, uint32_t surface_id)
|
||||
{
|
||||
draw_depend_on_me(display, surface_id);
|
||||
/* note that draw_depend_on_me must be called before current_remove_all.
|
||||
otherwise "current" will hold items that other drawables may depend on, and then
|
||||
current_remove_all will remove them from the pipe. */
|
||||
current_remove_all(display, surface_id);
|
||||
clear_surface_drawables_from_pipes(display, surface_id, FALSE);
|
||||
display_channel_surface_unref(display, surface_id);
|
||||
}
|
||||
|
||||
void display_channel_destroy_surface_wait(DisplayChannel *display, uint32_t surface_id)
|
||||
{
|
||||
if (!validate_surface(display, surface_id))
|
||||
return;
|
||||
if (!display->surfaces[surface_id].context.canvas)
|
||||
return;
|
||||
|
||||
draw_depend_on_me(display, surface_id);
|
||||
/* note that draw_depend_on_me must be called before current_remove_all.
|
||||
otherwise "current" will hold items that other drawables may depend on, and then
|
||||
current_remove_all will remove them from the pipe. */
|
||||
current_remove_all(display, surface_id);
|
||||
clear_surface_drawables_from_pipes(display, surface_id, TRUE);
|
||||
}
|
||||
|
||||
/* called upon device reset */
|
||||
/* TODO: split me*/
|
||||
void display_channel_destroy_surfaces(DisplayChannel *display)
|
||||
{
|
||||
int i;
|
||||
|
||||
spice_debug(NULL);
|
||||
//to handle better
|
||||
for (i = 0; i < NUM_SURFACES; ++i) {
|
||||
if (display->surfaces[i].context.canvas) {
|
||||
display_channel_destroy_surface_wait(display, i);
|
||||
if (display->surfaces[i].context.canvas) {
|
||||
display_channel_surface_unref(display, i);
|
||||
}
|
||||
spice_assert(!display->surfaces[i].context.canvas);
|
||||
}
|
||||
}
|
||||
spice_warn_if_fail(ring_is_empty(&display->streams));
|
||||
|
||||
if (red_channel_is_connected(RED_CHANNEL(display))) {
|
||||
red_channel_pipes_add_type(RED_CHANNEL(display), PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
|
||||
red_pipes_add_verb(RED_CHANNEL(display), SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
|
||||
}
|
||||
|
||||
display_channel_free_glz_drawables(display);
|
||||
}
|
||||
|
||||
static void on_disconnect(RedChannelClient *rcc)
|
||||
{
|
||||
DisplayChannel *display;
|
||||
|
||||
@ -284,6 +284,11 @@ int display_channel_wait_for_migrate_data (DisplayCha
|
||||
void display_channel_flush_all_surfaces (DisplayChannel *display);
|
||||
void display_channel_free_glz_drawables_to_free(DisplayChannel *display);
|
||||
void display_channel_free_glz_drawables (DisplayChannel *display);
|
||||
void display_channel_destroy_surface_wait (DisplayChannel *display,
|
||||
uint32_t surface_id);
|
||||
void display_channel_destroy_surfaces (DisplayChannel *display);
|
||||
void display_channel_destroy_surface (DisplayChannel *display,
|
||||
uint32_t surface_id);
|
||||
|
||||
static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
|
||||
{
|
||||
@ -415,6 +420,21 @@ static inline void region_add_clip_rects(QRegion *rgn, SpiceClipRects *data)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id)
|
||||
{
|
||||
RedSurface *surface;
|
||||
RingItem *ring_item;
|
||||
|
||||
surface = &display->surfaces[surface_id];
|
||||
|
||||
while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
|
||||
Drawable *drawable;
|
||||
DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
|
||||
drawable = depended_item->drawable;
|
||||
display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
|
||||
}
|
||||
}
|
||||
|
||||
void current_remove_drawable(DisplayChannel *display, Drawable *item);
|
||||
void red_pipes_remove_drawable(Drawable *drawable);
|
||||
void current_remove(DisplayChannel *display, TreeItem *item);
|
||||
|
||||
@ -72,8 +72,6 @@
|
||||
#define CMD_RING_POLL_TIMEOUT 10 //milli
|
||||
#define CMD_RING_POLL_RETRIES 200
|
||||
|
||||
#define DISPLAY_CLIENT_SHORT_TIMEOUT 15000000000ULL //nano
|
||||
|
||||
#define MAX_EVENT_SOURCES 20
|
||||
#define INF_EVENT_WAIT ~0
|
||||
|
||||
@ -334,101 +332,6 @@ void current_remove_all(DisplayChannel *display, int surface_id)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return: TRUE if wait_if_used == FALSE, or otherwise, if all of the pipe items that
|
||||
* are related to the surface have been cleared (or sent) from the pipe.
|
||||
*/
|
||||
static int red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id,
|
||||
int wait_if_used)
|
||||
{
|
||||
Ring *ring;
|
||||
PipeItem *item;
|
||||
int x;
|
||||
RedChannelClient *rcc;
|
||||
|
||||
if (!dcc) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* removing the newest drawables that their destination is surface_id and
|
||||
no other drawable depends on them */
|
||||
|
||||
rcc = RED_CHANNEL_CLIENT(dcc);
|
||||
ring = &rcc->pipe;
|
||||
item = (PipeItem *) ring;
|
||||
while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
|
||||
Drawable *drawable;
|
||||
DrawablePipeItem *dpi = NULL;
|
||||
int depend_found = FALSE;
|
||||
|
||||
if (item->type == PIPE_ITEM_TYPE_DRAW) {
|
||||
dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
|
||||
drawable = dpi->drawable;
|
||||
} else if (item->type == PIPE_ITEM_TYPE_UPGRADE) {
|
||||
drawable = ((UpgradeItem *)item)->drawable;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drawable->surface_id == surface_id) {
|
||||
PipeItem *tmp_item = item;
|
||||
item = (PipeItem *)ring_prev(ring, (RingItem *)item);
|
||||
red_channel_client_pipe_remove_and_release(rcc, tmp_item);
|
||||
if (!item) {
|
||||
item = (PipeItem *)ring;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = 0; x < 3; ++x) {
|
||||
if (drawable->surface_deps[x] == surface_id) {
|
||||
depend_found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (depend_found) {
|
||||
spice_debug("surface %d dependent item found %p, %p", surface_id, drawable, item);
|
||||
if (wait_if_used) {
|
||||
break;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_if_used) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (item) {
|
||||
return red_channel_client_wait_pipe_item_sent(RED_CHANNEL_CLIENT(dcc), item,
|
||||
DISPLAY_CLIENT_TIMEOUT);
|
||||
} else {
|
||||
/*
|
||||
* in case that the pipe didn't contain any item that is dependent on the surface, but
|
||||
* there is one during sending. Use a shorter timeout, since it is just one item
|
||||
*/
|
||||
return red_channel_client_wait_outgoing_item(RED_CHANNEL_CLIENT(dcc),
|
||||
DISPLAY_CLIENT_SHORT_TIMEOUT);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void red_clear_surface_drawables_from_pipes(DisplayChannel *display,
|
||||
int surface_id,
|
||||
int wait_if_used)
|
||||
{
|
||||
RingItem *item, *next;
|
||||
DisplayChannelClient *dcc;
|
||||
|
||||
FOREACH_DCC(display, item, next, dcc) {
|
||||
if (!red_clear_surface_drawables_from_pipe(dcc, surface_id, wait_if_used)) {
|
||||
red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
|
||||
{
|
||||
DrawablePipeItem *dpi;
|
||||
@ -697,23 +600,6 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
|
||||
return drawable;
|
||||
}
|
||||
|
||||
static inline int red_handle_depends_on_target_surface(DisplayChannel *display, uint32_t surface_id)
|
||||
{
|
||||
RedSurface *surface;
|
||||
RingItem *ring_item;
|
||||
|
||||
surface = &display->surfaces[surface_id];
|
||||
|
||||
while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
|
||||
Drawable *drawable;
|
||||
DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item);
|
||||
drawable = depended_item->drawable;
|
||||
display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void add_to_surface_dependency(DisplayChannel *display, int depend_on_surface_id,
|
||||
DependItem *depend_item, Drawable *drawable)
|
||||
{
|
||||
@ -812,9 +698,7 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!red_handle_depends_on_target_surface(worker->display_channel, surface_id)) {
|
||||
goto cleanup;
|
||||
}
|
||||
draw_depend_on_me(display, surface_id);
|
||||
|
||||
if (!red_handle_surfaces_dependencies(worker->display_channel, drawable)) {
|
||||
goto cleanup;
|
||||
@ -870,16 +754,10 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
|
||||
break;
|
||||
}
|
||||
set_surface_release_info(&red_surface->destroy, surface->release_info, group_id);
|
||||
red_handle_depends_on_target_surface(display, surface_id);
|
||||
/* note that red_handle_depends_on_target_surface must be called before current_remove_all.
|
||||
otherwise "current" will hold items that other drawables may depend on, and then
|
||||
current_remove_all will remove them from the pipe. */
|
||||
current_remove_all(display, surface_id);
|
||||
red_clear_surface_drawables_from_pipes(display, surface_id, FALSE);
|
||||
display_channel_surface_unref(display, surface_id);
|
||||
display_channel_destroy_surface(display, surface_id);
|
||||
break;
|
||||
default:
|
||||
spice_error("unknown surface command");
|
||||
spice_warn_if_reached();
|
||||
};
|
||||
exit:
|
||||
red_put_surface_cmd(surface);
|
||||
@ -4119,21 +3997,6 @@ static void handle_dev_del_memslot(void *opaque, void *payload)
|
||||
red_memslot_info_del_slot(&worker->mem_slots, slot_group_id, slot_id);
|
||||
}
|
||||
|
||||
void display_channel_destroy_surface_wait(DisplayChannel *display, int surface_id)
|
||||
{
|
||||
if (!validate_surface(display, surface_id))
|
||||
return;
|
||||
if (!display->surfaces[surface_id].context.canvas)
|
||||
return;
|
||||
|
||||
red_handle_depends_on_target_surface(display, surface_id);
|
||||
/* note that red_handle_depends_on_target_surface must be called before current_remove_all.
|
||||
otherwise "current" will hold items that other drawables may depend on, and then
|
||||
current_remove_all will remove them from the pipe. */
|
||||
current_remove_all(display, surface_id);
|
||||
red_clear_surface_drawables_from_pipes(display, surface_id, TRUE);
|
||||
}
|
||||
|
||||
static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
|
||||
{
|
||||
RedWorkerMessageDestroySurfaceWait *msg = payload;
|
||||
@ -4145,34 +4008,6 @@ static void handle_dev_destroy_surface_wait(void *opaque, void *payload)
|
||||
display_channel_destroy_surface_wait(worker->display_channel, msg->surface_id);
|
||||
}
|
||||
|
||||
/* called upon device reset */
|
||||
|
||||
/* TODO: split me*/
|
||||
void display_channel_destroy_surfaces(DisplayChannel *display)
|
||||
{
|
||||
int i;
|
||||
|
||||
spice_debug(NULL);
|
||||
//to handle better
|
||||
for (i = 0; i < NUM_SURFACES; ++i) {
|
||||
if (display->surfaces[i].context.canvas) {
|
||||
display_channel_destroy_surface_wait(display, i);
|
||||
if (display->surfaces[i].context.canvas) {
|
||||
display_channel_surface_unref(display, i);
|
||||
}
|
||||
spice_assert(!display->surfaces[i].context.canvas);
|
||||
}
|
||||
}
|
||||
spice_warn_if_fail(ring_is_empty(&display->streams));
|
||||
|
||||
if (red_channel_is_connected(RED_CHANNEL(display))) {
|
||||
red_channel_pipes_add_type(RED_CHANNEL(display), PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
|
||||
red_pipes_add_verb(RED_CHANNEL(display), SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
|
||||
}
|
||||
|
||||
display_channel_free_glz_drawables(display);
|
||||
}
|
||||
|
||||
static void handle_dev_destroy_surfaces(void *opaque, void *payload)
|
||||
{
|
||||
RedWorker *worker = opaque;
|
||||
@ -4738,6 +4573,8 @@ static void register_callbacks(Dispatcher *dispatcher)
|
||||
dispatcher_register_async_done_callback(
|
||||
dispatcher,
|
||||
worker_handle_dispatcher_async_done);
|
||||
|
||||
/* TODO: register cursor & display specific msg in respective channel files */
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_DISPLAY_CONNECT,
|
||||
handle_dev_display_connect,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user