]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/hw/vnc/translate.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / hw / vnc / translate.c
1 /*
2  * translate.c - translate between different pixel formats
3  */
4
5 /*
6  *  Copyright (C) 2002 RealVNC Ltd.
7  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
8  *
9  *  This is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This software is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this software; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
22  *  USA.
23  */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include "rfb.h"
28
29 static void PrintPixelFormat(rfbPixelFormat *pf);
30 static Bool rfbSetClientColourMapBGR233();
31
32 Bool rfbEconomicTranslate = FALSE;
33
34 /*
35  * Structure representing pixel format for RFB server (i.e. us).
36  */
37
38 rfbPixelFormat rfbServerFormat;
39
40
41 /*
42  * Some standard pixel formats.
43  */
44
45 static const rfbPixelFormat BGR233Format = {
46     8, 8, 0, 1, 7, 7, 3, 0, 3, 6
47 };
48
49
50 /*
51  * Macro to compare pixel formats.
52  */
53
54 #define PF_EQ(x,y)                                                      \
55         ((x.bitsPerPixel == y.bitsPerPixel) &&                          \
56          (x.depth == y.depth) &&                                        \
57          ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) &&     \
58          (x.trueColour == y.trueColour) &&                              \
59          (!x.trueColour || ((x.redMax == y.redMax) &&                   \
60                             (x.greenMax == y.greenMax) &&               \
61                             (x.blueMax == y.blueMax) &&                 \
62                             (x.redShift == y.redShift) &&               \
63                             (x.greenShift == y.greenShift) &&           \
64                             (x.blueShift == y.blueShift))))
65
66 #define CONCAT2(a,b) a##b
67 #define CONCAT2E(a,b) CONCAT2(a,b)
68 #define CONCAT4(a,b,c,d) a##b##c##d
69 #define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d)
70
71 #define OUT 8
72 #include "tableinittctemplate.c"
73 #include "tableinitcmtemplate.c"
74 #define IN 8
75 #include "tabletranstemplate.c"
76 #undef IN
77 #define IN 16
78 #include "tabletranstemplate.c"
79 #undef IN
80 #define IN 32
81 #include "tabletranstemplate.c"
82 #undef IN
83 #undef OUT
84
85 #define OUT 16
86 #include "tableinittctemplate.c"
87 #include "tableinitcmtemplate.c"
88 #define IN 8
89 #include "tabletranstemplate.c"
90 #undef IN
91 #define IN 16
92 #include "tabletranstemplate.c"
93 #undef IN
94 #define IN 32
95 #include "tabletranstemplate.c"
96 #undef IN
97 #undef OUT
98
99 #define OUT 32
100 #include "tableinittctemplate.c"
101 #include "tableinitcmtemplate.c"
102 #define IN 8
103 #include "tabletranstemplate.c"
104 #undef IN
105 #define IN 16
106 #include "tabletranstemplate.c"
107 #undef IN
108 #define IN 32
109 #include "tabletranstemplate.c"
110 #undef IN
111 #undef OUT
112
113 typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in,
114                                    rfbPixelFormat *out);
115
116 rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = {
117     rfbInitTrueColourSingleTable8,
118     rfbInitTrueColourSingleTable16,
119     rfbInitTrueColourSingleTable32
120 };
121
122 rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = {
123     rfbInitColourMapSingleTable8,
124     rfbInitColourMapSingleTable16,
125     rfbInitColourMapSingleTable32
126 };
127
128 rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = {
129     rfbInitTrueColourRGBTables8,
130     rfbInitTrueColourRGBTables16,
131     rfbInitTrueColourRGBTables32
132 };
133
134 rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = {
135     { rfbTranslateWithSingleTable8to8,
136       rfbTranslateWithSingleTable8to16,
137       rfbTranslateWithSingleTable8to32 },
138     { rfbTranslateWithSingleTable16to8,
139       rfbTranslateWithSingleTable16to16,
140       rfbTranslateWithSingleTable16to32 },
141     { rfbTranslateWithSingleTable32to8,
142       rfbTranslateWithSingleTable32to16,
143       rfbTranslateWithSingleTable32to32 }
144 };
145
146 rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = {
147     { rfbTranslateWithRGBTables8to8,
148       rfbTranslateWithRGBTables8to16,
149       rfbTranslateWithRGBTables8to32 },
150     { rfbTranslateWithRGBTables16to8,
151       rfbTranslateWithRGBTables16to16,
152       rfbTranslateWithRGBTables16to32 },
153     { rfbTranslateWithRGBTables32to8,
154       rfbTranslateWithRGBTables32to16,
155       rfbTranslateWithRGBTables32to32 }
156 };
157
158
159
160 /*
161  * rfbTranslateNone is used when no translation is required.
162  */
163
164 void
165 rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out,
166                  char *iptr, char *optr, int bytesBetweenInputLines,
167                  int width, int height)
168 {
169     int bytesPerOutputLine = width * (out->bitsPerPixel / 8);
170
171     while (height > 0) {
172         memcpy(optr, iptr, bytesPerOutputLine);
173         iptr += bytesBetweenInputLines;
174         optr += bytesPerOutputLine;
175         height--;
176     }
177 }
178
179
180 /*
181  * rfbSetTranslateFunction sets the translation function.
182  */
183
184 Bool
185 rfbSetTranslateFunction(cl)
186     rfbClientPtr cl;
187 {
188     rfbLog("Pixel format for client %s:\n",cl->host);
189     PrintPixelFormat(&cl->format);
190
191     /*
192      * Check that bits per pixel values are valid
193      */
194
195     if ((rfbServerFormat.bitsPerPixel != 8) &&
196         (rfbServerFormat.bitsPerPixel != 16) &&
197         (rfbServerFormat.bitsPerPixel != 32))
198     {
199         rfbLog("%s: server bits per pixel not 8, 16 or 32\n",
200                 "rfbSetTranslateFunction");
201         rfbCloseSock(cl->sock);
202         return FALSE;
203     }
204
205     if ((cl->format.bitsPerPixel != 8) &&
206         (cl->format.bitsPerPixel != 16) &&
207         (cl->format.bitsPerPixel != 32))
208     {
209         rfbLog("%s: client bits per pixel not 8, 16 or 32\n",
210                 "rfbSetTranslateFunction");
211         rfbCloseSock(cl->sock);
212         return FALSE;
213     }
214
215     if (!rfbServerFormat.trueColour && (rfbServerFormat.bitsPerPixel != 8)) {
216         rfbLog("rfbSetTranslateFunction: server has colour map "
217                 "but %d-bit - can only cope with 8-bit colour maps\n",
218                 rfbServerFormat.bitsPerPixel);
219         rfbCloseSock(cl->sock);
220         return FALSE;
221     }
222
223     if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) {
224         rfbLog("rfbSetTranslateFunction: client has colour map "
225                 "but %d-bit - can only cope with 8-bit colour maps\n",
226                 cl->format.bitsPerPixel);
227         rfbCloseSock(cl->sock);
228         return FALSE;
229     }
230
231     /*
232      * bpp is valid, now work out how to translate
233      */
234
235     if (!cl->format.trueColour) {
236
237         /* ? -> colour map */
238
239         if (!rfbServerFormat.trueColour) {
240
241             /* colour map -> colour map */
242
243             rfbLog("rfbSetTranslateFunction: both 8-bit colour map: "
244                     "no translation needed\n");
245             cl->translateFn = rfbTranslateNone;
246             return rfbSetClientColourMap(cl, 0, 0);
247         }
248
249         /*
250          * truecolour -> colour map
251          *
252          * Set client's colour map to BGR233, then effectively it's
253          * truecolour as well
254          */
255
256         if (!rfbSetClientColourMapBGR233(cl))
257             return FALSE;
258
259         cl->format = BGR233Format;
260     }
261
262     /* ? -> truecolour */
263
264     if (!rfbServerFormat.trueColour) {
265
266         /* colour map -> truecolour */
267
268         rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour,"
269                 " server has colour map\n",cl->format.bitsPerPixel);
270
271         cl->translateFn = rfbTranslateWithSingleTableFns
272                               [rfbServerFormat.bitsPerPixel / 16]
273                                   [cl->format.bitsPerPixel / 16];
274
275         return rfbSetClientColourMap(cl, 0, 0);
276     }
277
278     /* truecolour -> truecolour */
279
280     if (PF_EQ(cl->format,rfbServerFormat)) {
281
282         /* client & server the same */
283
284         rfbLog("no translation needed\n");
285         cl->translateFn = rfbTranslateNone;
286         return TRUE;
287     }
288
289     if ((rfbServerFormat.bitsPerPixel < 16) ||
290         (!rfbEconomicTranslate && (rfbServerFormat.bitsPerPixel == 16))) {
291
292         /* we can use a single lookup table for <= 16 bpp */
293
294         cl->translateFn = rfbTranslateWithSingleTableFns
295                               [rfbServerFormat.bitsPerPixel / 16]
296                                   [cl->format.bitsPerPixel / 16];
297
298         (*rfbInitTrueColourSingleTableFns
299             [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
300                                              &rfbServerFormat, &cl->format);
301
302     } else {
303
304         /* otherwise we use three separate tables for red, green and blue */
305
306         cl->translateFn = rfbTranslateWithRGBTablesFns
307                               [rfbServerFormat.bitsPerPixel / 16]
308                                   [cl->format.bitsPerPixel / 16];
309
310         (*rfbInitTrueColourRGBTablesFns
311             [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
312                                              &rfbServerFormat, &cl->format);
313     }
314
315     return TRUE;
316 }
317
318
319
320 /*
321  * rfbSetClientColourMapBGR233 sets the client's colour map so that it's
322  * just like an 8-bit BGR233 true colour client.
323  */
324
325 static Bool
326 rfbSetClientColourMapBGR233(cl)
327     rfbClientPtr cl;
328 {
329     char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
330     rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
331     CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
332     int i, len;
333     int r, g, b;
334
335     if (cl->format.bitsPerPixel != 8) {
336         rfbLog("%s: client not 8 bits per pixel\n",
337                 "rfbSetClientColourMapBGR233");
338         rfbCloseSock(cl->sock);
339         return FALSE;
340     }
341
342     scme->type = rfbSetColourMapEntries;
343
344     scme->firstColour = Swap16IfLE(0);
345     scme->nColours = Swap16IfLE(256);
346
347     len = sz_rfbSetColourMapEntriesMsg;
348
349     i = 0;
350
351     for (b = 0; b < 4; b++) {
352         for (g = 0; g < 8; g++) {
353             for (r = 0; r < 8; r++) {
354                 rgb[i++] = Swap16IfLE(r * 65535 / 7);
355                 rgb[i++] = Swap16IfLE(g * 65535 / 7);
356                 rgb[i++] = Swap16IfLE(b * 65535 / 3);
357             }
358         }
359     }
360
361     len += 256 * 3 * 2;
362
363     if (WriteExact(cl->sock, buf, len) < 0) {
364         rfbLogPerror("rfbSetClientColourMapBGR233: write");
365         rfbCloseSock(cl->sock);
366         return FALSE;
367     }
368     return TRUE;
369 }
370
371
372 /*
373  * rfbSetClientColourMap is called to set the client's colour map.  If the
374  * client is a true colour client, we simply update our own translation table
375  * and mark the whole screen as having been modified.
376  */
377
378 Bool
379 rfbSetClientColourMap(cl, firstColour, nColours)
380     rfbClientPtr cl;
381     int firstColour;
382     int nColours;
383 {
384     BoxRec box;
385
386     if (nColours == 0) {
387         nColours = rfbInstalledColormap->pVisual->ColormapEntries;
388     }
389
390     if (rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) {
391         return TRUE;
392     }
393
394     if (cl->format.trueColour) {
395         (*rfbInitColourMapSingleTableFns
396             [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable,
397                                              &rfbServerFormat, &cl->format);
398
399         REGION_UNINIT(pScreen,&cl->modifiedRegion);
400         box.x1 = box.y1 = 0;
401         box.x2 = rfbScreen.width;
402         box.y2 = rfbScreen.height;
403         REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
404
405         return TRUE;
406     }
407
408     return rfbSendSetColourMapEntries(cl, firstColour, nColours);
409 }
410
411
412 /*
413  * rfbSetClientColourMaps sets the colour map for each RFB client.
414  */
415
416 void
417 rfbSetClientColourMaps(firstColour, nColours)
418     int firstColour;
419     int nColours;
420 {
421     rfbClientPtr cl, nextCl;
422
423     for (cl = rfbClientHead; cl; cl = nextCl) {
424         nextCl = cl->next;
425         rfbSetClientColourMap(cl, firstColour, nColours);
426     }
427 }
428
429
430 static void
431 PrintPixelFormat(pf)
432     rfbPixelFormat *pf;
433 {
434     if (pf->bitsPerPixel == 1) {
435         rfbLog("  1 bpp, %s sig bit in each byte is leftmost on the screen.\n",
436                (pf->bigEndian ? "most" : "least"));
437     } else {
438         rfbLog("  %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth,
439                ((pf->bitsPerPixel == 8) ? ""
440                 : (pf->bigEndian ? ", big endian" : ", little endian")));
441         if (pf->trueColour) {
442             rfbLog("  true colour: max r %d g %d b %d, shift r %d g %d b %d\n",
443                    pf->redMax, pf->greenMax, pf->blueMax,
444                    pf->redShift, pf->greenShift, pf->blueShift);
445         } else {
446             rfbLog("  uses a colour map (not true colour).\n");
447         }
448     }
449 }