mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2026-01-26 02:28:37 +00:00
worker: move dcc_start()
Author: Marc-André Lureau <marcandre.lureau@gmail.com> Acked-by: Fabiano Fidêncio <fidencio@redhat.com>
This commit is contained in:
parent
85920bb2e9
commit
0e224d04fb
170
server/dcc.c
170
server/dcc.c
@ -22,6 +22,97 @@
|
||||
#include "dcc.h"
|
||||
#include "display-channel.h"
|
||||
|
||||
static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
|
||||
uint32_t surface_id, uint32_t width,
|
||||
uint32_t height, uint32_t format, uint32_t flags)
|
||||
{
|
||||
SurfaceCreateItem *create;
|
||||
|
||||
create = spice_malloc(sizeof(SurfaceCreateItem));
|
||||
|
||||
create->surface_create.surface_id = surface_id;
|
||||
create->surface_create.width = width;
|
||||
create->surface_create.height = height;
|
||||
create->surface_create.flags = flags;
|
||||
create->surface_create.format = format;
|
||||
|
||||
red_channel_pipe_item_init(channel,
|
||||
&create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
|
||||
return create;
|
||||
}
|
||||
|
||||
void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
|
||||
{
|
||||
DisplayChannel *display;
|
||||
RedSurface *surface;
|
||||
SurfaceCreateItem *create;
|
||||
uint32_t flags;
|
||||
|
||||
if (!dcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
display = DCC_TO_DC(dcc);
|
||||
flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
|
||||
|
||||
/* don't send redundant create surface commands to client */
|
||||
if (!dcc || display->common.during_target_migrate ||
|
||||
dcc->surface_client_created[surface_id]) {
|
||||
return;
|
||||
}
|
||||
surface = &display->surfaces[surface_id];
|
||||
create = surface_create_item_new(RED_CHANNEL_CLIENT(dcc)->channel,
|
||||
surface_id, surface->context.width, surface->context.height,
|
||||
surface->context.format, flags);
|
||||
dcc->surface_client_created[surface_id] = TRUE;
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &create->pipe_item);
|
||||
}
|
||||
|
||||
void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
|
||||
{
|
||||
DisplayChannel *display;
|
||||
SpiceRect area;
|
||||
RedSurface *surface;
|
||||
|
||||
if (!dcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
display = DCC_TO_DC(dcc);
|
||||
surface = &display->surfaces[surface_id];
|
||||
if (!surface->context.canvas) {
|
||||
return;
|
||||
}
|
||||
area.top = area.left = 0;
|
||||
area.right = surface->context.width;
|
||||
area.bottom = surface->context.height;
|
||||
|
||||
/* 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"*/
|
||||
dcc_add_surface_area_image(dcc, surface_id, &area, NULL, FALSE);
|
||||
red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
|
||||
}
|
||||
|
||||
static void dcc_init_stream_agents(DisplayChannelClient *dcc)
|
||||
{
|
||||
int i;
|
||||
DisplayChannel *display = DCC_TO_DC(dcc);
|
||||
RedChannel *channel = RED_CHANNEL_CLIENT(dcc)->channel;
|
||||
|
||||
for (i = 0; i < NUM_STREAMS; i++) {
|
||||
StreamAgent *agent = &dcc->stream_agents[i];
|
||||
agent->stream = &display->streams_buf[i];
|
||||
region_init(&agent->vis_region);
|
||||
region_init(&agent->clip);
|
||||
red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
|
||||
red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
|
||||
}
|
||||
dcc->use_mjpeg_encoder_rate_control =
|
||||
red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT);
|
||||
}
|
||||
|
||||
#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
|
||||
|
||||
DisplayChannelClient *dcc_new(DisplayChannel *display,
|
||||
RedClient *client, RedsStream *stream,
|
||||
int mig_target,
|
||||
@ -40,6 +131,7 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
|
||||
common_caps, num_common_caps,
|
||||
caps, num_caps);
|
||||
spice_return_val_if_fail(dcc, NULL);
|
||||
spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream);
|
||||
|
||||
ring_init(&dcc->palette_cache_lru);
|
||||
dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
|
||||
@ -49,11 +141,89 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
|
||||
// TODO: tune quality according to bandwidth
|
||||
dcc->jpeg_quality = 85;
|
||||
|
||||
size_t stream_buf_size;
|
||||
stream_buf_size = 32*1024;
|
||||
dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
|
||||
dcc->send_data.stream_outbuf_size = stream_buf_size;
|
||||
dcc->send_data.free_list.res =
|
||||
spice_malloc(sizeof(SpiceResourceList) +
|
||||
DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
|
||||
dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
|
||||
|
||||
dcc_init_stream_agents(dcc);
|
||||
|
||||
dcc_encoders_init(dcc);
|
||||
|
||||
return dcc;
|
||||
}
|
||||
|
||||
static void dcc_create_all_streams(DisplayChannelClient *dcc)
|
||||
{
|
||||
Ring *ring = &DCC_TO_DC(dcc)->streams;
|
||||
RingItem *item = ring;
|
||||
|
||||
while ((item = ring_next(ring, item))) {
|
||||
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
|
||||
dcc_create_stream(dcc, stream);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: this function is evil^Wsynchronous, fix */
|
||||
static int display_channel_client_wait_for_init(DisplayChannelClient *dcc)
|
||||
{
|
||||
dcc->expect_init = TRUE;
|
||||
uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_TIMEOUT;
|
||||
for (;;) {
|
||||
red_channel_client_receive(RED_CHANNEL_CLIENT(dcc));
|
||||
if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(dcc))) {
|
||||
break;
|
||||
}
|
||||
if (dcc->pixmap_cache && dcc->glz_dict) {
|
||||
dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
|
||||
/* TODO: move common.id? if it's used for a per client structure.. */
|
||||
spice_info("creating encoder with id == %d", dcc->common.id);
|
||||
dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
|
||||
if (!dcc->glz) {
|
||||
spice_critical("create global lz failed");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
if (red_get_monotonic_time() > end_time) {
|
||||
spice_warning("timeout");
|
||||
red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
|
||||
break;
|
||||
}
|
||||
usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void dcc_start(DisplayChannelClient *dcc)
|
||||
{
|
||||
DisplayChannel *display = DCC_TO_DC(dcc);
|
||||
RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
|
||||
|
||||
red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
|
||||
|
||||
if (red_channel_client_waits_for_migrate_data(rcc))
|
||||
return;
|
||||
|
||||
if (!display_channel_client_wait_for_init(dcc))
|
||||
return;
|
||||
|
||||
red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
|
||||
if (display->surfaces[0].context.canvas) {
|
||||
display_channel_current_flush(display, 0);
|
||||
red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
|
||||
dcc_create_surface(dcc, 0);
|
||||
dcc_push_surface_image(dcc, 0);
|
||||
dcc_push_monitors_config(dcc);
|
||||
red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
|
||||
dcc_create_all_streams(dcc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
|
||||
{
|
||||
StreamClipItem *item = stream_clip_item_new(dcc, agent);
|
||||
|
||||
33
server/dcc.h
33
server/dcc.h
@ -31,6 +31,10 @@
|
||||
#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK)
|
||||
#define CLIENT_PALETTE_CACHE_SIZE 128
|
||||
|
||||
#define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
|
||||
#define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
|
||||
#define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
|
||||
|
||||
/* Each drawable can refer to at most 3 images: src, brush and mask */
|
||||
#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
|
||||
|
||||
@ -111,6 +115,25 @@ struct DisplayChannelClient {
|
||||
SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base)
|
||||
#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
|
||||
|
||||
typedef struct SurfaceCreateItem {
|
||||
SpiceMsgSurfaceCreate surface_create;
|
||||
PipeItem pipe_item;
|
||||
} SurfaceCreateItem;
|
||||
|
||||
typedef struct ImageItem {
|
||||
PipeItem link;
|
||||
int refs;
|
||||
SpicePoint pos;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
int top_down;
|
||||
int surface_id;
|
||||
int image_format;
|
||||
uint32_t image_flags;
|
||||
int can_lossy;
|
||||
uint8_t data[0];
|
||||
} ImageItem;
|
||||
|
||||
DisplayChannelClient* dcc_new (DisplayChannel *display,
|
||||
RedClient *client,
|
||||
@ -123,6 +146,7 @@ DisplayChannelClient* dcc_new (DisplayCha
|
||||
SpiceImageCompression image_compression,
|
||||
spice_wan_compression_t jpeg_state,
|
||||
spice_wan_compression_t zlib_glz_state);
|
||||
void dcc_start (DisplayChannelClient *dcc);
|
||||
void dcc_push_monitors_config (DisplayChannelClient *dcc);
|
||||
void dcc_destroy_surface (DisplayChannelClient *dcc,
|
||||
uint32_t surface_id);
|
||||
@ -130,5 +154,14 @@ void dcc_stream_agent_clip (DisplayCha
|
||||
StreamAgent *agent);
|
||||
void dcc_create_stream (DisplayChannelClient *dcc,
|
||||
Stream *stream);
|
||||
void dcc_create_surface (DisplayChannelClient *dcc,
|
||||
int surface_id);
|
||||
void dcc_push_surface_image (DisplayChannelClient *dcc,
|
||||
int surface_id);
|
||||
ImageItem * dcc_add_surface_area_image (DisplayChannelClient *dcc,
|
||||
int surface_id,
|
||||
SpiceRect *area,
|
||||
PipeItem *pos,
|
||||
int can_lossy);
|
||||
|
||||
#endif /* DCC_H_ */
|
||||
|
||||
@ -253,11 +253,6 @@ typedef struct SurfaceDestroyItem {
|
||||
PipeItem pipe_item;
|
||||
} SurfaceDestroyItem;
|
||||
|
||||
typedef struct SurfaceCreateItem {
|
||||
SpiceMsgSurfaceCreate surface_create;
|
||||
PipeItem pipe_item;
|
||||
} SurfaceCreateItem;
|
||||
|
||||
|
||||
void display_channel_set_stream_video (DisplayChannel *display,
|
||||
int stream_video);
|
||||
@ -271,6 +266,8 @@ bool display_channel_surface_has_canvas (DisplayCha
|
||||
uint32_t surface_id);
|
||||
int display_channel_add_drawable (DisplayChannel *display,
|
||||
Drawable *drawable);
|
||||
void display_channel_current_flush (DisplayChannel *display,
|
||||
int surface_id);
|
||||
|
||||
static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
|
||||
{
|
||||
|
||||
@ -119,21 +119,6 @@ struct SpiceWatch {
|
||||
#define WIDE_CLIENT_ACK_WINDOW 40
|
||||
#define NARROW_CLIENT_ACK_WINDOW 20
|
||||
|
||||
typedef struct ImageItem {
|
||||
PipeItem link;
|
||||
int refs;
|
||||
SpicePoint pos;
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
int top_down;
|
||||
int surface_id;
|
||||
int image_format;
|
||||
uint32_t image_flags;
|
||||
int can_lossy;
|
||||
uint8_t data[0];
|
||||
} ImageItem;
|
||||
|
||||
pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
Ring glz_dictionary_list = {&glz_dictionary_list, &glz_dictionary_list};
|
||||
|
||||
@ -199,7 +184,6 @@ typedef struct BitmapData {
|
||||
static inline int validate_surface(DisplayChannel *display, uint32_t surface_id);
|
||||
|
||||
static void red_draw_qxl_drawable(DisplayChannel *display, Drawable *drawable);
|
||||
static void red_current_flush(DisplayChannel *display, int surface_id);
|
||||
static void red_draw_drawable(DisplayChannel *display, Drawable *item);
|
||||
static void red_update_area(DisplayChannel *display, const SpiceRect *area, int surface_id);
|
||||
static void red_update_area_till(DisplayChannel *display, const SpiceRect *area, int surface_id,
|
||||
@ -211,8 +195,6 @@ static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type
|
||||
uint64_t* sync_data);
|
||||
static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc);
|
||||
static void dcc_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable);
|
||||
static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
|
||||
SpiceRect *area, PipeItem *pos, int can_lossy);
|
||||
static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
|
||||
PipeItem *item);
|
||||
static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
|
||||
@ -369,8 +351,6 @@ static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id);
|
||||
static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id);
|
||||
|
||||
static inline void red_handle_drawable_surfaces_client_synced(
|
||||
DisplayChannelClient *dcc, Drawable *drawable)
|
||||
@ -386,9 +366,9 @@ static inline void red_handle_drawable_surfaces_client_synced(
|
||||
if (dcc->surface_client_created[surface_id] == TRUE) {
|
||||
continue;
|
||||
}
|
||||
red_create_surface_item(dcc, surface_id);
|
||||
red_current_flush(display, surface_id);
|
||||
red_push_surface_image(dcc, surface_id);
|
||||
dcc_create_surface(dcc, surface_id);
|
||||
display_channel_current_flush(display, surface_id);
|
||||
dcc_push_surface_image(dcc, surface_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,9 +376,9 @@ static inline void red_handle_drawable_surfaces_client_synced(
|
||||
return;
|
||||
}
|
||||
|
||||
red_create_surface_item(dcc, drawable->surface_id);
|
||||
red_current_flush(display, drawable->surface_id);
|
||||
red_push_surface_image(dcc, drawable->surface_id);
|
||||
dcc_create_surface(dcc, drawable->surface_id);
|
||||
display_channel_current_flush(display, drawable->surface_id);
|
||||
dcc_push_surface_image(dcc, drawable->surface_id);
|
||||
}
|
||||
|
||||
static int display_is_connected(RedWorker *worker)
|
||||
@ -985,7 +965,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
|
||||
} else {
|
||||
red_update_area(DCC_TO_DC(dcc), &upgrade_area, 0);
|
||||
}
|
||||
red_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
|
||||
dcc_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
|
||||
}
|
||||
clear_vis_region:
|
||||
region_clear(&agent->vis_region);
|
||||
@ -1065,35 +1045,6 @@ static void display_channel_streams_timeout(DisplayChannel *display)
|
||||
}
|
||||
}
|
||||
|
||||
static void dcc_create_all_streams(DisplayChannelClient *dcc)
|
||||
{
|
||||
Ring *ring = &DCC_TO_DC(dcc)->streams;
|
||||
RingItem *item = ring;
|
||||
|
||||
while ((item = ring_next(ring, item))) {
|
||||
Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
|
||||
dcc_create_stream(dcc, stream);
|
||||
}
|
||||
}
|
||||
|
||||
static void dcc_init_stream_agents(DisplayChannelClient *dcc)
|
||||
{
|
||||
int i;
|
||||
DisplayChannel *display = DCC_TO_DC(dcc);
|
||||
RedChannel *channel = RED_CHANNEL_CLIENT(dcc)->channel;
|
||||
|
||||
for (i = 0; i < NUM_STREAMS; i++) {
|
||||
StreamAgent *agent = &dcc->stream_agents[i];
|
||||
agent->stream = &display->streams_buf[i];
|
||||
region_init(&agent->vis_region);
|
||||
region_init(&agent->clip);
|
||||
red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
|
||||
red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
|
||||
}
|
||||
dcc->use_mjpeg_encoder_rate_control =
|
||||
red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT);
|
||||
}
|
||||
|
||||
static void dcc_destroy_stream_agents(DisplayChannelClient *dcc)
|
||||
{
|
||||
int i;
|
||||
@ -1999,7 +1950,7 @@ static void red_free_some(RedWorker *worker)
|
||||
}
|
||||
}
|
||||
|
||||
static void red_current_flush(DisplayChannel *display, int surface_id)
|
||||
void display_channel_current_flush(DisplayChannel *display, int surface_id)
|
||||
{
|
||||
while (!ring_is_empty(&display->surfaces[surface_id].current_list)) {
|
||||
free_one_drawable(display, FALSE);
|
||||
@ -2008,8 +1959,8 @@ static void red_current_flush(DisplayChannel *display, int surface_id)
|
||||
}
|
||||
|
||||
// adding the pipe item after pos. If pos == NULL, adding to head.
|
||||
static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
|
||||
SpiceRect *area, PipeItem *pos, int can_lossy)
|
||||
ImageItem *dcc_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
|
||||
SpiceRect *area, PipeItem *pos, int can_lossy)
|
||||
{
|
||||
DisplayChannel *display = DCC_TO_DC(dcc);
|
||||
RedChannel *channel = RED_CHANNEL(display);
|
||||
@ -2071,31 +2022,6 @@ static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
|
||||
return item;
|
||||
}
|
||||
|
||||
static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id)
|
||||
{
|
||||
DisplayChannel *display;
|
||||
SpiceRect area;
|
||||
RedSurface *surface;
|
||||
|
||||
if (!dcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
display = DCC_TO_DC(dcc);
|
||||
surface = &display->surfaces[surface_id];
|
||||
if (!surface->context.canvas) {
|
||||
return;
|
||||
}
|
||||
area.top = area.left = 0;
|
||||
area.right = surface->context.width;
|
||||
area.bottom = surface->context.height;
|
||||
|
||||
/* 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(dcc, surface_id, &area, NULL, FALSE);
|
||||
red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
|
||||
}
|
||||
|
||||
static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
|
||||
{
|
||||
SpiceMsgDisplayBase base;
|
||||
@ -3501,7 +3427,7 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
|
||||
continue;
|
||||
}
|
||||
|
||||
image = red_add_surface_area_image(dcc, drawable->red_drawable->surface_id,
|
||||
image = dcc_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;
|
||||
@ -3557,7 +3483,7 @@ static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc,
|
||||
// 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(dcc, deps_surfaces_ids[i], deps_areas[i],
|
||||
dcc_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i],
|
||||
red_pipe_get_tail(dcc), FALSE);
|
||||
|
||||
}
|
||||
@ -3578,7 +3504,7 @@ static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc,
|
||||
&drawable->bbox);
|
||||
}
|
||||
|
||||
red_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox,
|
||||
dcc_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox,
|
||||
red_pipe_get_tail(dcc), TRUE);
|
||||
}
|
||||
}
|
||||
@ -5574,60 +5500,13 @@ static inline void *create_canvas_for_surface(DisplayChannel *display, RedSurfac
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SurfaceCreateItem *get_surface_create_item(
|
||||
RedChannel* channel,
|
||||
uint32_t surface_id, uint32_t width,
|
||||
uint32_t height, uint32_t format, uint32_t flags)
|
||||
{
|
||||
SurfaceCreateItem *create;
|
||||
|
||||
create = spice_malloc(sizeof(SurfaceCreateItem));
|
||||
|
||||
create->surface_create.surface_id = surface_id;
|
||||
create->surface_create.width = width;
|
||||
create->surface_create.height = height;
|
||||
create->surface_create.flags = flags;
|
||||
create->surface_create.format = format;
|
||||
|
||||
red_channel_pipe_item_init(channel,
|
||||
&create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
|
||||
return create;
|
||||
}
|
||||
|
||||
static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id)
|
||||
{
|
||||
DisplayChannel *display;
|
||||
RedSurface *surface;
|
||||
SurfaceCreateItem *create;
|
||||
uint32_t flags;
|
||||
|
||||
if (!dcc) {
|
||||
return;
|
||||
}
|
||||
|
||||
display = DCC_TO_DC(dcc);
|
||||
flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
|
||||
|
||||
/* don't send redundant create surface commands to client */
|
||||
if (display->common.during_target_migrate ||
|
||||
dcc->surface_client_created[surface_id]) {
|
||||
return;
|
||||
}
|
||||
surface = &display->surfaces[surface_id];
|
||||
create = get_surface_create_item(RED_CHANNEL_CLIENT(dcc)->channel,
|
||||
surface_id, surface->context.width, surface->context.height,
|
||||
surface->context.format, flags);
|
||||
dcc->surface_client_created[surface_id] = TRUE;
|
||||
red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &create->pipe_item);
|
||||
}
|
||||
|
||||
static void red_worker_create_surface_item(DisplayChannel *display, int surface_id)
|
||||
{
|
||||
DisplayChannelClient *dcc;
|
||||
RingItem *item, *next;
|
||||
|
||||
FOREACH_DCC(display, item, next, dcc) {
|
||||
red_create_surface_item(dcc, surface_id);
|
||||
dcc_create_surface(dcc, surface_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5638,7 +5517,7 @@ static void red_worker_push_surface_image(DisplayChannel *display, int surface_i
|
||||
RingItem *item, *next;
|
||||
|
||||
FOREACH_DCC(display, item, next, dcc) {
|
||||
red_push_surface_image(dcc, surface_id);
|
||||
dcc_push_surface_image(dcc, surface_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5803,70 +5682,6 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
|
||||
flush_cursor_commands(worker);
|
||||
}
|
||||
|
||||
static void push_new_primary_surface(DisplayChannelClient *dcc)
|
||||
{
|
||||
RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
|
||||
|
||||
red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
|
||||
red_create_surface_item(dcc, 0);
|
||||
red_channel_client_push(rcc);
|
||||
}
|
||||
|
||||
/* TODO: this function is evil^Wsynchronous, fix */
|
||||
static int display_channel_client_wait_for_init(DisplayChannelClient *dcc)
|
||||
{
|
||||
dcc->expect_init = TRUE;
|
||||
uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_TIMEOUT;
|
||||
for (;;) {
|
||||
red_channel_client_receive(RED_CHANNEL_CLIENT(dcc));
|
||||
if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(dcc))) {
|
||||
break;
|
||||
}
|
||||
if (dcc->pixmap_cache && dcc->glz_dict) {
|
||||
dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
|
||||
/* TODO: move common.id? if it's used for a per client structure.. */
|
||||
spice_info("creating encoder with id == %d", dcc->common.id);
|
||||
dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
|
||||
if (!dcc->glz) {
|
||||
spice_critical("create global lz failed");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
if (red_get_monotonic_time() > end_time) {
|
||||
spice_warning("timeout");
|
||||
red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
|
||||
break;
|
||||
}
|
||||
usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void on_new_display_channel_client(DisplayChannelClient *dcc)
|
||||
{
|
||||
DisplayChannel *display = DCC_TO_DC(dcc);
|
||||
RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
|
||||
|
||||
red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
|
||||
|
||||
if (red_channel_client_waits_for_migrate_data(rcc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!display_channel_client_wait_for_init(dcc)) {
|
||||
return;
|
||||
}
|
||||
red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
|
||||
if (display->surfaces[0].context.canvas) {
|
||||
red_current_flush(display, 0);
|
||||
push_new_primary_surface(dcc);
|
||||
red_push_surface_image(dcc, 0);
|
||||
dcc_push_monitors_config(dcc);
|
||||
red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
|
||||
dcc_create_all_streams(dcc);
|
||||
}
|
||||
}
|
||||
|
||||
static GlzSharedDictionary *_red_find_glz_dictionary(RedClient *client, uint8_t dict_id)
|
||||
{
|
||||
RingItem *now;
|
||||
@ -6707,12 +6522,9 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
|
||||
{
|
||||
DisplayChannel *display_channel;
|
||||
DisplayChannelClient *dcc;
|
||||
size_t stream_buf_size;
|
||||
|
||||
if (!worker->display_channel) {
|
||||
spice_warning("Display channel was not created");
|
||||
return;
|
||||
}
|
||||
spice_return_if_fail(worker->display_channel);
|
||||
|
||||
display_channel = worker->display_channel;
|
||||
spice_info("add display channel client");
|
||||
dcc = dcc_new(display_channel, client, stream, migrate,
|
||||
@ -6721,14 +6533,6 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
|
||||
if (!dcc) {
|
||||
return;
|
||||
}
|
||||
spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream);
|
||||
stream_buf_size = 32*1024;
|
||||
dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
|
||||
dcc->send_data.stream_outbuf_size = stream_buf_size;
|
||||
dcc->send_data.free_list.res =
|
||||
spice_malloc(sizeof(SpiceResourceList) +
|
||||
DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
|
||||
dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
|
||||
|
||||
if (dcc->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
|
||||
display_channel->enable_jpeg = dcc->common.is_low_bandwidth;
|
||||
@ -6742,14 +6546,11 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
|
||||
display_channel->enable_zlib_glz_wrap = (dcc->zlib_glz_state ==
|
||||
SPICE_WAN_COMPRESSION_ALWAYS);
|
||||
}
|
||||
|
||||
spice_info("jpeg %s", display_channel->enable_jpeg ? "enabled" : "disabled");
|
||||
spice_info("zlib-over-glz %s", display_channel->enable_zlib_glz_wrap ? "enabled" : "disabled");
|
||||
|
||||
guest_set_client_capabilities(worker);
|
||||
|
||||
dcc_init_stream_agents(dcc);
|
||||
on_new_display_channel_client(dcc);
|
||||
dcc_start(dcc);
|
||||
}
|
||||
|
||||
static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream *stream,
|
||||
@ -7066,7 +6867,7 @@ static void flush_all_surfaces(DisplayChannel *display)
|
||||
|
||||
for (x = 0; x < NUM_SURFACES; ++x) {
|
||||
if (display->surfaces[x].context.canvas) {
|
||||
red_current_flush(display, x);
|
||||
display_channel_current_flush(display, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user