Commit 3512779a88128808eee4c5ecbeb3ad7679f97a50

Authored by bellard
1 parent 5c3ff3a7

support for all VNC pixel formats


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1923 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 195 additions and 51 deletions
... ... @@ -42,6 +42,14 @@ typedef struct VncState VncState;
42 42  
43 43 typedef int VncReadEvent(VncState *vs, char *data, size_t len);
44 44  
  45 +typedef void VncWritePixels(VncState *vs, void *data, int size);
  46 +
  47 +typedef void VncSendHextileTile(VncState *vs,
  48 + int x, int y, int w, int h,
  49 + uint32_t *last_bg,
  50 + uint32_t *last_fg,
  51 + int *has_bg, int *has_fg);
  52 +
45 53 struct VncState
46 54 {
47 55 QEMUTimer *timer;
... ... @@ -53,12 +61,19 @@ struct VncState
53 61 int height;
54 62 uint64_t dirty_row[768];
55 63 char *old_data;
56   - int depth;
  64 + int depth; /* internal VNC frame buffer byte per pixel */
57 65 int has_resize;
58 66 int has_hextile;
59 67 Buffer output;
60 68 Buffer input;
61 69 kbd_layout_t *kbd_layout;
  70 + /* current output mode information */
  71 + VncWritePixels *write_pixels;
  72 + VncSendHextileTile *send_hextile_tile;
  73 + int pix_bpp, pix_big_endian;
  74 + int red_shift, red_max, red_shift1;
  75 + int green_shift, green_max, green_shift1;
  76 + int blue_shift, blue_max, blue_shift1;
62 77  
63 78 VncReadEvent *read_handler;
64 79 size_t read_handler_expect;
... ... @@ -130,6 +145,66 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h)
130 145 }
131 146 }
132 147  
  148 +/* fastest code */
  149 +static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
  150 +{
  151 + vnc_write(vs, pixels, size);
  152 +}
  153 +
  154 +/* slowest but generic code. */
  155 +static void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
  156 +{
  157 + unsigned int r, g, b;
  158 +
  159 + r = (v >> vs->red_shift1) & vs->red_max;
  160 + g = (v >> vs->green_shift1) & vs->green_max;
  161 + b = (v >> vs->blue_shift1) & vs->blue_max;
  162 + v = (r << vs->red_shift) |
  163 + (g << vs->green_shift) |
  164 + (b << vs->blue_shift);
  165 + switch(vs->pix_bpp) {
  166 + case 1:
  167 + buf[0] = v;
  168 + break;
  169 + case 2:
  170 + if (vs->pix_big_endian) {
  171 + buf[0] = v >> 8;
  172 + buf[1] = v;
  173 + } else {
  174 + buf[1] = v >> 8;
  175 + buf[0] = v;
  176 + }
  177 + break;
  178 + default:
  179 + case 4:
  180 + if (vs->pix_big_endian) {
  181 + buf[0] = v >> 24;
  182 + buf[1] = v >> 16;
  183 + buf[2] = v >> 8;
  184 + buf[3] = v;
  185 + } else {
  186 + buf[3] = v >> 24;
  187 + buf[2] = v >> 16;
  188 + buf[1] = v >> 8;
  189 + buf[0] = v;
  190 + }
  191 + break;
  192 + }
  193 +}
  194 +
  195 +static void vnc_write_pixels_generic(VncState *vs, void *pixels1, int size)
  196 +{
  197 + uint32_t *pixels = pixels1;
  198 + uint8_t buf[4];
  199 + int n, i;
  200 +
  201 + n = size >> 2;
  202 + for(i = 0; i < n; i++) {
  203 + vnc_convert_pixel(vs, buf, pixels[i]);
  204 + vnc_write(vs, buf, vs->pix_bpp);
  205 + }
  206 +}
  207 +
