Home | History | Annotate | Download | only in renderer
      1 //
      2 // Copyright (c) 2013 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // copyvertex.h: Defines vertex buffer copying and conversion functions
      8 
      9 #ifndef LIBGLESV2_RENDERER_COPYVERTEX_H_
     10 #define LIBGLESV2_RENDERER_COPYVERTEX_H_
     11 
     12 #include "common/mathutil.h"
     13 
     14 // 'widenDefaultValueBits' gives the default value for the alpha channel (4th component)
     15 //  the sentinel value 0 means we do not want to widen the input or add an alpha channel
     16 template <typename T, unsigned int componentCount, unsigned int widenDefaultValueBits>
     17 inline void copyVertexData(const void *input, size_t stride, size_t count, void *output)
     18 {
     19     const unsigned int attribSize = sizeof(T) * componentCount;
     20     const T defaultValue = gl::bitCast<T>(widenDefaultValueBits);
     21     const bool widen = (widenDefaultValueBits != 0);
     22 
     23     if (attribSize == stride && !widen)
     24     {
     25         memcpy(output, input, count * attribSize);
     26     }
     27     else
     28     {
     29         unsigned int outputStride = widen ? 4 : componentCount;
     30 
     31         for (unsigned int i = 0; i < count; i++)
     32         {
     33             const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + i * stride);
     34             T *offsetOutput = reinterpret_cast<T*>(output) + i * outputStride;
     35 
     36             for (unsigned int j = 0; j < componentCount; j++)
     37             {
     38                 offsetOutput[j] = offsetInput[j];
     39             }
     40 
     41             if (widen)
     42             {
     43                 offsetOutput[3] = defaultValue;
     44             }
     45         }
     46     }
     47 }
     48 
     49 template <unsigned int componentCount>
     50 inline void copyFixedVertexData(const void* input, size_t stride, size_t count, void* output)
     51 {
     52     static const float divisor = 1.0f / (1 << 16);
     53 
     54     for (unsigned int i = 0; i < count; i++)
     55     {
     56         const GLfixed* offsetInput = reinterpret_cast<const GLfixed*>(reinterpret_cast<const char*>(input) + stride * i);
     57         float* offsetOutput = reinterpret_cast<float*>(output) + i * componentCount;
     58 
     59         for (unsigned int j = 0; j < componentCount; j++)
     60         {
     61             offsetOutput[j] = static_cast<float>(offsetInput[j]) * divisor;
     62         }
     63     }
     64 }
     65 
     66 template <typename T, unsigned int componentCount, bool normalized>
     67 inline void copyToFloatVertexData(const void* input, size_t stride, size_t count, void* output)
     68 {
     69     typedef std::numeric_limits<T> NL;
     70 
     71     for (unsigned int i = 0; i < count; i++)
     72     {
     73         const T *offsetInput = reinterpret_cast<const T*>(reinterpret_cast<const char*>(input) + stride * i);
     74         float *offsetOutput = reinterpret_cast<float*>(output) + i * componentCount;
     75 
     76         for (unsigned int j = 0; j < componentCount; j++)
     77         {
     78             if (normalized)
     79             {
     80                 if (NL::is_signed)
     81                 {
     82                     const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1);
     83                     offsetOutput[j] = (2 * static_cast<float>(offsetInput[j]) + 1) * divisor;
     84                 }
     85                 else
     86                 {
     87                     offsetOutput[j] =  static_cast<float>(offsetInput[j]) / NL::max();
     88                 }
     89             }
     90             else
     91             {
     92                 offsetOutput[j] =  static_cast<float>(offsetInput[j]);
     93             }
     94         }
     95     }
     96 }
     97 
     98 inline void copyPackedUnsignedVertexData(const void* input, size_t stride, size_t count, void* output)
     99 {
    100     const unsigned int attribSize = 4;
    101 
    102     if (attribSize == stride)
    103     {
    104         memcpy(output, input, count * attribSize);
    105     }
    106     else
    107     {
    108         for (unsigned int i = 0; i < count; i++)
    109         {
    110             const GLuint *offsetInput = reinterpret_cast<const GLuint*>(reinterpret_cast<const char*>(input) + (i * stride));
    111             GLuint *offsetOutput = reinterpret_cast<GLuint*>(output) + (i * attribSize);
    112 
    113             offsetOutput[i] = offsetInput[i];
    114         }
    115     }
    116 }
    117 
    118 template <bool isSigned, bool normalized, bool toFloat>
    119 static inline void copyPackedRGB(unsigned int data, void *output)
    120 {
    121     const unsigned int rgbSignMask = 0x200;       // 1 set at the 9 bit
    122     const unsigned int negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1
    123 
    124     if (toFloat)
    125     {
    126         GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output);
    127         if (isSigned)
    128         {
    129             GLfloat finalValue = 0;
    130             if (data & rgbSignMask)
    131             {
    132                 int negativeNumber = data | negativeMask;
    133                 finalValue = static_cast<GLfloat>(negativeNumber);
    134             }
    135             else
    136             {
    137                 finalValue = static_cast<GLfloat>(data);
    138             }
    139 
    140             if (normalized)
    141             {
    142                 const int maxValue = 0x1FF;      // 1 set in bits 0 through 8
    143                 const int minValue = 0xFFFFFE01; // Inverse of maxValue
    144 
    145                 // A 10-bit two's complement number has the possibility of being minValue - 1 but
    146                 // OpenGL's normalization rules dictate that it should be clamped to minValue in this
    147                 // case.
    148                 if (finalValue < minValue)
    149                 {
    150                     finalValue = minValue;
    151                 }
    152 
    153                 const int halfRange = (maxValue - minValue) >> 1;
    154                 *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f;
    155             }
    156             else
    157             {
    158                 *floatOutput = finalValue;
    159             }
    160         }
    161         else
    162         {
    163             if (normalized)
    164             {
    165                 const unsigned int maxValue = 0x3FF; // 1 set in bits 0 through 9
    166                 *floatOutput = static_cast<GLfloat>(data) / static_cast<GLfloat>(maxValue);
    167             }
    168             else
    169             {
    170                 *floatOutput = static_cast<GLfloat>(data);
    171             }
    172         }
    173     }
    174     else
    175     {
    176         if (isSigned)
    177         {
    178             GLshort *intOutput = reinterpret_cast<GLshort*>(output);
    179 
    180             if (data & rgbSignMask)
    181             {
    182                 *intOutput = data | negativeMask;
    183             }
    184             else
    185             {
    186                 *intOutput = data;
    187             }
    188         }
    189         else
    190         {
    191             GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
    192             *uintOutput = data;
    193         }
    194     }
    195 }
    196 
    197 template <bool isSigned, bool normalized, bool toFloat>
    198 inline void copyPackedAlpha(unsigned int data, void *output)
    199 {
    200     if (toFloat)
    201     {
    202         GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output);
    203         if (isSigned)
    204         {
    205             if (normalized)
    206             {
    207                 switch (data)
    208                 {
    209                   case 0x0: *floatOutput =  0.0f; break;
    210                   case 0x1: *floatOutput =  1.0f; break;
    211                   case 0x2: *floatOutput = -1.0f; break;
    212                   case 0x3: *floatOutput = -1.0f; break;
    213                   default: UNREACHABLE();
    214                 }
    215             }
    216             else
    217             {
    218                 switch (data)
    219                 {
    220                   case 0x0: *floatOutput =  0.0f; break;
    221                   case 0x1: *floatOutput =  1.0f; break;
    222                   case 0x2: *floatOutput = -2.0f; break;
    223                   case 0x3: *floatOutput = -1.0f; break;
    224                   default: UNREACHABLE();
    225                 }
    226             }
    227         }
    228         else
    229         {
    230             if (normalized)
    231             {
    232                 switch (data)
    233                 {
    234                   case 0x0: *floatOutput = 0.0f / 3.0f; break;
    235                   case 0x1: *floatOutput = 1.0f / 3.0f; break;
    236                   case 0x2: *floatOutput = 2.0f / 3.0f; break;
    237                   case 0x3: *floatOutput = 3.0f / 3.0f; break;
    238                   default: UNREACHABLE();
    239                 }
    240             }
    241             else
    242             {
    243                 switch (data)
    244                 {
    245                   case 0x0: *floatOutput = 0.0f; break;
    246                   case 0x1: *floatOutput = 1.0f; break;
    247                   case 0x2: *floatOutput = 2.0f; break;
    248                   case 0x3: *floatOutput = 3.0f; break;
    249                   default: UNREACHABLE();
    250                 }
    251             }
    252         }
    253     }
    254     else
    255     {
    256         if (isSigned)
    257         {
    258             GLshort *intOutput = reinterpret_cast<GLshort*>(output);
    259             switch (data)
    260             {
    261               case 0x0: *intOutput =  0; break;
    262               case 0x1: *intOutput =  1; break;
    263               case 0x2: *intOutput = -2; break;
    264               case 0x3: *intOutput = -1; break;
    265               default: UNREACHABLE();
    266             }
    267         }
    268         else
    269         {
    270             GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
    271             switch (data)
    272             {
    273               case 0x0: *uintOutput = 0; break;
    274               case 0x1: *uintOutput = 1; break;
    275               case 0x2: *uintOutput = 2; break;
    276               case 0x3: *uintOutput = 3; break;
    277               default: UNREACHABLE();
    278             }
    279         }
    280     }
    281 }
    282 
    283 template <bool isSigned, bool normalized, bool toFloat>
    284 inline void copyPackedVertexData(const void* input, size_t stride, size_t count, void* output)
    285 {
    286     const unsigned int outputComponentSize = toFloat ? 4 : 2;
    287     const unsigned int componentCount = 4;
    288 
    289     const unsigned int rgbMask = 0x3FF; // 1 set in bits 0 through 9
    290     const unsigned int redShift = 0;    // red is bits 0 through 9
    291     const unsigned int greenShift = 10; // green is bits 10 through 19
    292     const unsigned int blueShift = 20;  // blue is bits 20 through 29
    293 
    294     const unsigned int alphaMask = 0x3; // 1 set in bits 0 and 1
    295     const unsigned int alphaShift = 30; // Alpha is the 30 and 31 bits
    296 
    297     for (unsigned int i = 0; i < count; i++)
    298     {
    299         GLuint packedValue = *reinterpret_cast<const GLuint*>(reinterpret_cast<const char*>(input) + (i * stride));
    300         GLbyte *offsetOutput = reinterpret_cast<GLbyte*>(output) + (i * outputComponentSize * componentCount);
    301 
    302         copyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> redShift) & rgbMask,     offsetOutput + (0 * outputComponentSize));
    303         copyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> greenShift) & rgbMask,   offsetOutput + (1 * outputComponentSize));
    304         copyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> blueShift) & rgbMask,    offsetOutput + (2 * outputComponentSize));
    305         copyPackedAlpha<isSigned, normalized, toFloat>((packedValue >> alphaShift) & alphaMask, offsetOutput + (3* outputComponentSize));
    306     }
    307 }
    308 
    309 #endif // LIBGLESV2_RENDERER_COPYVERTEX_H_
    310