X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=screen.c;h=265d986c5150dd670b66ac2e0f928163d0755c85;hb=ead260d74d2348610d190cba685fa66e95db2f7c;hp=e41bc914a86ff93ab109439981b2d6c466d7abe7;hpb=4ef70811b874c94010dc2b295a581481bc1273c1;p=spiceterm.git diff --git a/screen.c b/screen.c index e41bc91..265d986 100644 --- a/screen.c +++ b/screen.c @@ -39,11 +39,20 @@ #include #include #include +#include #include "glyphs.h" #include "spiceterm.h" +static int debug = 0; + +#define DPRINTF(x, format, ...) { \ + if (x <= debug) { \ + printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \ + } \ +} + #define MEM_SLOT_GROUP_ID 0 #define NOTIFY_DISPLAY_BATCH (SINGLE_PART/2) @@ -61,10 +70,11 @@ int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, /* Parts cribbed from spice-display.h/.c/qxl.c */ typedef struct SimpleSpiceUpdate { - QXLCommandExt ext; // first + QXLCommandExt ext; // needs to be first member QXLDrawable drawable; QXLImage image; uint8_t *bitmap; + int cache_id; // do not free bitmap if cache_id != 0 } SimpleSpiceUpdate; static void @@ -77,14 +87,14 @@ spice_screen_destroy_update(SimpleSpiceUpdate *update) uint8_t *ptr = (uint8_t*)update->drawable.clip.data; free(ptr); } - g_free(update->bitmap); + if (update->bitmap && !update->cache_id) { + g_free(update->bitmap); + } + g_free(update); } -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 320 - -static int unique = 1; +static int unique = 0x0ffff + 1; static void set_cmd(QXLCommandExt *ext, uint32_t type, QXLPHYSICAL data) @@ -108,6 +118,8 @@ simple_set_release_info(QXLReleaseInfo *info, intptr_t ptr) static void push_command(SpiceScreen *spice_screen, QXLCommandExt *ext) { + int need_wakeup = 1; + g_mutex_lock(spice_screen->command_mutex); while (spice_screen->commands_end - spice_screen->commands_start >= COMMANDS_SIZE) { @@ -116,17 +128,24 @@ push_command(SpiceScreen *spice_screen, QXLCommandExt *ext) g_assert(spice_screen->commands_end - spice_screen->commands_start < COMMANDS_SIZE); + if ((spice_screen->commands_end - spice_screen->commands_start) > 0) { + need_wakeup = 0; + } + spice_screen->commands[spice_screen->commands_end % COMMANDS_SIZE] = ext; spice_screen->commands_end++; + if (need_wakeup) { + spice_screen->qxl_worker->wakeup(spice_screen->qxl_worker); + } + g_mutex_unlock(spice_screen->command_mutex); - spice_screen->qxl_worker->wakeup(spice_screen->qxl_worker); } /* bitmap are freed, so they must be allocated with g_malloc */ static SimpleSpiceUpdate * -spice_screen_update_from_bitmap_cmd(uint32_t surface_id, QXLRect bbox, uint8_t *bitmap) +spice_screen_update_from_bitmap_cmd(uint32_t surface_id, QXLRect bbox, uint8_t *bitmap, int cache_id) { SimpleSpiceUpdate *update; QXLDrawable *drawable; @@ -157,7 +176,13 @@ spice_screen_update_from_bitmap_cmd(uint32_t surface_id, QXLRect bbox, uint8_t * drawable->u.copy.src_area.right = bw; drawable->u.copy.src_area.bottom = bh; - QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, unique); + if (cache_id) { + QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, cache_id); + image->descriptor.flags = SPICE_IMAGE_FLAGS_CACHE_ME; + update->cache_id = cache_id; + } else { + QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ++unique); + } image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN; image->bitmap.stride = bw * 4; @@ -174,64 +199,78 @@ spice_screen_update_from_bitmap_cmd(uint32_t surface_id, QXLRect bbox, uint8_t * static SimpleSpiceUpdate * spice_screen_draw_char_cmd(SpiceScreen *spice_screen, int x, int y, int c, - int fg, int bg) + int fg, int bg, gboolean uline) { int top, left; uint8_t *dst; - uint8_t *bitmap; + uint8_t *bitmap = NULL; int bw, bh; int i, j; QXLRect bbox; + int cache_id = 0; + CachedImage *ce; + + if (!uline && c < 256) { + cache_id = ((fg << 12) | (bg << 8) | (c & 255)) & 0x0ffff; + if ((ce = (CachedImage *)g_hash_table_lookup(spice_screen->image_cache, &cache_id))) { + bitmap = ce->bitmap; + } + } left = x*8; top = y*16; - unique++; - bw = 8; bh = 16; - bitmap = dst = g_malloc(bw * bh * 4); - - unsigned char *data = vt_font_data + c*16; - unsigned char d = *data; - - g_assert(fg >= 0 && fg < 16); - g_assert(bg >= 0 && bg < 16); - - unsigned char fgc_red = default_red[fg]; - unsigned char fgc_blue = default_blu[fg]; - unsigned char fgc_green = default_grn[fg]; - unsigned char bgc_red = default_red[bg]; - unsigned char bgc_blue = default_blu[bg]; - unsigned char bgc_green = default_grn[bg]; - - for (j = 0; j < 16; j++) { - for (i = 0; i < 8; i++) { - if ((i&7) == 0) { - d=*data; - data++; + if (!bitmap) { + bitmap = dst = g_malloc(bw * bh * 4); + + unsigned char *data = vt_font_data + c*16; + unsigned char d = *data; + + g_assert(fg >= 0 && fg < 16); + g_assert(bg >= 0 && bg < 16); + + unsigned char fgc_red = default_red[fg]; + unsigned char fgc_blue = default_blu[fg]; + unsigned char fgc_green = default_grn[fg]; + unsigned char bgc_red = default_red[bg]; + unsigned char bgc_blue = default_blu[bg]; + unsigned char bgc_green = default_grn[bg]; + + for (j = 0; j < 16; j++) { + gboolean ul = (j == 14) && uline; + for (i = 0; i < 8; i++) { + if (i == 0) { + d=*data; + data++; + } + if (ul || d&0x80) { + *(dst) = fgc_blue; + *(dst+1) = fgc_green; + *(dst+2) = fgc_red; + *(dst+3) = 0; + } else { + *(dst) = bgc_blue; + *(dst+1) = bgc_green; + *(dst+2) = bgc_red; + *(dst+3) = 0; + } + d<<=1; + dst += 4; } - if (d&0x80) { - *(dst) = fgc_blue; - *(dst+1) = fgc_green; - *(dst+2) = fgc_red; - *(dst+3) = 0; - } else { - *(dst) = bgc_blue; - *(dst+1) = bgc_green; - *(dst+2) = bgc_red; - *(dst+3) = 0; - } - d<<=1; - dst += 4; } + ce = g_new(CachedImage, 1); + ce->cache_id = cache_id; + ce->bitmap = bitmap; + g_hash_table_insert(spice_screen->image_cache, &ce->cache_id, ce); } bbox.left = left; bbox.top = top; bbox.right = left + bw; bbox.bottom = top + bh; - return spice_screen_update_from_bitmap_cmd(0, bbox, bitmap); + return spice_screen_update_from_bitmap_cmd(0, bbox, bitmap, cache_id); } void @@ -311,11 +350,16 @@ create_primary_surface(SpiceScreen *spice_screen, uint32_t width, QXLWorker *qxl_worker = spice_screen->qxl_worker; QXLDevSurfaceCreate surface = { 0, }; - g_assert(height <= MAX_HEIGHT); - g_assert(width <= MAX_WIDTH); g_assert(height > 0); g_assert(width > 0); + if (height > MAX_HEIGHT) + height = MAX_HEIGHT; + + if (width > MAX_WIDTH) + width = MAX_WIDTH; + + surface.format = SPICE_SURFACE_FMT_32_xRGB; surface.width = spice_screen->primary_width = width; surface.height = spice_screen->primary_height = height; @@ -333,6 +377,22 @@ create_primary_surface(SpiceScreen *spice_screen, uint32_t width, qxl_worker->create_primary_surface(qxl_worker, 0, &surface); } +void +spice_screen_resize(SpiceScreen *spice_screen, uint32_t width, + uint32_t height) +{ + QXLWorker *qxl_worker = spice_screen->qxl_worker; + + if (spice_screen->width == width && spice_screen->height == height) { + return; + } + + qxl_worker->destroy_primary_surface(qxl_worker, 0); + + create_primary_surface(spice_screen, width, height); +} + + QXLDevMemSlot slot = { .slot_group_id = MEM_SLOT_GROUP_ID, .slot_id = 0, @@ -354,7 +414,7 @@ attache_worker(QXLInstance *qin, QXLWorker *_qxl_worker) spice_screen->qxl_worker = _qxl_worker; spice_screen->qxl_worker->add_memslot(spice_screen->qxl_worker, &slot); - create_primary_surface(spice_screen, DEFAULT_WIDTH, DEFAULT_HEIGHT); + create_primary_surface(spice_screen, spice_screen->width, spice_screen->height); spice_screen->qxl_worker->start(spice_screen->qxl_worker); } @@ -550,7 +610,7 @@ set_client_capabilities(QXLInstance *qin, uint8_t client_present, { SpiceScreen *spice_screen = SPICE_CONTAINEROF(qin, SpiceScreen, qxl_instance); - printf("%s: present %d caps %d\n", __func__, client_present, caps[0]); + DPRINTF(1, "present %d caps %d", client_present, caps[0]); if (spice_screen->on_client_connected && client_present) { spice_screen->on_client_connected(spice_screen); @@ -565,17 +625,17 @@ static int client_count = 0; static void client_connected(SpiceScreen *spice_screen) { - printf("Client connected\n"); client_count++; + + DPRINTF(1, "client_count = %d", client_count); } static void client_disconnected(SpiceScreen *spice_screen) { - if (client_count > 0) { client_count--; - printf("Client disconnected\n"); + DPRINTF(1, "client_count = %d", client_count); exit(0); // fixme: cleanup? } } @@ -586,7 +646,7 @@ do_conn_timeout(void *opaque) // SpiceScreen *spice_screen = opaque; if (client_count <= 0) { - printf("connection timeout\n"); + printf("connection timeout - stopping server\n"); exit (0); // fixme: cleanup? } } @@ -615,60 +675,21 @@ QXLInterface display_sif = { .set_client_capabilities = set_client_capabilities, }; -void -spice_screen_add_display_interface(SpiceScreen* spice_screen) -{ - spice_server_add_interface(spice_screen->server, &spice_screen->qxl_instance.base); -} - -/* vdagent interface - not sure why we need that? */ -static int -vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) -{ - return len; -} - -static int -vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) -{ - return 0; -} - -static void -vmc_state(SpiceCharDeviceInstance *sin, int connected) -{ - -} - -static SpiceCharDeviceInterface vdagent_sif = { - .base.type = SPICE_INTERFACE_CHAR_DEVICE, - .base.description = "spice virtual channel char device", - .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, - .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, - .state = vmc_state, - .write = vmc_write, - .read = vmc_read, -}; - -SpiceCharDeviceInstance vdagent_sin = { - .base = { - .sif = &vdagent_sif.base, - }, - .subtype = "vdagent", -}; - -void -spice_screen_add_agent_interface(SpiceServer *server) -{ - spice_server_add_interface(server, &vdagent_sin.base); -} void -spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar ch, TextAttributes attrib) +spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar2 ch, + TextAttributes attrib) { int fg, bg; + int invers; if (attrib.invers) { + invers = attrib.selected ? 0 : 1; + } else { + invers = attrib.selected ? 1 : 0; + } + + if (invers) { bg = attrib.fgcol; fg = attrib.bgcol; } else { @@ -682,25 +703,23 @@ spice_screen_draw_char(SpiceScreen *spice_screen, int x, int y, gunichar ch, Tex // unsuported attributes = (attrib.blink || attrib.unvisible) - // fixme: - //if (attrib.uline) { - //rfbDrawLine (vt->screen, rx, ry + 14, rxe, ry + 14, fg); - //} - int c = vt_fontmap[ch]; SimpleSpiceUpdate *update; - update = spice_screen_draw_char_cmd(spice_screen, x, y, c, fg, bg); + update = spice_screen_draw_char_cmd(spice_screen, x, y, c, fg, bg, attrib.uline); push_command(spice_screen, &update->ext); } SpiceScreen * -spice_screen_new(SpiceCoreInterface *core) +spice_screen_new(SpiceCoreInterface *core, uint32_t width, uint32_t height, guint timeout) { int port = 5912; SpiceScreen *spice_screen = g_new0(SpiceScreen, 1); SpiceServer* server = spice_server_new(); + spice_screen->width = width; + spice_screen->height = height; + spice_screen->command_cond = g_cond_new(); spice_screen->command_mutex = g_mutex_new(); @@ -727,9 +746,10 @@ spice_screen_new(SpiceCoreInterface *core) cursor_init(); - int timeout = 10; // max time to wait for client connection spice_screen->conn_timeout_timer = core->timer_add(do_conn_timeout, spice_screen); spice_screen->core->timer_start(spice_screen->conn_timeout_timer, timeout*1000); + spice_server_add_interface(spice_screen->server, &spice_screen->qxl_instance.base); + return spice_screen; }