133 208 static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h)
134 209 {
135 210 int i;
... ... @@ -139,7 +214,7 @@ static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h
139 214  
140 215 row = vs->ds->data + y * vs->ds->linesize + x * vs->depth;
141 216 for (i = 0; i < h; i++) {
142   - vnc_write(vs, row, w * vs->depth);
  217 + vs->write_pixels(vs, row, w * vs->depth);
143 218 row += vs->ds->linesize;
144 219 }
145 220 }
... ... @@ -162,35 +237,26 @@ static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h)
162 237 #include "vnchextile.h"
163 238 #undef BPP
164 239  
  240 +#define GENERIC
  241 +#define BPP 32
  242 +#include "vnchextile.h"
  243 +#undef BPP
  244 +#undef GENERIC
  245 +
165 246 static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h)
166 247 {
167 248 int i, j;
168 249 int has_fg, has_bg;
169 250 uint32_t last_fg32, last_bg32;
170   - uint16_t last_fg16, last_bg16;
171   - uint8_t last_fg8, last_bg8;
172 251  
173 252 vnc_framebuffer_update(vs, x, y, w, h, 5);
174 253  
175 254 has_fg = has_bg = 0;
176 255 for (j = y; j < (y + h); j += 16) {
177 256 for (i = x; i < (x + w); i += 16) {
178   - switch (vs->depth) {
179   - case 1:
180   - send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
181   - &last_bg8, &last_fg8, &has_bg, &has_fg);
182   - break;
183   - case 2:
184   - send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
185   - &last_bg16, &last_fg16, &has_bg, &has_fg);
186   - break;
187   - case 4:
188   - send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j),
189   - &last_bg32, &last_fg32, &has_bg, &has_fg);
190   - break;
191   - default:
192   - break;
193   - }
  257 + vs->send_hextile_tile(vs, i, j,
  258 + MIN(16, x + w - i), MIN(16, y + h - j),
  259 + &last_bg32, &last_fg32, &has_bg, &has_fg);
194 260 }
195 261 }
196 262 }
... ... @@ -660,30 +726,79 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
660 726 }
661 727 }
662 728  
  729 +static int compute_nbits(unsigned int val)
  730 +{
  731 + int n;
  732 + n = 0;
  733 + while (val != 0) {
  734 + n++;
  735 + val >>= 1;
  736 + }
  737 + return n;
  738 +}
  739 +
