worker: move more stream functions

Acked-by: Fabiano Fidêncio <fidencio@redhat.com>
This commit is contained in:
Marc-André Lureau 2013-10-01 16:53:31 +02:00 committed by Frediano Ziglio
parent c26a825451
commit d9b17bbebb
6 changed files with 180 additions and 176 deletions

View File

@ -43,6 +43,20 @@ static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
return create;
}
int dcc_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
{
DrawablePipeItem *dpi;
RingItem *dpi_link, *dpi_next;
DRAWABLE_FOREACH_DPI_SAFE(drawable, dpi_link, dpi_next, dpi) {
if (dpi->dcc == dcc) {
return TRUE;
}
}
return FALSE;
}
/*
* 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.

View File

@ -203,6 +203,8 @@ void dcc_send_item (DisplayCha
PipeItem *item);
int dcc_clear_surface_drawables_from_pipe (DisplayChannelClient *dcc,
int surface_id, int force);
int dcc_drawable_is_in_pipe (DisplayChannelClient *dcc,
Drawable *drawable);
typedef struct compress_send_data_t {
void* comp_buf;

View File

@ -448,7 +448,6 @@ static inline void draw_depend_on_me(DisplayChannel *display, uint32_t surface_i
void current_remove_drawable(DisplayChannel *display, Drawable *item);
void red_pipes_remove_drawable(Drawable *drawable);
void current_remove(DisplayChannel *display, TreeItem *item);
void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
void current_remove_all(DisplayChannel *display, int surface_id);
#endif /* DISPLAY_CHANNEL_H_ */

View File

