1//
2// Copyright (c) 2014-2015 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
7namespace rx
8{
9
10template <typename T, size_t inputComponentCount, size_t outputComponentCount, uint32_t alphaDefaultValueBits>
11inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
12{
13    const size_t attribSize = sizeof(T)* inputComponentCount;
14
15    if (attribSize == stride && inputComponentCount == outputComponentCount)
16    {
17        memcpy(output, input, count * attribSize);
18        return;
19    }
20
21    if (inputComponentCount == outputComponentCount)
22    {
23        for (size_t i = 0; i < count; i++)
24        {
25            const T *offsetInput = reinterpret_cast<const T*>(input + (i * stride));
26            T *offsetOutput = reinterpret_cast<T*>(output) + i * outputComponentCount;
27
28            memcpy(offsetOutput, offsetInput, attribSize);
29        }
30        return;
31    }
32
33    const T defaultAlphaValue = gl::bitCast<T>(alphaDefaultValueBits);
34    const size_t lastNonAlphaOutputComponent = std::min<size_t>(outputComponentCount, 3);
35
36    for (size_t i = 0; i < count; i++)
37    {
38        const T *offsetInput = reinterpret_cast<const T*>(input + (i * stride));
39        T *offsetOutput = reinterpret_cast<T*>(output) + i * outputComponentCount;
40
41        memcpy(offsetOutput, offsetInput, attribSize);
42
43        if (inputComponentCount < lastNonAlphaOutputComponent)
44        {
45            // Set the remaining G/B channels to 0.
46            size_t numComponents = (lastNonAlphaOutputComponent - inputComponentCount);
47            memset(&offsetOutput[inputComponentCount], 0, numComponents * sizeof(T));
48        }
49
50        if (inputComponentCount < outputComponentCount && outputComponentCount == 4)
51        {
52            // Set the remaining alpha channel to the defaultAlphaValue.
53            offsetOutput[3] = defaultAlphaValue;
54        }
55    }
56}
57
58template <size_t inputComponentCount, size_t outputComponentCount>
59inline void Copy8SintTo16SintVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
60{
61    const size_t lastNonAlphaOutputComponent = std::min<size_t>(outputComponentCount, 3);
62
63    for (size_t i = 0; i < count; i++)
64    {
65        const GLbyte *offsetInput = reinterpret_cast<const GLbyte*>(input + i * stride);
66        GLshort *offsetOutput = reinterpret_cast<GLshort*>(output)+i * outputComponentCount;
67
68        for (size_t j = 0; j < inputComponentCount; j++)
69        {
70            offsetOutput[j] = static_cast<GLshort>(offsetInput[j]);
71        }
72
73        for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++)
74        {
75            // Set remaining G/B channels to 0.
76            offsetOutput[j] = 0;
77        }
78
79        if (inputComponentCount < outputComponentCount && outputComponentCount == 4)
80        {
81            // On integer formats, we must set the Alpha channel to 1 if it's unused.
82            offsetOutput[3] = 1;
83        }
84    }
85}
86
87template <size_t inputComponentCount, size_t outputComponentCount>
88inline void Copy8SnormTo16SnormVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
89{
90    for (size_t i = 0; i < count; i++)
91    {
92        const GLbyte *offsetInput = reinterpret_cast<const GLbyte*>(input + i * stride);
93        GLshort *offsetOutput = reinterpret_cast<GLshort*>(output) + i * outputComponentCount;
94
95        for (size_t j = 0; j < inputComponentCount; j++)
96        {
97            // The original GLbyte value ranges from -128 to +127 (INT8_MAX).
98            // When converted to GLshort, the value must be scaled to between -32768 and +32767 (INT16_MAX).
99            if (offsetInput[j] > 0)
100            {
101                offsetOutput[j] = offsetInput[j] << 8 | offsetInput[j] << 1 | ((offsetInput[j] & 0x40) >> 6);
102            }
103            else
104            {
105                offsetOutput[j] = offsetInput[j] << 8;
106            }
107        }
108
109        for (size_t j = inputComponentCount; j < std::min<size_t>(outputComponentCount, 3); j++)
110        {
111            // Set remaining G/B channels to 0.
112            offsetOutput[j] = 0;
113        }
114
115        if (inputComponentCount < outputComponentCount && outputComponentCount == 4)
116        {
117            // On normalized formats, we must set the Alpha channel to the max value if it's unused.
118            offsetOutput[3] = INT16_MAX;
119        }
120    }
121}
122
123template <size_t inputComponentCount, size_t outputComponentCount>
124inline void Copy32FixedTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
125{
126    static const float divisor = 1.0f / (1 << 16);
127
128    for (size_t i = 0; i < count; i++)
129    {
130        const GLfixed* offsetInput = reinterpret_cast<const GLfixed*>(input + (stride * i));
131        float* offsetOutput = reinterpret_cast<float*>(output) + i * outputComponentCount;
132
133        for (size_t j = 0; j < inputComponentCount; j++)
134        {
135            offsetOutput[j] = static_cast<float>(offsetInput[j]) * divisor;
136        }
137
138        // 4-component output formats would need special padding in the alpha channel.
139        static_assert(!(inputComponentCount < 4 && outputComponentCount == 4),
140                      "An inputComponentCount less than 4 and an outputComponentCount equal to 4 is not supported.");
141
142        for (size_t j = inputComponentCount; j < outputComponentCount; j++)
143        {
144            offsetOutput[j] = 0.0f;
145        }
146    }
147}
148
149template <typename T, size_t inputComponentCount, size_t outputComponentCount, bool normalized>
150inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
151{
152    typedef std::numeric_limits<T> NL;
153
154    for (size_t i = 0; i < count; i++)
155    {
156        const T *offsetInput = reinterpret_cast<const T*>(input + (stride * i));
157        float *offsetOutput = reinterpret_cast<float*>(output) + i * outputComponentCount;
158
159        for (size_t j = 0; j < inputComponentCount; j++)
160        {
161            if (normalized)
162            {
163                if (NL::is_signed)
164                {
165                    const float divisor = 1.0f / (2 * static_cast<float>(NL::max()) + 1);
166                    offsetOutput[j] = (2 * static_cast<float>(offsetInput[j]) + 1) * divisor;
167                }
168                else
169                {
170                    offsetOutput[j] =  static_cast<float>(offsetInput[j]) / NL::max();
171                }
172            }
173            else
174            {
175                offsetOutput[j] =  static_cast<float>(offsetInput[j]);
176            }
177        }
178
179        // This would require special padding.
180        static_assert(!(inputComponentCount < 4 && outputComponentCount == 4),
181                      "An inputComponentCount less than 4 and an outputComponentCount equal to 4 is not supported.");
182
183        for (size_t j = inputComponentCount; j < outputComponentCount; j++)
184        {
185            offsetOutput[j] = 0.0f;
186        }
187    }
188}
189
190namespace priv
191{
192
193template <bool isSigned, bool normalized, bool toFloat>
194static inline void CopyPackedRGB(uint32_t data, uint8_t *output)
195{
196    const uint32_t rgbSignMask = 0x200;       // 1 set at the 9 bit
197    const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1
198
199    if (toFloat)
200    {
201        GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output);
202        if (isSigned)
203        {
204            GLfloat finalValue = 0;
205            if (data & rgbSignMask)
206            {
207                int negativeNumber = data | negativeMask;
208                finalValue = static_cast<GLfloat>(negativeNumber);
209            }
210            else
211            {
212                finalValue = static_cast<GLfloat>(data);
213            }
214
215            if (normalized)
216            {
217                const int32_t maxValue = 0x1FF;      // 1 set in bits 0 through 8
218                const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue
219
220                // A 10-bit two's complement number has the possibility of being minValue - 1 but
221                // OpenGL's normalization rules dictate that it should be clamped to minValue in this
222                // case.
223                if (finalValue < minValue)
224                {
225                    finalValue = minValue;
226                }
227
228                const int32_t halfRange = (maxValue - minValue) >> 1;
229                *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f;
230            }
231            else
232            {
233                *floatOutput = finalValue;
234            }
235        }
236        else
237        {
238            if (normalized)
239            {
240                const uint32_t maxValue = 0x3FF; // 1 set in bits 0 through 9
241                *floatOutput = static_cast<GLfloat>(data) / static_cast<GLfloat>(maxValue);
242            }
243            else
244            {
245                *floatOutput = static_cast<GLfloat>(data);
246            }
247        }
248    }
249    else
250    {
251        if (isSigned)
252        {
253            GLshort *intOutput = reinterpret_cast<GLshort*>(output);
254
255            if (data & rgbSignMask)
256            {
257                *intOutput = static_cast<GLshort>(data | negativeMask);
258            }
259            else
260            {
261                *intOutput = static_cast<GLshort>(data);
262            }
263        }
264        else
265        {
266            GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
267            *uintOutput = static_cast<GLushort>(data);
268        }
269    }
270}
271
272template <bool isSigned, bool normalized, bool toFloat>
273inline void CopyPackedAlpha(uint32_t data, uint8_t *output)
274{
275    if (toFloat)
276    {
277        GLfloat *floatOutput = reinterpret_cast<GLfloat*>(output);
278        if (isSigned)
279        {
280            if (normalized)
281            {
282                switch (data)
283                {
284                  case 0x0: *floatOutput =  0.0f; break;
285                  case 0x1: *floatOutput =  1.0f; break;
286                  case 0x2: *floatOutput = -1.0f; break;
287                  case 0x3: *floatOutput = -1.0f; break;
288                  default: UNREACHABLE();
289                }
290            }
291            else
292            {
293                switch (data)
294                {
295                  case 0x0: *floatOutput =  0.0f; break;
296                  case 0x1: *floatOutput =  1.0f; break;
297                  case 0x2: *floatOutput = -2.0f; break;
298                  case 0x3: *floatOutput = -1.0f; break;
299                  default: UNREACHABLE();
300                }
301            }
302        }
303        else
304        {
305            if (normalized)
306            {
307                switch (data)
308                {
309                  case 0x0: *floatOutput = 0.0f / 3.0f; break;
310                  case 0x1: *floatOutput = 1.0f / 3.0f; break;
311                  case 0x2: *floatOutput = 2.0f / 3.0f; break;
312                  case 0x3: *floatOutput = 3.0f / 3.0f; break;
313                  default: UNREACHABLE();
314                }
315            }
316            else
317            {
318                switch (data)
319                {
320                  case 0x0: *floatOutput = 0.0f; break;
321                  case 0x1: *floatOutput = 1.0f; break;
322                  case 0x2: *floatOutput = 2.0f; break;
323                  case 0x3: *floatOutput = 3.0f; break;
324                  default: UNREACHABLE();
325                }
326            }
327        }
328    }
329    else
330    {
331        if (isSigned)
332        {
333            GLshort *intOutput = reinterpret_cast<GLshort*>(output);
334            switch (data)
335            {
336              case 0x0: *intOutput =  0; break;
337              case 0x1: *intOutput =  1; break;
338              case 0x2: *intOutput = -2; break;
339              case 0x3: *intOutput = -1; break;
340              default: UNREACHABLE();
341            }
342        }
343        else
344        {
345            GLushort *uintOutput = reinterpret_cast<GLushort*>(output);
346            switch (data)
347            {
348              case 0x0: *uintOutput = 0; break;
349              case 0x1: *uintOutput = 1; break;
350              case 0x2: *uintOutput = 2; break;
351              case 0x3: *uintOutput = 3; break;
352              default: UNREACHABLE();
353            }
354        }
355    }
356}
357
358}
359
360template <bool isSigned, bool normalized, bool toFloat>
361inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
362{
363    const size_t outputComponentSize = toFloat ? 4 : 2;
364    const size_t componentCount = 4;
365
366    const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9
367    const size_t redShift = 0;    // red is bits 0 through 9
368    const size_t greenShift = 10; // green is bits 10 through 19
369    const size_t blueShift = 20;  // blue is bits 20 through 29
370
371    const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1
372    const size_t alphaShift = 30; // Alpha is the 30 and 31 bits
373
374    for (size_t i = 0; i < count; i++)
375    {
376        GLuint packedValue = *reinterpret_cast<const GLuint*>(input + (i * stride));
377        uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
378
379        priv::CopyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> redShift)   & rgbMask,   offsetOutput + (0 * outputComponentSize));
380        priv::CopyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> greenShift) & rgbMask,   offsetOutput + (1 * outputComponentSize));
381        priv::CopyPackedRGB<isSigned, normalized, toFloat>(  (packedValue >> blueShift)  & rgbMask,   offsetOutput + (2 * outputComponentSize));
382        priv::CopyPackedAlpha<isSigned, normalized, toFloat>((packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize));
383    }
384}
385
386}
387