• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 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.inc.h: Implementation of vertex buffer copying and conversion functions
8 
9 namespace rx
10 {
11 
12 template <typename T,
13           size_t inputComponentCount,
14           size_t outputComponentCount,
15           uint32_t alphaDefaultValueBits>
CopyNativeVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)16 inline void CopyNativeVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
17 {
18     const size_t attribSize = sizeof(T) * inputComponentCount;
19 
20     if (attribSize == stride && inputComponentCount == outputComponentCount)
21     {
22         memcpy(output, input, count * attribSize);
23         return;
24     }
25 
26     if (inputComponentCount == outputComponentCount)
27     {
28         for (size_t i = 0; i < count; i++)
29         {
30             const T *offsetInput = reinterpret_cast<const T *>(input + (i * stride));
31             T *offsetOutput      = reinterpret_cast<T *>(output) + i * outputComponentCount;
32 
33             memcpy(offsetOutput, offsetInput, attribSize);
34         }
35         return;
36     }
37 
38     const T defaultAlphaValue                = gl::bitCast<T>(alphaDefaultValueBits);
39     const size_t lastNonAlphaOutputComponent = std::min<size_t>(outputComponentCount, 3);
40 
41     for (size_t i = 0; i < count; i++)
42     {
43         const T *offsetInput = reinterpret_cast<const T *>(input + (i * stride));
44         T *offsetOutput      = reinterpret_cast<T *>(output) + i * outputComponentCount;
45 
46         memcpy(offsetOutput, offsetInput, attribSize);
47 
48         if (inputComponentCount < lastNonAlphaOutputComponent)
49         {
50             // Set the remaining G/B channels to 0.
51             size_t numComponents = (lastNonAlphaOutputComponent - inputComponentCount);
52             memset(&offsetOutput[inputComponentCount], 0, numComponents * sizeof(T));
53         }
54 
55         if (inputComponentCount < outputComponentCount && outputComponentCount == 4)
56         {
57             // Set the remaining alpha channel to the defaultAlphaValue.
58             offsetOutput[3] = defaultAlphaValue;
59         }
60     }
61 }
62 
63 template <size_t inputComponentCount, size_t outputComponentCount>
Copy8SintTo16SintVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)64 inline void Copy8SintTo16SintVertexData(const uint8_t *input,
65                                         size_t stride,
66                                         size_t count,
67                                         uint8_t *output)
68 {
69     const size_t lastNonAlphaOutputComponent = std::min<size_t>(outputComponentCount, 3);
70 
71     for (size_t i = 0; i < count; i++)
72     {
73         const GLbyte *offsetInput = reinterpret_cast<const GLbyte *>(input + i * stride);
74         GLshort *offsetOutput     = reinterpret_cast<GLshort *>(output) + i * outputComponentCount;
75 
76         for (size_t j = 0; j < inputComponentCount; j++)
77         {
78             offsetOutput[j] = static_cast<GLshort>(offsetInput[j]);
79         }
80 
81         for (size_t j = inputComponentCount; j < lastNonAlphaOutputComponent; j++)
82         {
83             // Set remaining G/B channels to 0.
84             offsetOutput[j] = 0;
85         }
86 
87         if (inputComponentCount < outputComponentCount && outputComponentCount == 4)
88         {
89             // On integer formats, we must set the Alpha channel to 1 if it's unused.
90             offsetOutput[3] = 1;
91         }
92     }
93 }
94 
95 template <size_t inputComponentCount, size_t outputComponentCount>
Copy8SnormTo16SnormVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)96 inline void Copy8SnormTo16SnormVertexData(const uint8_t *input,
97                                           size_t stride,
98                                           size_t count,
99                                           uint8_t *output)
100 {
101     for (size_t i = 0; i < count; i++)
102     {
103         const GLbyte *offsetInput = reinterpret_cast<const GLbyte *>(input + i * stride);
104         GLshort *offsetOutput     = reinterpret_cast<GLshort *>(output) + i * outputComponentCount;
105 
106         for (size_t j = 0; j < inputComponentCount; j++)
107         {
108             // The original GLbyte value ranges from -128 to +127 (INT8_MAX).
109             // When converted to GLshort, the value must be scaled to between -32768 and +32767
110             // (INT16_MAX).
111             if (offsetInput[j] > 0)
112             {
113                 offsetOutput[j] =
114                     offsetInput[j] << 8 | offsetInput[j] << 1 | ((offsetInput[j] & 0x40) >> 6);
115             }
116             else
117             {
118                 offsetOutput[j] = offsetInput[j] << 8;
119             }
120         }
121 
122         for (size_t j = inputComponentCount; j < std::min<size_t>(outputComponentCount, 3); j++)
123         {
124             // Set remaining G/B channels to 0.
125             offsetOutput[j] = 0;
126         }
127 
128         if (inputComponentCount < outputComponentCount && outputComponentCount == 4)
129         {
130             // On normalized formats, we must set the Alpha channel to the max value if it's unused.
131             offsetOutput[3] = INT16_MAX;
132         }
133     }
134 }
135 
136 template <size_t inputComponentCount, size_t outputComponentCount>
Copy32FixedTo32FVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)137 inline void Copy32FixedTo32FVertexData(const uint8_t *input,
138                                        size_t stride,
139                                        size_t count,
140                                        uint8_t *output)
141 {
142     static const float divisor = 1.0f / (1 << 16);
143 
144     for (size_t i = 0; i < count; i++)
145     {
146         const uint8_t *offsetInput = input + i * stride;
147         float *offsetOutput        = reinterpret_cast<float *>(output) + i * outputComponentCount;
148 
149         // GLfixed access must be 4-byte aligned on arm32, input and stride sometimes are not
150         if (reinterpret_cast<uintptr_t>(offsetInput) % sizeof(GLfixed) == 0)
151         {
152             for (size_t j = 0; j < inputComponentCount; j++)
153             {
154                 offsetOutput[j] =
155                     static_cast<float>(reinterpret_cast<const GLfixed *>(offsetInput)[j]) * divisor;
156             }
157         }
158         else
159         {
160             for (size_t j = 0; j < inputComponentCount; j++)
161             {
162                 GLfixed alignedInput;
163                 memcpy(&alignedInput, offsetInput + j * sizeof(GLfixed), sizeof(GLfixed));
164                 offsetOutput[j] = static_cast<float>(alignedInput) * divisor;
165             }
166         }
167 
168         // 4-component output formats would need special padding in the alpha channel.
169         static_assert(!(inputComponentCount < 4 && outputComponentCount == 4),
170                       "An inputComponentCount less than 4 and an outputComponentCount equal to 4 "
171                       "is not supported.");
172 
173         for (size_t j = inputComponentCount; j < outputComponentCount; j++)
174         {
175             offsetOutput[j] = 0.0f;
176         }
177     }
178 }
179 
180 template <typename T,
181           size_t inputComponentCount,
182           size_t outputComponentCount,
183           bool normalized,
184           bool toHalf>
CopyToFloatVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)185 inline void CopyToFloatVertexData(const uint8_t *input,
186                                   size_t stride,
187                                   size_t count,
188                                   uint8_t *output)
189 {
190     typedef std::numeric_limits<T> NL;
191     typedef typename std::conditional<toHalf, GLhalf, float>::type outputType;
192 
193     for (size_t i = 0; i < count; i++)
194     {
195         const T *offsetInput = reinterpret_cast<const T *>(input + (stride * i));
196         outputType *offsetOutput =
197             reinterpret_cast<outputType *>(output) + i * outputComponentCount;
198 
199         for (size_t j = 0; j < inputComponentCount; j++)
200         {
201             float result = 0;
202 
203             if (normalized)
204             {
205                 if (NL::is_signed)
206                 {
207                     result = static_cast<float>(offsetInput[j]) / static_cast<float>(NL::max());
208                     result = result >= -1.0f ? result : -1.0f;
209                 }
210                 else
211                 {
212                     result = static_cast<float>(offsetInput[j]) / static_cast<float>(NL::max());
213                 }
214             }
215             else
216             {
217                 result = static_cast<float>(offsetInput[j]);
218             }
219 
220             if (toHalf)
221             {
222                 offsetOutput[j] = gl::float32ToFloat16(result);
223             }
224             else
225             {
226                 offsetOutput[j] = static_cast<outputType>(result);
227             }
228         }
229 
230         for (size_t j = inputComponentCount; j < outputComponentCount; j++)
231         {
232             offsetOutput[j] = 0;
233         }
234 
235         if (inputComponentCount < 4 && outputComponentCount == 4)
236         {
237             if (toHalf)
238             {
239                 offsetOutput[3] = gl::Float16One;
240             }
241             else
242             {
243                 offsetOutput[3] = static_cast<outputType>(gl::Float32One);
244             }
245         }
246     }
247 }
248 
249 template <size_t inputComponentCount, size_t outputComponentCount>
Copy32FTo16FVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)250 void Copy32FTo16FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
251 {
252     const unsigned short kZero = gl::float32ToFloat16(0.0f);
253     const unsigned short kOne  = gl::float32ToFloat16(1.0f);
254 
255     for (size_t i = 0; i < count; i++)
256     {
257         const float *offsetInput = reinterpret_cast<const float *>(input + (stride * i));
258         unsigned short *offsetOutput =
259             reinterpret_cast<unsigned short *>(output) + i * outputComponentCount;
260 
261         for (size_t j = 0; j < inputComponentCount; j++)
262         {
263             offsetOutput[j] = gl::float32ToFloat16(offsetInput[j]);
264         }
265 
266         for (size_t j = inputComponentCount; j < outputComponentCount; j++)
267         {
268             offsetOutput[j] = (j == 3) ? kOne : kZero;
269         }
270     }
271 }
272 
CopyXYZ32FToXYZ9E5(const uint8_t * input,size_t stride,size_t count,uint8_t * output)273 inline void CopyXYZ32FToXYZ9E5(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
274 {
275     for (size_t i = 0; i < count; i++)
276     {
277         const float *offsetInput   = reinterpret_cast<const float *>(input + (stride * i));
278         unsigned int *offsetOutput = reinterpret_cast<unsigned int *>(output) + i;
279 
280         *offsetOutput = gl::convertRGBFloatsTo999E5(offsetInput[0], offsetInput[1], offsetInput[2]);
281     }
282 }
283 
CopyXYZ32FToX11Y11B10F(const uint8_t * input,size_t stride,size_t count,uint8_t * output)284 inline void CopyXYZ32FToX11Y11B10F(const uint8_t *input,
285                                    size_t stride,
286                                    size_t count,
287                                    uint8_t *output)
288 {
289     for (size_t i = 0; i < count; i++)
290     {
291         const float *offsetInput   = reinterpret_cast<const float *>(input + (stride * i));
292         unsigned int *offsetOutput = reinterpret_cast<unsigned int *>(output) + i;
293 
294         *offsetOutput = gl::float32ToFloat11(offsetInput[0]) << 0 |
295                         gl::float32ToFloat11(offsetInput[1]) << 11 |
296                         gl::float32ToFloat10(offsetInput[2]) << 22;
297     }
298 }
299 
300 namespace priv
301 {
302 
303 template <bool isSigned, bool normalized, bool toFloat, bool toHalf>
CopyPackedRGB(uint32_t data,uint8_t * output)304 static inline void CopyPackedRGB(uint32_t data, uint8_t *output)
305 {
306     const uint32_t rgbSignMask  = 0x200;       // 1 set at the 9 bit
307     const uint32_t negativeMask = 0xFFFFFC00;  // All bits from 10 to 31 set to 1
308 
309     if (toFloat || toHalf)
310     {
311         GLfloat finalValue = static_cast<GLfloat>(data);
312         if (isSigned)
313         {
314             if (data & rgbSignMask)
315             {
316                 int negativeNumber = data | negativeMask;
317                 finalValue         = static_cast<GLfloat>(negativeNumber);
318             }
319 
320             if (normalized)
321             {
322                 const int32_t maxValue = 0x1FF;       // 1 set in bits 0 through 8
323                 const int32_t minValue = 0xFFFFFE01;  // Inverse of maxValue
324 
325                 // A 10-bit two's complement number has the possibility of being minValue - 1 but
326                 // OpenGL's normalization rules dictate that it should be clamped to minValue in
327                 // this case.
328                 if (finalValue < minValue)
329                 {
330                     finalValue = minValue;
331                 }
332 
333                 const int32_t halfRange = (maxValue - minValue) >> 1;
334                 finalValue              = ((finalValue - minValue) / halfRange) - 1.0f;
335             }
336         }
337         else
338         {
339             if (normalized)
340             {
341                 const uint32_t maxValue = 0x3FF;  // 1 set in bits 0 through 9
342                 finalValue /= static_cast<GLfloat>(maxValue);
343             }
344         }
345 
346         if (toHalf)
347         {
348             *reinterpret_cast<GLhalf *>(output) = gl::float32ToFloat16(finalValue);
349         }
350         else
351         {
352             *reinterpret_cast<GLfloat *>(output) = finalValue;
353         }
354     }
355     else
356     {
357         if (isSigned)
358         {
359             GLshort *intOutput = reinterpret_cast<GLshort *>(output);
360 
361             if (data & rgbSignMask)
362             {
363                 *intOutput = static_cast<GLshort>(data | negativeMask);
364             }
365             else
366             {
367                 *intOutput = static_cast<GLshort>(data);
368             }
369         }
370         else
371         {
372             GLushort *uintOutput = reinterpret_cast<GLushort *>(output);
373             *uintOutput          = static_cast<GLushort>(data);
374         }
375     }
376 }
377 
378 template <bool isSigned, bool normalized, bool toFloat, bool toHalf>
CopyPackedAlpha(uint32_t data,uint8_t * output)379 inline void CopyPackedAlpha(uint32_t data, uint8_t *output)
380 {
381     ASSERT(data >= 0 && data <= 3);
382 
383     if (toFloat || toHalf)
384     {
385         GLfloat finalValue = 0;
386         if (isSigned)
387         {
388             if (normalized)
389             {
390                 switch (data)
391                 {
392                     case 0x0:
393                         finalValue = 0.0f;
394                         break;
395                     case 0x1:
396                         finalValue = 1.0f;
397                         break;
398                     case 0x2:
399                         finalValue = -1.0f;
400                         break;
401                     case 0x3:
402                         finalValue = -1.0f;
403                         break;
404                     default:
405                         UNREACHABLE();
406                 }
407             }
408             else
409             {
410                 switch (data)
411                 {
412                     case 0x0:
413                         finalValue = 0.0f;
414                         break;
415                     case 0x1:
416                         finalValue = 1.0f;
417                         break;
418                     case 0x2:
419                         finalValue = -2.0f;
420                         break;
421                     case 0x3:
422                         finalValue = -1.0f;
423                         break;
424                     default:
425                         UNREACHABLE();
426                 }
427             }
428         }
429         else
430         {
431             if (normalized)
432             {
433                 finalValue = data / 3.0f;
434             }
435             else
436             {
437                 finalValue = static_cast<float>(data);
438             }
439         }
440 
441         if (toHalf)
442         {
443             *reinterpret_cast<GLhalf *>(output) = gl::float32ToFloat16(finalValue);
444         }
445         else
446         {
447             *reinterpret_cast<GLfloat *>(output) = finalValue;
448         }
449     }
450     else
451     {
452         if (isSigned)
453         {
454             GLshort *intOutput = reinterpret_cast<GLshort *>(output);
455             switch (data)
456             {
457                 case 0x0:
458                     *intOutput = 0;
459                     break;
460                 case 0x1:
461                     *intOutput = 1;
462                     break;
463                 case 0x2:
464                     *intOutput = -2;
465                     break;
466                 case 0x3:
467                     *intOutput = -1;
468                     break;
469                 default:
470                     UNREACHABLE();
471             }
472         }
473         else
474         {
475             *reinterpret_cast<GLushort *>(output) = static_cast<GLushort>(data);
476         }
477     }
478 }
479 
480 }  // namespace priv
481 
482 template <bool isSigned, bool normalized, bool toFloat, bool toHalf>
CopyXYZ10W2ToXYZWFloatVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)483 inline void CopyXYZ10W2ToXYZWFloatVertexData(const uint8_t *input,
484                                              size_t stride,
485                                              size_t count,
486                                              uint8_t *output)
487 {
488     const size_t outputComponentSize = toFloat && !toHalf ? 4 : 2;
489     const size_t componentCount      = 4;
490 
491     const uint32_t rgbMask  = 0x3FF;  // 1 set in bits 0 through 9
492     const size_t redShift   = 0;      // red is bits 0 through 9
493     const size_t greenShift = 10;     // green is bits 10 through 19
494     const size_t blueShift  = 20;     // blue is bits 20 through 29
495 
496     const uint32_t alphaMask = 0x3;  // 1 set in bits 0 and 1
497     const size_t alphaShift  = 30;   // Alpha is the 30 and 31 bits
498 
499     for (size_t i = 0; i < count; i++)
500     {
501         GLuint packedValue    = *reinterpret_cast<const GLuint *>(input + (i * stride));
502         uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
503 
504         priv::CopyPackedRGB<isSigned, normalized, toFloat, toHalf>(
505             (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize));
506         priv::CopyPackedRGB<isSigned, normalized, toFloat, toHalf>(
507             (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize));
508         priv::CopyPackedRGB<isSigned, normalized, toFloat, toHalf>(
509             (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize));
510         priv::CopyPackedAlpha<isSigned, normalized, toFloat, toHalf>(
511             (packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize));
512     }
513 }
514 
515 template <bool isSigned, bool normalized, bool toHalf>
CopyXYZ10ToXYZWFloatVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)516 inline void CopyXYZ10ToXYZWFloatVertexData(const uint8_t *input,
517                                            size_t stride,
518                                            size_t count,
519                                            uint8_t *output)
520 {
521     const size_t outputComponentSize = toHalf ? 2 : 4;
522     const size_t componentCount      = 4;
523 
524     const uint32_t rgbMask  = 0x3FF;  // 1 set in bits 0 through 9
525     const size_t redShift   = 22;     // red is bits 22 through 31
526     const size_t greenShift = 12;     // green is bits 12 through 21
527     const size_t blueShift  = 2;      // blue is bits 2 through 11
528 
529     const uint32_t alphaDefaultValueBits = normalized ? (isSigned ? 0x1 : 0x3) : 0x1;
530 
531     for (size_t i = 0; i < count; i++)
532     {
533         GLuint packedValue    = *reinterpret_cast<const GLuint *>(input + (i * stride));
534         uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
535 
536         priv::CopyPackedRGB<isSigned, normalized, true, toHalf>(
537             (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize));
538         priv::CopyPackedRGB<isSigned, normalized, true, toHalf>(
539             (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize));
540         priv::CopyPackedRGB<isSigned, normalized, true, toHalf>(
541             (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize));
542         priv::CopyPackedAlpha<isSigned, normalized, true, toHalf>(
543             alphaDefaultValueBits, offsetOutput + (3 * outputComponentSize));
544     }
545 }
546 
547 template <bool isSigned, bool normalized, bool toHalf>
CopyW2XYZ10ToXYZWFloatVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)548 inline void CopyW2XYZ10ToXYZWFloatVertexData(const uint8_t *input,
549                                              size_t stride,
550                                              size_t count,
551                                              uint8_t *output)
552 {
553     const size_t outputComponentSize = toHalf ? 2 : 4;
554     const size_t componentCount      = 4;
555 
556     const uint32_t rgbMask  = 0x3FF;  // 1 set in bits 0 through 9
557     const size_t redShift   = 22;     // red is bits 22 through 31
558     const size_t greenShift = 12;     // green is bits 12 through 21
559     const size_t blueShift  = 2;      // blue is bits 2 through 11
560 
561     const uint32_t alphaMask = 0x3;  // 1 set in bits 0 and 1
562     const size_t alphaShift  = 0;    // Alpha is the 30 and 31 bits
563 
564     for (size_t i = 0; i < count; i++)
565     {
566         GLuint packedValue    = *reinterpret_cast<const GLuint *>(input + (i * stride));
567         uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
568 
569         priv::CopyPackedRGB<isSigned, normalized, true, toHalf>(
570             (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize));
571         priv::CopyPackedRGB<isSigned, normalized, true, toHalf>(
572             (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize));
573         priv::CopyPackedRGB<isSigned, normalized, true, toHalf>(
574             (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize));
575         priv::CopyPackedAlpha<isSigned, normalized, true, toHalf>(
576             (packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize));
577     }
578 }
579 }  // namespace rx
580