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, size_t inputComponentCount, size_t outputComponentCount, bool normalized>
CopyTo32FVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)181 inline void CopyTo32FVertexData(const uint8_t *input, size_t stride, size_t count, uint8_t *output)
182 {
183 typedef std::numeric_limits<T> NL;
184
185 for (size_t i = 0; i < count; i++)
186 {
187 const T *offsetInput = reinterpret_cast<const T *>(input + (stride * i));
188 float *offsetOutput = reinterpret_cast<float *>(output) + i * outputComponentCount;
189
190 for (size_t j = 0; j < inputComponentCount; j++)
191 {
192 if (normalized)
193 {
194 if (NL::is_signed)
195 {
196 offsetOutput[j] = static_cast<float>(offsetInput[j]) / NL::max();
197 offsetOutput[j] = (offsetOutput[j] >= -1.0f) ? (offsetOutput[j]) : (-1.0f);
198 }
199 else
200 {
201 offsetOutput[j] = static_cast<float>(offsetInput[j]) / NL::max();
202 }
203 }
204 else
205 {
206 offsetOutput[j] = static_cast<float>(offsetInput[j]);
207 }
208 }
209
210 // This would require special padding.
211 static_assert(!(inputComponentCount < 4 && outputComponentCount == 4),
212 "An inputComponentCount less than 4 and an outputComponentCount equal to 4 "
213 "is not supported.");
214
215 for (size_t j = inputComponentCount; j < outputComponentCount; j++)
216 {
217 offsetOutput[j] = 0.0f;
218 }
219 }
220 }
221
222 namespace priv
223 {
224
225 template <bool isSigned, bool normalized, bool toFloat>
CopyPackedRGB(uint32_t data,uint8_t * output)226 static inline void CopyPackedRGB(uint32_t data, uint8_t *output)
227 {
228 const uint32_t rgbSignMask = 0x200; // 1 set at the 9 bit
229 const uint32_t negativeMask = 0xFFFFFC00; // All bits from 10 to 31 set to 1
230
231 if (toFloat)
232 {
233 GLfloat *floatOutput = reinterpret_cast<GLfloat *>(output);
234 if (isSigned)
235 {
236 GLfloat finalValue = 0;
237 if (data & rgbSignMask)
238 {
239 int negativeNumber = data | negativeMask;
240 finalValue = static_cast<GLfloat>(negativeNumber);
241 }
242 else
243 {
244 finalValue = static_cast<GLfloat>(data);
245 }
246
247 if (normalized)
248 {
249 const int32_t maxValue = 0x1FF; // 1 set in bits 0 through 8
250 const int32_t minValue = 0xFFFFFE01; // Inverse of maxValue
251
252 // A 10-bit two's complement number has the possibility of being minValue - 1 but
253 // OpenGL's normalization rules dictate that it should be clamped to minValue in
254 // this case.
255 if (finalValue < minValue)
256 {
257 finalValue = minValue;
258 }
259
260 const int32_t halfRange = (maxValue - minValue) >> 1;
261 *floatOutput = ((finalValue - minValue) / halfRange) - 1.0f;
262 }
263 else
264 {
265 *floatOutput = finalValue;
266 }
267 }
268 else
269 {
270 if (normalized)
271 {
272 const uint32_t maxValue = 0x3FF; // 1 set in bits 0 through 9
273 *floatOutput = static_cast<GLfloat>(data) / static_cast<GLfloat>(maxValue);
274 }
275 else
276 {
277 *floatOutput = static_cast<GLfloat>(data);
278 }
279 }
280 }
281 else
282 {
283 if (isSigned)
284 {
285 GLshort *intOutput = reinterpret_cast<GLshort *>(output);
286
287 if (data & rgbSignMask)
288 {
289 *intOutput = static_cast<GLshort>(data | negativeMask);
290 }
291 else
292 {
293 *intOutput = static_cast<GLshort>(data);
294 }
295 }
296 else
297 {
298 GLushort *uintOutput = reinterpret_cast<GLushort *>(output);
299 *uintOutput = static_cast<GLushort>(data);
300 }
301 }
302 }
303
304 template <bool isSigned, bool normalized, bool toFloat>
CopyPackedAlpha(uint32_t data,uint8_t * output)305 inline void CopyPackedAlpha(uint32_t data, uint8_t *output)
306 {
307 if (toFloat)
308 {
309 GLfloat *floatOutput = reinterpret_cast<GLfloat *>(output);
310 if (isSigned)
311 {
312 if (normalized)
313 {
314 switch (data)
315 {
316 case 0x0:
317 *floatOutput = 0.0f;
318 break;
319 case 0x1:
320 *floatOutput = 1.0f;
321 break;
322 case 0x2:
323 *floatOutput = -1.0f;
324 break;
325 case 0x3:
326 *floatOutput = -1.0f;
327 break;
328 default:
329 UNREACHABLE();
330 }
331 }
332 else
333 {
334 switch (data)
335 {
336 case 0x0:
337 *floatOutput = 0.0f;
338 break;
339 case 0x1:
340 *floatOutput = 1.0f;
341 break;
342 case 0x2:
343 *floatOutput = -2.0f;
344 break;
345 case 0x3:
346 *floatOutput = -1.0f;
347 break;
348 default:
349 UNREACHABLE();
350 }
351 }
352 }
353 else
354 {
355 if (normalized)
356 {
357 switch (data)
358 {
359 case 0x0:
360 *floatOutput = 0.0f / 3.0f;
361 break;
362 case 0x1:
363 *floatOutput = 1.0f / 3.0f;
364 break;
365 case 0x2:
366 *floatOutput = 2.0f / 3.0f;
367 break;
368 case 0x3:
369 *floatOutput = 3.0f / 3.0f;
370 break;
371 default:
372 UNREACHABLE();
373 }
374 }
375 else
376 {
377 switch (data)
378 {
379 case 0x0:
380 *floatOutput = 0.0f;
381 break;
382 case 0x1:
383 *floatOutput = 1.0f;
384 break;
385 case 0x2:
386 *floatOutput = 2.0f;
387 break;
388 case 0x3:
389 *floatOutput = 3.0f;
390 break;
391 default:
392 UNREACHABLE();
393 }
394 }
395 }
396 }
397 else
398 {
399 if (isSigned)
400 {
401 GLshort *intOutput = reinterpret_cast<GLshort *>(output);
402 switch (data)
403 {
404 case 0x0:
405 *intOutput = 0;
406 break;
407 case 0x1:
408 *intOutput = 1;
409 break;
410 case 0x2:
411 *intOutput = -2;
412 break;
413 case 0x3:
414 *intOutput = -1;
415 break;
416 default:
417 UNREACHABLE();
418 }
419 }
420 else
421 {
422 GLushort *uintOutput = reinterpret_cast<GLushort *>(output);
423 switch (data)
424 {
425 case 0x0:
426 *uintOutput = 0;
427 break;
428 case 0x1:
429 *uintOutput = 1;
430 break;
431 case 0x2:
432 *uintOutput = 2;
433 break;
434 case 0x3:
435 *uintOutput = 3;
436 break;
437 default:
438 UNREACHABLE();
439 }
440 }
441 }
442 }
443
444 } // namespace priv
445
446 template <bool isSigned, bool normalized, bool toFloat>
CopyXYZ10W2ToXYZW32FVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)447 inline void CopyXYZ10W2ToXYZW32FVertexData(const uint8_t *input,
448 size_t stride,
449 size_t count,
450 uint8_t *output)
451 {
452 const size_t outputComponentSize = toFloat ? 4 : 2;
453 const size_t componentCount = 4;
454
455 const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9
456 const size_t redShift = 0; // red is bits 0 through 9
457 const size_t greenShift = 10; // green is bits 10 through 19
458 const size_t blueShift = 20; // blue is bits 20 through 29
459
460 const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1
461 const size_t alphaShift = 30; // Alpha is the 30 and 31 bits
462
463 for (size_t i = 0; i < count; i++)
464 {
465 GLuint packedValue = *reinterpret_cast<const GLuint *>(input + (i * stride));
466 uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
467
468 priv::CopyPackedRGB<isSigned, normalized, toFloat>(
469 (packedValue >> redShift) & rgbMask, offsetOutput + (0 * outputComponentSize));
470 priv::CopyPackedRGB<isSigned, normalized, toFloat>(
471 (packedValue >> greenShift) & rgbMask, offsetOutput + (1 * outputComponentSize));
472 priv::CopyPackedRGB<isSigned, normalized, toFloat>(
473 (packedValue >> blueShift) & rgbMask, offsetOutput + (2 * outputComponentSize));
474 priv::CopyPackedAlpha<isSigned, normalized, toFloat>(
475 (packedValue >> alphaShift) & alphaMask, offsetOutput + (3 * outputComponentSize));
476 }
477 }
478
479 template <bool isSigned, bool normalized>
CopyXYZ10ToXYZW32FVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)480 inline void CopyXYZ10ToXYZW32FVertexData(const uint8_t *input,
481 size_t stride,
482 size_t count,
483 uint8_t *output)
484 {
485 const size_t outputComponentSize = 4;
486 const size_t componentCount = 4;
487
488 const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9
489 const size_t redShift = 22; // red is bits 22 through 31
490 const size_t greenShift = 12; // green is bits 12 through 21
491 const size_t blueShift = 2; // blue is bits 2 through 11
492
493 const uint32_t alphaDefaultValueBits = normalized ? (isSigned ? 0x1 : 0x3) : 0x1;
494
495 for (size_t i = 0; i < count; i++)
496 {
497 GLuint packedValue = *reinterpret_cast<const GLuint *>(input + (i * stride));
498 uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
499
500 priv::CopyPackedRGB<isSigned, normalized, true>((packedValue >> redShift) & rgbMask,
501 offsetOutput + (0 * outputComponentSize));
502 priv::CopyPackedRGB<isSigned, normalized, true>((packedValue >> greenShift) & rgbMask,
503 offsetOutput + (1 * outputComponentSize));
504 priv::CopyPackedRGB<isSigned, normalized, true>((packedValue >> blueShift) & rgbMask,
505 offsetOutput + (2 * outputComponentSize));
506 priv::CopyPackedAlpha<isSigned, normalized, true>(alphaDefaultValueBits,
507 offsetOutput + (3 * outputComponentSize));
508 }
509 }
510
511 template <bool isSigned, bool normalized>
CopyW2XYZ10ToXYZW32FVertexData(const uint8_t * input,size_t stride,size_t count,uint8_t * output)512 inline void CopyW2XYZ10ToXYZW32FVertexData(const uint8_t *input,
513 size_t stride,
514 size_t count,
515 uint8_t *output)
516 {
517 const size_t outputComponentSize = 4;
518 const size_t componentCount = 4;
519
520 const uint32_t rgbMask = 0x3FF; // 1 set in bits 0 through 9
521 const size_t redShift = 22; // red is bits 22 through 31
522 const size_t greenShift = 12; // green is bits 12 through 21
523 const size_t blueShift = 2; // blue is bits 2 through 11
524
525 const uint32_t alphaMask = 0x3; // 1 set in bits 0 and 1
526 const size_t alphaShift = 0; // Alpha is the 30 and 31 bits
527
528 for (size_t i = 0; i < count; i++)
529 {
530 GLuint packedValue = *reinterpret_cast<const GLuint *>(input + (i * stride));
531 uint8_t *offsetOutput = output + (i * outputComponentSize * componentCount);
532
533 priv::CopyPackedRGB<isSigned, normalized, true>((packedValue >> redShift) & rgbMask,
534 offsetOutput + (0 * outputComponentSize));
535 priv::CopyPackedRGB<isSigned, normalized, true>((packedValue >> greenShift) & rgbMask,
536 offsetOutput + (1 * outputComponentSize));
537 priv::CopyPackedRGB<isSigned, normalized, true>((packedValue >> blueShift) & rgbMask,
538 offsetOutput + (2 * outputComponentSize));
539 priv::CopyPackedAlpha<isSigned, normalized, true>((packedValue >> alphaShift) & alphaMask,
540 offsetOutput + (3 * outputComponentSize));
541 }
542 }
543 } // namespace rx
544