Revision 3512779a vnc.c
b/vnc.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 |
|
Also available in: Unified diff