| // | |
| // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // utilities.cpp: Conversion functions and other utility routines. | |
| #include "common/utilities.h" | |
| #include <GLSLANG/ShaderVars.h> | |
| #include "common/mathutil.h" | |
| #include "common/platform.h" | |
| #include <set> | |
| #if defined(ANGLE_ENABLE_WINDOWS_STORE) | |
| # include <wrl.h> | |
| # include <wrl/wrappers/corewrappers.h> | |
| # include <windows.applicationmodel.core.h> | |
| # include <windows.graphics.display.h> | |
| #endif | |
| namespace | |
| { | |
| template <class IndexType> | |
| gl::IndexRange ComputeTypedIndexRange(const IndexType *indices, | |
| size_t count, | |
| bool primitiveRestartEnabled, | |
| GLuint primitiveRestartIndex) | |
| { | |
| ASSERT(count > 0); | |
| IndexType minIndex = 0; | |
| IndexType maxIndex = 0; | |
| size_t nonPrimitiveRestartIndices = 0; | |
| if (primitiveRestartEnabled) | |
| { | |
| // Find the first non-primitive restart index to initialize the min and max values | |
| size_t i = 0; | |
| for (; i < count; i++) | |
| { | |
| if (indices[i] != primitiveRestartIndex) | |
| { | |
| minIndex = indices[i]; | |
| maxIndex = indices[i]; | |
| nonPrimitiveRestartIndices++; | |
| break; | |
| } | |
| } | |
| // Loop over the rest of the indices | |
| for (; i < count; i++) | |
| { | |
| if (indices[i] != primitiveRestartIndex) | |
| { | |
| if (minIndex > indices[i]) | |
| { | |
| minIndex = indices[i]; | |
| } | |
| if (maxIndex < indices[i]) | |
| { | |
| maxIndex = indices[i]; | |
| } | |
| nonPrimitiveRestartIndices++; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| minIndex = indices[0]; | |
| maxIndex = indices[0]; | |
| nonPrimitiveRestartIndices = count; | |
| for (size_t i = 1; i < count; i++) | |
| { | |
| if (minIndex > indices[i]) | |
| { | |
| minIndex = indices[i]; | |
| } | |
| if (maxIndex < indices[i]) | |
| { | |
| maxIndex = indices[i]; | |
| } | |
| } | |
| } | |
| return gl::IndexRange(static_cast<size_t>(minIndex), static_cast<size_t>(maxIndex), | |
| nonPrimitiveRestartIndices); | |
| } | |
| } // anonymous namespace | |
| namespace gl | |
| { | |
| int VariableComponentCount(GLenum type) | |
| { | |
| return VariableRowCount(type) * VariableColumnCount(type); | |
| } | |
| GLenum VariableComponentType(GLenum type) | |
| { | |
| switch(type) | |
| { | |
| case GL_BOOL: | |
| case GL_BOOL_VEC2: | |
| case GL_BOOL_VEC3: | |
| case GL_BOOL_VEC4: | |
| return GL_BOOL; | |
| case GL_FLOAT: | |
| case GL_FLOAT_VEC2: | |
| case GL_FLOAT_VEC3: | |
| case GL_FLOAT_VEC4: | |
| case GL_FLOAT_MAT2: | |
| case GL_FLOAT_MAT3: | |
| case GL_FLOAT_MAT4: | |
| case GL_FLOAT_MAT2x3: | |
| case GL_FLOAT_MAT3x2: | |
| case GL_FLOAT_MAT2x4: | |
| case GL_FLOAT_MAT4x2: | |
| case GL_FLOAT_MAT3x4: | |
| case GL_FLOAT_MAT4x3: | |
| return GL_FLOAT; | |
| case GL_INT: | |
| case GL_SAMPLER_2D: | |
| case GL_SAMPLER_2D_RECT_ANGLE: | |
| case GL_SAMPLER_3D: | |
| case GL_SAMPLER_CUBE: | |
| case GL_SAMPLER_2D_ARRAY: | |
| case GL_SAMPLER_EXTERNAL_OES: | |
| case GL_SAMPLER_2D_MULTISAMPLE: | |
| case GL_INT_SAMPLER_2D: | |
| case GL_INT_SAMPLER_3D: | |
| case GL_INT_SAMPLER_CUBE: | |
| case GL_INT_SAMPLER_2D_ARRAY: | |
| case GL_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D: | |
| case GL_UNSIGNED_INT_SAMPLER_3D: | |
| case GL_UNSIGNED_INT_SAMPLER_CUBE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_2D_SHADOW: | |
| case GL_SAMPLER_CUBE_SHADOW: | |
| case GL_SAMPLER_2D_ARRAY_SHADOW: | |
| case GL_INT_VEC2: | |
| case GL_INT_VEC3: | |
| case GL_INT_VEC4: | |
| case GL_IMAGE_2D: | |
| case GL_INT_IMAGE_2D: | |
| case GL_UNSIGNED_INT_IMAGE_2D: | |
| case GL_IMAGE_3D: | |
| case GL_INT_IMAGE_3D: | |
| case GL_UNSIGNED_INT_IMAGE_3D: | |
| case GL_IMAGE_2D_ARRAY: | |
| case GL_INT_IMAGE_2D_ARRAY: | |
| case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: | |
| case GL_IMAGE_CUBE: | |
| case GL_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_ATOMIC_COUNTER: | |
| return GL_INT; | |
| case GL_UNSIGNED_INT: | |
| case GL_UNSIGNED_INT_VEC2: | |
| case GL_UNSIGNED_INT_VEC3: | |
| case GL_UNSIGNED_INT_VEC4: | |
| return GL_UNSIGNED_INT; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| return GL_NONE; | |
| } | |
| size_t VariableComponentSize(GLenum type) | |
| { | |
| switch(type) | |
| { | |
| case GL_BOOL: return sizeof(GLint); | |
| case GL_FLOAT: return sizeof(GLfloat); | |
| case GL_INT: return sizeof(GLint); | |
| case GL_UNSIGNED_INT: return sizeof(GLuint); | |
| default: UNREACHABLE(); | |
| } | |
| return 0; | |
| } | |
| size_t VariableInternalSize(GLenum type) | |
| { | |
| // Expanded to 4-element vectors | |
| return VariableComponentSize(VariableComponentType(type)) * VariableRowCount(type) * 4; | |
| } | |
| size_t VariableExternalSize(GLenum type) | |
| { | |
| return VariableComponentSize(VariableComponentType(type)) * VariableComponentCount(type); | |
| } | |
| GLenum VariableBoolVectorType(GLenum type) | |
| { | |
| switch (type) | |
| { | |
| case GL_FLOAT: | |
| case GL_INT: | |
| case GL_UNSIGNED_INT: | |
| return GL_BOOL; | |
| case GL_FLOAT_VEC2: | |
| case GL_INT_VEC2: | |
| case GL_UNSIGNED_INT_VEC2: | |
| return GL_BOOL_VEC2; | |
| case GL_FLOAT_VEC3: | |
| case GL_INT_VEC3: | |
| case GL_UNSIGNED_INT_VEC3: | |
| return GL_BOOL_VEC3; | |
| case GL_FLOAT_VEC4: | |
| case GL_INT_VEC4: | |
| case GL_UNSIGNED_INT_VEC4: | |
| return GL_BOOL_VEC4; | |
| default: | |
| UNREACHABLE(); | |
| return GL_NONE; | |
| } | |
| } | |
| int VariableRowCount(GLenum type) | |
| { | |
| switch (type) | |
| { | |
| case GL_NONE: | |
| return 0; | |
| case GL_BOOL: | |
| case GL_FLOAT: | |
| case GL_INT: | |
| case GL_UNSIGNED_INT: | |
| case GL_BOOL_VEC2: | |
| case GL_FLOAT_VEC2: | |
| case GL_INT_VEC2: | |
| case GL_UNSIGNED_INT_VEC2: | |
| case GL_BOOL_VEC3: | |
| case GL_FLOAT_VEC3: | |
| case GL_INT_VEC3: | |
| case GL_UNSIGNED_INT_VEC3: | |
| case GL_BOOL_VEC4: | |
| case GL_FLOAT_VEC4: | |
| case GL_INT_VEC4: | |
| case GL_UNSIGNED_INT_VEC4: | |
| case GL_SAMPLER_2D: | |
| case GL_SAMPLER_3D: | |
| case GL_SAMPLER_CUBE: | |
| case GL_SAMPLER_2D_ARRAY: | |
| case GL_SAMPLER_EXTERNAL_OES: | |
| case GL_SAMPLER_2D_RECT_ANGLE: | |
| case GL_SAMPLER_2D_MULTISAMPLE: | |
| case GL_INT_SAMPLER_2D: | |
| case GL_INT_SAMPLER_3D: | |
| case GL_INT_SAMPLER_CUBE: | |
| case GL_INT_SAMPLER_2D_ARRAY: | |
| case GL_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D: | |
| case GL_UNSIGNED_INT_SAMPLER_3D: | |
| case GL_UNSIGNED_INT_SAMPLER_CUBE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_2D_SHADOW: | |
| case GL_SAMPLER_CUBE_SHADOW: | |
| case GL_SAMPLER_2D_ARRAY_SHADOW: | |
| case GL_IMAGE_2D: | |
| case GL_INT_IMAGE_2D: | |
| case GL_UNSIGNED_INT_IMAGE_2D: | |
| case GL_IMAGE_2D_ARRAY: | |
| case GL_INT_IMAGE_2D_ARRAY: | |
| case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: | |
| case GL_IMAGE_3D: | |
| case GL_INT_IMAGE_3D: | |
| case GL_UNSIGNED_INT_IMAGE_3D: | |
| case GL_IMAGE_CUBE: | |
| case GL_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_ATOMIC_COUNTER: | |
| return 1; | |
| case GL_FLOAT_MAT2: | |
| case GL_FLOAT_MAT3x2: | |
| case GL_FLOAT_MAT4x2: | |
| return 2; | |
| case GL_FLOAT_MAT3: | |
| case GL_FLOAT_MAT2x3: | |
| case GL_FLOAT_MAT4x3: | |
| return 3; | |
| case GL_FLOAT_MAT4: | |
| case GL_FLOAT_MAT2x4: | |
| case GL_FLOAT_MAT3x4: | |
| return 4; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| return 0; | |
| } | |
| int VariableColumnCount(GLenum type) | |
| { | |
| switch (type) | |
| { | |
| case GL_NONE: | |
| return 0; | |
| case GL_BOOL: | |
| case GL_FLOAT: | |
| case GL_INT: | |
| case GL_UNSIGNED_INT: | |
| case GL_SAMPLER_2D: | |
| case GL_SAMPLER_3D: | |
| case GL_SAMPLER_CUBE: | |
| case GL_SAMPLER_2D_ARRAY: | |
| case GL_SAMPLER_2D_MULTISAMPLE: | |
| case GL_INT_SAMPLER_2D: | |
| case GL_INT_SAMPLER_3D: | |
| case GL_INT_SAMPLER_CUBE: | |
| case GL_INT_SAMPLER_2D_ARRAY: | |
| case GL_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_EXTERNAL_OES: | |
| case GL_SAMPLER_2D_RECT_ANGLE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D: | |
| case GL_UNSIGNED_INT_SAMPLER_3D: | |
| case GL_UNSIGNED_INT_SAMPLER_CUBE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_2D_SHADOW: | |
| case GL_SAMPLER_CUBE_SHADOW: | |
| case GL_SAMPLER_2D_ARRAY_SHADOW: | |
| case GL_IMAGE_2D: | |
| case GL_INT_IMAGE_2D: | |
| case GL_UNSIGNED_INT_IMAGE_2D: | |
| case GL_IMAGE_3D: | |
| case GL_INT_IMAGE_3D: | |
| case GL_UNSIGNED_INT_IMAGE_3D: | |
| case GL_IMAGE_2D_ARRAY: | |
| case GL_INT_IMAGE_2D_ARRAY: | |
| case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: | |
| case GL_IMAGE_CUBE: | |
| case GL_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_ATOMIC_COUNTER: | |
| return 1; | |
| case GL_BOOL_VEC2: | |
| case GL_FLOAT_VEC2: | |
| case GL_INT_VEC2: | |
| case GL_UNSIGNED_INT_VEC2: | |
| case GL_FLOAT_MAT2: | |
| case GL_FLOAT_MAT2x3: | |
| case GL_FLOAT_MAT2x4: | |
| return 2; | |
| case GL_BOOL_VEC3: | |
| case GL_FLOAT_VEC3: | |
| case GL_INT_VEC3: | |
| case GL_UNSIGNED_INT_VEC3: | |
| case GL_FLOAT_MAT3: | |
| case GL_FLOAT_MAT3x2: | |
| case GL_FLOAT_MAT3x4: | |
| return 3; | |
| case GL_BOOL_VEC4: | |
| case GL_FLOAT_VEC4: | |
| case GL_INT_VEC4: | |
| case GL_UNSIGNED_INT_VEC4: | |
| case GL_FLOAT_MAT4: | |
| case GL_FLOAT_MAT4x2: | |
| case GL_FLOAT_MAT4x3: | |
| return 4; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| return 0; | |
| } | |
| bool IsSamplerType(GLenum type) | |
| { | |
| switch (type) | |
| { | |
| case GL_SAMPLER_2D: | |
| case GL_SAMPLER_3D: | |
| case GL_SAMPLER_CUBE: | |
| case GL_SAMPLER_2D_ARRAY: | |
| case GL_SAMPLER_EXTERNAL_OES: | |
| case GL_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_2D_RECT_ANGLE: | |
| case GL_INT_SAMPLER_2D: | |
| case GL_INT_SAMPLER_3D: | |
| case GL_INT_SAMPLER_CUBE: | |
| case GL_INT_SAMPLER_2D_ARRAY: | |
| case GL_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D: | |
| case GL_UNSIGNED_INT_SAMPLER_3D: | |
| case GL_UNSIGNED_INT_SAMPLER_CUBE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_2D_SHADOW: | |
| case GL_SAMPLER_CUBE_SHADOW: | |
| case GL_SAMPLER_2D_ARRAY_SHADOW: | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool IsImageType(GLenum type) | |
| { | |
| switch (type) | |
| { | |
| case GL_IMAGE_2D: | |
| case GL_INT_IMAGE_2D: | |
| case GL_UNSIGNED_INT_IMAGE_2D: | |
| case GL_IMAGE_3D: | |
| case GL_INT_IMAGE_3D: | |
| case GL_UNSIGNED_INT_IMAGE_3D: | |
| case GL_IMAGE_2D_ARRAY: | |
| case GL_INT_IMAGE_2D_ARRAY: | |
| case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: | |
| case GL_IMAGE_CUBE: | |
| case GL_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_IMAGE_CUBE: | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool IsAtomicCounterType(GLenum type) | |
| { | |
| return type == GL_UNSIGNED_INT_ATOMIC_COUNTER; | |
| } | |
| bool IsOpaqueType(GLenum type) | |
| { | |
| // ESSL 3.10 section 4.1.7 defines opaque types as: samplers, images and atomic counters. | |
| return IsImageType(type) || IsSamplerType(type) || IsAtomicCounterType(type); | |
| } | |
| bool IsMatrixType(GLenum type) | |
| { | |
| return VariableRowCount(type) > 1; | |
| } | |
| GLenum TransposeMatrixType(GLenum type) | |
| { | |
| if (!IsMatrixType(type)) | |
| { | |
| return type; | |
| } | |
| switch (type) | |
| { | |
| case GL_FLOAT_MAT2: return GL_FLOAT_MAT2; | |
| case GL_FLOAT_MAT3: return GL_FLOAT_MAT3; | |
| case GL_FLOAT_MAT4: return GL_FLOAT_MAT4; | |
| case GL_FLOAT_MAT2x3: return GL_FLOAT_MAT3x2; | |
| case GL_FLOAT_MAT3x2: return GL_FLOAT_MAT2x3; | |
| case GL_FLOAT_MAT2x4: return GL_FLOAT_MAT4x2; | |
| case GL_FLOAT_MAT4x2: return GL_FLOAT_MAT2x4; | |
| case GL_FLOAT_MAT3x4: return GL_FLOAT_MAT4x3; | |
| case GL_FLOAT_MAT4x3: return GL_FLOAT_MAT3x4; | |
| default: UNREACHABLE(); return GL_NONE; | |
| } | |
| } | |
| int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix) | |
| { | |
| ASSERT(IsMatrixType(type)); | |
| return isRowMajorMatrix ? VariableRowCount(type) : VariableColumnCount(type); | |
| } | |
| int MatrixComponentCount(GLenum type, bool isRowMajorMatrix) | |
| { | |
| ASSERT(IsMatrixType(type)); | |
| return isRowMajorMatrix ? VariableColumnCount(type) : VariableRowCount(type); | |
| } | |
| int VariableRegisterCount(GLenum type) | |
| { | |
| return IsMatrixType(type) ? VariableColumnCount(type) : 1; | |
| } | |
| int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize) | |
| { | |
| ASSERT(allocationSize <= bitsSize); | |
| unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize); | |
| for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++) | |
| { | |
| if ((*bits & mask) == 0) | |
| { | |
| *bits |= mask; | |
| return i; | |
| } | |
| mask <<= 1; | |
| } | |
| return -1; | |
| } | |
| IndexRange ComputeIndexRange(GLenum indexType, | |
| const GLvoid *indices, | |
| size_t count, | |
| bool primitiveRestartEnabled) | |
| { | |
| switch (indexType) | |
| { | |
| case GL_UNSIGNED_BYTE: | |
| return ComputeTypedIndexRange(static_cast<const GLubyte *>(indices), count, | |
| primitiveRestartEnabled, | |
| GetPrimitiveRestartIndex(indexType)); | |
| case GL_UNSIGNED_SHORT: | |
| return ComputeTypedIndexRange(static_cast<const GLushort *>(indices), count, | |
| primitiveRestartEnabled, | |
| GetPrimitiveRestartIndex(indexType)); | |
| case GL_UNSIGNED_INT: | |
| return ComputeTypedIndexRange(static_cast<const GLuint *>(indices), count, | |
| primitiveRestartEnabled, | |
| GetPrimitiveRestartIndex(indexType)); | |
| default: | |
| UNREACHABLE(); | |
| return IndexRange(); | |
| } | |
| } | |
| GLuint GetPrimitiveRestartIndex(GLenum indexType) | |
| { | |
| switch (indexType) | |
| { | |
| case GL_UNSIGNED_BYTE: | |
| return 0xFF; | |
| case GL_UNSIGNED_SHORT: | |
| return 0xFFFF; | |
| case GL_UNSIGNED_INT: | |
| return 0xFFFFFFFF; | |
| default: | |
| UNREACHABLE(); | |
| return 0; | |
| } | |
| } | |
| bool IsTriangleMode(GLenum drawMode) | |
| { | |
| switch (drawMode) | |
| { | |
| case GL_TRIANGLES: | |
| case GL_TRIANGLE_FAN: | |
| case GL_TRIANGLE_STRIP: | |
| return true; | |
| case GL_POINTS: | |
| case GL_LINES: | |
| case GL_LINE_LOOP: | |
| case GL_LINE_STRIP: | |
| return false; | |
| default: UNREACHABLE(); | |
| } | |
| return false; | |
| } | |
| bool IsIntegerFormat(GLenum unsizedFormat) | |
| { | |
| switch (unsizedFormat) | |
| { | |
| case GL_RGBA_INTEGER: | |
| case GL_RGB_INTEGER: | |
| case GL_RG_INTEGER: | |
| case GL_RED_INTEGER: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| // [OpenGL ES SL 3.00.4] Section 11 p. 120 | |
| // Vertex Outs/Fragment Ins packing priorities | |
| int VariableSortOrder(GLenum type) | |
| { | |
| switch (type) | |
| { | |
| // 1. Arrays of mat4 and mat4 | |
| // Non-square matrices of type matCxR consume the same space as a square | |
| // matrix of type matN where N is the greater of C and R | |
| case GL_FLOAT_MAT4: | |
| case GL_FLOAT_MAT2x4: | |
| case GL_FLOAT_MAT3x4: | |
| case GL_FLOAT_MAT4x2: | |
| case GL_FLOAT_MAT4x3: | |
| return 0; | |
| // 2. Arrays of mat2 and mat2 (since they occupy full rows) | |
| case GL_FLOAT_MAT2: | |
| return 1; | |
| // 3. Arrays of vec4 and vec4 | |
| case GL_FLOAT_VEC4: | |
| case GL_INT_VEC4: | |
| case GL_BOOL_VEC4: | |
| case GL_UNSIGNED_INT_VEC4: | |
| return 2; | |
| // 4. Arrays of mat3 and mat3 | |
| case GL_FLOAT_MAT3: | |
| case GL_FLOAT_MAT2x3: | |
| case GL_FLOAT_MAT3x2: | |
| return 3; | |
| // 5. Arrays of vec3 and vec3 | |
| case GL_FLOAT_VEC3: | |
| case GL_INT_VEC3: | |
| case GL_BOOL_VEC3: | |
| case GL_UNSIGNED_INT_VEC3: | |
| return 4; | |
| // 6. Arrays of vec2 and vec2 | |
| case GL_FLOAT_VEC2: | |
| case GL_INT_VEC2: | |
| case GL_BOOL_VEC2: | |
| case GL_UNSIGNED_INT_VEC2: | |
| return 5; | |
| // 7. Single component types | |
| case GL_FLOAT: | |
| case GL_INT: | |
| case GL_BOOL: | |
| case GL_UNSIGNED_INT: | |
| case GL_SAMPLER_2D: | |
| case GL_SAMPLER_CUBE: | |
| case GL_SAMPLER_EXTERNAL_OES: | |
| case GL_SAMPLER_2D_RECT_ANGLE: | |
| case GL_SAMPLER_2D_ARRAY: | |
| case GL_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_3D: | |
| case GL_INT_SAMPLER_2D: | |
| case GL_INT_SAMPLER_3D: | |
| case GL_INT_SAMPLER_CUBE: | |
| case GL_INT_SAMPLER_2D_ARRAY: | |
| case GL_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D: | |
| case GL_UNSIGNED_INT_SAMPLER_3D: | |
| case GL_UNSIGNED_INT_SAMPLER_CUBE: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: | |
| case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: | |
| case GL_SAMPLER_2D_SHADOW: | |
| case GL_SAMPLER_2D_ARRAY_SHADOW: | |
| case GL_SAMPLER_CUBE_SHADOW: | |
| case GL_IMAGE_2D: | |
| case GL_INT_IMAGE_2D: | |
| case GL_UNSIGNED_INT_IMAGE_2D: | |
| case GL_IMAGE_3D: | |
| case GL_INT_IMAGE_3D: | |
| case GL_UNSIGNED_INT_IMAGE_3D: | |
| case GL_IMAGE_2D_ARRAY: | |
| case GL_INT_IMAGE_2D_ARRAY: | |
| case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: | |
| case GL_IMAGE_CUBE: | |
| case GL_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_IMAGE_CUBE: | |
| case GL_UNSIGNED_INT_ATOMIC_COUNTER: | |
| return 6; | |
| default: | |
| UNREACHABLE(); | |
| return 0; | |
| } | |
| } | |
| std::string ParseResourceName(const std::string &name, std::vector<unsigned int> *outSubscripts) | |
| { | |
| if (outSubscripts) | |
| { | |
| outSubscripts->clear(); | |
| } | |
| // Strip any trailing array indexing operators and retrieve the subscripts. | |
| size_t baseNameLength = name.length(); | |
| bool hasIndex = true; | |
| while (hasIndex) | |
| { | |
| size_t open = name.find_last_of('[', baseNameLength - 1); | |
| size_t close = name.find_last_of(']', baseNameLength - 1); | |
| hasIndex = (open != std::string::npos) && (close == baseNameLength - 1); | |
| if (hasIndex) | |
| { | |
| baseNameLength = open; | |
| if (outSubscripts) | |
| { | |
| int index = atoi(name.substr(open + 1).c_str()); | |
| if (index >= 0) | |
| { | |
| outSubscripts->push_back(index); | |
| } | |
| else | |
| { | |
| outSubscripts->push_back(GL_INVALID_INDEX); | |
| } | |
| } | |
| } | |
| } | |
| return name.substr(0, baseNameLength); | |
| } | |
| const sh::ShaderVariable *FindShaderVarField(const sh::ShaderVariable &var, | |
| const std::string &fullName) | |
| { | |
| if (var.fields.empty()) | |
| { | |
| return nullptr; | |
| } | |
| size_t pos = fullName.find_first_of("."); | |
| if (pos == std::string::npos) | |
| { | |
| return nullptr; | |
| } | |
| std::string topName = fullName.substr(0, pos); | |
| if (topName != var.name) | |
| { | |
| return nullptr; | |
| } | |
| std::string fieldName = fullName.substr(pos + 1); | |
| if (fieldName.empty()) | |
| { | |
| return nullptr; | |
| } | |
| for (const auto &field : var.fields) | |
| { | |
| if (field.name == fieldName) | |
| { | |
| return &field; | |
| } | |
| } | |
| return nullptr; | |
| } | |
| unsigned int ArraySizeProduct(const std::vector<unsigned int> &arraySizes) | |
| { | |
| unsigned int arraySizeProduct = 1u; | |
| for (unsigned int arraySize : arraySizes) | |
| { | |
| arraySizeProduct *= arraySize; | |
| } | |
| return arraySizeProduct; | |
| } | |
| unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut) | |
| { | |
| ASSERT(nameLengthWithoutArrayIndexOut != nullptr); | |
| // Strip any trailing array operator and retrieve the subscript | |
| size_t open = name.find_last_of('['); | |
| if (open != std::string::npos && name.back() == ']') | |
| { | |
| bool indexIsValidDecimalNumber = true; | |
| for (size_t i = open + 1; i < name.length() - 1u; ++i) | |
| { | |
| if (!isdigit(name[i])) | |
| { | |
| indexIsValidDecimalNumber = false; | |
| break; | |
| } | |
| } | |
| if (indexIsValidDecimalNumber) | |
| { | |
| errno = 0; // reset global error flag. | |
| unsigned long subscript = | |
| strtoul(name.c_str() + open + 1, /*endptr*/ nullptr, /*radix*/ 10); | |
| // Check if resulting integer is out-of-range or conversion error. | |
| if ((subscript <= static_cast<unsigned long>(UINT_MAX)) && | |
| !(subscript == ULONG_MAX && errno == ERANGE) && !(errno != 0 && subscript == 0)) | |
| { | |
| *nameLengthWithoutArrayIndexOut = open; | |
| return static_cast<unsigned int>(subscript); | |
| } | |
| } | |
| } | |
| *nameLengthWithoutArrayIndexOut = name.length(); | |
| return GL_INVALID_INDEX; | |
| } | |
| const char *GetGenericErrorMessage(GLenum error) | |
| { | |
| switch (error) | |
| { | |
| case GL_NO_ERROR: | |
| return ""; | |
| case GL_INVALID_ENUM: | |
| return "Invalid enum."; | |
| case GL_INVALID_VALUE: | |
| return "Invalid value."; | |
| case GL_INVALID_OPERATION: | |
| return "Invalid operation."; | |
| case GL_STACK_OVERFLOW: | |
| return "Stack overflow."; | |
| case GL_STACK_UNDERFLOW: | |
| return "Stack underflow."; | |
| case GL_OUT_OF_MEMORY: | |
| return "Out of memory."; | |
| case GL_INVALID_FRAMEBUFFER_OPERATION: | |
| return "Invalid framebuffer operation."; | |
| default: | |
| UNREACHABLE(); | |
| return "Unknown error."; | |
| } | |
| } | |
| unsigned int ElementTypeSize(GLenum elementType) | |
| { | |
| switch (elementType) | |
| { | |
| case GL_UNSIGNED_BYTE: | |
| return sizeof(GLubyte); | |
| case GL_UNSIGNED_SHORT: | |
| return sizeof(GLushort); | |
| case GL_UNSIGNED_INT: | |
| return sizeof(GLuint); | |
| default: | |
| UNREACHABLE(); | |
| return 0; | |
| } | |
| } | |
| } // namespace gl | |
| namespace egl | |
| { | |
| static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 1, | |
| "Unexpected EGL cube map enum value."); | |
| static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 2, | |
| "Unexpected EGL cube map enum value."); | |
| static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 3, | |
| "Unexpected EGL cube map enum value."); | |
| static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 4, | |
| "Unexpected EGL cube map enum value."); | |
| static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 5, | |
| "Unexpected EGL cube map enum value."); | |
| bool IsCubeMapTextureTarget(EGLenum target) | |
| { | |
| return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget); | |
| } | |
| size_t CubeMapTextureTargetToLayerIndex(EGLenum target) | |
| { | |
| ASSERT(IsCubeMapTextureTarget(target)); | |
| return target - static_cast<size_t>(FirstCubeMapTextureTarget); | |
| } | |
| EGLenum LayerIndexToCubeMapTextureTarget(size_t index) | |
| { | |
| ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget)); | |
| return FirstCubeMapTextureTarget + static_cast<GLenum>(index); | |
| } | |
| bool IsTextureTarget(EGLenum target) | |
| { | |
| switch (target) | |
| { | |
| case EGL_GL_TEXTURE_2D_KHR: | |
| case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: | |
| case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: | |
| case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: | |
| case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: | |
| case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: | |
| case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: | |
| case EGL_GL_TEXTURE_3D_KHR: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| bool IsRenderbufferTarget(EGLenum target) | |
| { | |
| return target == EGL_GL_RENDERBUFFER_KHR; | |
| } | |
| const char *GetGenericErrorMessage(EGLint error) | |
| { | |
| switch (error) | |
| { | |
| case EGL_SUCCESS: | |
| return ""; | |
| case EGL_NOT_INITIALIZED: | |
| return "Not initialized."; | |
| case EGL_BAD_ACCESS: | |
| return "Bad access."; | |
| case EGL_BAD_ALLOC: | |
| return "Bad allocation."; | |
| case EGL_BAD_ATTRIBUTE: | |
| return "Bad attribute."; | |
| case EGL_BAD_CONFIG: | |
| return "Bad config."; | |
| case EGL_BAD_CONTEXT: | |
| return "Bad context."; | |
| case EGL_BAD_CURRENT_SURFACE: | |
| return "Bad current surface."; | |
| case EGL_BAD_DISPLAY: | |
| return "Bad display."; | |
| case EGL_BAD_MATCH: | |
| return "Bad match."; | |
| case EGL_BAD_NATIVE_WINDOW: | |
| return "Bad native window."; | |
| case EGL_BAD_PARAMETER: | |
| return "Bad parameter."; | |
| case EGL_BAD_SURFACE: | |
| return "Bad surface."; | |
| case EGL_CONTEXT_LOST: | |
| return "Context lost."; | |
| case EGL_BAD_STREAM_KHR: | |
| return "Bad stream."; | |
| case EGL_BAD_STATE_KHR: | |
| return "Bad state."; | |
| case EGL_BAD_DEVICE_EXT: | |
| return "Bad device."; | |
| default: | |
| UNREACHABLE(); | |
| return "Unknown error."; | |
| } | |
| } | |
| } // namespace egl | |
| namespace egl_gl | |
| { | |
| GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer) | |
| { | |
| return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer)); | |
| } | |
| } // namespace egl_gl | |
| namespace gl_egl | |
| { | |
| EGLenum GLComponentTypeToEGLColorComponentType(GLenum glComponentType) | |
| { | |
| switch (glComponentType) | |
| { | |
| case GL_FLOAT: | |
| return EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT; | |
| case GL_UNSIGNED_NORMALIZED: | |
| return EGL_COLOR_COMPONENT_TYPE_FIXED_EXT; | |
| default: | |
| UNREACHABLE(); | |
| return EGL_NONE; | |
| } | |
| } | |
| } // namespace gl_egl | |
| #if !defined(ANGLE_ENABLE_WINDOWS_STORE) | |
| std::string getTempPath() | |
| { | |
| #ifdef ANGLE_PLATFORM_WINDOWS | |
| char path[MAX_PATH]; | |
| DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); | |
| if (pathLen == 0) | |
| { | |
| UNREACHABLE(); | |
| return std::string(); | |
| } | |
| UINT unique = GetTempFileNameA(path, "sh", 0, path); | |
| if (unique == 0) | |
| { | |
| UNREACHABLE(); | |
| return std::string(); | |
| } | |
| return path; | |
| #else | |
| UNIMPLEMENTED(); | |
| return ""; | |
| #endif | |
| } | |
| void writeFile(const char* path, const void* content, size_t size) | |
| { | |
| FILE* file = fopen(path, "w"); | |
| if (!file) | |
| { | |
| UNREACHABLE(); | |
| return; | |
| } | |
| fwrite(content, sizeof(char), size, file); | |
| fclose(file); | |
| } | |
| #endif // !ANGLE_ENABLE_WINDOWS_STORE | |
| #if defined (ANGLE_PLATFORM_WINDOWS) | |
| // Causes the thread to relinquish the remainder of its time slice to any | |
| // other thread that is ready to run.If there are no other threads ready | |
| // to run, the function returns immediately, and the thread continues execution. | |
| void ScheduleYield() | |
| { | |
| Sleep(0); | |
| } | |
| #endif |