Commit 0ad91336 authored by Jeremy White's avatar Jeremy White

Begin to transmit draws across.

parent 06ac2055
......@@ -63,11 +63,16 @@ int display_open(display_t *d, options_t *options)
return 0;
}
int create_shm_image(display_t *d, shm_image_t *shmi, int w, int h)
shm_image_t * create_shm_image(display_t *d, int w, int h)
{
shm_image_t *shmi;
int scr = DefaultScreen(d->xdisplay);
int imgsize;
shmi = calloc(1, sizeof(*shmi));
if (! shmi)
return shmi;
shmi->img = XShmCreateImage(d->xdisplay,
DefaultVisual(d->xdisplay, scr),
DefaultDepth(d->xdisplay, scr),
......@@ -76,7 +81,10 @@ int create_shm_image(display_t *d, shm_image_t *shmi, int w, int h)
w ? w : DisplayWidth(d->xdisplay, scr),
h ? h : DisplayHeight(d->xdisplay, scr));
if (! shmi->img)
return X11SPICE_ERR_NOSHM;
{
free(shmi);
return NULL;
}
imgsize = shmi->img->bytes_per_line * shmi->img->height;
......@@ -85,7 +93,8 @@ int create_shm_image(display_t *d, shm_image_t *shmi, int w, int h)
{
g_error("Cannot get shared memory of size %d", imgsize);
XDestroyImage(shmi->img);
return X11SPICE_ERR_NOSHM;
free(shmi);
return NULL;
}
shmi->info.shmaddr = shmi->img->data = shmat(shmi->info.shmid, 0, 0);
......@@ -97,10 +106,11 @@ int create_shm_image(display_t *d, shm_image_t *shmi, int w, int h)
shmdt(shmi->info.shmaddr);
shmctl(shmi->info.shmid, IPC_RMID, NULL);
XDestroyImage(shmi->img);
return X11SPICE_ERR_NOSHM;
free(shmi);
return NULL;
}
return 0;
return shmi;
}
int read_shm_image(display_t *d, shm_image_t *shmi, int x, int y)
......@@ -121,11 +131,18 @@ void destroy_shm_image(display_t *d, shm_image_t *shmi)
shmdt(shmi->info.shmaddr);
shmctl(shmi->info.shmid, IPC_RMID, NULL);
XDestroyImage(shmi->img);
if (shmi->drawable_ptr)
free(shmi->drawable_ptr);
}
void display_close(display_t *d)
{
XDamageDestroy(d->xdisplay, d->xdamage);
XCloseDisplay(d->xdisplay);
if (d->fullscreen)
{
destroy_shm_image(d, d->fullscreen);
d->fullscreen = NULL;
}
}
......@@ -32,6 +32,7 @@ typedef struct
{
XImage *img;
XShmSegmentInfo info;
void *drawable_ptr;
}shm_image_t;
typedef struct
......@@ -40,7 +41,7 @@ typedef struct
Damage xdamage;
int xd_event_base;
int xd_error_base;
shm_image_t fullscreen;
shm_image_t *fullscreen;
} display_t;
......@@ -49,7 +50,7 @@ typedef struct
**--------------------------------------------------------------------------*/
int display_open(display_t *display, options_t *options);
void display_close(display_t *display);
int create_shm_image(display_t *d, shm_image_t *shmi, int w, int h);
shm_image_t * create_shm_image(display_t *d, int w, int h);
int read_shm_image(display_t *d, shm_image_t *shmi, int x, int y);
void destroy_shm_image(display_t *d, shm_image_t *shmi);
......
......@@ -35,6 +35,8 @@ typedef struct
QXLInstance display_sin;
QXLWorker *worker;
int compression_level;
void *session_ptr;
} spice_t;
/*----------------------------------------------------------------------------
......
......@@ -49,55 +49,134 @@ static void save_ximage_pnm(XImage *img)
fclose(fp);
}
static QXLDrawable *shm_image_to_drawable(shm_image_t *shmi, int x, int y)
{
QXLDrawable *drawable;
QXLImage *qxl_image;
int i;
drawable = calloc(1, sizeof(*drawable) + sizeof(*qxl_image));
if (! drawable)
return NULL;
qxl_image = (QXLImage *) (drawable + 1);
drawable->release_info.id = (uint64_t) shmi;
shmi->drawable_ptr = drawable;
drawable->surface_id = 0;
drawable->type = QXL_DRAW_COPY;;
drawable->effect = QXL_EFFECT_OPAQUE;
drawable->clip.type = SPICE_CLIP_TYPE_NONE;
drawable->bbox.left = x;
drawable->bbox.top = y;
drawable->bbox.right = x + shmi->img->width;
drawable->bbox.bottom = y + shmi->img->height;
/*
* surfaces_dest[i] should apparently be filled out with the
* surfaces that we depend on, and surface_rects should be
* filled with the rectangles of those surfaces that we
* are going to use.
* FIXME - explore this instead of blindly copying...
*/
for (i = 0; i < 3; ++i)
drawable->surfaces_dest[i] = -1;
drawable->u.copy.src_area = drawable->bbox;
drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT;
drawable->u.copy.src_bitmap = (QXLPHYSICAL) qxl_image;
qxl_image->descriptor.id = 0;
qxl_image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
qxl_image->descriptor.flags = 0;
qxl_image->descriptor.width = shmi->img->width;
qxl_image->descriptor.height = shmi->img->height;
// FIXME - be a bit more dynamic...
qxl_image->bitmap.format = SPICE_BITMAP_FMT_RGBA;
qxl_image->bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN | QXL_BITMAP_DIRECT;
qxl_image->bitmap.x = shmi->img->width;
qxl_image->bitmap.y = shmi->img->height;
qxl_image->bitmap.stride = shmi->img->bytes_per_line;
qxl_image->bitmap.palette = 0;
qxl_image->bitmap.data = (QXLPHYSICAL) shmi->img->data;
// FIXME - cache images at all?
return drawable;
}
static void session_handle_xevent(int fd, int event, void *opaque)
{
session_t *s = (session_t *) opaque;
XEvent xev;
int rc;
XDamageNotifyEvent *dev = (XDamageNotifyEvent *) &xev;;
shm_image_t *shmi = NULL;
rc = XNextEvent(s->display.xdisplay, &xev);
if (rc == 0)
if (rc)
return;
if (xev.type != s->display.xd_event_base + XDamageNotify)
{
shm_image_t shmi;
g_debug("Unexpected X event %d", xev.type);
return;
}
g_debug("XDamageNotify [ser %ld|send_event %d|level %d|more %d|area (%dx%d)@%dx%d|geo (%dx%d)@%dx%d",
dev->serial, dev->send_event, dev->level, dev->more,
dev->area.width, dev->area.height, dev->area.x, dev->area.y,
dev->geometry.width, dev->geometry.height, dev->geometry.x, dev->geometry.y);
shmi = create_shm_image(&s->display, dev->area.width, dev->area.height);
if (!shmi)
{
g_debug("Unexpected failure to create_shm_image of area %dx%d", dev->area.width, dev->area.width);
return;
}
if (xev.type != s->display.xd_event_base + XDamageNotify)
if (read_shm_image(&s->display, shmi, dev->area.x, dev->area.y) == 0)
{
//save_ximage_pnm(shmi.img);
QXLDrawable *drawable = shm_image_to_drawable(shmi, dev->area.x, dev->area.y);
if (drawable)
{
g_debug("Unexpected X event %d", xev.type);
g_async_queue_push(s->draw_queue, drawable);
spice_qxl_wakeup(&s->spice.display_sin);
// FIXME - Note that shmi is not cleaned up at this point
return;
}
else
g_debug("Unexpected failure to create drawable");
}
else
g_debug("Unexpected failure to read shm of area %dx%d", dev->area.width, dev->area.width);
g_debug("XDamageNotify [ser %ld|send_event %d|level %d|more %d|area (%dx%d)@%dx%d|geo (%dx%d)@%dx%d",
dev->serial, dev->send_event, dev->level, dev->more,
dev->area.width, dev->area.height, dev->area.x, dev->area.y,
dev->geometry.width, dev->geometry.height, dev->geometry.x, dev->geometry.y);
if (create_shm_image(&s->display, &shmi, dev->area.width, dev->area.height) == 0)
{
if (read_shm_image(&s->display, &shmi, dev->area.x, dev->area.y) == 0)
{
//save_ximage_pnm(shmi.img);
spice_qxl_wakeup(&s->spice.display_sin);
}
destroy_shm_image(&s->display, &shmi);
}
}
if (shmi)
destroy_shm_image(&s->display, shmi);
}
// FIXME - this is not really satisfying. It'd be
// nicer over in spice.c. But spice.c needs
// access to the display info if it can.
static int create_primary(session_t *s)
{
int rc;
int scr = DefaultScreen(s->display.xdisplay);
QXLDevSurfaceCreate surface;
rc = create_shm_image(&s->display, &s->display.fullscreen, 0, 0);
if (rc)
return rc;
s->display.fullscreen = create_shm_image(&s->display, 0, 0);
if (!s->display.fullscreen)
return X11SPICE_ERR_NOSHM;
memset(&surface, 0, sizeof(surface));
surface.height = DisplayHeight(s->display.xdisplay, scr);
surface.width = DisplayWidth(s->display.xdisplay, scr);
surface.stride = -s->display.fullscreen.img->bytes_per_line;
// FIXME - negative stride?
surface.stride = s->display.fullscreen->img->bytes_per_line;
surface.type = QXL_SURF_TYPE_PRIMARY;
surface.flags = 0;
surface.group_id = 0;
......@@ -108,20 +187,49 @@ static int create_primary(session_t *s)
// FIXME - compute this dynamically?
surface.format = SPICE_SURFACE_FMT_32_xRGB;
surface.mem = (QXLPHYSICAL) s->display.fullscreen.img->data;
surface.mem = (QXLPHYSICAL) s->display.fullscreen->img->data;
spice_qxl_create_primary_surface(&s->spice.display_sin, 0, &surface);
return 0;
}
void free_cursor_queue_item(gpointer data)
{
// FIXME
}
void free_draw_queue_item(gpointer data)
{
// FIXME
}
void *session_pop_draw(void *session_ptr)
{
session_t *s = (session_t *) session_ptr;
return g_async_queue_try_pop(s->draw_queue);
}
int session_draw_waiting(void *session_ptr)
{
session_t *s = (session_t *) session_ptr;
return g_async_queue_length(s->draw_queue);
}
int session_start(session_t *s)
{
int rc;
int rc = 0;
s->spice.session_ptr = s;
s->xwatch = s->spice.core->watch_add(ConnectionNumber(s->display.xdisplay),
SPICE_WATCH_EVENT_READ, session_handle_xevent, s);
if (! s->xwatch)
return X11SPICE_ERR_NOWATCH;
return(X11SPICE_ERR_NOWATCH);
s->cursor_queue = g_async_queue_new_full(free_cursor_queue_item);
s->draw_queue = g_async_queue_new_full(free_draw_queue_item);
/* In order for the watch to function,
we seem to have to request at least one event */
......@@ -130,12 +238,16 @@ int session_start(session_t *s)
rc = create_primary(s);
if (rc)
return rc;
session_end(s);
return 0;
return rc;
}
void session_end(session_t *s)
{
s->spice.core->watch_remove(s->xwatch);
if (s->cursor_queue)
g_async_queue_unref(s->cursor_queue);
if (s->draw_queue)
g_async_queue_unref(s->draw_queue);
}
......@@ -36,6 +36,9 @@ typedef struct
spice_t spice;
gui_t gui;
SpiceWatch *xwatch;
GAsyncQueue *cursor_queue;
GAsyncQueue *draw_queue;
} session_t;
/*----------------------------------------------------------------------------
......@@ -43,4 +46,7 @@ typedef struct
**--------------------------------------------------------------------------*/
int session_start(session_t *s);
void session_end(session_t *s);
void *session_pop_draw(void *session_ptr);
int session_draw_waiting(void *session_ptr);
#endif
......@@ -25,6 +25,8 @@
#include "local_spice.h"
#include "x11spice.h"
#include "display.h"
#include "session.h"
struct SpiceTimer {
SpiceTimerFunc func;
......@@ -216,15 +218,32 @@ static void get_init_info(QXLInstance *qin, QXLDevInitInfo *info)
// uint8_t internal_groupslot_id;
}
static int get_command(QXLInstance *qin, struct QXLCommandExt *cmd)
{
g_debug("FIXME! UNIMPLEMENTED! %s", __func__);
return 0;
spice_t *s = SPICE_CONTAINEROF(qin, spice_t, display_sin);
QXLDrawable *drawable;
drawable = session_pop_draw(s->session_ptr);
if (! drawable)
return 0;
cmd->group_id = 0;
cmd->flags = 0;
cmd->cmd.type = QXL_CMD_DRAW;
cmd->cmd.padding = 0;
cmd->cmd.data = (QXLPHYSICAL) drawable;
return 1;
}
static int req_cmd_notification(QXLInstance *qin)
{
g_debug("FIXME! UNIMPLEMENTED! %s", __func__);
spice_t *s = SPICE_CONTAINEROF(qin, spice_t, display_sin);
if (session_draw_waiting(s->session_ptr) > 0)
return 0;
return 1;
}
......@@ -381,216 +400,3 @@ void spice_end(spice_t *s)
{
spice_server_destroy(s->server);
}
#if defined(HACK_REFERENCE)
void xspice_set_spice_server_options(OptionInfoPtr options)
{
/* environment variables take precedense. If not then take
* parameters from the config file. */
int addr_flags;
int len;
spice_image_compression_t compression;
spice_wan_compression_t wan_compr;
int port = get_int_option(options, OPTION_SPICE_PORT, "XSPICE_PORT");
int tls_port =
get_int_option(options, OPTION_SPICE_TLS_PORT, "XSPICE_TLS_PORT");
const char *password =
get_str_option(options, OPTION_SPICE_PASSWORD, "XSPICE_PASSWORD");
int disable_ticketing =
get_bool_option(options, OPTION_SPICE_DISABLE_TICKETING, "XSPICE_DISABLE_TICKETING");
const char *x509_dir =
get_str_option(options, OPTION_SPICE_X509_DIR, "XSPICE_X509_DIR");
int sasl = get_bool_option(options, OPTION_SPICE_SASL, "XSPICE_SASL");
const char *x509_key_file_base =
get_str_option(options, OPTION_SPICE_X509_KEY_FILE,
"XSPICE_X509_KEY_FILE");
char *x509_key_file = NULL;
const char *x509_cert_file_base =
get_str_option(options, OPTION_SPICE_X509_CERT_FILE,
"XSPICE_X509_CERT_FILE");
char *x509_cert_file = NULL;
const char *x509_key_password =
get_str_option(options, OPTION_SPICE_X509_KEY_PASSWORD,
"XSPICE_X509_KEY_PASSWORD");
const char *tls_ciphers =
get_str_option(options, OPTION_SPICE_TLS_CIPHERS,
"XSPICE_TLS_CIPHERS");
const char *x509_cacert_file_base =
get_str_option(options, OPTION_SPICE_CACERT_FILE,
"XSPICE_CACERT_FILE");
char *x509_cacert_file = NULL;
const char * addr =
get_str_option(options, OPTION_SPICE_ADDR, "XSPICE_ADDR");
int ipv4 =
get_bool_option(options, OPTION_SPICE_IPV4_ONLY, "XSPICE_IPV4_ONLY");
int ipv6 =
get_bool_option(options, OPTION_SPICE_IPV6_ONLY, "XSPICE_IPV6_ONLY");
const char *x509_dh_file =
get_str_option(options, OPTION_SPICE_DH_FILE, "XSPICE_DH_FILE");
int disable_copy_paste =
get_bool_option(options, OPTION_SPICE_DISABLE_COPY_PASTE,
"XSPICE_DISABLE_COPY_PASTE");
int exit_on_disconnect =
get_bool_option(options, OPTION_SPICE_EXIT_ON_DISCONNECT,
"XSPICE_EXIT_ON_DISCONNECT");
const char *image_compression =
get_str_option(options, OPTION_SPICE_IMAGE_COMPRESSION,
"XSPICE_IMAGE_COMPRESSION");
const char *jpeg_wan_compression =
get_str_option(options, OPTION_SPICE_JPEG_WAN_COMPRESSION,
"XSPICE_JPEG_WAN_COMPRESSION");
const char *zlib_glz_wan_compression =
get_str_option(options, OPTION_SPICE_ZLIB_GLZ_WAN_COMPRESSION,
"XSPICE_ZLIB_GLZ_WAN_COMPRESSION");
const char *streaming_video =
get_str_option(options, OPTION_SPICE_STREAMING_VIDEO,
"XSPICE_STREAMING_VIDEO");
const char *video_codecs =
get_str_option(options, OPTION_SPICE_VIDEO_CODECS,
"XSPICE_VIDEO_CODECS");
int agent_mouse =
get_bool_option(options, OPTION_SPICE_AGENT_MOUSE,
"XSPICE_AGENT_MOUSE");
int playback_compression =
get_bool_option(options, OPTION_SPICE_PLAYBACK_COMPRESSION,
"XSPICE_PLAYBACK_COMPRESSION");
SpiceServer *spice_server = xspice_get_spice_server();
if (!port && !tls_port) {
printf("one of tls-port or port must be set\n");
exit(1);
}
printf("xspice: port = %d, tls_port = %d\n", port, tls_port);
if (disable_ticketing) {
spice_server_set_noauth(spice_server);
}
if (tls_port) {
if (NULL == x509_dir) {
x509_dir = ".";
}
len = strlen(x509_dir) + 32;
if (x509_key_file_base) {
x509_key_file = strdup(x509_key_file_base);
} else {
x509_key_file = malloc(len);
snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
}
if (x509_cert_file_base) {
x509_cert_file = strdup(x509_cert_file_base);
} else {
x509_cert_file = malloc(len);
snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
}
if (x509_cacert_file_base) {
x509_cacert_file = strdup(x509_cert_file_base);
} else {
x509_cacert_file = malloc(len);
snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
}
}
addr_flags = 0;
if (ipv4) {
addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY;
} else if (ipv6) {
addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY;
}
spice_server_set_addr(spice_server, addr ? addr : "", addr_flags);
if (port) {
spice_server_set_port(spice_server, port);
}
if (tls_port) {
spice_server_set_tls(spice_server, tls_port,
x509_cacert_file,
x509_cert_file,
x509_key_file,
x509_key_password,
x509_dh_file,
tls_ciphers);
}
if (password) {
spice_server_set_ticket(spice_server, password, 0, 0, 0);
}
if (sasl) {
#if SPICE_SERVER_VERSION >= 0x000802 /* 0.8.2 */
if (spice_server_set_sasl_appname(spice_server, "xspice") == -1 ||
spice_server_set_sasl(spice_server, 1) == -1) {
fprintf(stderr, "spice: failed to enable sasl\n");
exit(1);
}
#else
fprintf(stderr, "spice: sasl is not available (spice >= 0.8.2 required)\n");
exit(1);
#endif
}
#if SPICE_SERVER_VERSION >= 0x000801
/* we still don't actually support agent in xspice, but this
* can't hurt for later, just copied from qemn/ui/spice-core.c */
if (disable_copy_paste) {
spice_server_set_agent_copypaste(spice_server, 0);
}
#endif
if (exit_on_disconnect) {
#if SPICE_SERVER_VERSION >= 0x000b04 /* 0.11.4 */
spice_server_set_exit_on_disconnect(spice_server, exit_on_disconnect);
#else
fprintf(stderr, "spice: cannot set exit_on_disconnect (spice >= 0.11.4 required)\n");
exit(1);
#endif
}
compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
if (image_compression) {
compression = parse_compression(image_compression);
}
spice_server_set_image_compression(spice_server, compression);
wan_compr = SPICE_WAN_COMPRESSION_AUTO;
if (jpeg_wan_compression) {
wan_compr = parse_wan_compression(jpeg_wan_compression);
}
spice_server_set_jpeg_compression(spice_server, wan_compr);
wan_compr = SPICE_WAN_COMPRESSION_AUTO;
if (zlib_glz_wan_compression) {
wan_compr = parse_wan_compression(zlib_glz_wan_compression);
}
spice_server_set_zlib_glz_compression(spice_server, wan_compr);
if (streaming_video) {
int streaming_video_opt = parse_stream_video(streaming_video);
spice_server_set_streaming_video(spice_server, streaming_video_opt);
}
if (video_codecs) {
#if SPICE_SERVER_VERSION >= 0x000c06 /* 0.12.6 */
if (spice_server_set_video_codecs(spice_server, video_codecs)) {
fprintf(stderr, "spice: invalid video encoder %s\n", video_codecs);
exit(1);
}
#else
fprintf(stderr, "spice: video_codecs are not available (spice >= 0.12.6 required)\n");
exit(1);
#endif
}
spice_server_set_agent_mouse(spice_server, agent_mouse);
spice_server_set_playback_compression(spice_server, playback_compression);
free(x509_key_file);
free(x509_cert_file);
free(x509_cacert_file);
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment