summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2011-04-13 09:24:31 +0300
committerAlon Levy <alevy@redhat.com>2011-08-23 18:02:38 +0300
commit4db9f1d1a9df95e84312f142cf5a0fa233376e21 (patch)
tree9efd2d8c43a2d1ede03132e679530b2029dfda45 /server
parent6a1d65737300627b77bf0c5b813028146e40159b (diff)
downloadspice-4db9f1d1a9df95e84312f142cf5a0fa233376e21.tar.gz
spice-4db9f1d1a9df95e84312f142cf5a0fa233376e21.tar.xz
spice-4db9f1d1a9df95e84312f142cf5a0fa233376e21.zip
server/red_channel: introduce client ring in RedChannel
Also adds Drawable pipes and glz rings. main_channel and red_worker had several locations that still accessed rcc directly, so they had to be touched too, but the changes are minimal. Most changes are in red_channel: drop the single client reference in RedChannel and add a ring of channels. Things missing / not done right in red_worker: * StreamAgents are in DCC - right/wrong? * GlzDict is multiplied - multiple compressions. We still are missing: * remove the disconnect calls on new connections
Diffstat (limited to 'server')
-rw-r--r--server/main_channel.c8
-rw-r--r--server/red_channel.c238
-rw-r--r--server/red_channel.h17
-rw-r--r--server/red_worker.c875
4 files changed, 811 insertions, 327 deletions
diff --git a/server/main_channel.c b/server/main_channel.c
index 1c801051..3337c469 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -165,15 +165,13 @@ static void main_disconnect(MainChannel *main_chan)
red_channel_destroy(&main_chan->base);
}
-#define MAIN_FOREACH(_link, _main, _mcc) \
- if ((_main) && ((_mcc) = \
- SPICE_CONTAINEROF((_main)->base.rcc, MainChannelClient, base)))
-
RedClient *main_channel_get_client_by_link_id(MainChannel *main_chan, uint32_t connection_id)
{
+ RingItem *link;
MainChannelClient *mcc;
- MAIN_FOREACH(link, main_chan, mcc) {
+ RING_FOREACH(link, &main_chan->base.clients) {
+ mcc = SPICE_CONTAINEROF(link, MainChannelClient, base.channel_link);
if (mcc->connection_id == connection_id) {
return mcc->base.client;
}
diff --git a/server/red_channel.c b/server/red_channel.c
index eb00aba1..b5a0330e 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include "ring.h"
#include "stat.h"
#include "red_channel.h"
#include "generated_marshallers.h"
@@ -159,7 +160,14 @@ void red_channel_client_receive(RedChannelClient *rcc)
void red_channel_receive(RedChannel *channel)
{
- red_channel_client_receive(channel->rcc);
+ RingItem *link;
+ RingItem *next;
+ RedChannelClient *rcc;
+
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ red_channel_client_receive(rcc);
+ }
}
static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
@@ -358,8 +366,8 @@ static void red_channel_client_pipe_remove(RedChannelClient *rcc, PipeItem *item
static void red_channel_add_client(RedChannel *channel, RedChannelClient *rcc)
{
- ASSERT(rcc && !channel->rcc);
- channel->rcc = rcc;
+ ASSERT(rcc);
+ ring_add(&channel->clients, &rcc->channel_link);
channel->clients_num++;
}
@@ -442,6 +450,7 @@ RedChannel *red_channel_create(int size,
channel->core = core;
channel->migrate = migrate;
+ ring_init(&channel->clients);
channel->incoming_cb.alloc_msg_buf = (alloc_msg_recv_buf_proc)alloc_recv_buf;
channel->incoming_cb.release_msg_buf = (release_msg_recv_buf_proc)release_recv_buf;
@@ -511,12 +520,16 @@ void red_channel_client_destroy(RedChannelClient *rcc)
void red_channel_destroy(RedChannel *channel)
{
+ RingItem *link;
+ RingItem *next;
+
if (!channel) {
return;
}
red_channel_pipes_clear(channel);
- if (channel->rcc) {
- red_channel_client_destroy(channel->rcc);
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ red_channel_client_destroy(
+ SPICE_CONTAINEROF(link, RedChannelClient, channel_link));
}
free(channel);
}
@@ -535,8 +548,12 @@ void red_channel_client_shutdown(RedChannelClient *rcc)
void red_channel_shutdown(RedChannel *channel)
{
- if (channel->rcc) {
- red_channel_client_shutdown(channel->rcc);
+ RingItem *link;
+ RingItem *next;
+
+ red_printf("%d", channel->clients_num);
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ red_channel_client_shutdown(SPICE_CONTAINEROF(link, RedChannelClient, channel_link));
}
red_channel_pipes_clear(channel);
}
@@ -548,8 +565,11 @@ void red_channel_client_send(RedChannelClient *rcc)
void red_channel_send(RedChannel *channel)
{
- if (channel->rcc) {
- red_channel_client_send(channel->rcc);
+ RingItem *link;
+ RingItem *next;
+
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ red_channel_client_send(SPICE_CONTAINEROF(link, RedChannelClient, channel_link));
}
}
@@ -586,7 +606,7 @@ void red_channel_client_push(RedChannelClient *rcc)
red_channel_client_send(rcc);
}
- if (rcc->send_data.item && !rcc->send_data.blocked) {
+ if (!red_channel_client_no_item_being_sent(rcc) && !rcc->send_data.blocked) {
rcc->send_data.blocked = TRUE;
red_printf("ERROR: an item waiting to be sent and not blocked");
}
@@ -599,10 +619,21 @@ void red_channel_client_push(RedChannelClient *rcc)
void red_channel_push(RedChannel *channel)
{
- if (!channel || !channel->rcc) {
+ RingItem *link;
+ RingItem *next;
+ RedChannelClient *rcc;
+
+ if (!channel) {
return;
}
- red_channel_client_push(channel->rcc);
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ if (rcc->stream == NULL) {
+ rcc->channel->disconnect(rcc);
+ } else {
+ red_channel_client_push(rcc);
+ }
+ }
}
static void red_channel_client_init_outgoing_messages_window(RedChannelClient *rcc)
@@ -615,8 +646,12 @@ static void red_channel_client_init_outgoing_messages_window(RedChannelClient *r
// specific
void red_channel_init_outgoing_messages_window(RedChannel *channel)
{
- if (channel->rcc) {
- red_channel_client_init_outgoing_messages_window(channel->rcc);
+ RingItem *link;
+ RingItem *next;
+
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ red_channel_client_init_outgoing_messages_window(
+ SPICE_CONTAINEROF(link, RedChannelClient, channel_link));
}
}
@@ -790,8 +825,12 @@ void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type)
void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type)
{
- if (channel->rcc) {
- red_channel_client_pipe_add_type(channel->rcc, pipe_item_type);
+ RingItem *link;
+
+ RING_FOREACH(link, &channel->clients) {
+ red_channel_client_pipe_add_type(
+ SPICE_CONTAINEROF(link, RedChannelClient, channel_link),
+ pipe_item_type);
}
}
@@ -807,7 +846,18 @@ void red_channel_pipe_item_remove(RedChannel *channel, PipeItem *item)
int red_channel_is_connected(RedChannel *channel)
{
- return (channel->rcc != NULL) && red_channel_client_is_connected(channel->rcc);
+ RingItem *link;
+
+ if (!channel || channel->clients_num == 0) {
+ return FALSE;
+ }
+ RING_FOREACH(link, &channel->clients) {
+ if (red_channel_client_is_connected(
+ SPICE_CONTAINEROF(link, RedChannelClient, channel_link))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
}
void red_channel_client_clear_sent_item(RedChannelClient *rcc)
@@ -836,10 +886,17 @@ void red_channel_client_pipe_clear(RedChannelClient *rcc)
void red_channel_pipes_clear(RedChannel *channel)
{
- if (!channel || !channel->rcc) {
+ RingItem *link;
+ RingItem *next;
+ RedChannelClient *rcc;
+
+ if (!channel) {
return;
}
- red_channel_client_pipe_clear(channel->rcc);
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ red_channel_client_pipe_clear(rcc);
+ }
}
void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
@@ -856,8 +913,7 @@ static void red_channel_client_remove(RedChannelClient *rcc)
{
ring_remove(&rcc->client_link);
rcc->client->channels_num--;
- ASSERT(rcc->channel->rcc == rcc);
- rcc->channel->rcc = NULL;
+ ring_remove(&rcc->channel_link);
rcc->channel->clients_num--;
}
@@ -878,46 +934,94 @@ void red_channel_client_disconnect(RedChannelClient *rcc)
void red_channel_disconnect(RedChannel *channel)
{
+ RingItem *link;
+ RingItem *next;
+
red_channel_pipes_clear(channel);
- if (channel->rcc) {
- red_channel_client_disconnect(channel->rcc);
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ red_channel_client_disconnect(
+ SPICE_CONTAINEROF(link, RedChannelClient, channel_link));
}
}
int red_channel_all_clients_serials_are_zero(RedChannel *channel)
{
- return (!channel->rcc || channel->rcc->send_data.serial == 0);
+ RingItem *link;
+ RedChannelClient *rcc;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ if (rcc->send_data.serial != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
}
void red_channel_apply_clients(RedChannel *channel, channel_client_callback cb)
{
- if (channel->rcc) {
- cb(channel->rcc);
+ RingItem *link;
+ RingItem *next;
+ RedChannelClient *rcc;
+
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ cb(rcc);
}
}
void red_channel_apply_clients_data(RedChannel *channel, channel_client_callback_data cb, void *data)
{
- if (channel->rcc) {
- cb(channel->rcc, data);
+ RingItem *link;
+ RingItem *next;
+ RedChannelClient *rcc;
+
+ RING_FOREACH_SAFE(link, next, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ cb(rcc, data);
}
}
void red_channel_set_shut(RedChannel *channel)
{
- if (channel->rcc) {
- channel->rcc->incoming.shut = TRUE;
+ RingItem *link;
+ RedChannelClient *rcc;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ rcc->incoming.shut = TRUE;
}
}
int red_channel_all_blocked(RedChannel *channel)
{
- return !channel || !channel->rcc || channel->rcc->send_data.blocked;
+ RingItem *link;
+ RedChannelClient *rcc;
+
+ if (!channel || channel->clients_num == 0) {
+ return FALSE;
+ }
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ if (!rcc->send_data.blocked) {
+ return FALSE;
+ }
+ }
+ return TRUE;
}
int red_channel_any_blocked(RedChannel *channel)
{
- return !channel || !channel->rcc || channel->rcc->send_data.blocked;
+ RingItem *link;
+ RedChannelClient *rcc;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ if (rcc->send_data.blocked) {
+ return TRUE;
+ }
+ }
+ return FALSE;
}
int red_channel_client_blocked(RedChannelClient *rcc)
@@ -954,10 +1058,11 @@ SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc)
int red_channel_get_first_socket(RedChannel *channel)
{
- if (!channel->rcc || !channel->rcc->stream) {
+ if (!channel || channel->clients_num == 0) {
return -1;
}
- return channel->rcc->stream->socket;
+ return SPICE_CONTAINEROF(ring_get_head(&channel->clients),
+ RedChannelClient, channel_link)->stream->socket;
}
int red_channel_client_item_being_sent(RedChannelClient *rcc, PipeItem *item)
@@ -967,12 +1072,30 @@ int red_channel_client_item_being_sent(RedChannelClient *rcc, PipeItem *item)
int red_channel_item_being_sent(RedChannel *channel, PipeItem *item)
{
- return channel->rcc && red_channel_client_item_being_sent(channel->rcc, item);
+ RingItem *link;
+ RedChannelClient *rcc;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ if (rcc->send_data.item == item) {
+ return TRUE;
+ }
+ }
+ return FALSE;
}
int red_channel_no_item_being_sent(RedChannel *channel)
{
- return !channel->rcc || red_channel_client_no_item_being_sent(channel->rcc);
+ RingItem *link;
+ RedChannelClient *rcc;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ if (!red_channel_client_no_item_being_sent(rcc)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
}
int red_channel_client_no_item_being_sent(RedChannelClient *rcc)
@@ -1073,16 +1196,17 @@ static void red_channel_pipes_create_batch(RedChannel *channel,
new_pipe_item_t creator, void *data,
rcc_item_t callback)
{
+ RingItem *link;
RedChannelClient *rcc;
PipeItem *item;
int num = 0;
- if (!(rcc = channel->rcc)) {
- return;
- }
- item = (*creator)(rcc, data, num++);
- if (callback) {
- (*callback)(rcc, item);
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ item = (*creator)(rcc, data, num++);
+ if (callback) {
+ (*callback)(rcc, item);
+ }
}
}
@@ -1108,15 +1232,39 @@ void red_channel_pipes_new_add_tail(RedChannel *channel, new_pipe_item_t creator
uint32_t red_channel_max_pipe_size(RedChannel *channel)
{
- return channel->rcc ? channel->rcc->pipe_size : 0;
+ RingItem *link;
+ RedChannelClient *rcc;
+ uint32_t pipe_size = 0;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ pipe_size = pipe_size > rcc->pipe_size ? pipe_size : rcc->pipe_size;
+ }
+ return pipe_size;
}
uint32_t red_channel_min_pipe_size(RedChannel *channel)
{
- return channel->rcc ? channel->rcc->pipe_size : 0;
+ RingItem *link;
+ RedChannelClient *rcc;
+ uint32_t pipe_size = ~0;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ pipe_size = pipe_size < rcc->pipe_size ? pipe_size : rcc->pipe_size;
+ }
+ return pipe_size == ~0 ? 0 : pipe_size;
}
uint32_t red_channel_sum_pipes_size(RedChannel *channel)
{
- return channel->rcc ? channel->rcc->pipe_size : 0;
+ RingItem *link;
+ RedChannelClient *rcc;
+ uint32_t sum = 0;
+
+ RING_FOREACH(link, &channel->clients) {
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);
+ sum += rcc->pipe_size;
+ }
+ return sum;
}
diff --git a/server/red_channel.h b/server/red_channel.h
index 4b29b0cc..652673b5 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -173,7 +173,7 @@ struct RedChannel {
int migrate;
int handle_acks;
- RedChannelClient *rcc;
+ Ring clients;
uint32_t clients_num;
OutgoingHandlerInterface outgoing_cb;
@@ -200,7 +200,7 @@ struct RedChannel {
};
/* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
- explicitly destroy the channel */
+ * explicitly destroy the channel */
RedChannel *red_channel_create(int size,
SpiceCoreInterface *core,
int migrate, int handle_acks,
@@ -235,6 +235,7 @@ RedChannel *red_channel_create_parser(int size,
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark,
channel_handle_migrate_data_proc handle_migrate_data,
channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial);
+
RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedClient *client,
RedsStream *stream);
@@ -314,8 +315,10 @@ int red_channel_client_send_message_pending(RedChannelClient *rcc);
/* returns TRUE if item is being sent by one of the channel clients. This will
* be true if someone called init_send_data but send has not completed (or perhaps
- * hasn't even begun, i.e. no one called begin_send_)
- * */
+ * hasn't even begun, i.e. no one called begin_send_).
+ * However, note that red_channel_client_init_send_data can also be called with
+ * item==NULL, thus not all pipe items can be tracked.
+ */
int red_channel_item_being_sent(RedChannel *channel, PipeItem *item);
int red_channel_client_item_being_sent(RedChannelClient *rcc, PipeItem *item);
@@ -387,8 +390,10 @@ struct RedClient {
};
RedClient *red_client_new();
-void red_client_destroy(RedClient *client);
-void red_client_set_main(RedClient *client, MainChannelClient *mcc);
MainChannelClient *red_client_get_main(RedClient *client);
+void red_client_set_main(RedClient *client, MainChannelClient *mcc);
+void red_client_destroy(RedClient *client);
+void red_client_disconnect(RedClient *client);
+void red_client_remove_channel(RedClient *client, RedChannelClient *rcc);
#endif
diff --git a/server/red_worker.c b/server/red_worker.c
index cbd90010..4225d0e8 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -530,6 +530,12 @@ typedef struct {
typedef struct RedGlzDrawable RedGlzDrawable;
/* for each qxl drawable, there may be several instances of lz drawables */
+/* TODO - reuse this stuff for the top level. I just added a second level of multiplicity
+ * at the Drawable by keeping a ring, so:
+ * Drawable -> (ring of) RedGlzDrawable -> (up to 2) GlzDrawableInstanceItem
+ * and it should probably (but need to be sure...) be
+ * Drawable -> ring of GlzDrawableInstanceItem.
+ */
typedef struct GlzDrawableInstanceItem {
RingItem glz_link;
RingItem free_link;
@@ -539,6 +545,7 @@ typedef struct GlzDrawableInstanceItem {
struct RedGlzDrawable {
RingItem link; // ordered by the time it was encoded
+ RingItem drawable_link;
RedDrawable *red_drawable;
Drawable *drawable;
uint32_t group_id;
@@ -739,12 +746,20 @@ typedef struct DependItem {
RingItem ring_item;
} DependItem;
+typedef struct DrawablePipeItem {
+ RingItem base; /* link for a list of pipe items held by Drawable */
+ PipeItem dpi_pipe_item; /* link for the client's pipe itself */
+ Drawable *drawable;
+ DisplayChannelClient *dcc;
+ uint8_t refs;
+} DrawablePipeItem;
+
struct Drawable {
uint8_t refs;
RingItem surface_list_link;
RingItem list_link;
DrawItem tree_item;
- PipeItem pipe_item;
+ Ring pipes;
PipeItem *pipe_item_rest;
uint32_t size_pipe_item_rest;
#ifdef UPDATE_AREA_BY_TREE
@@ -752,7 +767,7 @@ struct Drawable {
#endif
RedDrawable *red_drawable;
- RedGlzDrawable *red_glz_drawable;
+ Ring glz_ring;
red_time_t creation_time;
int frames_count;
@@ -989,6 +1004,87 @@ static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
#endif
+/*
+ * Macros to make iterating over stuff easier
+ * The two collections we iterate over:
+ * given a channel, iterate over it's clients
+ */
+
+#define RCC_FOREACH(link, rcc, channel) \
+ for (link = ring_get_head(&(channel)->clients),\
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link);\
+ (link); \
+ (link) = ring_next(&(channel)->clients, link),\
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link))
+
+#define RCC_FOREACH_SAFE(link, next, rcc, channel) \
+ for (link = ring_get_head(&(channel)->clients), \
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link), \
+ (next) = (link) ? ring_next(&(channel)->clients, (link)) : NULL; \
+ (link); \
+ (link) = (next), \
+ (next) = (link) ? ring_next(&(channel)->clients, (link)) : NULL, \
+ rcc = SPICE_CONTAINEROF(link, RedChannelClient, channel_link))
+
+#define DCC_FOREACH(link, dcc, channel) \
+ for (link = channel ? ring_get_head(&(channel)->clients) : NULL,\
+ dcc = link ? SPICE_CONTAINEROF((link), DisplayChannelClient, common.base.channel_link) : NULL;\
+ (link); \
+ (link) = ring_next(&(channel)->clients, link),\
+ dcc = SPICE_CONTAINEROF((link), DisplayChannelClient, common.base.channel_link))
+
+#define WORKER_FOREACH_DCC(worker, link, dcc) \
+ for (link = ((worker) && (worker)->display_channel) ? ring_get_head(&(worker)->display_channel->common.base.clients) : NULL,\
+ dcc = link ? SPICE_CONTAINEROF((link), DisplayChannelClient, common.base.channel_link) : NULL;\
+ (link); \
+ (link) = ring_next(&(worker)->display_channel->common.base.clients, link),\
+ dcc = SPICE_CONTAINEROF((link), DisplayChannelClient, common.base.channel_link))
+
+#define DRAWABLE_FOREACH_DPI(drawable, link, dpi) \
+ for (link = (drawable) ? ring_get_head(&(drawable)->pipes) : NULL,\
+ dpi = (link) ? SPICE_CONTAINEROF((link), DrawablePipeItem, base) : NULL; \
+ (link);\
+ (link) = ring_next(&(drawable)->pipes, (link)),\
+ dpi = (link) ? SPICE_CONTAINEROF((link), DrawablePipeItem, base) : NULL)
+
+#define DRAWABLE_FOREACH_GLZ(drawable, link, glz) \
+ for (link = (drawable) ? ring_get_head(&drawable->glz_ring) : NULL,\
+ glz = (link) ? SPICE_CONTAINEROF((link), RedGlzDrawable, drawable_link) : NULL;\
+ (link);\
+ (link) = ring_next(&drawable->glz_ring, (link)),\
+ glz = (link) ? SPICE_CONTAINEROF((link), RedGlzDrawable, drawable_link) : NULL)
+
+#define DRAWABLE_FOREACH_GLZ_SAFE(drawable, link, next, glz) \
+ for (link = (drawable) ? ring_get_head(&drawable->glz_ring) : NULL,\
+ next = (link) ? ring_next(&drawable->glz_ring, link) : NULL,\
+ glz = (link) ? SPICE_CONTAINEROF((link), RedGlzDrawable, drawable_link) : NULL;\
+ (link);\
+ (link) = (next),\
+ (next) = (link) ? ring_next(&drawable->glz_ring, (link)) : NULL,\
+ glz = (link) ? SPICE_CONTAINEROF((link), RedGlzDrawable, drawable_link) : NULL)
+
+#define CCC_FOREACH(link, ccc, channel) \
+ for (link = ring_get_head(&(channel)->clients),\
+ ccc = SPICE_CONTAINEROF(link, CommonChannelClient, base.channel_link);\
+ (link); \
+ (link) = ring_next(&(channel)->clients, link),\
+ ccc = SPICE_CONTAINEROF(link, CommonChannelClient, base.channel_link))
+
+#define DCC_TO_WORKER(dcc) \
+ (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker)
+
+// TODO: replace with DCC_FOREACH when it is introduced
+#define WORKER_TO_DCC(worker) \
+ (worker->display_channel ? SPICE_CONTAINEROF(worker->display_channel->common.base.rcc, DisplayChannelClient, common.base) : NULL)
+
+#define DCC_TO_DC(dcc) SPICE_CONTAINEROF((dcc)->common.base.channel,\
+ DisplayChannel, common.base)
+
+#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
+#define RCC_TO_CCC(rcc) SPICE_CONTAINEROF((rcc), CursorChannelClient, common.base)
+
+
+
#ifdef COMPRESS_STAT
static void print_compress_stats(DisplayChannel *display_channel)
{
@@ -1189,30 +1285,17 @@ static void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id);
static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id);
+
static void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
{
- RedChannelClient *rcc = channel->rcc;
+ RedChannelClient *rcc;
+ RingItem *link;
- if (!rcc) {
- return;
+ RCC_FOREACH(link, rcc, channel) {
+ red_pipe_add_verb(rcc, verb);
}
- red_pipe_add_verb(rcc, verb);
}
-
-// TODO: replace with FOREACH_DCC when it is introduced
-#define WORKER_TO_DCC(worker) \
- (worker->display_channel ? SPICE_CONTAINEROF(worker->display_channel->common.base.rcc, DisplayChannelClient, common.base) : NULL)
-
-#define DCC_TO_WORKER(dcc) \
- (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker)
-
-#define DCC_TO_DC(dcc) SPICE_CONTAINEROF((dcc)->common.base.channel,\
- DisplayChannel, common.base)
-
-#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
-#define RCC_TO_CCC(rcc) SPICE_CONTAINEROF((rcc), CursorChannelClient, common.base)
-
static inline void red_handle_drawable_surfaces_client_synced(
DisplayChannelClient *dcc, Drawable *drawable)
{
@@ -1254,44 +1337,111 @@ static int cursor_is_connected(RedWorker *worker)
&worker->cursor_channel->common.base));
}
-// TODO: remove red_pipe_add_drawable, replace with red_clients_add_drawable
-static inline void red_pipe_add_drawable(DisplayChannelClient *dcc, Drawable *drawable)
+static void put_drawable_pipe_item(DrawablePipeItem *dpi)
{
- if (!dcc) {
+ RedWorker *worker = DCC_TO_WORKER(dpi->dcc);
+
+ if (--dpi->refs) {
return;
}
- red_handle_drawable_surfaces_client_synced(dcc, drawable);
+ ASSERT(!ring_item_is_linked(&dpi->dpi_pipe_item.link));
+ ASSERT(!ring_item_is_linked(&dpi->base));
+ release_drawable(worker, dpi->drawable);
+ free(dpi);
+}
+
+static inline DrawablePipeItem *get_drawable_pipe_item(DisplayChannelClient *dcc,
+ Drawable *drawable)
+{
+ DrawablePipeItem *dpi;
+ dpi = spice_malloc0(sizeof(*dpi));
+ dpi->drawable = drawable;
+ dpi->dcc = dcc;
+ ring_item_init(&dpi->base);
+ ring_add(&drawable->pipes, &dpi->base);
+ red_channel_pipe_item_init(dcc->common.base.channel, &dpi->dpi_pipe_item, PIPE_ITEM_TYPE_DRAW);
+ dpi->refs++;
drawable->refs++;
- red_channel_client_pipe_add(&dcc->common.base, &drawable->pipe_item);
+ return dpi;
+}
+
+static inline DrawablePipeItem *ref_drawable_pipe_item(DrawablePipeItem *dpi)
+{
+ ASSERT(dpi->drawable);
+ dpi->refs++;
+ return dpi;
+}
+
+static inline void red_pipe_add_drawable(DisplayChannelClient *dcc, Drawable *drawable)
+{
+ DrawablePipeItem *dpi;
+
+ red_handle_drawable_surfaces_client_synced(dcc, drawable);
+ dpi = get_drawable_pipe_item(dcc, drawable);
+ red_channel_client_pipe_add(&dcc->common.base, &dpi->dpi_pipe_item);
+}
+
+static inline void red_pipes_add_drawable(RedWorker *worker, Drawable *drawable)
+{
+ DisplayChannelClient *dcc;
+ RingItem *dcc_ring_item;
+
+ PANIC_ON(!ring_is_empty(&drawable->pipes));
+ WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) {
+ red_pipe_add_drawable(dcc, drawable);
+ }
}
static inline void red_pipe_add_drawable_to_tail(DisplayChannelClient *dcc, Drawable *drawable)
{
+ DrawablePipeItem *dpi;
+
if (!dcc) {
return;
}
red_handle_drawable_surfaces_client_synced(dcc, drawable);
- drawable->refs++;
- red_channel_client_pipe_add_tail(&dcc->common.base, &drawable->pipe_item);
+ dpi = get_drawable_pipe_item(dcc, drawable);
+ red_channel_client_pipe_add_tail(&dcc->common.base, &dpi->dpi_pipe_item);
}
-static inline void red_pipe_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable,
- Drawable *pos_after)
+static inline void red_pipes_add_drawable_after(RedWorker *worker,
+ Drawable *drawable, Drawable *pos_after)
{
- if (!dcc) {
+ DrawablePipeItem *dpi, *dpi_pos_after;
+ RingItem *dpi_link;
+ DisplayChannelClient *dcc;
+ int num_other_linked = 0;
+
+ DRAWABLE_FOREACH_DPI(pos_after, dpi_link, dpi_pos_after) {
+ num_other_linked++;
+ dcc = dpi_pos_after->dcc;
+ red_handle_drawable_surfaces_client_synced(dcc, drawable);
+ dpi = get_drawable_pipe_item(dcc, drawable);
+ red_channel_client_pipe_add_after(&dcc->common.base, &dpi->dpi_pipe_item,
+ &dpi_pos_after->dpi_pipe_item);
+ }
+ if (num_other_linked == 0) {
+ red_pipes_add_drawable(worker, drawable);
return;
}
-
- if (!pos_after || !pipe_item_is_linked(&pos_after->pipe_item)) {
- red_pipe_add_drawable(dcc, drawable);
- return;
+ if (num_other_linked != worker->display_channel->common.base.clients_num) {
+ RingItem *worker_item;
+ red_printf("TODO: not O(n^2)");
+ WORKER_FOREACH_DCC(worker, worker_item, dcc) {
+ int sent = 0;
+ DRAWABLE_FOREACH_DPI(pos_after, dpi_link, dpi_pos_after) {
+ if (dpi_pos_after->dcc == dcc) {
+ sent = 1;
+ break;
+ }
+ }
+ if (!sent) {
+ red_pipe_add_drawable(dcc, drawable);
+ }
+ }
}
- red_handle_drawable_surfaces_client_synced(dcc, drawable);
- drawable->refs++;
- red_channel_client_pipe_add_after(&dcc->common.base, &drawable->pipe_item,
- &pos_after->pipe_item);
}
static inline PipeItem *red_pipe_get_tail(DisplayChannelClient *dcc)
@@ -1305,10 +1455,16 @@ static inline PipeItem *red_pipe_get_tail(DisplayChannelClient *dcc)
static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id);
-static inline void red_pipe_remove_drawable(DisplayChannelClient *dcc, Drawable *drawable)
+static inline void red_pipes_remove_drawable(Drawable *drawable)
{
- if (pipe_item_is_linked(&drawable->pipe_item)) {
- red_channel_client_pipe_remove_and_release(&dcc->common.base, &drawable->pipe_item);
+ DrawablePipeItem *dpi;
+ RingItem *item, *next;
+
+ RING_FOREACH_SAFE(item, next, &drawable->pipes) {
+ dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, base);
+ if (pipe_item_is_linked(&dpi->dpi_pipe_item)) {
+ red_channel_client_pipe_remove_and_release(&dpi->dcc->common.base, &dpi->dpi_pipe_item);
+ }
}
}
@@ -1445,6 +1601,8 @@ static inline void red_destroy_surface_item(RedWorker *worker,
static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
{
RedSurface *surface = &worker->surfaces[surface_id];
+ DisplayChannelClient *dcc;
+ RingItem *link;
if (!--surface->refs) {
// only primary surface streams are supported
@@ -1463,13 +1621,15 @@ static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id)
region_destroy(&surface->draw_dirty_region);
surface->context.canvas = NULL;
- red_destroy_surface_item(worker, WORKER_TO_DCC(worker), surface_id);
+ WORKER_FOREACH_DCC(worker, link, dcc) {
+ red_destroy_surface_item(worker, dcc, surface_id);
+ }
PANIC_ON(!ring_is_empty(&surface->depend_on_me));
}
}
-static inline void set_surface_release_info(RedWorker *worker, uint32_t surface_id, int is_create,
+static inline void set_surface_release_info(RedWorker *worker, uint32_t surface_id, int is_create,
QXLReleaseInfo *release_info, uint32_t group_id)
{
RedSurface *surface;
@@ -1535,23 +1695,31 @@ static void remove_drawable_dependencies(RedWorker *worker, Drawable *drawable)
}
}
-static inline void release_drawable(RedWorker *worker, Drawable *item)
+static inline void release_drawable(RedWorker *worker, Drawable *drawable)
{
- if (!--item->refs) {
- ASSERT(!item->stream);
- ASSERT(!item->tree_item.shadow);
- region_destroy(&item->tree_item.base.rgn);
+ int glz_count = 0;
+ RingItem *item, *next;
- remove_drawable_dependencies(worker, item);
- red_dec_surfaces_drawable_dependencies(worker, item);
- red_destroy_surface(worker, item->surface_id);
+ if (!--drawable->refs) {
+ ASSERT(!drawable->stream);
+ ASSERT(!drawable->tree_item.shadow);
+ ASSERT(ring_is_empty(&drawable->pipes));
+ region_destroy(&drawable->tree_item.base.rgn);
- if (item->red_glz_drawable) {
- item->red_glz_drawable->drawable = NULL;
- } else { // no reference to the qxl drawable left
- free_red_drawable(worker, item->red_drawable, item->group_id, item->self_bitmap);
+ remove_drawable_dependencies(worker, drawable);
+ red_dec_surfaces_drawable_dependencies(worker, drawable);
+ red_destroy_surface(worker, drawable->surface_id);
+
+ RING_FOREACH_SAFE(item, next, &drawable->glz_ring) {
+ SPICE_CONTAINEROF(item, RedGlzDrawable, drawable_link)->drawable = NULL;
+ ring_remove(item);
+ glz_count++;
+ }
+ if (!glz_count) { // no reference to the qxl drawable left
+ free_red_drawable(worker, drawable->red_drawable,
+ drawable->group_id, drawable->self_bitmap);
}
- free_drawable(worker, item);
+ free_drawable(worker, drawable);
}
}
@@ -1653,10 +1821,10 @@ static inline void current_remove_drawable(RedWorker *worker, Drawable *item)
worker->current_size--;
}
-static void remove_drawable(RedWorker *worker, Drawable *item)
+static void remove_drawable(RedWorker *worker, Drawable *drawable)
{
- red_pipe_remove_drawable(WORKER_TO_DCC(worker), item);
- current_remove_drawable(worker, item);
+ red_pipes_remove_drawable(drawable);
+ current_remove_drawable(worker, drawable);
}
static inline void current_remove(RedWorker *worker, TreeItem *item)
@@ -1760,9 +1928,12 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int
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) {
- drawable = SPICE_CONTAINEROF(item, Drawable, pipe_item);
+ dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
+ drawable = dpi->drawable;
} else if (item->type == PIPE_ITEM_TYPE_UPGRADE) {
drawable = ((UpgradeItem *)item)->drawable;
} else {
@@ -1800,6 +1971,28 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int
}
}
+static void red_wait_outgoing_item(RedChannelClient *rcc);
+static void red_wait_outgoing_items(RedChannel *channel);
+
+static void red_clear_surface_drawables_from_pipes(RedWorker *worker, int surface_id,
+ int force, int wait_for_outgoing_item)
+{
+ RingItem *item;
+ DisplayChannelClient *dcc;
+
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ red_clear_surface_drawables_from_pipe(dcc, surface_id, force);
+ if (wait_for_outgoing_item) {
+ // in case that the pipe didn't contain any item that is dependent on the surface, but
+ // there is one during sending.
+ red_wait_outgoing_item(&dcc->common.base);
+ if (dcc) {
+ ASSERT(red_channel_client_no_item_being_sent(&dcc->common.base));
+ }
+ }
+ }
+}
+
#ifdef PIPE_DEBUG
static void print_rgn(const char* prefix, const QRegion* rgn)
@@ -2267,6 +2460,7 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
{
DisplayChannelClient *dcc;
StreamAgent *agent;
+ RingItem *item;
ASSERT(!drawable->stream && !stream->current);
ASSERT(drawable && stream);
@@ -2274,8 +2468,7 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
drawable->stream = stream;
stream->last_time = drawable->creation_time;
- dcc = WORKER_TO_DCC(worker);
- if (dcc) {
+ WORKER_FOREACH_DCC(worker, item, dcc) {
agent = &dcc->stream_agents[stream - worker->streams_buf];
if (!region_is_equal(&agent->vis_region, &drawable->tree_item.base.rgn)) {
region_destroy(&agent->vis_region);
@@ -2287,11 +2480,12 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str
static void red_stop_stream(RedWorker *worker, Stream *stream)
{
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
+ DisplayChannelClient *dcc;
+ RingItem *item;
+
ASSERT(ring_item_is_linked(&stream->link));
ASSERT(!stream->current);
-
- if (dcc) {
+ WORKER_FOREACH_DCC(worker, item, dcc) {
StreamAgent *stream_agent;
stream_agent = &dcc->stream_agents[stream - worker->streams_buf];
region_clear(&stream_agent->vis_region);
@@ -2303,18 +2497,27 @@ static void red_stop_stream(RedWorker *worker, Stream *stream)
red_release_stream(worker, stream);
}
+static int drawable_is_linked(Drawable *drawable)
+{
+ return !ring_is_empty(&drawable->pipes);
+}
+
static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *stream)
{
RedChannel *channel;
+ RingItem *item;
RedChannelClient *rcc;
+ DisplayChannelClient *dcc;
ASSERT(stream->current);
- if (WORKER_TO_DCC(worker) && !pipe_item_is_linked(&stream->current->pipe_item)) {
+ WORKER_FOREACH_DCC(worker, item, dcc) {
UpgradeItem *upgrade_item;
int n_rects;
- rcc = &WORKER_TO_DCC(worker)->common.base;
+ if (drawable_is_linked(stream->current)) {
+ continue;
+ }
+ rcc = &dcc->common.base;
channel = rcc->channel;
-
upgrade_item = spice_new(UpgradeItem, 1);
upgrade_item->refs = 1;
red_channel_pipe_item_init(channel,
@@ -2336,24 +2539,33 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
{
Ring *ring = &worker->streams;
RingItem *item = ring_get_head(ring);
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
+ RingItem *dcc_ring_item;
+ DisplayChannelClient *dcc;
+ int has_clients = display_is_connected(worker);
while (item) {
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
+ int detach_stream = 0;
item = ring_next(ring, item);
- if (dcc) {
+ WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) {
StreamAgent *agent = &dcc->stream_agents[stream - worker->streams_buf];
if (region_intersects(&agent->vis_region, region)) {
region_clear(&agent->vis_region);
push_stream_clip(dcc, agent);
- if (stream->current) {
- red_detach_stream_gracefully(worker, stream);
- }
+ detach_stream = 1;
+ }
+ }
+ if (!has_clients) {
+ if (stream->current &&
+ region_intersects(&stream->current->tree_item.base.rgn, region)) {
+ red_detach_stream(worker, stream);
+ }
+ }
+ if (detach_stream) {
+ if (stream->current) {
+ red_detach_stream_gracefully(worker, stream);
}
- } else if (stream->current && region_intersects(&stream->current->tree_item.base.rgn,
- region)) {
- red_detach_stream(worker, stream);
}
}
}
@@ -2362,9 +2574,10 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
{
Ring *ring;
RingItem *item;
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
+ RingItem *dcc_ring_item;
+ DisplayChannelClient *dcc;
- if (!dcc) {
+ if (!display_is_connected(worker)) {
return;
}
@@ -2381,15 +2594,17 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
item = ring_next(ring, item);
- agent = &dcc->stream_agents[stream - worker->streams_buf];
-
if (stream->current == drawable) {
continue;
}
- if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
- region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
- push_stream_clip(dcc, agent);
+ WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) {
+ agent = &dcc->stream_agents[stream - worker->streams_buf];
+
+ if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
+ region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
+ push_stream_clip(dcc, agent);
+ }
}
}
}
@@ -2474,6 +2689,21 @@ static int get_bit_rate(DisplayChannelClient *dcc,
return bit_rate;
}
+static int get_minimal_bit_rate(RedWorker *worker, int width, int height)
+{
+ RingItem *item;
+ DisplayChannelClient *dcc;
+ int ret = INT_MAX;
+
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ int bit_rate = get_bit_rate(dcc, width, height);
+ if (bit_rate < ret) {
+ ret = bit_rate;
+ }
+ }
+ return ret;
+}
+
static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
{
StreamAgent *agent = &dcc->stream_agents[stream - dcc->common.worker->streams_buf];
@@ -2496,7 +2726,8 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
* maybe we can't reach this function in that case? question: do we want to? */
static void red_create_stream(RedWorker *worker, Drawable *drawable)
{
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
+ DisplayChannelClient *dcc;
+ RingItem *dcc_ring_item;
Stream *stream;
SpiceRect* src_rect;
int stream_width;
@@ -2522,12 +2753,12 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
stream->height = src_rect->bottom - src_rect->top;
stream->dest_area = drawable->red_drawable->bbox;
stream->refs = 1;
- stream->bit_rate = get_bit_rate(dcc, stream_width, stream_height);
+ stream->bit_rate = get_minimal_bit_rate(worker, stream_width, stream_height);
SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap;
stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
drawable->stream = stream;
- if (dcc) {
+ WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) {
red_display_create_stream(dcc, stream);
}
@@ -2645,51 +2876,57 @@ static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent)
/* MJpeg has no rate limiting anyway, so do nothing */
}
-static int display_channel_is_low_bandwidth(DisplayChannelClient *dcc)
+static int display_channel_client_is_low_bandwidth(DisplayChannelClient *dcc)
{
- RedChannelClient *rcc = &dcc->common.base;
-
- return dcc && main_channel_client_is_low_bandwidth(
- red_client_get_main(red_channel_client_get_client(rcc)));
+ return main_channel_client_is_low_bandwidth(
+ red_client_get_main(red_channel_client_get_client(&dcc->common.base)));
}
static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream)
{
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
+ DrawablePipeItem *dpi;
+ DisplayChannelClient *dcc;
int index;
StreamAgent *agent;
+ RingItem *ring_item;
ASSERT(stream->current);
- if (!dcc || !display_channel_is_low_bandwidth(dcc)) {
+ if (!display_is_connected(worker)) {
return;
}
index = stream - worker->streams_buf;
- agent = &dcc->stream_agents[index];
+ DRAWABLE_FOREACH_DPI(stream->current, ring_item, dpi) {
+ dcc = dpi->dcc;
+ if (!display_channel_client_is_low_bandwidth(dcc)) {
+ continue;
+ }
+ agent = &dcc->stream_agents[index];
- if (pipe_item_is_linked(&stream->current->pipe_item)) {
- ++agent->drops;
- }
+ if (pipe_item_is_linked(&dpi->dpi_pipe_item)) {
+ ++agent->drops;
+ }
- if (agent->frames / agent->fps < FPS_TEST_INTERVAL) {
- agent->frames++;
- return;
- }
+ if (agent->frames / agent->fps < FPS_TEST_INTERVAL) {
+ agent->frames++;
+ return;
+ }
- double drop_factor = ((double)agent->frames - (double)agent->drops) / (double)agent->frames;
+ double drop_factor = ((double)agent->frames - (double)agent->drops) / (double)agent->frames;
- if (drop_factor == 1) {
- if (agent->fps < MAX_FPS) {
- agent->fps++;
- }
- } else if (drop_factor < 0.9) {
- if (agent->fps > 1) {
- agent->fps--;
+ if (drop_factor == 1) {
+ if (agent->fps < MAX_FPS) {
+ agent->fps++;
+ }
+ } else if (drop_factor < 0.9) {
+ if (agent->fps > 1) {
+ agent->fps--;
+ }
}
+ agent->frames = 1;
+ agent->drops = 0;
}
- agent->frames = 1;
- agent->drops = 0;
}
static inline void red_update_copy_graduality(RedWorker* worker, Drawable *drawable)
@@ -2798,7 +3035,6 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
DrawItem *other_draw_item;
Drawable *drawable;
Drawable *other_drawable;
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
if (other->type != TREE_ITEM_TYPE_DRAWABLE) {
return FALSE;
@@ -2819,11 +3055,11 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
other_drawable->refs++;
current_remove_drawable(worker, other_drawable);
if (add_after) {
- red_pipe_add_drawable_after(dcc, drawable, other_drawable);
+ red_pipes_add_drawable_after(worker, drawable, other_drawable);
} else {
- red_pipe_add_drawable(dcc, drawable);
+ red_pipes_add_drawable(worker, drawable);
}
- red_pipe_remove_drawable(dcc, other_drawable);
+ red_pipes_remove_drawable(other_drawable);
release_drawable(worker, other_drawable);
return TRUE;
}
@@ -2831,13 +3067,42 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
switch (item->effect) {
case QXL_EFFECT_REVERT_ON_DUP:
if (is_same_drawable(worker, drawable, other_drawable)) {
+
+ DisplayChannelClient *dcc;
+ DrawablePipeItem *dpi;
+ RingItem *worker_ring_item, *dpi_ring_item;
+
other_drawable->refs++;
current_remove_drawable(worker, other_drawable);
- if (!ring_item_is_linked(&other_drawable->pipe_item.link)) {
- red_pipe_add_drawable(dcc, drawable);
- } else {
- red_pipe_remove_drawable(dcc, other_drawable);
+
+ /* sending the drawable to clients that already received
+ * (or will receive) other_drawable */
+ worker_ring_item = ring_get_head(&worker->display_channel->common.base.clients);
+ dpi_ring_item = ring_get_head(&other_drawable->pipes);
+ /* dpi contains a sublist of dcc's, ordered the same */
+ while (worker_ring_item) {
+ dcc = SPICE_CONTAINEROF(worker_ring_item, DisplayChannelClient,
+ common.base.channel_link);
+ dpi = SPICE_CONTAINEROF(dpi_ring_item, DrawablePipeItem, base);
+ while (worker_ring_item && (!dpi || dcc != dpi->dcc)) {
+ red_pipe_add_drawable(dcc, drawable);
+ worker_ring_item = ring_next(&worker->display_channel->common.base.clients,
+ worker_ring_item);
+ dcc = SPICE_CONTAINEROF(worker_ring_item, DisplayChannelClient,
+ common.base.channel_link);
+ }
+
+ if (dpi_ring_item) {
+ dpi_ring_item = ring_next(&other_drawable->pipes, dpi_ring_item);
+ }
+ if (worker_ring_item) {
+ worker_ring_item = ring_next(&worker->display_channel->common.base.clients,
+ worker_ring_item);
+ }
}
+ /* not sending other_drawable where possible */
+ red_pipes_remove_drawable(other_drawable);
+
release_drawable(worker, other_drawable);
return TRUE;
}
@@ -2846,7 +3111,7 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
if (is_same_geometry(worker, drawable, other_drawable)) {
__current_add_drawable(worker, drawable, &other->siblings_link);
remove_drawable(worker, other_drawable);
- red_pipe_add_drawable(dcc, drawable);
+ red_pipes_add_drawable(worker, drawable);
return TRUE;
}
break;
@@ -3318,13 +3583,15 @@ static void free_one_drawable(RedWorker *worker, int force_glz_free)
RingItem *ring_item = ring_get_tail(&worker->current_list);
Drawable *drawable;
Container *container;
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
ASSERT(ring_item);
drawable = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
- if (drawable->red_glz_drawable && force_glz_free) {
- ASSERT(worker->display_channel);
- red_display_free_glz_drawable(dcc, drawable->red_glz_drawable);
+ if (force_glz_free) {
+ RingItem *glz_item, *next_item;
+ RedGlzDrawable *glz;
+ DRAWABLE_FOREACH_GLZ_SAFE(drawable, glz_item, next_item, glz) {
+ red_display_free_glz_drawable(glz->dcc, glz);
+ }
}
red_draw_drawable(worker, drawable);
container = drawable->tree_item.base.container;
@@ -3358,8 +3625,6 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
drawable->tree_item.base.type = TREE_ITEM_TYPE_DRAWABLE;
region_init(&drawable->tree_item.base.rgn);
drawable->tree_item.effect = effect;
- red_channel_pipe_item_init(&worker->display_channel->common.base,
- &drawable->pipe_item, PIPE_ITEM_TYPE_DRAW);
drawable->red_drawable = red_drawable;
drawable->group_id = group_id;
@@ -3371,6 +3636,8 @@ static Drawable *get_drawable(RedWorker *worker, uint8_t effect, RedDrawable *re
validate_surface(worker, drawable->surfaces_dest[x]);
}
}
+ ring_init(&drawable->pipes);
+ ring_init(&drawable->glz_ring);
return drawable;
}
@@ -3451,7 +3718,6 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
{
int surface_id;
Drawable *item = get_drawable(worker, drawable->effect, drawable, group_id);
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
ASSERT(item);
@@ -3509,7 +3775,7 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
worker->transparent_count++;
}
- red_pipe_add_drawable(dcc, item);
+ red_pipes_add_drawable(worker, item);
#ifdef DRAW_ALL
red_draw_qxl_drawable(worker, item);
#endif
@@ -3558,7 +3824,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
otherwise "current" will hold items that other drawables may depend on, and then
red_current_clear will remove them from the pipe. */
red_current_clear(worker, surface_id);
- red_clear_surface_drawables_from_pipe(WORKER_TO_DCC(worker), surface_id, FALSE);
+ red_clear_surface_drawables_from_pipes(worker, surface_id, FALSE, FALSE);
red_destroy_surface(worker, surface_id);
break;
default:
@@ -4446,22 +4712,30 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
static void red_free_some(RedWorker *worker)
{
int n = 0;
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
- GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
+ DisplayChannelClient *dcc;
+ RingItem *item;
- if (glz_dict) {
- // encoding using the dictionary is prevented since the following operations might
- // change the dictionary
- pthread_rwlock_wrlock(&glz_dict->encode_lock);
- n = red_display_free_some_independent_glz_drawables(dcc);
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
+
+ if (glz_dict) {
+ // encoding using the dictionary is prevented since the following operations might
+ // change the dictionary
+ pthread_rwlock_wrlock(&glz_dict->encode_lock);
+ n = red_display_free_some_independent_glz_drawables(dcc);
+ }
}
while (!ring_is_empty(&worker->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
free_one_drawable(worker, TRUE);
}
- if (glz_dict) {
- pthread_rwlock_unlock(&glz_dict->encode_lock);
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
+
+ if (glz_dict) {
+ pthread_rwlock_unlock(&glz_dict->encode_lock);
+ }
}
}
@@ -4474,11 +4748,11 @@ static void red_current_flush(RedWorker *worker, int surface_id)
}
// adding the pipe item after pos. If pos == NULL, adding to head.
-static ImageItem *red_add_surface_area_image(RedWorker *worker, int surface_id, SpiceRect *area,
+static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id, SpiceRect *area,
PipeItem *pos, int can_lossy)
{
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
- DisplayChannel *display_channel = worker ? worker->display_channel : NULL;
+ DisplayChannel *display_channel = DCC_TO_DC(dcc);
+ RedWorker *worker = display_channel->common.worker;
RedChannel *channel = &display_channel->common.base;
RedSurface *surface = &worker->surfaces[surface_id];
SpiceCanvas *canvas = surface->context.canvas;
@@ -4491,9 +4765,6 @@ static ImageItem *red_add_surface_area_image(RedWorker *worker, int surface_id,
ASSERT(area);
- if (!dcc) {
- return NULL;
- }
width = area->right - area->left;
height = area->bottom - area->top;
bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
@@ -4561,7 +4832,7 @@ static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id)
/* not allowing lossy compression because probably, especially if it is a primary surface,
it combines both "picture-like" areas with areas that are more "artificial"*/
- red_add_surface_area_image(worker, surface_id, &area, NULL, FALSE);
+ red_add_surface_area_image(dcc, surface_id, &area, NULL, FALSE);
red_channel_client_push(&dcc->common.base);
}
@@ -4706,9 +4977,15 @@ static void red_display_destroy_compress_bufs(DisplayChannel *display_channel)
static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
{
RedGlzDrawable *ret;
+ RingItem *item;
- if (drawable->red_glz_drawable) {
- return drawable->red_glz_drawable;
+ // TODO - I don't really understand what's going on here, so just doing the technical equivalent
+ // now that we have multiple glz_dicts, so the only way to go from dcc to drawable glz is to go
+ // over the glz_ring (unless adding some better data structure then a ring)
+ DRAWABLE_FOREACH_GLZ(drawable, item, ret) {
+ if (ret->dcc == dcc) {
+ return ret;
+ }
}
ret = spice_new(RedGlzDrawable, 1);
@@ -4722,8 +4999,9 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, D
ring_init(&ret->instances);
ring_item_init(&ret->link);
+ ring_item_init(&ret->drawable_link);
ring_add_before(&ret->link, &dcc->glz_drawables);
- drawable->red_glz_drawable = ret;
+ ring_add(&drawable->glz_ring, &ret->drawable_link);
return ret;
}
@@ -4780,7 +5058,7 @@ static void red_display_free_glz_drawable_instance(DisplayChannelClient *dcc,
Drawable *drawable = glz_drawable->drawable;
if (drawable) {
- drawable->red_glz_drawable = NULL;
+ ring_remove(&glz_drawable->drawable_link);
} else { // no reference to the qxl drawable left
free_red_drawable(worker, glz_drawable->red_drawable,
glz_drawable->group_id, glz_drawable->self_bitmap);
@@ -4867,13 +5145,15 @@ static void red_display_client_clear_glz_drawables(DisplayChannelClient *dcc)
static void red_display_clear_glz_drawables(DisplayChannel *display_channel)
{
- DisplayChannelClient *dcc = display_channel ?
- RCC_TO_DCC(display_channel->common.base.rcc) : NULL;
+ RingItem *link;
+ DisplayChannelClient *dcc;
- if (!dcc) {
+ if (!display_channel) {
return;
}
- red_display_client_clear_glz_drawables(dcc);
+ DCC_FOREACH(link, dcc, &display_channel->common.base) {
+ red_display_client_clear_glz_drawables(dcc);
+ }
}
/*
@@ -5828,7 +6108,7 @@ static inline int red_compress_image(DisplayChannelClient *dcc,
if (can_lossy && display_channel->enable_jpeg &&
((image_compression == SPICE_IMAGE_COMPRESS_AUTO_LZ) ||
(image_compression == SPICE_IMAGE_COMPRESS_AUTO_GLZ))) {
- // if we use lz for alpha, the stride can't be extra
+ // if we use lz for alpha, the stride can't be extra
if (src->format != SPICE_BITMAP_FMT_RGBA || !_stride_is_extra(src)) {
return red_jpeg_compress_image(dcc, dest,
src, o_comp_data, drawable->group_id);
@@ -6344,7 +6624,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
if (pipe_item->type != PIPE_ITEM_TYPE_DRAW)
continue;
- drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
+ drawable = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item)->drawable;
if (ring_item_is_linked(&drawable->list_link))
continue; // item hasn't been rendered
@@ -6380,15 +6660,18 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
pipe_item;
pipe_item = (PipeItem *)ring_prev(pipe, &pipe_item->link)) {
Drawable *drawable;
+ DrawablePipeItem *dpi;
ImageItem *image;
+
if (pipe_item->type != PIPE_ITEM_TYPE_DRAW)
continue;
- drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
+ dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item);
+ drawable = dpi->drawable;
if (ring_item_is_linked(&drawable->list_link))
continue; // item hasn't been rendered
// When a drawable command, X, depends on bitmaps that were resent,
- // these bitmaps state at the client might not be synchronized with X
+ // these bitmaps state at the client might not be synchronized with X
// (i.e., the bitmaps can be more futuristic w.r.t X). Thus, X shouldn't
// be rendered at the client, and we replace it with an image as well.
if (!drawable_depends_on_areas(drawable,
@@ -6398,14 +6681,14 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
continue;
}
- image = red_add_surface_area_image(worker, drawable->red_drawable->surface_id,
+ image = red_add_surface_area_image(dcc, drawable->red_drawable->surface_id,
&drawable->red_drawable->bbox, pipe_item, TRUE);
resent_surface_ids[num_resent] = drawable->red_drawable->surface_id;
resent_areas[num_resent] = drawable->red_drawable->bbox;
num_resent++;
ASSERT(image);
- red_pipe_remove_drawable(dcc, drawable);
+ red_channel_client_pipe_remove_and_release(&dcc->common.base, &dpi->dpi_pipe_item);
pipe_item = &image->link;
}
}
@@ -6454,7 +6737,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
// the surfaces areas will be sent as DRAW_COPY commands, that
// will be executed before the current drawable
for (i = 0; i < num_deps; i++) {
- red_add_surface_area_image(worker, deps_surfaces_ids[i], deps_areas[i],
+ red_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i],
red_pipe_get_tail(dcc), FALSE);
}
@@ -6475,7 +6758,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
&drawable->bbox);
}
- red_add_surface_area_image(worker, drawable->surface_id, &drawable->bbox,
+ red_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox,
red_pipe_get_tail(dcc), TRUE);
}
}
@@ -6483,15 +6766,16 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
static void red_marshall_qxl_draw_fill(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
SpiceMarshaller *brush_pat_out;
SpiceMarshaller *mask_bitmap_out;
SpiceFill fill;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
fill = drawable->u.fill;
spice_marshall_Fill(base_marshaller,
@@ -6510,8 +6794,9 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *m,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
@@ -6539,7 +6824,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
!(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) {
int has_mask = !!drawable->u.fill.mask.bitmap;
- red_marshall_qxl_draw_fill(worker, rcc, m, item);
+ red_marshall_qxl_draw_fill(worker, rcc, m, dpi);
// either the brush operation is opaque, or the dest is not lossy
surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
} else {
@@ -6567,8 +6852,9 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item, int src_allowed_lossy)
+ DrawablePipeItem *dpi, int src_allowed_lossy)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceMarshaller *brush_pat_out;
@@ -6577,7 +6863,7 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
SpiceOpaque opaque;
FillBitsType src_send_type;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
opaque = drawable->u.opaque;
spice_marshall_Opaque(base_marshaller,
@@ -6600,8 +6886,9 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *m,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
@@ -6632,7 +6919,7 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
FillBitsType src_send_type;
int has_mask = !!drawable->u.opaque.mask.bitmap;
- src_send_type = red_marshall_qxl_draw_opaque(worker, rcc, m, item, src_allowed_lossy);
+ src_send_type = red_marshall_qxl_draw_opaque(worker, rcc, m, dpi, src_allowed_lossy);
if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
src_is_lossy = TRUE;
} else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) {
@@ -6665,8 +6952,9 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item, int src_allowed_lossy)
+ DrawablePipeItem *dpi, int src_allowed_lossy)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
SpiceMarshaller *src_bitmap_out;
@@ -6674,7 +6962,7 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
SpiceCopy copy;
FillBitsType src_send_type;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
copy = drawable->u.copy;
spice_marshall_Copy(base_marshaller,
@@ -6691,8 +6979,9 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int has_mask = !!drawable->u.copy.mask.bitmap;
@@ -6703,7 +6992,7 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
src_is_lossy = is_bitmap_lossy(rcc, drawable->u.copy.src_bitmap,
&drawable->u.copy.src_area, item, &src_bitmap_data);
- src_send_type = red_marshall_qxl_draw_copy(worker, rcc, base_marshaller, item, TRUE);
+ src_send_type = red_marshall_qxl_draw_copy(worker, rcc, base_marshaller, dpi, TRUE);
if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
src_is_lossy = TRUE;
@@ -6718,14 +7007,15 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
static void red_marshall_qxl_draw_transparent(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceMarshaller *src_bitmap_out;
SpiceTransparent transparent;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
transparent = drawable->u.transparent;
spice_marshall_Transparent(base_marshaller,
@@ -6737,8 +7027,9 @@ static void red_marshall_qxl_draw_transparent(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
int src_is_lossy;
BitmapData src_bitmap_data;
@@ -6747,7 +7038,7 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
&drawable->u.transparent.src_area, item, &src_bitmap_data);
if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) {
- red_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, dpi);
// don't update surface lossy region since transperent areas might be lossy
} else {
int resend_surface_ids[1];
@@ -6764,16 +7055,17 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item,
+ DrawablePipeItem *dpi,
int src_allowed_lossy)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceMarshaller *src_bitmap_out;
SpiceAlphaBlend alpha_blend;
FillBitsType src_send_type;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
alpha_blend = drawable->u.alpha_blend;
spice_marshall_AlphaBlend(base_marshaller,
@@ -6787,8 +7079,9 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int src_is_lossy;
@@ -6798,7 +7091,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
src_is_lossy = is_bitmap_lossy(rcc, drawable->u.alpha_blend.src_bitmap,
&drawable->u.alpha_blend.src_area, item, &src_bitmap_data);
- src_send_type = red_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, item, TRUE);
+ src_send_type = red_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, dpi, TRUE);
if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) {
src_is_lossy = TRUE;
@@ -6814,12 +7107,13 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
static void red_marshall_qxl_copy_bits(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
SpicePoint copy_bits;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_COPY_BITS, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_COPY_BITS, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
copy_bits = drawable->u.copy_bits.src_pos;
spice_marshall_Point(base_marshaller,
@@ -6829,8 +7123,9 @@ static void red_marshall_qxl_copy_bits(RedWorker *worker,
static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceRect src_rect;
@@ -6839,7 +7134,7 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
int src_is_lossy;
SpiceRect src_lossy_area;
- red_marshall_qxl_copy_bits(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_copy_bits(worker, rcc, base_marshaller, dpi);
horz_offset = drawable->u.copy_bits.src_pos.x - drawable->bbox.left;
vert_offset = drawable->u.copy_bits.src_pos.y - drawable->bbox.top;
@@ -6859,15 +7154,16 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
static void red_marshall_qxl_draw_blend(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceMarshaller *src_bitmap_out;
SpiceMarshaller *mask_bitmap_out;
SpiceBlend blend;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLEND, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLEND, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
blend = drawable->u.blend;
spice_marshall_Blend(base_marshaller,
@@ -6883,8 +7179,9 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int src_is_lossy;
@@ -6899,7 +7196,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
if (!dest_is_lossy &&
(!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
- red_marshall_qxl_draw_blend(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_blend(worker, rcc, base_marshaller, dpi);
} else {
int resend_surface_ids[2];
SpiceRect *resend_areas[2];
@@ -6925,13 +7222,14 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
static void red_marshall_qxl_draw_blackness(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
SpiceMarshaller *mask_bitmap_out;
SpiceBlackness blackness;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
blackness = drawable->u.blackness;
@@ -6945,13 +7243,14 @@ static void red_marshall_qxl_draw_blackness(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_blackness(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int has_mask = !!drawable->u.blackness.mask.bitmap;
- red_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, dpi);
surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
}
@@ -6959,13 +7258,14 @@ static void red_lossy_marshall_qxl_draw_blackness(RedWorker *worker,
static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
SpiceMarshaller *mask_bitmap_out;
SpiceWhiteness whiteness;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
whiteness = drawable->u.whiteness;
@@ -6979,13 +7279,14 @@ static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_whiteness(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int has_mask = !!drawable->u.whiteness.mask.bitmap;
- red_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, dpi);
surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
}
@@ -7021,8 +7322,9 @@ static void red_lossy_marshall_qxl_draw_inverse(RedWorker *worker,
static void red_marshall_qxl_draw_rop3(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceRop3 rop3;
@@ -7030,7 +7332,7 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
SpiceMarshaller *brush_pat_out;
SpiceMarshaller *mask_bitmap_out;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ROP3, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ROP3, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
rop3 = drawable->u.rop3;
spice_marshall_Rop3(base_marshaller,
@@ -7050,8 +7352,9 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int src_is_lossy;
@@ -7072,7 +7375,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
(!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
!dest_is_lossy) {
int has_mask = !!drawable->u.rop3.mask.bitmap;
- red_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, dpi);
surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
} else {
int resend_surface_ids[3];
@@ -7105,15 +7408,16 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
static void red_marshall_qxl_draw_stroke(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceStroke stroke;
SpiceMarshaller *brush_pat_out;
SpiceMarshaller *style_out;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_STROKE, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_STROKE, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
stroke = drawable->u.stroke;
spice_marshall_Stroke(base_marshaller,
@@ -7130,8 +7434,9 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int brush_is_lossy;
@@ -7158,7 +7463,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
if (!dest_is_lossy &&
(!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)))
{
- red_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, dpi);
} else {
int resend_surface_ids[2];
SpiceRect *resend_areas[2];
@@ -7185,15 +7490,16 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
static void red_marshall_qxl_draw_text(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
SpiceText text;
SpiceMarshaller *brush_pat_out;
SpiceMarshaller *back_brush_pat_out;
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TEXT, &item->pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TEXT, &dpi->dpi_pipe_item);
fill_base(base_marshaller, item);
text = drawable->u.text;
spice_marshall_Text(base_marshaller,
@@ -7212,8 +7518,9 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
RedChannelClient *rcc,
SpiceMarshaller *base_marshaller,
- Drawable *item)
+ DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
RedDrawable *drawable = item->red_drawable;
int fg_is_lossy;
@@ -7248,7 +7555,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
if (!dest_is_lossy &&
(!fg_is_lossy || (fg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
(!bg_is_lossy || (bg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) {
- red_marshall_qxl_draw_text(worker, rcc, base_marshaller, item);
+ red_marshall_qxl_draw_text(worker, rcc, base_marshaller, dpi);
} else {
int resend_surface_ids[3];
SpiceRect *resend_areas[3];
@@ -7277,47 +7584,48 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
}
static void red_lossy_marshall_qxl_drawable(RedWorker *worker, RedChannelClient *rcc,
- SpiceMarshaller *base_marshaller, Drawable *item)
+ SpiceMarshaller *base_marshaller, DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
switch (item->red_drawable->type) {
case QXL_DRAW_FILL:
- red_lossy_marshall_qxl_draw_fill(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_fill(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_OPAQUE:
- red_lossy_marshall_qxl_draw_opaque(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_opaque(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_COPY:
- red_lossy_marshall_qxl_draw_copy(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_copy(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_TRANSPARENT:
- red_lossy_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_transparent(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_ALPHA_BLEND:
- red_lossy_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_alpha_blend(worker, rcc, base_marshaller, dpi);
break;
case QXL_COPY_BITS:
- red_lossy_marshall_qxl_copy_bits(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_copy_bits(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_BLEND:
- red_lossy_marshall_qxl_draw_blend(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_blend(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_BLACKNESS:
- red_lossy_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_WHITENESS:
- red_lossy_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_INVERS:
red_lossy_marshall_qxl_draw_inverse(worker, rcc, base_marshaller, item);
break;
case QXL_DRAW_ROP3:
- red_lossy_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_STROKE:
- red_lossy_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_stroke(worker, rcc, base_marshaller, dpi);
break;
case QXL_DRAW_TEXT:
- red_lossy_marshall_qxl_draw_text(worker, rcc, base_marshaller, item);
+ red_lossy_marshall_qxl_draw_text(worker, rcc, base_marshaller, dpi);
break;
default:
red_error("invalid type");
@@ -7325,49 +7633,50 @@ static void red_lossy_marshall_qxl_drawable(RedWorker *worker, RedChannelClient
}
static inline void red_marshall_qxl_drawable(RedWorker *worker, RedChannelClient *rcc,
- SpiceMarshaller *m, Drawable *item)
+ SpiceMarshaller *m, DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
RedDrawable *drawable = item->red_drawable;
switch (drawable->type) {
case QXL_DRAW_FILL:
- red_marshall_qxl_draw_fill(worker, rcc, m, item);
+ red_marshall_qxl_draw_fill(worker, rcc, m, dpi);
break;
case QXL_DRAW_OPAQUE:
- red_marshall_qxl_draw_opaque(worker, rcc, m, item, FALSE);
+ red_marshall_qxl_draw_opaque(worker, rcc, m, dpi, FALSE);
break;
case QXL_DRAW_COPY:
- red_marshall_qxl_draw_copy(worker, rcc, m, item, FALSE);
+ red_marshall_qxl_draw_copy(worker, rcc, m, dpi, FALSE);
break;
case QXL_DRAW_TRANSPARENT:
- red_marshall_qxl_draw_transparent(worker, rcc, m, item);
+ red_marshall_qxl_draw_transparent(worker, rcc, m, dpi);
break;
case QXL_DRAW_ALPHA_BLEND:
- red_marshall_qxl_draw_alpha_blend(worker, rcc, m, item, FALSE);
+ red_marshall_qxl_draw_alpha_blend(worker, rcc, m, dpi, FALSE);
break;
case QXL_COPY_BITS:
- red_marshall_qxl_copy_bits(worker, rcc, m, item);
+ red_marshall_qxl_copy_bits(worker, rcc, m, dpi);
break;
case QXL_DRAW_BLEND:
- red_marshall_qxl_draw_blend(worker, rcc, m, item);
+ red_marshall_qxl_draw_blend(worker, rcc, m, dpi);
break;
case QXL_DRAW_BLACKNESS:
- red_marshall_qxl_draw_blackness(worker, rcc, m, item);
+ red_marshall_qxl_draw_blackness(worker, rcc, m, dpi);
break;
case QXL_DRAW_WHITENESS:
- red_marshall_qxl_draw_whiteness(worker, rcc, m, item);
+ red_marshall_qxl_draw_whiteness(worker, rcc, m, dpi);
break;
case QXL_DRAW_INVERS:
red_marshall_qxl_draw_inverse(worker, rcc, m, item);
break;
case QXL_DRAW_ROP3:
- red_marshall_qxl_draw_rop3(worker, rcc, m, item);
+ red_marshall_qxl_draw_rop3(worker, rcc, m, dpi);
break;
case QXL_DRAW_STROKE:
- red_marshall_qxl_draw_stroke(worker, rcc, m, item);
+ red_marshall_qxl_draw_stroke(worker, rcc, m, dpi);
break;
case QXL_DRAW_TEXT:
- red_marshall_qxl_draw_text(worker, rcc, m, item);
+ red_marshall_qxl_draw_text(worker, rcc, m, dpi);
break;
default:
red_error("invalid type");
@@ -7571,8 +7880,9 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
}
static inline void marshall_qxl_drawable(RedChannelClient *rcc,
- SpiceMarshaller *m, Drawable *item)
+ SpiceMarshaller *m, DrawablePipeItem *dpi)
{
+ Drawable *item = dpi->drawable;
DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
ASSERT(display_channel && rcc);
@@ -7580,9 +7890,9 @@ static inline void marshall_qxl_drawable(RedChannelClient *rcc,
return;
}
if (!display_channel->enable_jpeg)
- red_marshall_qxl_drawable(display_channel->common.worker, rcc, m, item);
+ red_marshall_qxl_drawable(display_channel->common.worker, rcc, m, dpi);
else
- red_lossy_marshall_qxl_drawable(display_channel->common.worker, rcc, m, item);
+ red_lossy_marshall_qxl_drawable(display_channel->common.worker, rcc, m, dpi);
}
static inline void red_marshall_verb(RedChannelClient *rcc, uint16_t verb)
@@ -7683,7 +7993,7 @@ static void display_channel_marshall_reset_cache(RedChannelClient *rcc,
&wait);
}
-static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item)
+static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item)
{
DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
DisplayChannel *display_channel = DCC_TO_DC(dcc);
@@ -7854,8 +8164,7 @@ static void red_display_marshall_stream_start(RedChannelClient *rcc,
agent->last_send_time = 0;
ASSERT(stream);
- red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE,
- stream->current ? &stream->current->pipe_item : NULL);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE, &agent->create_item);
SpiceMsgDisplayStreamCreate stream_create;
SpiceClipRects clip_rects;
@@ -8043,8 +8352,8 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
red_display_reset_send_data(dcc);
switch (pipe_item->type) {
case PIPE_ITEM_TYPE_DRAW: {
- Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
- marshall_qxl_drawable(rcc, m, drawable);
+ DrawablePipeItem *dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item);
+ marshall_qxl_drawable(rcc, m, dpi);
break;
}
case PIPE_ITEM_TYPE_INVAL_ONE:
@@ -8419,13 +8728,34 @@ static inline void red_create_surface_item(DisplayChannelClient *dcc, int surfac
red_channel_client_pipe_add(&dcc->common.base, &create->pipe_item);
}
+static void red_worker_create_surface_item(RedWorker *worker, int surface_id)
+{
+ DisplayChannelClient *dcc;
+ RingItem *item;
+
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ red_create_surface_item(dcc, surface_id);
+ }
+}
+
+
+static void red_worker_push_surface_image(RedWorker *worker, int surface_id)
+{
+ DisplayChannelClient *dcc;
+ RingItem *item;
+
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ red_push_surface_image(dcc, surface_id);
+ }
+}
+
static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
uint32_t height, int32_t stride, uint32_t format,
void *line_0, int data_is_valid, int send_client)
{
RedSurface *surface = &worker->surfaces[surface_id];
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
uint32_t i;
+
if (stride >= 0) {
PANIC("Untested path stride >= 0");
}
@@ -8456,9 +8786,9 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
}
if (send_client) {
- red_create_surface_item(dcc, surface_id);
+ red_worker_create_surface_item(worker, surface_id);
if (data_is_valid) {
- red_push_surface_image(dcc, surface_id);
+ red_worker_push_surface_image(worker, surface_id);
}
}
return;
@@ -8471,9 +8801,9 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
if (surface->context.canvas) { //no need canvas check
worker->renderer = worker->renderers[i];
if (send_client) {
- red_create_surface_item(dcc, surface_id);
+ red_worker_create_surface_item(worker, surface_id);
if (data_is_valid) {
- red_push_surface_image(dcc, surface_id);
+ red_worker_push_surface_image(worker, surface_id);
}
}
return;
@@ -8483,9 +8813,6 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
PANIC("unable to create drawing canvas");
}
-static void red_wait_outgoing_item(RedChannelClient *rcc);
-static void red_wait_outgoing_items(RedChannel *channel);
-
static inline void flush_display_commands(RedWorker *worker)
{
RedChannel *display_red_channel = &worker->display_channel->common.base;
@@ -9163,9 +9490,15 @@ static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item
ASSERT(item);
switch (item->type) {
case PIPE_ITEM_TYPE_DRAW:
- case PIPE_ITEM_TYPE_STREAM_CREATE:
- SPICE_CONTAINEROF(item, Drawable, pipe_item)->refs++;
+ ref_drawable_pipe_item(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item));
break;
+ case PIPE_ITEM_TYPE_STREAM_CREATE: {
+ StreamAgent *stream_agent = SPICE_CONTAINEROF(item, StreamAgent, create_item);
+ if (stream_agent->stream->current) {
+ stream_agent->stream->current->refs++;
+ }
+ break;
+ }
case PIPE_ITEM_TYPE_STREAM_CLIP:
((StreamClipItem *)item)->refs++;
break;
@@ -9187,9 +9520,15 @@ static void display_channel_client_release_item_after_push(DisplayChannelClient
switch (item->type) {
case PIPE_ITEM_TYPE_DRAW:
- case PIPE_ITEM_TYPE_STREAM_CREATE:
- release_drawable(worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
+ put_drawable_pipe_item(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item));
break;
+ case PIPE_ITEM_TYPE_STREAM_CREATE: {
+ StreamAgent *stream_agent = SPICE_CONTAINEROF(item, StreamAgent, create_item);
+ if (stream_agent->stream->current) {
+ release_drawable(worker, stream_agent->stream->current);
+ }
+ break;
+ }
case PIPE_ITEM_TYPE_STREAM_CLIP:
red_display_release_stream_clip(worker, (StreamClipItem *)item);
break;
@@ -9213,9 +9552,12 @@ static void display_channel_client_release_item_before_push(DisplayChannelClient
RedWorker *worker = dcc->common.worker;
switch (item->type) {
- case PIPE_ITEM_TYPE_DRAW:
- release_drawable(worker, SPICE_CONTAINEROF(item, Drawable, pipe_item));
+ case PIPE_ITEM_TYPE_DRAW: {
+ DrawablePipeItem *dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
+ ring_remove(&dpi->base);
+ put_drawable_pipe_item(dpi);
break;
+ }
case PIPE_ITEM_TYPE_STREAM_CREATE: {
StreamAgent *agent = SPICE_CONTAINEROF(item, StreamAgent, create_item);
red_display_release_stream(worker, agent);
@@ -9407,7 +9749,7 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
if (worker->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) {
display_channel->enable_zlib_glz_wrap = is_low_bandwidth;
} else {
- display_channel->enable_zlib_glz_wrap = (worker->zlib_glz_state ==
+ display_channel->enable_zlib_glz_wrap = (worker->zlib_glz_state ==
SPICE_WAN_COMPRESSION_ALWAYS);
}
@@ -9612,7 +9954,7 @@ static void red_wait_outgoing_items(RedChannel *channel)
if (!red_channel_any_blocked(channel)) {
return;
}
-
+
end_time = red_now() + DETACH_TIMEOUT;
red_printf("blocked");
@@ -9783,9 +10125,6 @@ static inline void handle_dev_del_memslot(RedWorker *worker)
static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
{
- DisplayChannelClient *dcc = WORKER_TO_DCC(worker);
- RedChannelClient *rcc = &dcc->common.base;
-
if (!worker->surfaces[surface_id].context.canvas) {
return;
}
@@ -9795,13 +10134,7 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
otherwise "current" will hold items that other drawables may depend on, and then
red_current_clear will remove them from the pipe. */
red_current_clear(worker, surface_id);
- red_clear_surface_drawables_from_pipe(dcc, surface_id, TRUE);
- // in case that the pipe didn't contain any item that is dependent on the surface, but
- // there is one during sending.
- red_wait_outgoing_item(rcc);
- if (dcc) {
- ASSERT(red_channel_client_no_item_being_sent(rcc));
- }
+ red_clear_surface_drawables_from_pipes(worker, surface_id, TRUE, TRUE);
}
static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
@@ -9811,7 +10144,7 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
receive_data(worker->channel, &surface_id, sizeof(uint32_t));
ASSERT(surface_id == 0);
-
+
flush_all_qxl_commands(worker);
if (worker->surfaces[0].context.canvas) {
@@ -9949,7 +10282,7 @@ static void handle_dev_stop(RedWorker *worker)
{
ASSERT(worker->running);
worker->running = FALSE;
- red_display_client_clear_glz_drawables(WORKER_TO_DCC(worker));
+ red_display_clear_glz_drawables(worker->display_channel);
flush_all_surfaces(worker);
red_wait_outgoing_items(&worker->display_channel->common.base);
red_wait_outgoing_items(&worker->cursor_channel->common.base);