X-Git-Url: https://git.sesse.net/?p=rdpsrv;a=blobdiff_plain;f=Xserver%2Fprograms%2FXserver%2Fhw%2Fvnc%2Ftranslate.c;fp=Xserver%2Fprograms%2FXserver%2Fhw%2Fvnc%2Ftranslate.c;h=acbc8b10e3edfa12e81657038072278584dd4c15;hp=0000000000000000000000000000000000000000;hb=b6e6afccf37f4ad0515ef2a698f714fdf1bf23b3;hpb=e3340a110a3b01756b8e67531395a33b40a17d37 diff --git a/Xserver/programs/Xserver/hw/vnc/translate.c b/Xserver/programs/Xserver/hw/vnc/translate.c new file mode 100644 index 0000000..acbc8b1 --- /dev/null +++ b/Xserver/programs/Xserver/hw/vnc/translate.c @@ -0,0 +1,449 @@ +/* + * translate.c - translate between different pixel formats + */ + +/* + * Copyright (C) 2002 RealVNC Ltd. + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include +#include +#include "rfb.h" + +static void PrintPixelFormat(rfbPixelFormat *pf); +static Bool rfbSetClientColourMapBGR233(); + +Bool rfbEconomicTranslate = FALSE; + +/* + * Structure representing pixel format for RFB server (i.e. us). + */ + +rfbPixelFormat rfbServerFormat; + + +/* + * Some standard pixel formats. + */ + +static const rfbPixelFormat BGR233Format = { + 8, 8, 0, 1, 7, 7, 3, 0, 3, 6 +}; + + +/* + * Macro to compare pixel formats. + */ + +#define PF_EQ(x,y) \ + ((x.bitsPerPixel == y.bitsPerPixel) && \ + (x.depth == y.depth) && \ + ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \ + (x.trueColour == y.trueColour) && \ + (!x.trueColour || ((x.redMax == y.redMax) && \ + (x.greenMax == y.greenMax) && \ + (x.blueMax == y.blueMax) && \ + (x.redShift == y.redShift) && \ + (x.greenShift == y.greenShift) && \ + (x.blueShift == y.blueShift)))) + +#define CONCAT2(a,b) a##b +#define CONCAT2E(a,b) CONCAT2(a,b) +#define CONCAT4(a,b,c,d) a##b##c##d +#define CONCAT4E(a,b,c,d) CONCAT4(a,b,c,d) + +#define OUT 8 +#include "tableinittctemplate.c" +#include "tableinitcmtemplate.c" +#define IN 8 +#include "tabletranstemplate.c" +#undef IN +#define IN 16 +#include "tabletranstemplate.c" +#undef IN +#define IN 32 +#include "tabletranstemplate.c" +#undef IN +#undef OUT + +#define OUT 16 +#include "tableinittctemplate.c" +#include "tableinitcmtemplate.c" +#define IN 8 +#include "tabletranstemplate.c" +#undef IN +#define IN 16 +#include "tabletranstemplate.c" +#undef IN +#define IN 32 +#include "tabletranstemplate.c" +#undef IN +#undef OUT + +#define OUT 32 +#include "tableinittctemplate.c" +#include "tableinitcmtemplate.c" +#define IN 8 +#include "tabletranstemplate.c" +#undef IN +#define IN 16 +#include "tabletranstemplate.c" +#undef IN +#define IN 32 +#include "tabletranstemplate.c" +#undef IN +#undef OUT + +typedef void (*rfbInitTableFnType)(char **table, rfbPixelFormat *in, + rfbPixelFormat *out); + +rfbInitTableFnType rfbInitTrueColourSingleTableFns[3] = { + rfbInitTrueColourSingleTable8, + rfbInitTrueColourSingleTable16, + rfbInitTrueColourSingleTable32 +}; + +rfbInitTableFnType rfbInitColourMapSingleTableFns[3] = { + rfbInitColourMapSingleTable8, + rfbInitColourMapSingleTable16, + rfbInitColourMapSingleTable32 +}; + +rfbInitTableFnType rfbInitTrueColourRGBTablesFns[3] = { + rfbInitTrueColourRGBTables8, + rfbInitTrueColourRGBTables16, + rfbInitTrueColourRGBTables32 +}; + +rfbTranslateFnType rfbTranslateWithSingleTableFns[3][3] = { + { rfbTranslateWithSingleTable8to8, + rfbTranslateWithSingleTable8to16, + rfbTranslateWithSingleTable8to32 }, + { rfbTranslateWithSingleTable16to8, + rfbTranslateWithSingleTable16to16, + rfbTranslateWithSingleTable16to32 }, + { rfbTranslateWithSingleTable32to8, + rfbTranslateWithSingleTable32to16, + rfbTranslateWithSingleTable32to32 } +}; + +rfbTranslateFnType rfbTranslateWithRGBTablesFns[3][3] = { + { rfbTranslateWithRGBTables8to8, + rfbTranslateWithRGBTables8to16, + rfbTranslateWithRGBTables8to32 }, + { rfbTranslateWithRGBTables16to8, + rfbTranslateWithRGBTables16to16, + rfbTranslateWithRGBTables16to32 }, + { rfbTranslateWithRGBTables32to8, + rfbTranslateWithRGBTables32to16, + rfbTranslateWithRGBTables32to32 } +}; + + + +/* + * rfbTranslateNone is used when no translation is required. + */ + +void +rfbTranslateNone(char *table, rfbPixelFormat *in, rfbPixelFormat *out, + char *iptr, char *optr, int bytesBetweenInputLines, + int width, int height) +{ + int bytesPerOutputLine = width * (out->bitsPerPixel / 8); + + while (height > 0) { + memcpy(optr, iptr, bytesPerOutputLine); + iptr += bytesBetweenInputLines; + optr += bytesPerOutputLine; + height--; + } +} + + +/* + * rfbSetTranslateFunction sets the translation function. + */ + +Bool +rfbSetTranslateFunction(cl) + rfbClientPtr cl; +{ + rfbLog("Pixel format for client %s:\n",cl->host); + PrintPixelFormat(&cl->format); + + /* + * Check that bits per pixel values are valid + */ + + if ((rfbServerFormat.bitsPerPixel != 8) && + (rfbServerFormat.bitsPerPixel != 16) && + (rfbServerFormat.bitsPerPixel != 32)) + { + rfbLog("%s: server bits per pixel not 8, 16 or 32\n", + "rfbSetTranslateFunction"); + rfbCloseSock(cl->sock); + return FALSE; + } + + if ((cl->format.bitsPerPixel != 8) && + (cl->format.bitsPerPixel != 16) && + (cl->format.bitsPerPixel != 32)) + { + rfbLog("%s: client bits per pixel not 8, 16 or 32\n", + "rfbSetTranslateFunction"); + rfbCloseSock(cl->sock); + return FALSE; + } + + if (!rfbServerFormat.trueColour && (rfbServerFormat.bitsPerPixel != 8)) { + rfbLog("rfbSetTranslateFunction: server has colour map " + "but %d-bit - can only cope with 8-bit colour maps\n", + rfbServerFormat.bitsPerPixel); + rfbCloseSock(cl->sock); + return FALSE; + } + + if (!cl->format.trueColour && (cl->format.bitsPerPixel != 8)) { + rfbLog("rfbSetTranslateFunction: client has colour map " + "but %d-bit - can only cope with 8-bit colour maps\n", + cl->format.bitsPerPixel); + rfbCloseSock(cl->sock); + return FALSE; + } + + /* + * bpp is valid, now work out how to translate + */ + + if (!cl->format.trueColour) { + + /* ? -> colour map */ + + if (!rfbServerFormat.trueColour) { + + /* colour map -> colour map */ + + rfbLog("rfbSetTranslateFunction: both 8-bit colour map: " + "no translation needed\n"); + cl->translateFn = rfbTranslateNone; + return rfbSetClientColourMap(cl, 0, 0); + } + + /* + * truecolour -> colour map + * + * Set client's colour map to BGR233, then effectively it's + * truecolour as well + */ + + if (!rfbSetClientColourMapBGR233(cl)) + return FALSE; + + cl->format = BGR233Format; + } + + /* ? -> truecolour */ + + if (!rfbServerFormat.trueColour) { + + /* colour map -> truecolour */ + + rfbLog("rfbSetTranslateFunction: client is %d-bit trueColour," + " server has colour map\n",cl->format.bitsPerPixel); + + cl->translateFn = rfbTranslateWithSingleTableFns + [rfbServerFormat.bitsPerPixel / 16] + [cl->format.bitsPerPixel / 16]; + + return rfbSetClientColourMap(cl, 0, 0); + } + + /* truecolour -> truecolour */ + + if (PF_EQ(cl->format,rfbServerFormat)) { + + /* client & server the same */ + + rfbLog("no translation needed\n"); + cl->translateFn = rfbTranslateNone; + return TRUE; + } + + if ((rfbServerFormat.bitsPerPixel < 16) || + (!rfbEconomicTranslate && (rfbServerFormat.bitsPerPixel == 16))) { + + /* we can use a single lookup table for <= 16 bpp */ + + cl->translateFn = rfbTranslateWithSingleTableFns + [rfbServerFormat.bitsPerPixel / 16] + [cl->format.bitsPerPixel / 16]; + + (*rfbInitTrueColourSingleTableFns + [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable, + &rfbServerFormat, &cl->format); + + } else { + + /* otherwise we use three separate tables for red, green and blue */ + + cl->translateFn = rfbTranslateWithRGBTablesFns + [rfbServerFormat.bitsPerPixel / 16] + [cl->format.bitsPerPixel / 16]; + + (*rfbInitTrueColourRGBTablesFns + [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable, + &rfbServerFormat, &cl->format); + } + + return TRUE; +} + + + +/* + * rfbSetClientColourMapBGR233 sets the client's colour map so that it's + * just like an 8-bit BGR233 true colour client. + */ + +static Bool +rfbSetClientColourMapBGR233(cl) + rfbClientPtr cl; +{ + char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; + rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf; + CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]); + int i, len; + int r, g, b; + + if (cl->format.bitsPerPixel != 8) { + rfbLog("%s: client not 8 bits per pixel\n", + "rfbSetClientColourMapBGR233"); + rfbCloseSock(cl->sock); + return FALSE; + } + + scme->type = rfbSetColourMapEntries; + + scme->firstColour = Swap16IfLE(0); + scme->nColours = Swap16IfLE(256); + + len = sz_rfbSetColourMapEntriesMsg; + + i = 0; + + for (b = 0; b < 4; b++) { + for (g = 0; g < 8; g++) { + for (r = 0; r < 8; r++) { + rgb[i++] = Swap16IfLE(r * 65535 / 7); + rgb[i++] = Swap16IfLE(g * 65535 / 7); + rgb[i++] = Swap16IfLE(b * 65535 / 3); + } + } + } + + len += 256 * 3 * 2; + + if (WriteExact(cl->sock, buf, len) < 0) { + rfbLogPerror("rfbSetClientColourMapBGR233: write"); + rfbCloseSock(cl->sock); + return FALSE; + } + return TRUE; +} + + +/* + * rfbSetClientColourMap is called to set the client's colour map. If the + * client is a true colour client, we simply update our own translation table + * and mark the whole screen as having been modified. + */ + +Bool +rfbSetClientColourMap(cl, firstColour, nColours) + rfbClientPtr cl; + int firstColour; + int nColours; +{ + BoxRec box; + + if (nColours == 0) { + nColours = rfbInstalledColormap->pVisual->ColormapEntries; + } + + if (rfbServerFormat.trueColour || !cl->readyForSetColourMapEntries) { + return TRUE; + } + + if (cl->format.trueColour) { + (*rfbInitColourMapSingleTableFns + [cl->format.bitsPerPixel / 16]) (&cl->translateLookupTable, + &rfbServerFormat, &cl->format); + + REGION_UNINIT(pScreen,&cl->modifiedRegion); + box.x1 = box.y1 = 0; + box.x2 = rfbScreen.width; + box.y2 = rfbScreen.height; + REGION_INIT(pScreen,&cl->modifiedRegion,&box,0); + + return TRUE; + } + + return rfbSendSetColourMapEntries(cl, firstColour, nColours); +} + + +/* + * rfbSetClientColourMaps sets the colour map for each RFB client. + */ + +void +rfbSetClientColourMaps(firstColour, nColours) + int firstColour; + int nColours; +{ + rfbClientPtr cl, nextCl; + + for (cl = rfbClientHead; cl; cl = nextCl) { + nextCl = cl->next; + rfbSetClientColourMap(cl, firstColour, nColours); + } +} + + +static void +PrintPixelFormat(pf) + rfbPixelFormat *pf; +{ + if (pf->bitsPerPixel == 1) { + rfbLog(" 1 bpp, %s sig bit in each byte is leftmost on the screen.\n", + (pf->bigEndian ? "most" : "least")); + } else { + rfbLog(" %d bpp, depth %d%s\n",pf->bitsPerPixel,pf->depth, + ((pf->bitsPerPixel == 8) ? "" + : (pf->bigEndian ? ", big endian" : ", little endian"))); + if (pf->trueColour) { + rfbLog(" true colour: max r %d g %d b %d, shift r %d g %d b %d\n", + pf->redMax, pf->greenMax, pf->blueMax, + pf->redShift, pf->greenShift, pf->blueShift); + } else { + rfbLog(" uses a colour map (not true colour).\n"); + } + } +}