/* Copyright (C) 2009-2015 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #ifdef HAVE_CONFIG_H #include #endif #include "display-channel.h" void display_channel_compress_stats_reset(DisplayChannel *display) { spice_return_if_fail(display); #ifdef COMPRESS_STAT stat_reset(&display->quic_stat); stat_reset(&display->lz_stat); stat_reset(&display->glz_stat); stat_reset(&display->jpeg_stat); stat_reset(&display->zlib_glz_stat); stat_reset(&display->jpeg_alpha_stat); stat_reset(&display->lz4_stat); #endif } void display_channel_compress_stats_print(const DisplayChannel *display_channel) { spice_return_if_fail(display_channel); #ifdef COMPRESS_STAT uint64_t glz_enc_size; glz_enc_size = display_channel->enable_zlib_glz_wrap ? display_channel->zlib_glz_stat.comp_size : display_channel->glz_stat.comp_size; spice_info("==> Compression stats for display %u", display_channel->common.base.id); spice_info("Method \t count \torig_size(MB)\tenc_size(MB)\tenc_time(s)"); spice_info("QUIC \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->quic_stat.count, stat_byte_to_mega(display_channel->quic_stat.orig_size), stat_byte_to_mega(display_channel->quic_stat.comp_size), stat_cpu_time_to_sec(display_channel->quic_stat.total) ); spice_info("GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->glz_stat.count, stat_byte_to_mega(display_channel->glz_stat.orig_size), stat_byte_to_mega(display_channel->glz_stat.comp_size), stat_cpu_time_to_sec(display_channel->glz_stat.total) ); spice_info("ZLIB GLZ \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->zlib_glz_stat.count, stat_byte_to_mega(display_channel->zlib_glz_stat.orig_size), stat_byte_to_mega(display_channel->zlib_glz_stat.comp_size), stat_cpu_time_to_sec(display_channel->zlib_glz_stat.total) ); spice_info("LZ \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->lz_stat.count, stat_byte_to_mega(display_channel->lz_stat.orig_size), stat_byte_to_mega(display_channel->lz_stat.comp_size), stat_cpu_time_to_sec(display_channel->lz_stat.total) ); spice_info("JPEG \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->jpeg_stat.count, stat_byte_to_mega(display_channel->jpeg_stat.orig_size), stat_byte_to_mega(display_channel->jpeg_stat.comp_size), stat_cpu_time_to_sec(display_channel->jpeg_stat.total) ); spice_info("JPEG-RGBA\t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->jpeg_alpha_stat.count, stat_byte_to_mega(display_channel->jpeg_alpha_stat.orig_size), stat_byte_to_mega(display_channel->jpeg_alpha_stat.comp_size), stat_cpu_time_to_sec(display_channel->jpeg_alpha_stat.total) ); spice_info("LZ4 \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->lz4_stat.count, stat_byte_to_mega(display_channel->lz4_stat.orig_size), stat_byte_to_mega(display_channel->lz4_stat.comp_size), stat_cpu_time_to_sec(display_channel->lz4_stat.total) ); spice_info("-------------------------------------------------------------------"); spice_info("Total \t%8d\t%13.2f\t%12.2f\t%12.2f", display_channel->lz_stat.count + display_channel->glz_stat.count + display_channel->quic_stat.count + display_channel->jpeg_stat.count + display_channel->lz4_stat.count + display_channel->jpeg_alpha_stat.count, stat_byte_to_mega(display_channel->lz_stat.orig_size + display_channel->glz_stat.orig_size + display_channel->quic_stat.orig_size + display_channel->jpeg_stat.orig_size + display_channel->lz4_stat.orig_size + display_channel->jpeg_alpha_stat.orig_size), stat_byte_to_mega(display_channel->lz_stat.comp_size + glz_enc_size + display_channel->quic_stat.comp_size + display_channel->jpeg_stat.comp_size + display_channel->lz4_stat.comp_size + display_channel->jpeg_alpha_stat.comp_size), stat_cpu_time_to_sec(display_channel->lz_stat.total + display_channel->glz_stat.total + display_channel->zlib_glz_stat.total + display_channel->quic_stat.total + display_channel->jpeg_stat.total + display_channel->lz4_stat.total + display_channel->jpeg_alpha_stat.total) ); #endif } DisplayChannelClient *dcc_new(DisplayChannel *display, RedClient *client, RedsStream *stream, int mig_target, uint32_t *common_caps, int num_common_caps, uint32_t *caps, int num_caps) { DisplayChannelClient *dcc; dcc = (DisplayChannelClient*)common_channel_new_client( (CommonChannel *)display, sizeof(DisplayChannelClient), client, stream, mig_target, TRUE, common_caps, num_common_caps, caps, num_caps); spice_return_val_if_fail(dcc, NULL); ring_init(&dcc->palette_cache_lru); dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE; return dcc; } MonitorsConfig* monitors_config_ref(MonitorsConfig *monitors_config) { monitors_config->refs++; return monitors_config; } void monitors_config_unref(MonitorsConfig *monitors_config) { if (!monitors_config) { return; } if (--monitors_config->refs != 0) { return; } spice_debug("freeing monitors config"); free(monitors_config); } static void monitors_config_debug(MonitorsConfig *mc) { int i; spice_debug("monitors config count:%d max:%d", mc->count, mc->max_allowed); for (i = 0; i < mc->count; i++) spice_debug("+%d+%d %dx%d", mc->heads[i].x, mc->heads[i].y, mc->heads[i].width, mc->heads[i].height); } MonitorsConfig* monitors_config_new(QXLHead *heads, ssize_t nheads, ssize_t max) { MonitorsConfig *mc; mc = spice_malloc(sizeof(MonitorsConfig) + nheads * sizeof(QXLHead)); mc->refs = 1; mc->count = nheads; mc->max_allowed = max; memcpy(mc->heads, heads, nheads * sizeof(QXLHead)); monitors_config_debug(mc); return mc; } static MonitorsConfigItem *monitors_config_item_new(RedChannel* channel, MonitorsConfig *monitors_config) { MonitorsConfigItem *mci; mci = (MonitorsConfigItem *)spice_malloc(sizeof(*mci)); mci->monitors_config = monitors_config; red_channel_pipe_item_init(channel, &mci->pipe_item, PIPE_ITEM_TYPE_MONITORS_CONFIG); return mci; } static inline void red_monitors_config_item_add(DisplayChannelClient *dcc) { DisplayChannel *dc = DCC_TO_DC(dcc); MonitorsConfigItem *mci; mci = monitors_config_item_new(dcc->common.base.channel, monitors_config_ref(dc->monitors_config)); red_channel_client_pipe_add(&dcc->common.base, &mci->pipe_item); } void dcc_push_monitors_config(DisplayChannelClient *dcc) { MonitorsConfig *monitors_config = DCC_TO_DC(dcc)->monitors_config; if (monitors_config == NULL) { spice_warning("monitors_config is NULL"); return; } if (!red_channel_client_test_remote_cap(&dcc->common.base, SPICE_DISPLAY_CAP_MONITORS_CONFIG)) { return; } red_monitors_config_item_add(dcc); red_channel_client_push(&dcc->common.base); } static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel, uint32_t surface_id) { SurfaceDestroyItem *destroy; destroy = spice_malloc(sizeof(SurfaceDestroyItem)); destroy->surface_destroy.surface_id = surface_id; red_channel_pipe_item_init(channel, &destroy->pipe_item, PIPE_ITEM_TYPE_DESTROY_SURFACE); return destroy; } void dcc_push_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id) { DisplayChannel *display; RedChannel *channel; SurfaceDestroyItem *destroy; if (!dcc) { return; } display = DCC_TO_DC(dcc); channel = RED_CHANNEL(display); if (COMMON_CHANNEL(display)->during_target_migrate || !dcc->surface_client_created[surface_id]) { return; } dcc->surface_client_created[surface_id] = FALSE; destroy = surface_destroy_item_new(channel, surface_id); red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item); } int display_channel_get_streams_timeout(DisplayChannel *display) { int timeout = INT_MAX; Ring *ring = &display->streams; RingItem *item = ring; red_time_t now = red_get_monotonic_time(); while ((item = ring_next(ring, item))) { Stream *stream; stream = SPICE_CONTAINEROF(item, Stream, link); red_time_t delta = (stream->last_time + RED_STREAM_TIMEOUT) - now; if (delta < 1000 * 1000) { return 0; } timeout = MIN(timeout, (unsigned int)(delta / (1000 * 1000))); } return timeout; } void display_channel_set_stream_video(DisplayChannel *display, int stream_video) { spice_return_if_fail(display); spice_return_if_fail(stream_video != SPICE_STREAM_VIDEO_INVALID); switch (stream_video) { case SPICE_STREAM_VIDEO_ALL: spice_info("sv all"); break; case SPICE_STREAM_VIDEO_FILTER: spice_info("sv filter"); break; case SPICE_STREAM_VIDEO_OFF: spice_info("sv off"); break; default: spice_warn_if_reached(); return; } display->stream_video = stream_video; }