@ -329,166 +329,6 @@ void current_remove_all(DisplayChannel *display, int surface_id)
}
}
static int red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
{
DrawablePipeItem *dpi;
RingItem *dpi_link, *dpi_next;
DRAWABLE_FOREACH_DPI_SAFE(drawable, dpi_link, dpi_next, dpi) {
if (dpi->dcc == dcc) {
return TRUE;
}
}
return FALSE;
}
/*
* after dcc_detach_stream_gracefully is called for all the display channel clients,
* detach_stream should be called. See comment (1).
*/
static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
Stream *stream,
Drawable *update_area_limit)
{
DisplayChannel *display = DCC_TO_DC(dcc);
int stream_id = get_stream_id(display, stream);
StreamAgent *agent = &dcc->stream_agents[stream_id];
/* stopping the client from playing older frames at once*/
region_clear(&agent->clip);
dcc_stream_agent_clip(dcc, agent);
if (region_is_empty(&agent->vis_region)) {
spice_debug("stream %d: vis region empty", stream_id);
return;
}
if (stream->current &&
region_contains(&stream->current->tree_item.base.rgn, &agent->vis_region)) {
RedChannel *channel;
RedChannelClient *rcc;
UpgradeItem *upgrade_item;
int n_rects;
/* (1) The caller should detach the drawable from the stream. This will
* lead to sending the drawable losslessly, as an ordinary drawable. */
if (red_display_drawable_is_in_pipe(dcc, stream->current)) {
spice_debug("stream %d: upgrade by linked drawable. sized %d, box ==>",
stream_id, stream->current->sized_stream != NULL);
rect_debug(&stream->current->red_drawable->bbox);
goto clear_vis_region;
}
spice_debug("stream %d: upgrade by drawable. sized %d, box ==>",
stream_id, stream->current->sized_stream != NULL);
rect_debug(&stream->current->red_drawable->bbox);
rcc = RED_CHANNEL_CLIENT(dcc);
channel = rcc->channel;
upgrade_item = spice_new(UpgradeItem, 1);
upgrade_item->refs = 1;
red_channel_pipe_item_init(channel,
&upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
upgrade_item->drawable = stream->current;
upgrade_item->drawable->refs++;
n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
upgrade_item->rects->num_rects = n_rects;
region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
upgrade_item->rects->rects, n_rects);
red_channel_client_pipe_add(rcc, &upgrade_item->base);
} else {
SpiceRect upgrade_area;
region_extents(&agent->vis_region, &upgrade_area);
spice_debug("stream %d: upgrade by screenshot. has current %d. box ==>",
stream_id, stream->current != NULL);
rect_debug(&upgrade_area);
if (update_area_limit) {
display_channel_draw_until(DCC_TO_DC(dcc), &upgrade_area, 0, update_area_limit);
} else {
display_channel_draw(DCC_TO_DC(dcc), &upgrade_area, 0);
}
dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
}
clear_vis_region:
region_clear(&agent->vis_region);
}
static void detach_stream_gracefully(DisplayChannel *display, Stream *stream,
Drawable *update_area_limit)
{
RingItem *item, *next;
DisplayChannelClient *dcc;
FOREACH_DCC(display, item, next, dcc) {
dcc_detach_stream_gracefully(dcc, stream, update_area_limit);
}
if (stream->current) {
detach_stream(display, stream, TRUE);
}
}
/*
* region : a primary surface region. Streams that intersects with the given
* region will be detached.
* drawable: If detaching the stream is triggered by the addition of a new drawable
* that is dependent on the given region, and the drawable is already a part
* of the "current tree", the drawable parameter should be set with
* this drawable, otherwise, it should be NULL. Then, if detaching the stream
* involves sending an upgrade image to the client, this drawable won't be rendered
* (see dcc_detach_stream_gracefully).
*/
void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable)
{
Ring *ring = &display->streams;
RingItem *item = ring_get_head(ring);
RingItem *dcc_ring_item, *next;
DisplayChannelClient *dcc;
bool is_connected = red_channel_is_connected(RED_CHANNEL(display));
while (item) {
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
int detach = 0;
item = ring_next(ring, item);
FOREACH_DCC(display, dcc_ring_item, next, dcc) {
StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)];
if (region_intersects(&agent->vis_region, region)) {
dcc_detach_stream_gracefully(dcc, stream, drawable);
detach = 1;
spice_debug("stream %d", get_stream_id(display, stream));
}
}
if (detach && stream->current) {
detach_stream(display, stream, TRUE);
} else if (!is_connected) {
if (stream->current &&
region_intersects(&stream->current->tree_item.base.rgn, region)) {
detach_stream(display, stream, TRUE);
}
}
}
}
static void display_channel_streams_timeout(DisplayChannel *display)
{
Ring *ring = &display->streams;
RingItem *item;
red_time_t now = red_get_monotonic_time();
item = ring_get_head(ring);
while (item) {
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
item = ring_next(ring, item);
if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) {
detach_stream_gracefully(display, stream, NULL);
stream_stop(display, stream);
}
}
}
static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area,
uint8_t *dest, int dest_stride, int update)
{
@ -3381,19 +3221,6 @@ void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
red_channel_apply_clients(channel, red_channel_client_disconnect);
}
static void detach_and_stop_streams(DisplayChannel *display)
{
RingItem *stream_item;
spice_debug(NULL);
while ((stream_item = ring_get_head(&display->streams))) {
Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
detach_stream_gracefully(display, stream, NULL);
stream_stop(display, stream);
}
}
static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
{
/* We need to stop the streams, and to send upgrade_items to the client.
@ -3406,7 +3233,7 @@ static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
* Notice that detach_and_stop_streams won't lead to any dev ram changes, since
* handle_dev_stop already took care of releasing all the dev ram resources.
*/
detach_and_stop_streams(display);
stream_detach_and_stop(display);
if (red_channel_client_is_connected(rcc)) {
red_channel_client_default_migrate(rcc);
}
@ -4701,7 +4528,7 @@ SPICE_GNUC_NORETURN static void *red_worker_main(void *arg)
timeout = display_channel_get_streams_timeout(worker->display_channel);
worker->event_timeout = MIN(timeout, worker->event_timeout);
num_events = poll(worker->poll_fds, MAX_EVENT_SOURCES, worker->event_timeout);
display_channel_streams_timeout(worker->display_channel);
stream_timeout(worker->display_channel);
spice_timer_queue_cb();
if (worker->display_channel) {

View File

@ -740,3 +740,162 @@ void stream_agent_stop(StreamAgent *agent)
agent->mjpeg_encoder = NULL;
}
}
/*
* after dcc_detach_stream_gracefully is called for all the display channel clients,
* detach_stream should be called. See comment (1).
*/
static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
Stream *stream,
Drawable *update_area_limit)
{
DisplayChannel *display = DCC_TO_DC(dcc);
int stream_id = get_stream_id(display, stream);
StreamAgent *agent = &dcc->stream_agents[stream_id];
/* stopping the client from playing older frames at once*/
region_clear(&agent->clip);
dcc_stream_agent_clip(dcc, agent);
if (region_is_empty(&agent->vis_region)) {
spice_debug("stream %d: vis region empty", stream_id);
return;
}
if (stream->current &&
region_contains(&stream->current->tree_item.base.rgn, &agent->vis_region)) {
RedChannel *channel;
RedChannelClient *rcc;
UpgradeItem *upgrade_item;
int n_rects;
/* (1) The caller should detach the drawable from the stream. This will
* lead to sending the drawable losslessly, as an ordinary drawable. */
if (dcc_drawable_is_in_pipe(dcc, stream->current)) {
spice_debug("stream %d: upgrade by linked drawable. sized %d, box ==>",
stream_id, stream->current->sized_stream != NULL);
rect_debug(&stream->current->red_drawable->bbox);
goto clear_vis_region;
}
spice_debug("stream %d: upgrade by drawable. sized %d, box ==>",
stream_id, stream->current->sized_stream != NULL);
rect_debug(&stream->current->red_drawable->bbox);
rcc = RED_CHANNEL_CLIENT(dcc);
channel = rcc->channel;
upgrade_item = spice_new(UpgradeItem, 1);
upgrade_item->refs = 1;
red_channel_pipe_item_init(channel,
&upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
upgrade_item->drawable = stream->current;
upgrade_item->drawable->refs++;
n_rects = pixman_region32_n_rects(&upgrade_item->drawable->tree_item.base.rgn);
upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
upgrade_item->rects->num_rects = n_rects;
region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
upgrade_item->rects->rects, n_rects);
red_channel_client_pipe_add(rcc, &upgrade_item->base);
} else {
SpiceRect upgrade_area;
region_extents(&agent->vis_region, &upgrade_area);
spice_debug("stream %d: upgrade by screenshot. has current %d. box ==>",
stream_id, stream->current != NULL);
rect_debug(&upgrade_area);
if (update_area_limit) {
display_channel_draw_until(DCC_TO_DC(dcc), &upgrade_area, 0, update_area_limit);
} else {
display_channel_draw(DCC_TO_DC(dcc), &upgrade_area, 0);
}
dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
}
clear_vis_region:
region_clear(&agent->vis_region);
}
static void detach_stream_gracefully(DisplayChannel *display, Stream *stream,
Drawable *update_area_limit)
{
RingItem *item, *next;
DisplayChannelClient *dcc;
FOREACH_DCC(display, item, next, dcc) {
dcc_detach_stream_gracefully(dcc, stream, update_area_limit);
}
if (stream->current) {
detach_stream(display, stream, TRUE);
}
}
/*
* region : a primary surface region. Streams that intersects with the given
* region will be detached.
* drawable: If detaching the stream is triggered by the addition of a new drawable
* that is dependent on the given region, and the drawable is already a part
* of the "current tree", the drawable parameter should be set with
* this drawable, otherwise, it should be NULL. Then, if detaching the stream
* involves sending an upgrade image to the client, this drawable won't be rendered
* (see dcc_detach_stream_gracefully).
*/
void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable)
{
Ring *ring = &display->streams;
RingItem *item = ring_get_head(ring);
RingItem *dcc_ring_item, *next;
DisplayChannelClient *dcc;
bool is_connected = red_channel_is_connected(RED_CHANNEL(display));
while (item) {
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
int detach = 0;
item = ring_next(ring, item);
FOREACH_DCC(display, dcc_ring_item, next, dcc) {
StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)];
if (region_intersects(&agent->vis_region, region)) {
dcc_detach_stream_gracefully(dcc, stream, drawable);
detach = 1;
spice_debug("stream %d", get_stream_id(display, stream));
}
}
if (detach && stream->current) {
detach_stream(display, stream, TRUE);
} else if (!is_connected) {
if (stream->current &&
region_intersects(&stream->current->tree_item.base.rgn, region)) {
detach_stream(display, stream, TRUE);
}
}
}
}
void stream_detach_and_stop(DisplayChannel *display)
{
RingItem *stream_item;
spice_debug(NULL);
while ((stream_item = ring_get_head(&display->streams))) {
Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
detach_stream_gracefully(display, stream, NULL);
stream_stop(display, stream);
}
}
void stream_timeout(DisplayChannel *display)
{
Ring *ring = &display->streams;
RingItem *item;
red_time_t now = red_get_monotonic_time();
item = ring_get_head(ring);
while (item) {
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
item = ring_next(ring, item);
if (now >= (stream->last_time + RED_STREAM_TIMEOUT)) {
detach_stream_gracefully(display, stream, NULL);
stream_stop(display, stream);
}
}
}

View File

@ -148,6 +148,8 @@ void stream_trace_update (DisplayChan
void stream_maintenance (DisplayChannel *display,
Drawable *candidate,
Drawable *prev);
void stream_timeout (DisplayChannel *display);
void stream_detach_and_stop (DisplayChannel *display);
void stream_agent_unref (DisplayChannel *display,
StreamAgent *agent);
@ -155,5 +157,6 @@ void stream_agent_stats_print (StreamAgent
void stream_agent_stop (StreamAgent *agent);
void detach_stream(DisplayChannel *display, Stream *stream, int detach_sized);
void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable);
#endif /* STREAM_H */