Home | History | Annotate | Download | only in glx
      1 /*
      2  * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
      3  * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice including the dates of first publication and
     13  * either this permission notice or a reference to
     14  * http://oss.sgi.com/projects/FreeB/
     15  * shall be included in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     22  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * Except as contained in this notice, the name of Silicon Graphics, Inc.
     26  * shall not be used in advertising or otherwise to promote the sale, use or
     27  * other dealings in this Software without prior written authorization from
     28  * Silicon Graphics, Inc.
     29  */
     30 
     31 #include "packrender.h"
     32 
     33 static const GLubyte MsbToLsbTable[256] = {
     34    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
     35    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
     36    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
     37    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
     38    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
     39    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
     40    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
     41    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
     42    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
     43    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
     44    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
     45    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
     46    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
     47    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
     48    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
     49    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
     50    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
     51    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
     52    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
     53    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
     54    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
     55    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
     56    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
     57    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
     58    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
     59    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
     60    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
     61    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
     62    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
     63    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
     64    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
     65    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
     66 };
     67 
     68 static const GLubyte LowBitsMask[9] = {
     69    0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
     70 };
     71 
     72 static const GLubyte HighBitsMask[9] = {
     73    0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff,
     74 };
     75 
     76 
     77 /*
     78 ** Copy bitmap data from clients packed memory applying unpacking modes as the
     79 ** data is transfered into the destImage buffer.  Return in modes the
     80 ** set of pixel modes that are to be done by the server.
     81 */
     82 static void
     83 FillBitmap(struct glx_context * gc, GLint width, GLint height,
     84            GLenum format, const GLvoid * userdata, GLubyte * destImage)
     85 {
     86    const __GLXattribute *state = gc->client_state_private;
     87    GLint rowLength = state->storeUnpack.rowLength;
     88    GLint alignment = state->storeUnpack.alignment;
     89    GLint skipPixels = state->storeUnpack.skipPixels;
     90    GLint skipRows = state->storeUnpack.skipRows;
     91    GLint lsbFirst = state->storeUnpack.lsbFirst;
     92    GLint elementsLeft, bitOffset, currentByte, nextByte, highBitMask;
     93    GLint lowBitMask, i;
     94    GLint components, groupsPerRow, rowSize, padding, elementsPerRow;
     95    const GLubyte *start, *iter;
     96 
     97    if (rowLength > 0) {
     98       groupsPerRow = rowLength;
     99    }
    100    else {
    101       groupsPerRow = width;
    102    }
    103    components = __glElementsPerGroup(format, GL_BITMAP);
    104    rowSize = (groupsPerRow * components + 7) >> 3;
    105    padding = (rowSize % alignment);
    106    if (padding) {
    107       rowSize += alignment - padding;
    108    }
    109    start = ((const GLubyte *) userdata) + skipRows * rowSize +
    110       ((skipPixels * components) >> 3);
    111    bitOffset = (skipPixels * components) & 7;
    112    highBitMask = LowBitsMask[8 - bitOffset];
    113    lowBitMask = HighBitsMask[bitOffset];
    114    elementsPerRow = width * components;
    115    for (i = 0; i < height; i++) {
    116       elementsLeft = elementsPerRow;
    117       iter = start;
    118       while (elementsLeft) {
    119          /* First retrieve low bits from current byte */
    120          if (lsbFirst) {
    121             currentByte = MsbToLsbTable[iter[0]];
    122          }
    123          else {
    124             currentByte = iter[0];
    125          }
    126          if (bitOffset) {
    127             /* Need to read next byte to finish current byte */
    128             if (elementsLeft > (8 - bitOffset)) {
    129                if (lsbFirst) {
    130                   nextByte = MsbToLsbTable[iter[1]];
    131                }
    132                else {
    133                   nextByte = iter[1];
    134                }
    135                currentByte =
    136                   ((currentByte & highBitMask) << bitOffset) |
    137                   ((nextByte & lowBitMask) >> (8 - bitOffset));
    138             }
    139             else {
    140                currentByte = ((currentByte & highBitMask) << bitOffset);
    141             }
    142          }
    143          if (elementsLeft >= 8) {
    144             *destImage = currentByte;
    145             elementsLeft -= 8;
    146          }
    147          else {
    148             *destImage = currentByte & HighBitsMask[elementsLeft];
    149             elementsLeft = 0;
    150          }
    151          destImage++;
    152          iter++;
    153       }
    154       start += rowSize;
    155    }
    156 }
    157 
    158 /*
    159 ** Extract array from user's data applying all pixel store modes.
    160 ** The internal packed array format used has LSB_FIRST = FALSE and
    161 ** ALIGNMENT = 1.
    162 */
    163 void
    164 __glFillImage(struct glx_context * gc, GLint dim, GLint width, GLint height,
    165               GLint depth, GLenum format, GLenum type,
    166               const GLvoid * userdata, GLubyte * newimage, GLubyte * modes)
    167 {
    168    const __GLXattribute *state = gc->client_state_private;
    169    GLint rowLength = state->storeUnpack.rowLength;
    170    GLint imageHeight = state->storeUnpack.imageHeight;
    171    GLint alignment = state->storeUnpack.alignment;
    172    GLint skipPixels = state->storeUnpack.skipPixels;
    173    GLint skipRows = state->storeUnpack.skipRows;
    174    GLint skipImages = state->storeUnpack.skipImages;
    175    GLint swapBytes = state->storeUnpack.swapEndian;
    176    GLint components, elementSize, rowSize, padding, groupsPerRow, groupSize;
    177    GLint elementsPerRow, imageSize, rowsPerImage, h, i, j, k;
    178    const GLubyte *start, *iter, *itera, *iterb, *iterc;
    179    GLubyte *iter2;
    180 
    181    if (type == GL_BITMAP) {
    182       FillBitmap(gc, width, height, format, userdata, newimage);
    183    }
    184    else {
    185       components = __glElementsPerGroup(format, type);
    186       if (rowLength > 0) {
    187          groupsPerRow = rowLength;
    188       }
    189       else {
    190          groupsPerRow = width;
    191       }
    192       if (imageHeight > 0) {
    193          rowsPerImage = imageHeight;
    194       }
    195       else {
    196          rowsPerImage = height;
    197       }
    198 
    199       elementSize = __glBytesPerElement(type);
    200       groupSize = elementSize * components;
    201       if (elementSize == 1)
    202          swapBytes = 0;
    203 
    204       rowSize = groupsPerRow * groupSize;
    205       padding = (rowSize % alignment);
    206       if (padding) {
    207          rowSize += alignment - padding;
    208       }
    209       imageSize = rowSize * rowsPerImage;
    210       start = ((const GLubyte *) userdata) + skipImages * imageSize +
    211          skipRows * rowSize + skipPixels * groupSize;
    212       iter2 = newimage;
    213       elementsPerRow = width * components;
    214 
    215       if (swapBytes) {
    216          itera = start;
    217          for (h = 0; h < depth; h++) {
    218             iterb = itera;
    219             for (i = 0; i < height; i++) {
    220                iterc = iterb;
    221                for (j = 0; j < elementsPerRow; j++) {
    222                   for (k = 1; k <= elementSize; k++) {
    223                      iter2[k - 1] = iterc[elementSize - k];
    224                   }
    225                   iter2 += elementSize;
    226                   iterc += elementSize;
    227                }
    228                iterb += rowSize;
    229             }
    230             itera += imageSize;
    231          }
    232       }
    233       else {
    234          itera = start;
    235          for (h = 0; h < depth; h++) {
    236             if (rowSize == elementsPerRow * elementSize) {
    237                /* Ha!  This is mondo easy! */
    238                __GLX_MEM_COPY(iter2, itera,
    239                               elementsPerRow * elementSize * height);
    240                iter2 += elementsPerRow * elementSize * height;
    241             }
    242             else {
    243                iter = itera;
    244                for (i = 0; i < height; i++) {
    245                   __GLX_MEM_COPY(iter2, iter, elementsPerRow * elementSize);
    246                   iter2 += elementsPerRow * elementSize;
    247                   iter += rowSize;
    248                }
    249             }
    250             itera += imageSize;
    251          }
    252       }
    253    }
    254 
    255    /* Setup store modes that describe what we just did */
    256    if (modes) {
    257       if (dim < 3) {
    258          (void) memcpy(modes, __glXDefaultPixelStore + 4, 20);
    259       }
    260       else {
    261          (void) memcpy(modes, __glXDefaultPixelStore + 0, 36);
    262       }
    263    }
    264 }
    265 
    266 /*
    267 ** Empty a bitmap in LSB_FIRST=GL_FALSE and ALIGNMENT=4 format packing it
    268 ** into the clients memory using the pixel store PACK modes.
    269 */
    270 static void
    271 EmptyBitmap(struct glx_context * gc, GLint width, GLint height,
    272             GLenum format, const GLubyte * sourceImage, GLvoid * userdata)
    273 {
    274    const __GLXattribute *state = gc->client_state_private;
    275    GLint rowLength = state->storePack.rowLength;
    276    GLint alignment = state->storePack.alignment;
    277    GLint skipPixels = state->storePack.skipPixels;
    278    GLint skipRows = state->storePack.skipRows;
    279    GLint lsbFirst = state->storePack.lsbFirst;
    280    GLint components, groupsPerRow, rowSize, padding, elementsPerRow;
    281    GLint sourceRowSize, sourcePadding, sourceSkip;
    282    GLubyte *start, *iter;
    283    GLint elementsLeft, bitOffset, currentByte, highBitMask, lowBitMask;
    284    GLint writeMask, i;
    285    GLubyte writeByte;
    286 
    287    components = __glElementsPerGroup(format, GL_BITMAP);
    288    if (rowLength > 0) {
    289       groupsPerRow = rowLength;
    290    }
    291    else {
    292       groupsPerRow = width;
    293    }
    294 
    295    rowSize = (groupsPerRow * components + 7) >> 3;
    296    padding = (rowSize % alignment);
    297    if (padding) {
    298       rowSize += alignment - padding;
    299    }
    300    sourceRowSize = (width * components + 7) >> 3;
    301    sourcePadding = (sourceRowSize % 4);
    302    if (sourcePadding) {
    303       sourceSkip = 4 - sourcePadding;
    304    }
    305    else {
    306       sourceSkip = 0;
    307    }
    308    start = ((GLubyte *) userdata) + skipRows * rowSize +
    309       ((skipPixels * components) >> 3);
    310    bitOffset = (skipPixels * components) & 7;
    311    highBitMask = LowBitsMask[8 - bitOffset];
    312    lowBitMask = HighBitsMask[bitOffset];
    313    elementsPerRow = width * components;
    314    for (i = 0; i < height; i++) {
    315       elementsLeft = elementsPerRow;
    316       iter = start;
    317       writeMask = highBitMask;
    318       writeByte = 0;
    319       while (elementsLeft) {
    320          /* Set up writeMask (to write to current byte) */
    321          if (elementsLeft + bitOffset < 8) {
    322             /* Need to trim writeMask */
    323             writeMask &= HighBitsMask[bitOffset + elementsLeft];
    324          }
    325 
    326          if (lsbFirst) {
    327             currentByte = MsbToLsbTable[iter[0]];
    328          }
    329          else {
    330             currentByte = iter[0];
    331          }
    332 
    333          if (bitOffset) {
    334             writeByte |= (sourceImage[0] >> bitOffset);
    335             currentByte = (currentByte & ~writeMask) |
    336                (writeByte & writeMask);
    337             writeByte = (sourceImage[0] << (8 - bitOffset));
    338          }
    339          else {
    340             currentByte = (currentByte & ~writeMask) |
    341                (sourceImage[0] & writeMask);
    342          }
    343 
    344          if (lsbFirst) {
    345             iter[0] = MsbToLsbTable[currentByte];
    346          }
    347          else {
    348             iter[0] = currentByte;
    349          }
    350 
    351          if (elementsLeft >= 8) {
    352             elementsLeft -= 8;
    353          }
    354          else {
    355             elementsLeft = 0;
    356          }
    357          sourceImage++;
    358          iter++;
    359          writeMask = 0xff;
    360       }
    361       if (writeByte) {
    362          /* Some data left over that still needs writing */
    363          writeMask &= lowBitMask;
    364          if (lsbFirst) {
    365             currentByte = MsbToLsbTable[iter[0]];
    366          }
    367          else {
    368             currentByte = iter[0];
    369          }
    370          currentByte = (currentByte & ~writeMask) | (writeByte & writeMask);
    371          if (lsbFirst) {
    372             iter[0] = MsbToLsbTable[currentByte];
    373          }
    374          else {
    375             iter[0] = currentByte;
    376          }
    377       }
    378       start += rowSize;
    379       sourceImage += sourceSkip;
    380    }
    381 }
    382 
    383 /*
    384 ** Insert array into user's data applying all pixel store modes.
    385 ** The packed array format from the server is LSB_FIRST = FALSE,
    386 ** SWAP_BYTES = the current pixel storage pack mode, and ALIGNMENT = 4.
    387 ** Named __glEmptyImage() because it is the opposite of __glFillImage().
    388 */
    389 /* ARGSUSED */
    390 void
    391 __glEmptyImage(struct glx_context * gc, GLint dim, GLint width, GLint height,
    392                GLint depth, GLenum format, GLenum type,
    393                const GLubyte * sourceImage, GLvoid * userdata)
    394 {
    395    const __GLXattribute *state = gc->client_state_private;
    396    GLint rowLength = state->storePack.rowLength;
    397    GLint imageHeight = state->storePack.imageHeight;
    398    GLint alignment = state->storePack.alignment;
    399    GLint skipPixels = state->storePack.skipPixels;
    400    GLint skipRows = state->storePack.skipRows;
    401    GLint skipImages = state->storePack.skipImages;
    402    GLint components, elementSize, rowSize, padding, groupsPerRow, groupSize;
    403    GLint elementsPerRow, sourceRowSize, sourcePadding, h, i;
    404    GLint imageSize, rowsPerImage;
    405    GLubyte *start, *iter, *itera;
    406 
    407    if (type == GL_BITMAP) {
    408       EmptyBitmap(gc, width, height, format, sourceImage, userdata);
    409    }
    410    else {
    411       components = __glElementsPerGroup(format, type);
    412       if (rowLength > 0) {
    413          groupsPerRow = rowLength;
    414       }
    415       else {
    416          groupsPerRow = width;
    417       }
    418       if (imageHeight > 0) {
    419          rowsPerImage = imageHeight;
    420       }
    421       else {
    422          rowsPerImage = height;
    423       }
    424       elementSize = __glBytesPerElement(type);
    425       groupSize = elementSize * components;
    426       rowSize = groupsPerRow * groupSize;
    427       padding = (rowSize % alignment);
    428       if (padding) {
    429          rowSize += alignment - padding;
    430       }
    431       sourceRowSize = width * groupSize;
    432       sourcePadding = (sourceRowSize % 4);
    433       if (sourcePadding) {
    434          sourceRowSize += 4 - sourcePadding;
    435       }
    436       imageSize = sourceRowSize * rowsPerImage;
    437       start = ((GLubyte *) userdata) + skipImages * imageSize +
    438          skipRows * rowSize + skipPixels * groupSize;
    439       elementsPerRow = width * components;
    440 
    441       itera = start;
    442       for (h = 0; h < depth; h++) {
    443          if ((rowSize == sourceRowSize) && (sourcePadding == 0)) {
    444             /* Ha!  This is mondo easy! */
    445             __GLX_MEM_COPY(itera, sourceImage,
    446                            elementsPerRow * elementSize * height);
    447             sourceImage += elementsPerRow * elementSize * height;
    448          }
    449          else {
    450             iter = itera;
    451             for (i = 0; i < height; i++) {
    452                __GLX_MEM_COPY(iter, sourceImage,
    453                               elementsPerRow * elementSize);
    454                sourceImage += sourceRowSize;
    455                iter += rowSize;
    456             }
    457          }
    458          itera += imageSize;
    459       }
    460    }
    461 }
    462