Commit 3512779a88128808eee4c5ecbeb3ad7679f97a50
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
vnc.c
... | ... | @@ -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 | ... | ... |