663 740 static void set_pixel_format(VncState *vs,
664 741 int bits_per_pixel, int depth,
665 742 int big_endian_flag, int true_color_flag,
666 743 int red_max, int green_max, int blue_max,
667 744 int red_shift, int green_shift, int blue_shift)
668 745 {
669   - switch (bits_per_pixel) {
670   - case 32:
671   - case 24:
672   - vs->depth = 4;
673   - break;
674   - case 16:
675   - vs->depth = 2;
676   - break;
677   - case 8:
678   - vs->depth = 1;
679   - break;
680   - default:
  746 + int host_big_endian_flag;
  747 +
  748 +#ifdef WORDS_BIGENDIAN
  749 + host_big_endian_flag = 1;
  750 +#else
  751 + host_big_endian_flag = 0;
  752 +#endif
  753 + if (!true_color_flag) {
  754 + fail:
681 755 vnc_client_error(vs);
682   - break;
  756 + return;
  757 + }
  758 + if (bits_per_pixel == 32 &&
  759 + host_big_endian_flag == big_endian_flag &&
  760 + red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
  761 + red_shift == 16 && green_shift == 8 && blue_shift == 0) {
  762 + vs->depth = 4;
  763 + vs->write_pixels = vnc_write_pixels_copy;
  764 + vs->send_hextile_tile = send_hextile_tile_32;
  765 + } else
  766 + if (bits_per_pixel == 16 &&
  767 + host_big_endian_flag == big_endian_flag &&
  768 + red_max == 31 && green_max == 63 && blue_max == 31 &&
  769 + red_shift == 11 && green_shift == 5 && blue_shift == 0) {
  770 + vs->depth = 2;
  771 + vs->write_pixels = vnc_write_pixels_copy;
  772 + vs->send_hextile_tile = send_hextile_tile_16;
  773 + } else
  774 + if (bits_per_pixel == 8 &&
  775 + red_max == 7 && green_max == 7 && blue_max == 3 &&
  776 + red_shift == 5 && green_shift == 2 && blue_shift == 0) {
  777 + vs->depth = 1;
  778 + vs->write_pixels = vnc_write_pixels_copy;
  779 + vs->send_hextile_tile = send_hextile_tile_8;
  780 + } else
  781 + {
  782 + /* generic and slower case */
  783 + if (bits_per_pixel != 8 &&
  784 + bits_per_pixel != 16 &&
  785 + bits_per_pixel != 32)
  786 + goto fail;
  787 + vs->depth = 4;
  788 + vs->red_shift = red_shift;
  789 + vs->red_max = red_max;
  790 + vs->red_shift1 = 24 - compute_nbits(red_max);
  791 + vs->green_shift = green_shift;
  792 + vs->green_max = green_max;
  793 + vs->green_shift1 = 16 - compute_nbits(green_max);
  794 + vs->blue_shift = blue_shift;
  795 + vs->blue_max = blue_max;
  796 + vs->blue_shift1 = 8 - compute_nbits(blue_max);
  797 + vs->pix_bpp = bits_per_pixel / 8;
  798 + vs->pix_big_endian = big_endian_flag;
  799 + vs->write_pixels = vnc_write_pixels_generic;
  800 + vs->send_hextile_tile = send_hextile_tile_generic;
683 801 }
684   -
685   - if (!true_color_flag)
686   - vnc_client_error(vs);
687 802  
688 803 vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height);
689 804 memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
... ... @@ -774,7 +889,11 @@ static int protocol_client_init(VncState *vs, char *data, size_t len)
774 889  
775 890 vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */
776 891 vnc_write_u8(vs, vs->depth * 8); /* depth */
  892 +#ifdef WORDS_BIGENDIAN
  893 + vnc_write_u8(vs, 1); /* big-endian-flag */
  894 +#else
777 895 vnc_write_u8(vs, 0); /* big-endian-flag */
  896 +#endif
778 897 vnc_write_u8(vs, 1); /* true-color-flag */
779 898 if (vs->depth == 4) {
780 899 vnc_write_u16(vs, 0xFF); /* red-max */
... ... @@ -783,6 +902,7 @@ static int protocol_client_init(VncState *vs, char *data, size_t len)
783 902 vnc_write_u8(vs, 16); /* red-shift */
784 903 vnc_write_u8(vs, 8); /* green-shift */
785 904 vnc_write_u8(vs, 0); /* blue-shift */
  905 + vs->send_hextile_tile = send_hextile_tile_32;
786 906 } else if (vs->depth == 2) {
787 907 vnc_write_u16(vs, 31); /* red-max */
788 908 vnc_write_u16(vs, 63); /* green-max */
... ... @@ -790,14 +910,18 @@ static int protocol_client_init(VncState *vs, char *data, size_t len)
790 910 vnc_write_u8(vs, 11); /* red-shift */
791 911 vnc_write_u8(vs, 5); /* green-shift */
792 912 vnc_write_u8(vs, 0); /* blue-shift */
  913 + vs->send_hextile_tile = send_hextile_tile_16;
793 914 } else if (vs->depth == 1) {
794   - vnc_write_u16(vs, 3); /* red-max */
  915 + /* XXX: change QEMU pixel 8 bit pixel format to match the VNC one ? */
  916 + vnc_write_u16(vs, 7); /* red-max */
795 917 vnc_write_u16(vs, 7); /* green-max */
796 918 vnc_write_u16(vs, 3); /* blue-max */
797 919 vnc_write_u8(vs, 5); /* red-shift */
798 920 vnc_write_u8(vs, 2); /* green-shift */
799 921 vnc_write_u8(vs, 0); /* blue-shift */
  922 + vs->send_hextile_tile = send_hextile_tile_8;
800 923 }
  924 + vs->write_pixels = vnc_write_pixels_copy;
801 925  
802 926 vnc_write(vs, pad, 3); /* padding */
803 927  
... ...
vnchextile.h
1 1 #define CONCAT_I(a, b) a ## b
2 2 #define CONCAT(a, b) CONCAT_I(a, b)
3 3 #define pixel_t CONCAT(uint, CONCAT(BPP, _t))
4   -
5   -static void CONCAT(send_hextile_tile_, BPP)(VncState *vs,
6   - int x, int y, int w, int h,
7   - pixel_t *last_bg, pixel_t *last_fg,
8   - int *has_bg, int *has_fg)
  4 +#ifdef GENERIC
  5 +#define NAME generic
  6 +#else
  7 +#define NAME BPP
  8 +#endif
  9 +
  10 +static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
  11 + int x, int y, int w, int h,
  12 + uint32_t *last_bg32,
  13 + uint32_t *last_fg32,
  14 + int *has_bg, int *has_fg)
