1 //
2 // Copyright 2002 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 // utilities.cpp: Conversion functions and other utility routines.
8
9 #include "common/utilities.h"
10 #include <GLSLANG/ShaderVars.h>
11 #include "GLES3/gl3.h"
12 #include "common/mathutil.h"
13 #include "common/platform.h"
14
15 #include <set>
16
17 #if defined(ANGLE_ENABLE_WINDOWS_UWP)
18 # include <windows.applicationmodel.core.h>
19 # include <windows.graphics.display.h>
20 # include <wrl.h>
21 # include <wrl/wrappers/corewrappers.h>
22 #endif
23
24 namespace
25 {
26
27 template <class IndexType>
ComputeTypedIndexRange(const IndexType * indices,size_t count,bool primitiveRestartEnabled,GLuint primitiveRestartIndex)28 gl::IndexRange ComputeTypedIndexRange(const IndexType *indices,
29 size_t count,
30 bool primitiveRestartEnabled,
31 GLuint primitiveRestartIndex)
32 {
33 ASSERT(count > 0);
34
35 IndexType minIndex = 0;
36 IndexType maxIndex = 0;
37 size_t nonPrimitiveRestartIndices = 0;
38
39 if (primitiveRestartEnabled)
40 {
41 // Find the first non-primitive restart index to initialize the min and max values
42 size_t i = 0;
43 for (; i < count; i++)
44 {
45 if (indices[i] != primitiveRestartIndex)
46 {
47 minIndex = indices[i];
48 maxIndex = indices[i];
49 nonPrimitiveRestartIndices++;
50 break;
51 }
52 }
53
54 // Loop over the rest of the indices
55 for (; i < count; i++)
56 {
57 if (indices[i] != primitiveRestartIndex)
58 {
59 if (minIndex > indices[i])
60 {
61 minIndex = indices[i];
62 }
63 if (maxIndex < indices[i])
64 {
65 maxIndex = indices[i];
66 }
67 nonPrimitiveRestartIndices++;
68 }
69 }
70 }
71 else
72 {
73 minIndex = indices[0];
74 maxIndex = indices[0];
75 nonPrimitiveRestartIndices = count;
76
77 for (size_t i = 1; i < count; i++)
78 {
79 if (minIndex > indices[i])
80 {
81 minIndex = indices[i];
82 }
83 if (maxIndex < indices[i])
84 {
85 maxIndex = indices[i];
86 }
87 }
88 }
89
90 return gl::IndexRange(static_cast<size_t>(minIndex), static_cast<size_t>(maxIndex),
91 nonPrimitiveRestartIndices);
92 }
93
94 } // anonymous namespace
95
96 namespace gl
97 {
98
VariableComponentCount(GLenum type)99 int VariableComponentCount(GLenum type)
100 {
101 return VariableRowCount(type) * VariableColumnCount(type);
102 }
103
VariableComponentType(GLenum type)104 GLenum VariableComponentType(GLenum type)
105 {
106 switch (type)
107 {
108 case GL_BOOL:
109 case GL_BOOL_VEC2:
110 case GL_BOOL_VEC3:
111 case GL_BOOL_VEC4:
112 return GL_BOOL;
113 case GL_FLOAT:
114 case GL_FLOAT_VEC2:
115 case GL_FLOAT_VEC3:
116 case GL_FLOAT_VEC4:
117 case GL_FLOAT_MAT2:
118 case GL_FLOAT_MAT3:
119 case GL_FLOAT_MAT4:
120 case GL_FLOAT_MAT2x3:
121 case GL_FLOAT_MAT3x2:
122 case GL_FLOAT_MAT2x4:
123 case GL_FLOAT_MAT4x2:
124 case GL_FLOAT_MAT3x4:
125 case GL_FLOAT_MAT4x3:
126 return GL_FLOAT;
127 case GL_INT:
128 case GL_SAMPLER_2D:
129 case GL_SAMPLER_2D_RECT_ANGLE:
130 case GL_SAMPLER_3D:
131 case GL_SAMPLER_CUBE:
132 case GL_SAMPLER_2D_ARRAY:
133 case GL_SAMPLER_EXTERNAL_OES:
134 case GL_SAMPLER_2D_MULTISAMPLE:
135 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
136 case GL_INT_SAMPLER_2D:
137 case GL_INT_SAMPLER_3D:
138 case GL_INT_SAMPLER_CUBE:
139 case GL_INT_SAMPLER_2D_ARRAY:
140 case GL_INT_SAMPLER_2D_MULTISAMPLE:
141 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
142 case GL_UNSIGNED_INT_SAMPLER_2D:
143 case GL_UNSIGNED_INT_SAMPLER_3D:
144 case GL_UNSIGNED_INT_SAMPLER_CUBE:
145 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
146 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
147 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
148 case GL_SAMPLER_2D_SHADOW:
149 case GL_SAMPLER_CUBE_SHADOW:
150 case GL_SAMPLER_2D_ARRAY_SHADOW:
151 case GL_INT_VEC2:
152 case GL_INT_VEC3:
153 case GL_INT_VEC4:
154 case GL_IMAGE_2D:
155 case GL_INT_IMAGE_2D:
156 case GL_UNSIGNED_INT_IMAGE_2D:
157 case GL_IMAGE_3D:
158 case GL_INT_IMAGE_3D:
159 case GL_UNSIGNED_INT_IMAGE_3D:
160 case GL_IMAGE_2D_ARRAY:
161 case GL_INT_IMAGE_2D_ARRAY:
162 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
163 case GL_IMAGE_CUBE:
164 case GL_INT_IMAGE_CUBE:
165 case GL_UNSIGNED_INT_IMAGE_CUBE:
166 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
167 case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
168 return GL_INT;
169 case GL_UNSIGNED_INT:
170 case GL_UNSIGNED_INT_VEC2:
171 case GL_UNSIGNED_INT_VEC3:
172 case GL_UNSIGNED_INT_VEC4:
173 return GL_UNSIGNED_INT;
174 default:
175 UNREACHABLE();
176 }
177
178 return GL_NONE;
179 }
180
VariableComponentSize(GLenum type)181 size_t VariableComponentSize(GLenum type)
182 {
183 switch (type)
184 {
185 case GL_BOOL:
186 return sizeof(GLint);
187 case GL_FLOAT:
188 return sizeof(GLfloat);
189 case GL_INT:
190 return sizeof(GLint);
191 case GL_UNSIGNED_INT:
192 return sizeof(GLuint);
193 default:
194 UNREACHABLE();
195 }
196
197 return 0;
198 }
199
VariableInternalSize(GLenum type)200 size_t VariableInternalSize(GLenum type)
201 {
202 // Expanded to 4-element vectors
203 return VariableComponentSize(VariableComponentType(type)) * VariableRowCount(type) * 4;
204 }
205
VariableExternalSize(GLenum type)206 size_t VariableExternalSize(GLenum type)
207 {
208 return VariableComponentSize(VariableComponentType(type)) * VariableComponentCount(type);
209 }
210
GetGLSLTypeString(GLenum type)211 std::string GetGLSLTypeString(GLenum type)
212 {
213 switch (type)
214 {
215 case GL_BOOL:
216 return "bool";
217 case GL_INT:
218 return "int";
219 case GL_UNSIGNED_INT:
220 return "uint";
221 case GL_FLOAT:
222 return "float";
223 case GL_BOOL_VEC2:
224 return "bvec2";
225 case GL_BOOL_VEC3:
226 return "bvec3";
227 case GL_BOOL_VEC4:
228 return "bvec4";
229 case GL_INT_VEC2:
230 return "ivec2";
231 case GL_INT_VEC3:
232 return "ivec3";
233 case GL_INT_VEC4:
234 return "ivec4";
235 case GL_FLOAT_VEC2:
236 return "vec2";
237 case GL_FLOAT_VEC3:
238 return "vec3";
239 case GL_FLOAT_VEC4:
240 return "vec4";
241 case GL_UNSIGNED_INT_VEC2:
242 return "uvec2";
243 case GL_UNSIGNED_INT_VEC3:
244 return "uvec3";
245 case GL_UNSIGNED_INT_VEC4:
246 return "uvec4";
247 case GL_FLOAT_MAT2:
248 return "mat2";
249 case GL_FLOAT_MAT3:
250 return "mat3";
251 case GL_FLOAT_MAT4:
252 return "mat4";
253 default:
254 UNREACHABLE();
255 return nullptr;
256 }
257 }
258
VariableBoolVectorType(GLenum type)259 GLenum VariableBoolVectorType(GLenum type)
260 {
261 switch (type)
262 {
263 case GL_FLOAT:
264 case GL_INT:
265 case GL_UNSIGNED_INT:
266 return GL_BOOL;
267 case GL_FLOAT_VEC2:
268 case GL_INT_VEC2:
269 case GL_UNSIGNED_INT_VEC2:
270 return GL_BOOL_VEC2;
271 case GL_FLOAT_VEC3:
272 case GL_INT_VEC3:
273 case GL_UNSIGNED_INT_VEC3:
274 return GL_BOOL_VEC3;
275 case GL_FLOAT_VEC4:
276 case GL_INT_VEC4:
277 case GL_UNSIGNED_INT_VEC4:
278 return GL_BOOL_VEC4;
279
280 default:
281 UNREACHABLE();
282 return GL_NONE;
283 }
284 }
285
VariableRowCount(GLenum type)286 int VariableRowCount(GLenum type)
287 {
288 switch (type)
289 {
290 case GL_NONE:
291 return 0;
292 case GL_BOOL:
293 case GL_FLOAT:
294 case GL_INT:
295 case GL_UNSIGNED_INT:
296 case GL_BOOL_VEC2:
297 case GL_FLOAT_VEC2:
298 case GL_INT_VEC2:
299 case GL_UNSIGNED_INT_VEC2:
300 case GL_BOOL_VEC3:
301 case GL_FLOAT_VEC3:
302 case GL_INT_VEC3:
303 case GL_UNSIGNED_INT_VEC3:
304 case GL_BOOL_VEC4:
305 case GL_FLOAT_VEC4:
306 case GL_INT_VEC4:
307 case GL_UNSIGNED_INT_VEC4:
308 case GL_SAMPLER_2D:
309 case GL_SAMPLER_3D:
310 case GL_SAMPLER_CUBE:
311 case GL_SAMPLER_2D_ARRAY:
312 case GL_SAMPLER_EXTERNAL_OES:
313 case GL_SAMPLER_2D_RECT_ANGLE:
314 case GL_SAMPLER_2D_MULTISAMPLE:
315 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
316 case GL_INT_SAMPLER_2D:
317 case GL_INT_SAMPLER_3D:
318 case GL_INT_SAMPLER_CUBE:
319 case GL_INT_SAMPLER_2D_ARRAY:
320 case GL_INT_SAMPLER_2D_MULTISAMPLE:
321 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
322 case GL_UNSIGNED_INT_SAMPLER_2D:
323 case GL_UNSIGNED_INT_SAMPLER_3D:
324 case GL_UNSIGNED_INT_SAMPLER_CUBE:
325 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
326 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
327 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
328 case GL_SAMPLER_2D_SHADOW:
329 case GL_SAMPLER_CUBE_SHADOW:
330 case GL_SAMPLER_2D_ARRAY_SHADOW:
331 case GL_IMAGE_2D:
332 case GL_INT_IMAGE_2D:
333 case GL_UNSIGNED_INT_IMAGE_2D:
334 case GL_IMAGE_2D_ARRAY:
335 case GL_INT_IMAGE_2D_ARRAY:
336 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
337 case GL_IMAGE_3D:
338 case GL_INT_IMAGE_3D:
339 case GL_UNSIGNED_INT_IMAGE_3D:
340 case GL_IMAGE_CUBE:
341 case GL_INT_IMAGE_CUBE:
342 case GL_UNSIGNED_INT_IMAGE_CUBE:
343 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
344 case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
345 return 1;
346 case GL_FLOAT_MAT2:
347 case GL_FLOAT_MAT3x2:
348 case GL_FLOAT_MAT4x2:
349 return 2;
350 case GL_FLOAT_MAT3:
351 case GL_FLOAT_MAT2x3:
352 case GL_FLOAT_MAT4x3:
353 return 3;
354 case GL_FLOAT_MAT4:
355 case GL_FLOAT_MAT2x4:
356 case GL_FLOAT_MAT3x4:
357 return 4;
358 default:
359 UNREACHABLE();
360 }
361
362 return 0;
363 }
364
VariableColumnCount(GLenum type)365 int VariableColumnCount(GLenum type)
366 {
367 switch (type)
368 {
369 case GL_NONE:
370 return 0;
371 case GL_BOOL:
372 case GL_FLOAT:
373 case GL_INT:
374 case GL_UNSIGNED_INT:
375 case GL_SAMPLER_2D:
376 case GL_SAMPLER_3D:
377 case GL_SAMPLER_CUBE:
378 case GL_SAMPLER_2D_ARRAY:
379 case GL_SAMPLER_2D_MULTISAMPLE:
380 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
381 case GL_INT_SAMPLER_2D:
382 case GL_INT_SAMPLER_3D:
383 case GL_INT_SAMPLER_CUBE:
384 case GL_INT_SAMPLER_2D_ARRAY:
385 case GL_INT_SAMPLER_2D_MULTISAMPLE:
386 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
387 case GL_SAMPLER_EXTERNAL_OES:
388 case GL_SAMPLER_2D_RECT_ANGLE:
389 case GL_UNSIGNED_INT_SAMPLER_2D:
390 case GL_UNSIGNED_INT_SAMPLER_3D:
391 case GL_UNSIGNED_INT_SAMPLER_CUBE:
392 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
393 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
394 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
395 case GL_SAMPLER_2D_SHADOW:
396 case GL_SAMPLER_CUBE_SHADOW:
397 case GL_SAMPLER_2D_ARRAY_SHADOW:
398 case GL_IMAGE_2D:
399 case GL_INT_IMAGE_2D:
400 case GL_UNSIGNED_INT_IMAGE_2D:
401 case GL_IMAGE_3D:
402 case GL_INT_IMAGE_3D:
403 case GL_UNSIGNED_INT_IMAGE_3D:
404 case GL_IMAGE_2D_ARRAY:
405 case GL_INT_IMAGE_2D_ARRAY:
406 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
407 case GL_IMAGE_CUBE:
408 case GL_INT_IMAGE_CUBE:
409 case GL_UNSIGNED_INT_IMAGE_CUBE:
410 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
411 case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
412 return 1;
413 case GL_BOOL_VEC2:
414 case GL_FLOAT_VEC2:
415 case GL_INT_VEC2:
416 case GL_UNSIGNED_INT_VEC2:
417 case GL_FLOAT_MAT2:
418 case GL_FLOAT_MAT2x3:
419 case GL_FLOAT_MAT2x4:
420 return 2;
421 case GL_BOOL_VEC3:
422 case GL_FLOAT_VEC3:
423 case GL_INT_VEC3:
424 case GL_UNSIGNED_INT_VEC3:
425 case GL_FLOAT_MAT3:
426 case GL_FLOAT_MAT3x2:
427 case GL_FLOAT_MAT3x4:
428 return 3;
429 case GL_BOOL_VEC4:
430 case GL_FLOAT_VEC4:
431 case GL_INT_VEC4:
432 case GL_UNSIGNED_INT_VEC4:
433 case GL_FLOAT_MAT4:
434 case GL_FLOAT_MAT4x2:
435 case GL_FLOAT_MAT4x3:
436 return 4;
437 default:
438 UNREACHABLE();
439 }
440
441 return 0;
442 }
443
IsSamplerType(GLenum type)444 bool IsSamplerType(GLenum type)
445 {
446 switch (type)
447 {
448 case GL_SAMPLER_2D:
449 case GL_SAMPLER_3D:
450 case GL_SAMPLER_CUBE:
451 case GL_SAMPLER_2D_ARRAY:
452 case GL_SAMPLER_EXTERNAL_OES:
453 case GL_SAMPLER_2D_MULTISAMPLE:
454 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
455 case GL_SAMPLER_2D_RECT_ANGLE:
456 case GL_INT_SAMPLER_2D:
457 case GL_INT_SAMPLER_3D:
458 case GL_INT_SAMPLER_CUBE:
459 case GL_INT_SAMPLER_2D_ARRAY:
460 case GL_INT_SAMPLER_2D_MULTISAMPLE:
461 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
462 case GL_UNSIGNED_INT_SAMPLER_2D:
463 case GL_UNSIGNED_INT_SAMPLER_3D:
464 case GL_UNSIGNED_INT_SAMPLER_CUBE:
465 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
466 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
467 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
468 case GL_SAMPLER_2D_SHADOW:
469 case GL_SAMPLER_CUBE_SHADOW:
470 case GL_SAMPLER_2D_ARRAY_SHADOW:
471 case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
472 return true;
473 }
474
475 return false;
476 }
477
IsSamplerCubeType(GLenum type)478 bool IsSamplerCubeType(GLenum type)
479 {
480 switch (type)
481 {
482 case GL_SAMPLER_CUBE:
483 case GL_INT_SAMPLER_CUBE:
484 case GL_UNSIGNED_INT_SAMPLER_CUBE:
485 case GL_SAMPLER_CUBE_SHADOW:
486 return true;
487 }
488
489 return false;
490 }
491
IsImageType(GLenum type)492 bool IsImageType(GLenum type)
493 {
494 switch (type)
495 {
496 case GL_IMAGE_2D:
497 case GL_INT_IMAGE_2D:
498 case GL_UNSIGNED_INT_IMAGE_2D:
499 case GL_IMAGE_3D:
500 case GL_INT_IMAGE_3D:
501 case GL_UNSIGNED_INT_IMAGE_3D:
502 case GL_IMAGE_2D_ARRAY:
503 case GL_INT_IMAGE_2D_ARRAY:
504 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
505 case GL_IMAGE_CUBE:
506 case GL_INT_IMAGE_CUBE:
507 case GL_UNSIGNED_INT_IMAGE_CUBE:
508 return true;
509 }
510 return false;
511 }
512
IsImage2DType(GLenum type)513 bool IsImage2DType(GLenum type)
514 {
515 switch (type)
516 {
517 case GL_IMAGE_2D:
518 case GL_INT_IMAGE_2D:
519 case GL_UNSIGNED_INT_IMAGE_2D:
520 return true;
521 case GL_IMAGE_3D:
522 case GL_INT_IMAGE_3D:
523 case GL_UNSIGNED_INT_IMAGE_3D:
524 case GL_IMAGE_2D_ARRAY:
525 case GL_INT_IMAGE_2D_ARRAY:
526 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
527 case GL_IMAGE_CUBE:
528 case GL_INT_IMAGE_CUBE:
529 case GL_UNSIGNED_INT_IMAGE_CUBE:
530 return false;
531 default:
532 UNREACHABLE();
533 return false;
534 }
535 }
536
IsAtomicCounterType(GLenum type)537 bool IsAtomicCounterType(GLenum type)
538 {
539 return type == GL_UNSIGNED_INT_ATOMIC_COUNTER;
540 }
541
IsOpaqueType(GLenum type)542 bool IsOpaqueType(GLenum type)
543 {
544 // ESSL 3.10 section 4.1.7 defines opaque types as: samplers, images and atomic counters.
545 return IsImageType(type) || IsSamplerType(type) || IsAtomicCounterType(type);
546 }
547
IsMatrixType(GLenum type)548 bool IsMatrixType(GLenum type)
549 {
550 return VariableRowCount(type) > 1;
551 }
552
TransposeMatrixType(GLenum type)553 GLenum TransposeMatrixType(GLenum type)
554 {
555 if (!IsMatrixType(type))
556 {
557 return type;
558 }
559
560 switch (type)
561 {
562 case GL_FLOAT_MAT2:
563 return GL_FLOAT_MAT2;
564 case GL_FLOAT_MAT3:
565 return GL_FLOAT_MAT3;
566 case GL_FLOAT_MAT4:
567 return GL_FLOAT_MAT4;
568 case GL_FLOAT_MAT2x3:
569 return GL_FLOAT_MAT3x2;
570 case GL_FLOAT_MAT3x2:
571 return GL_FLOAT_MAT2x3;
572 case GL_FLOAT_MAT2x4:
573 return GL_FLOAT_MAT4x2;
574 case GL_FLOAT_MAT4x2:
575 return GL_FLOAT_MAT2x4;
576 case GL_FLOAT_MAT3x4:
577 return GL_FLOAT_MAT4x3;
578 case GL_FLOAT_MAT4x3:
579 return GL_FLOAT_MAT3x4;
580 default:
581 UNREACHABLE();
582 return GL_NONE;
583 }
584 }
585
MatrixRegisterCount(GLenum type,bool isRowMajorMatrix)586 int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix)
587 {
588 ASSERT(IsMatrixType(type));
589 return isRowMajorMatrix ? VariableRowCount(type) : VariableColumnCount(type);
590 }
591
MatrixComponentCount(GLenum type,bool isRowMajorMatrix)592 int MatrixComponentCount(GLenum type, bool isRowMajorMatrix)
593 {
594 ASSERT(IsMatrixType(type));
595 return isRowMajorMatrix ? VariableColumnCount(type) : VariableRowCount(type);
596 }
597
VariableRegisterCount(GLenum type)598 int VariableRegisterCount(GLenum type)
599 {
600 return IsMatrixType(type) ? VariableColumnCount(type) : 1;
601 }
602
AllocateFirstFreeBits(unsigned int * bits,unsigned int allocationSize,unsigned int bitsSize)603 int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize)
604 {
605 ASSERT(allocationSize <= bitsSize);
606
607 unsigned int mask = std::numeric_limits<unsigned int>::max() >>
608 (std::numeric_limits<unsigned int>::digits - allocationSize);
609
610 for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++)
611 {
612 if ((*bits & mask) == 0)
613 {
614 *bits |= mask;
615 return i;
616 }
617
618 mask <<= 1;
619 }
620
621 return -1;
622 }
623
ComputeIndexRange(DrawElementsType indexType,const GLvoid * indices,size_t count,bool primitiveRestartEnabled)624 IndexRange ComputeIndexRange(DrawElementsType indexType,
625 const GLvoid *indices,
626 size_t count,
627 bool primitiveRestartEnabled)
628 {
629 switch (indexType)
630 {
631 case DrawElementsType::UnsignedByte:
632 return ComputeTypedIndexRange(static_cast<const GLubyte *>(indices), count,
633 primitiveRestartEnabled,
634 GetPrimitiveRestartIndex(indexType));
635 case DrawElementsType::UnsignedShort:
636 return ComputeTypedIndexRange(static_cast<const GLushort *>(indices), count,
637 primitiveRestartEnabled,
638 GetPrimitiveRestartIndex(indexType));
639 case DrawElementsType::UnsignedInt:
640 return ComputeTypedIndexRange(static_cast<const GLuint *>(indices), count,
641 primitiveRestartEnabled,
642 GetPrimitiveRestartIndex(indexType));
643 default:
644 UNREACHABLE();
645 return IndexRange();
646 }
647 }
648
GetPrimitiveRestartIndex(DrawElementsType indexType)649 GLuint GetPrimitiveRestartIndex(DrawElementsType indexType)
650 {
651 switch (indexType)
652 {
653 case DrawElementsType::UnsignedByte:
654 return 0xFF;
655 case DrawElementsType::UnsignedShort:
656 return 0xFFFF;
657 case DrawElementsType::UnsignedInt:
658 return 0xFFFFFFFF;
659 default:
660 UNREACHABLE();
661 return 0;
662 }
663 }
664
IsTriangleMode(PrimitiveMode drawMode)665 bool IsTriangleMode(PrimitiveMode drawMode)
666 {
667 switch (drawMode)
668 {
669 case PrimitiveMode::Triangles:
670 case PrimitiveMode::TriangleFan:
671 case PrimitiveMode::TriangleStrip:
672 return true;
673 case PrimitiveMode::Points:
674 case PrimitiveMode::Lines:
675 case PrimitiveMode::LineLoop:
676 case PrimitiveMode::LineStrip:
677 return false;
678 default:
679 UNREACHABLE();
680 }
681
682 return false;
683 }
684
IsPolygonMode(PrimitiveMode mode)685 bool IsPolygonMode(PrimitiveMode mode)
686 {
687 switch (mode)
688 {
689 case PrimitiveMode::Points:
690 case PrimitiveMode::Lines:
691 case PrimitiveMode::LineStrip:
692 case PrimitiveMode::LineLoop:
693 case PrimitiveMode::LinesAdjacency:
694 case PrimitiveMode::LineStripAdjacency:
695 return false;
696 default:
697 break;
698 }
699
700 return true;
701 }
702
703 namespace priv
704 {
705 const angle::PackedEnumMap<PrimitiveMode, bool> gLineModes = {
706 {{PrimitiveMode::LineLoop, true},
707 {PrimitiveMode::LineStrip, true},
708 {PrimitiveMode::LineStripAdjacency, true},
709 {PrimitiveMode::Lines, true}}};
710 } // namespace priv
711
IsIntegerFormat(GLenum unsizedFormat)712 bool IsIntegerFormat(GLenum unsizedFormat)
713 {
714 switch (unsizedFormat)
715 {
716 case GL_RGBA_INTEGER:
717 case GL_RGB_INTEGER:
718 case GL_RG_INTEGER:
719 case GL_RED_INTEGER:
720 return true;
721
722 default:
723 return false;
724 }
725 }
726
727 // [OpenGL ES SL 3.00.4] Section 11 p. 120
728 // Vertex Outs/Fragment Ins packing priorities
VariableSortOrder(GLenum type)729 int VariableSortOrder(GLenum type)
730 {
731 switch (type)
732 {
733 // 1. Arrays of mat4 and mat4
734 // Non-square matrices of type matCxR consume the same space as a square
735 // matrix of type matN where N is the greater of C and R
736 case GL_FLOAT_MAT4:
737 case GL_FLOAT_MAT2x4:
738 case GL_FLOAT_MAT3x4:
739 case GL_FLOAT_MAT4x2:
740 case GL_FLOAT_MAT4x3:
741 return 0;
742
743 // 2. Arrays of mat2 and mat2 (since they occupy full rows)
744 case GL_FLOAT_MAT2:
745 return 1;
746
747 // 3. Arrays of vec4 and vec4
748 case GL_FLOAT_VEC4:
749 case GL_INT_VEC4:
750 case GL_BOOL_VEC4:
751 case GL_UNSIGNED_INT_VEC4:
752 return 2;
753
754 // 4. Arrays of mat3 and mat3
755 case GL_FLOAT_MAT3:
756 case GL_FLOAT_MAT2x3:
757 case GL_FLOAT_MAT3x2:
758 return 3;
759
760 // 5. Arrays of vec3 and vec3
761 case GL_FLOAT_VEC3:
762 case GL_INT_VEC3:
763 case GL_BOOL_VEC3:
764 case GL_UNSIGNED_INT_VEC3:
765 return 4;
766
767 // 6. Arrays of vec2 and vec2
768 case GL_FLOAT_VEC2:
769 case GL_INT_VEC2:
770 case GL_BOOL_VEC2:
771 case GL_UNSIGNED_INT_VEC2:
772 return 5;
773
774 // 7. Single component types
775 case GL_FLOAT:
776 case GL_INT:
777 case GL_BOOL:
778 case GL_UNSIGNED_INT:
779 case GL_SAMPLER_2D:
780 case GL_SAMPLER_CUBE:
781 case GL_SAMPLER_EXTERNAL_OES:
782 case GL_SAMPLER_2D_RECT_ANGLE:
783 case GL_SAMPLER_2D_ARRAY:
784 case GL_SAMPLER_2D_MULTISAMPLE:
785 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
786 case GL_SAMPLER_3D:
787 case GL_INT_SAMPLER_2D:
788 case GL_INT_SAMPLER_3D:
789 case GL_INT_SAMPLER_CUBE:
790 case GL_INT_SAMPLER_2D_ARRAY:
791 case GL_INT_SAMPLER_2D_MULTISAMPLE:
792 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
793 case GL_UNSIGNED_INT_SAMPLER_2D:
794 case GL_UNSIGNED_INT_SAMPLER_3D:
795 case GL_UNSIGNED_INT_SAMPLER_CUBE:
796 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
797 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
798 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
799 case GL_SAMPLER_2D_SHADOW:
800 case GL_SAMPLER_2D_ARRAY_SHADOW:
801 case GL_SAMPLER_CUBE_SHADOW:
802 case GL_IMAGE_2D:
803 case GL_INT_IMAGE_2D:
804 case GL_UNSIGNED_INT_IMAGE_2D:
805 case GL_IMAGE_3D:
806 case GL_INT_IMAGE_3D:
807 case GL_UNSIGNED_INT_IMAGE_3D:
808 case GL_IMAGE_2D_ARRAY:
809 case GL_INT_IMAGE_2D_ARRAY:
810 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
811 case GL_IMAGE_CUBE:
812 case GL_INT_IMAGE_CUBE:
813 case GL_UNSIGNED_INT_IMAGE_CUBE:
814 case GL_UNSIGNED_INT_ATOMIC_COUNTER:
815 case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
816 return 6;
817
818 default:
819 UNREACHABLE();
820 return 0;
821 }
822 }
823
ParseResourceName(const std::string & name,std::vector<unsigned int> * outSubscripts)824 std::string ParseResourceName(const std::string &name, std::vector<unsigned int> *outSubscripts)
825 {
826 if (outSubscripts)
827 {
828 outSubscripts->clear();
829 }
830 // Strip any trailing array indexing operators and retrieve the subscripts.
831 size_t baseNameLength = name.length();
832 bool hasIndex = true;
833 while (hasIndex)
834 {
835 size_t open = name.find_last_of('[', baseNameLength - 1);
836 size_t close = name.find_last_of(']', baseNameLength - 1);
837 hasIndex = (open != std::string::npos) && (close == baseNameLength - 1);
838 if (hasIndex)
839 {
840 baseNameLength = open;
841 if (outSubscripts)
842 {
843 int index = atoi(name.substr(open + 1).c_str());
844 if (index >= 0)
845 {
846 outSubscripts->push_back(index);
847 }
848 else
849 {
850 outSubscripts->push_back(GL_INVALID_INDEX);
851 }
852 }
853 }
854 }
855
856 return name.substr(0, baseNameLength);
857 }
858
StripLastArrayIndex(const std::string & name)859 std::string StripLastArrayIndex(const std::string &name)
860 {
861 size_t strippedNameLength = name.find_last_of('[');
862 if (strippedNameLength != std::string::npos && name.back() == ']')
863 {
864 return name.substr(0, strippedNameLength);
865 }
866 return name;
867 }
868
SamplerNameContainsNonZeroArrayElement(const std::string & name)869 bool SamplerNameContainsNonZeroArrayElement(const std::string &name)
870 {
871 constexpr char kZERO_ELEMENT[] = "[0]";
872
873 size_t start = 0;
874 while (true)
875 {
876 start = name.find(kZERO_ELEMENT[0], start);
877 if (start == std::string::npos)
878 {
879 break;
880 }
881 if (name.compare(start, strlen(kZERO_ELEMENT), kZERO_ELEMENT) != 0)
882 {
883 return true;
884 }
885 start++;
886 }
887 return false;
888 }
889
FindShaderVarField(const sh::ShaderVariable & var,const std::string & fullName,GLuint * fieldIndexOut)890 const sh::ShaderVariable *FindShaderVarField(const sh::ShaderVariable &var,
891 const std::string &fullName,
892 GLuint *fieldIndexOut)
893 {
894 if (var.fields.empty())
895 {
896 return nullptr;
897 }
898 size_t pos = fullName.find_first_of(".");
899 if (pos == std::string::npos)
900 {
901 return nullptr;
902 }
903 std::string topName = fullName.substr(0, pos);
904 if (topName != var.name)
905 {
906 return nullptr;
907 }
908 std::string fieldName = fullName.substr(pos + 1);
909 if (fieldName.empty())
910 {
911 return nullptr;
912 }
913 for (size_t field = 0; field < var.fields.size(); ++field)
914 {
915 if (var.fields[field].name == fieldName)
916 {
917 *fieldIndexOut = static_cast<GLuint>(field);
918 return &var.fields[field];
919 }
920 }
921 return nullptr;
922 }
923
ArraySizeProduct(const std::vector<unsigned int> & arraySizes)924 unsigned int ArraySizeProduct(const std::vector<unsigned int> &arraySizes)
925 {
926 unsigned int arraySizeProduct = 1u;
927 for (unsigned int arraySize : arraySizes)
928 {
929 arraySizeProduct *= arraySize;
930 }
931 return arraySizeProduct;
932 }
933
ParseArrayIndex(const std::string & name,size_t * nameLengthWithoutArrayIndexOut)934 unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut)
935 {
936 ASSERT(nameLengthWithoutArrayIndexOut != nullptr);
937
938 // Strip any trailing array operator and retrieve the subscript
939 size_t open = name.find_last_of('[');
940 if (open != std::string::npos && name.back() == ']')
941 {
942 bool indexIsValidDecimalNumber = true;
943 for (size_t i = open + 1; i < name.length() - 1u; ++i)
944 {
945 if (!isdigit(name[i]))
946 {
947 indexIsValidDecimalNumber = false;
948 break;
949 }
950 }
951 if (indexIsValidDecimalNumber)
952 {
953 errno = 0; // reset global error flag.
954 unsigned long subscript =
955 strtoul(name.c_str() + open + 1, /*endptr*/ nullptr, /*radix*/ 10);
956
957 // Check if resulting integer is out-of-range or conversion error.
958 if (angle::base::IsValueInRangeForNumericType<uint32_t>(subscript) &&
959 !(subscript == ULONG_MAX && errno == ERANGE) && !(errno != 0 && subscript == 0))
960 {
961 *nameLengthWithoutArrayIndexOut = open;
962 return static_cast<unsigned int>(subscript);
963 }
964 }
965 }
966
967 *nameLengthWithoutArrayIndexOut = name.length();
968 return GL_INVALID_INDEX;
969 }
970
GetGenericErrorMessage(GLenum error)971 const char *GetGenericErrorMessage(GLenum error)
972 {
973 switch (error)
974 {
975 case GL_NO_ERROR:
976 return "";
977 case GL_INVALID_ENUM:
978 return "Invalid enum.";
979 case GL_INVALID_VALUE:
980 return "Invalid value.";
981 case GL_INVALID_OPERATION:
982 return "Invalid operation.";
983 case GL_STACK_OVERFLOW:
984 return "Stack overflow.";
985 case GL_STACK_UNDERFLOW:
986 return "Stack underflow.";
987 case GL_OUT_OF_MEMORY:
988 return "Out of memory.";
989 case GL_INVALID_FRAMEBUFFER_OPERATION:
990 return "Invalid framebuffer operation.";
991 default:
992 UNREACHABLE();
993 return "Unknown error.";
994 }
995 }
996
ElementTypeSize(GLenum elementType)997 unsigned int ElementTypeSize(GLenum elementType)
998 {
999 switch (elementType)
1000 {
1001 case GL_UNSIGNED_BYTE:
1002 return sizeof(GLubyte);
1003 case GL_UNSIGNED_SHORT:
1004 return sizeof(GLushort);
1005 case GL_UNSIGNED_INT:
1006 return sizeof(GLuint);
1007 default:
1008 UNREACHABLE();
1009 return 0;
1010 }
1011 }
1012
GetPipelineType(ShaderType type)1013 PipelineType GetPipelineType(ShaderType type)
1014 {
1015 switch (type)
1016 {
1017 case ShaderType::Vertex:
1018 case ShaderType::Fragment:
1019 case ShaderType::Geometry:
1020 return PipelineType::GraphicsPipeline;
1021 case ShaderType::Compute:
1022 return PipelineType::ComputePipeline;
1023 default:
1024 UNREACHABLE();
1025 return PipelineType::GraphicsPipeline;
1026 }
1027 }
1028
GetDebugMessageSourceString(GLenum source)1029 const char *GetDebugMessageSourceString(GLenum source)
1030 {
1031 switch (source)
1032 {
1033 case GL_DEBUG_SOURCE_API:
1034 return "API";
1035 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
1036 return "Window System";
1037 case GL_DEBUG_SOURCE_SHADER_COMPILER:
1038 return "Shader Compiler";
1039 case GL_DEBUG_SOURCE_THIRD_PARTY:
1040 return "Third Party";
1041 case GL_DEBUG_SOURCE_APPLICATION:
1042 return "Application";
1043 case GL_DEBUG_SOURCE_OTHER:
1044 return "Other";
1045 default:
1046 return "Unknown Source";
1047 }
1048 }
1049
GetDebugMessageTypeString(GLenum type)1050 const char *GetDebugMessageTypeString(GLenum type)
1051 {
1052 switch (type)
1053 {
1054 case GL_DEBUG_TYPE_ERROR:
1055 return "Error";
1056 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
1057 return "Deprecated behavior";
1058 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
1059 return "Undefined behavior";
1060 case GL_DEBUG_TYPE_PORTABILITY:
1061 return "Portability";
1062 case GL_DEBUG_TYPE_PERFORMANCE:
1063 return "Performance";
1064 case GL_DEBUG_TYPE_OTHER:
1065 return "Other";
1066 case GL_DEBUG_TYPE_MARKER:
1067 return "Marker";
1068 default:
1069 return "Unknown Type";
1070 }
1071 }
1072
GetDebugMessageSeverityString(GLenum severity)1073 const char *GetDebugMessageSeverityString(GLenum severity)
1074 {
1075 switch (severity)
1076 {
1077 case GL_DEBUG_SEVERITY_HIGH:
1078 return "High";
1079 case GL_DEBUG_SEVERITY_MEDIUM:
1080 return "Medium";
1081 case GL_DEBUG_SEVERITY_LOW:
1082 return "Low";
1083 case GL_DEBUG_SEVERITY_NOTIFICATION:
1084 return "Notification";
1085 default:
1086 return "Unknown Severity";
1087 }
1088 }
1089 } // namespace gl
1090
1091 namespace egl
1092 {
1093 static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 1,
1094 "Unexpected EGL cube map enum value.");
1095 static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 2,
1096 "Unexpected EGL cube map enum value.");
1097 static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 3,
1098 "Unexpected EGL cube map enum value.");
1099 static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 4,
1100 "Unexpected EGL cube map enum value.");
1101 static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 5,
1102 "Unexpected EGL cube map enum value.");
1103
IsCubeMapTextureTarget(EGLenum target)1104 bool IsCubeMapTextureTarget(EGLenum target)
1105 {
1106 return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget);
1107 }
1108
CubeMapTextureTargetToLayerIndex(EGLenum target)1109 size_t CubeMapTextureTargetToLayerIndex(EGLenum target)
1110 {
1111 ASSERT(IsCubeMapTextureTarget(target));
1112 return target - static_cast<size_t>(FirstCubeMapTextureTarget);
1113 }
1114
LayerIndexToCubeMapTextureTarget(size_t index)1115 EGLenum LayerIndexToCubeMapTextureTarget(size_t index)
1116 {
1117 ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget));
1118 return FirstCubeMapTextureTarget + static_cast<GLenum>(index);
1119 }
1120
IsTextureTarget(EGLenum target)1121 bool IsTextureTarget(EGLenum target)
1122 {
1123 switch (target)
1124 {
1125 case EGL_GL_TEXTURE_2D_KHR:
1126 case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
1127 case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
1128 case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
1129 case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
1130 case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
1131 case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
1132 case EGL_GL_TEXTURE_3D_KHR:
1133 return true;
1134
1135 default:
1136 return false;
1137 }
1138 }
1139
IsRenderbufferTarget(EGLenum target)1140 bool IsRenderbufferTarget(EGLenum target)
1141 {
1142 return target == EGL_GL_RENDERBUFFER_KHR;
1143 }
1144
IsExternalImageTarget(EGLenum target)1145 bool IsExternalImageTarget(EGLenum target)
1146 {
1147 switch (target)
1148 {
1149 case EGL_NATIVE_BUFFER_ANDROID:
1150 case EGL_D3D11_TEXTURE_ANGLE:
1151 return true;
1152
1153 default:
1154 return false;
1155 }
1156 }
1157
GetGenericErrorMessage(EGLint error)1158 const char *GetGenericErrorMessage(EGLint error)
1159 {
1160 switch (error)
1161 {
1162 case EGL_SUCCESS:
1163 return "";
1164 case EGL_NOT_INITIALIZED:
1165 return "Not initialized.";
1166 case EGL_BAD_ACCESS:
1167 return "Bad access.";
1168 case EGL_BAD_ALLOC:
1169 return "Bad allocation.";
1170 case EGL_BAD_ATTRIBUTE:
1171 return "Bad attribute.";
1172 case EGL_BAD_CONFIG:
1173 return "Bad config.";
1174 case EGL_BAD_CONTEXT:
1175 return "Bad context.";
1176 case EGL_BAD_CURRENT_SURFACE:
1177 return "Bad current surface.";
1178 case EGL_BAD_DISPLAY:
1179 return "Bad display.";
1180 case EGL_BAD_MATCH:
1181 return "Bad match.";
1182 case EGL_BAD_NATIVE_WINDOW:
1183 return "Bad native window.";
1184 case EGL_BAD_PARAMETER:
1185 return "Bad parameter.";
1186 case EGL_BAD_SURFACE:
1187 return "Bad surface.";
1188 case EGL_CONTEXT_LOST:
1189 return "Context lost.";
1190 case EGL_BAD_STREAM_KHR:
1191 return "Bad stream.";
1192 case EGL_BAD_STATE_KHR:
1193 return "Bad state.";
1194 case EGL_BAD_DEVICE_EXT:
1195 return "Bad device.";
1196 default:
1197 UNREACHABLE();
1198 return "Unknown error.";
1199 }
1200 }
1201
1202 } // namespace egl
1203
1204 namespace egl_gl
1205 {
EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)1206 GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)
1207 {
1208 return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
1209 }
1210 } // namespace egl_gl
1211
1212 namespace gl_egl
1213 {
GLComponentTypeToEGLColorComponentType(GLenum glComponentType)1214 EGLenum GLComponentTypeToEGLColorComponentType(GLenum glComponentType)
1215 {
1216 switch (glComponentType)
1217 {
1218 case GL_FLOAT:
1219 return EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT;
1220
1221 case GL_UNSIGNED_NORMALIZED:
1222 return EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
1223
1224 default:
1225 UNREACHABLE();
1226 return EGL_NONE;
1227 }
1228 }
1229
GLObjectHandleToEGLClientBuffer(GLuint handle)1230 EGLClientBuffer GLObjectHandleToEGLClientBuffer(GLuint handle)
1231 {
1232 return reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(handle));
1233 }
1234
1235 } // namespace gl_egl
1236
1237 #if !defined(ANGLE_ENABLE_WINDOWS_UWP)
getTempPath()1238 std::string getTempPath()
1239 {
1240 # ifdef ANGLE_PLATFORM_WINDOWS
1241 char path[MAX_PATH];
1242 DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
1243 if (pathLen == 0)
1244 {
1245 UNREACHABLE();
1246 return std::string();
1247 }
1248
1249 UINT unique = GetTempFileNameA(path, "sh", 0, path);
1250 if (unique == 0)
1251 {
1252 UNREACHABLE();
1253 return std::string();
1254 }
1255
1256 return path;
1257 # else
1258 UNIMPLEMENTED();
1259 return "";
1260 # endif
1261 }
1262
writeFile(const char * path,const void * content,size_t size)1263 void writeFile(const char *path, const void *content, size_t size)
1264 {
1265 FILE *file = fopen(path, "w");
1266 if (!file)
1267 {
1268 UNREACHABLE();
1269 return;
1270 }
1271
1272 fwrite(content, sizeof(char), size, file);
1273 fclose(file);
1274 }
1275 #endif // !ANGLE_ENABLE_WINDOWS_UWP
1276
1277 #if defined(ANGLE_PLATFORM_WINDOWS)
1278
1279 // Causes the thread to relinquish the remainder of its time slice to any
1280 // other thread that is ready to run.If there are no other threads ready
1281 // to run, the function returns immediately, and the thread continues execution.
ScheduleYield()1282 void ScheduleYield()
1283 {
1284 Sleep(0);
1285 }
1286
1287 #endif
1288