worker: move destroy_surface() familly

Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
Marc-André Lureau 2013-09-27 17:54:44 +02:00 committed by Frediano Ziglio
parent 9c828e8553
commit 0ebb539f48
5 changed files with 174 additions and 168 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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,