9 15 {
10 16 char *row = (vs->ds->data + y * vs->ds->linesize + x * vs->depth);
11 17 pixel_t *irow = (pixel_t *)row;
12 18 int j, i;
  19 + pixel_t *last_bg = (pixel_t *)last_bg32;
  20 + pixel_t *last_fg = (pixel_t *)last_fg32;
13 21 pixel_t bg = 0;
14 22 pixel_t fg = 0;
15 23 int n_colors = 0;
... ... @@ -122,10 +130,15 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs,
122 130 has_color = 1;
123 131 } else if (irow[i] != color) {
124 132 has_color = 0;
125   -
  133 +#ifdef GENERIC
  134 + vnc_convert_pixel(vs, data + n_data, color);
  135 + n_data += vs->pix_bpp;
  136 +#else
126 137 memcpy(data + n_data, &color, sizeof(color));
127   - hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1);
128   - n_data += 2 + sizeof(pixel_t);
  138 + n_data += sizeof(pixel_t);
  139 +#endif
  140 + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
  141 + n_data += 2;
129 142 n_subtiles++;
130 143  
131 144 min_x = -1;
... ... @@ -137,9 +150,15 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs,
137 150 }
138 151 }
139 152 if (has_color) {
140   - memcpy(data + n_data, &color, sizeof(color));
141   - hextile_enc_cord(data + n_data + sizeof(pixel_t), min_x, j, i - min_x, 1);
142   - n_data += 2 + sizeof(pixel_t);
  153 +#ifdef GENERIC
  154 + vnc_convert_pixel(vs, data + n_data, color);
  155 + n_data += vs->pix_bpp;
  156 +#else
  157 + memcpy(data + n_data, &color, sizeof(color));
  158 + n_data += sizeof(pixel_t);
  159 +#endif
  160 + hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
  161 + n_data += 2;
143 162 n_subtiles++;
144 163 }
145 164 irow += vs->ds->linesize / sizeof(pixel_t);
... ... @@ -169,21 +188,22 @@ static void CONCAT(send_hextile_tile_, BPP)(VncState *vs,
169 188 vnc_write_u8(vs, flags);
170 189 if (n_colors < 4) {
171 190 if (flags & 0x02)
172   - vnc_write(vs, last_bg, sizeof(pixel_t));
  191 + vs->write_pixels(vs, last_bg, sizeof(pixel_t));
173 192 if (flags & 0x04)
174   - vnc_write(vs, last_fg, sizeof(pixel_t));
  193 + vs->write_pixels(vs, last_fg, sizeof(pixel_t));
175 194 if (n_subtiles) {
176 195 vnc_write_u8(vs, n_subtiles);
177 196 vnc_write(vs, data, n_data);
178 197 }
179 198 } else {
180 199 for (j = 0; j < h; j++) {
181   - vnc_write(vs, row, w * vs->depth);
  200 + vs->write_pixels(vs, row, w * vs->depth);
182 201 row += vs->ds->linesize;
183 202 }
184 203 }
185 204 }
186 205  
  206 +#undef NAME
187 207 #undef pixel_t
188 208 #undef CONCAT_I
189 209 #undef CONCAT
... ...