// // Copyright 2002 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 "GLES3/gl3.h" #include "common/mathutil.h" #include "common/platform.h" #include "common/string_utils.h" #include #if defined(ANGLE_ENABLE_WINDOWS_UWP) # include # include # include # include #endif namespace { template 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(minIndex), static_cast(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_CUBE_MAP_ARRAY: case GL_SAMPLER_2D_ARRAY: case GL_SAMPLER_EXTERNAL_OES: case GL_SAMPLER_2D_MULTISAMPLE: case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_INT_SAMPLER_BUFFER: case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_3D: case GL_INT_SAMPLER_CUBE: case GL_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_INT_SAMPLER_2D_ARRAY: case GL_INT_SAMPLER_2D_MULTISAMPLE: case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_3D: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_BUFFER: 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_IMAGE_CUBE_MAP_ARRAY: case GL_INT_IMAGE_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case GL_IMAGE_BUFFER: case GL_INT_IMAGE_BUFFER: case GL_UNSIGNED_INT_SAMPLER_BUFFER: case GL_UNSIGNED_INT_IMAGE_BUFFER: case GL_UNSIGNED_INT_ATOMIC_COUNTER: case GL_SAMPLER_VIDEO_IMAGE_WEBGL: case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: 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); } std::string GetGLSLTypeString(GLenum type) { switch (type) { case GL_BOOL: return "bool"; case GL_INT: return "int"; case GL_UNSIGNED_INT: return "uint"; case GL_FLOAT: return "float"; case GL_BOOL_VEC2: return "bvec2"; case GL_BOOL_VEC3: return "bvec3"; case GL_BOOL_VEC4: return "bvec4"; case GL_INT_VEC2: return "ivec2"; case GL_INT_VEC3: return "ivec3"; case GL_INT_VEC4: return "ivec4"; case GL_FLOAT_VEC2: return "vec2"; case GL_FLOAT_VEC3: return "vec3"; case GL_FLOAT_VEC4: return "vec4"; case GL_UNSIGNED_INT_VEC2: return "uvec2"; case GL_UNSIGNED_INT_VEC3: return "uvec3"; case GL_UNSIGNED_INT_VEC4: return "uvec4"; case GL_FLOAT_MAT2: return "mat2"; case GL_FLOAT_MAT3: return "mat3"; case GL_FLOAT_MAT4: return "mat4"; default: UNREACHABLE(); return ""; } } 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_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_SAMPLER_CUBE_MAP_ARRAY: case GL_SAMPLER_BUFFER: 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_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_INT_SAMPLER_BUFFER: 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_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_SAMPLER_BUFFER: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_CUBE_MAP_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: case GL_IMAGE_CUBE_MAP_ARRAY: case GL_INT_IMAGE_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case GL_IMAGE_BUFFER: case GL_INT_IMAGE_BUFFER: case GL_UNSIGNED_INT_IMAGE_BUFFER: case GL_SAMPLER_VIDEO_IMAGE_WEBGL: case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: 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_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_SAMPLER_CUBE_MAP_ARRAY: case GL_SAMPLER_BUFFER: 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_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_INT_SAMPLER_BUFFER: 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_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_SAMPLER_BUFFER: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_CUBE_MAP_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_MAP_ARRAY: case GL_INT_IMAGE_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case GL_IMAGE_BUFFER: case GL_INT_IMAGE_BUFFER: case GL_UNSIGNED_INT_IMAGE_BUFFER: case GL_IMAGE_CUBE: case GL_INT_IMAGE_CUBE: case GL_UNSIGNED_INT_IMAGE_CUBE: case GL_UNSIGNED_INT_ATOMIC_COUNTER: case GL_SAMPLER_VIDEO_IMAGE_WEBGL: case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: 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_MULTISAMPLE_ARRAY: case GL_SAMPLER_CUBE_MAP_ARRAY: case GL_SAMPLER_BUFFER: 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_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_INT_SAMPLER_BUFFER: 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_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_SAMPLER_BUFFER: case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_CUBE_SHADOW: case GL_SAMPLER_2D_ARRAY_SHADOW: case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: case GL_SAMPLER_VIDEO_IMAGE_WEBGL: case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: return true; } return false; } bool IsSamplerCubeType(GLenum type) { switch (type) { case GL_SAMPLER_CUBE: case GL_INT_SAMPLER_CUBE: case GL_UNSIGNED_INT_SAMPLER_CUBE: case GL_SAMPLER_CUBE_SHADOW: return true; } return false; } bool IsSamplerYUVType(GLenum type) { switch (type) { case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: return true; default: 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_MAP_ARRAY: case GL_INT_IMAGE_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case GL_IMAGE_BUFFER: case GL_INT_IMAGE_BUFFER: case GL_UNSIGNED_INT_IMAGE_BUFFER: case GL_IMAGE_CUBE: case GL_INT_IMAGE_CUBE: case GL_UNSIGNED_INT_IMAGE_CUBE: return true; } return false; } bool IsImage2DType(GLenum type) { switch (type) { case GL_IMAGE_2D: case GL_INT_IMAGE_2D: case GL_UNSIGNED_INT_IMAGE_2D: return true; 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_MAP_ARRAY: case GL_INT_IMAGE_CUBE_MAP_ARRAY: case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case GL_IMAGE_CUBE: case GL_INT_IMAGE_CUBE: case GL_UNSIGNED_INT_IMAGE_CUBE: case GL_IMAGE_BUFFER: case GL_INT_IMAGE_BUFFER: case GL_UNSIGNED_INT_IMAGE_BUFFER: return false; default: UNREACHABLE(); 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::max() >> (std::numeric_limits::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(DrawElementsType indexType, const GLvoid *indices, size_t count, bool primitiveRestartEnabled) { switch (indexType) { case DrawElementsType::UnsignedByte: return ComputeTypedIndexRange(static_cast(indices), count, primitiveRestartEnabled, GetPrimitiveRestartIndex(indexType)); case DrawElementsType::UnsignedShort: return ComputeTypedIndexRange(static_cast(indices), count, primitiveRestartEnabled, GetPrimitiveRestartIndex(indexType)); case DrawElementsType::UnsignedInt: return ComputeTypedIndexRange(static_cast(indices), count, primitiveRestartEnabled, GetPrimitiveRestartIndex(indexType)); default: UNREACHABLE(); return IndexRange(); } } GLuint GetPrimitiveRestartIndex(DrawElementsType indexType) { switch (indexType) { case DrawElementsType::UnsignedByte: return 0xFF; case DrawElementsType::UnsignedShort: return 0xFFFF; case DrawElementsType::UnsignedInt: return 0xFFFFFFFF; default: UNREACHABLE(); return 0; } } bool IsTriangleMode(PrimitiveMode drawMode) { switch (drawMode) { case PrimitiveMode::Triangles: case PrimitiveMode::TriangleFan: case PrimitiveMode::TriangleStrip: return true; case PrimitiveMode::Points: case PrimitiveMode::Lines: case PrimitiveMode::LineLoop: case PrimitiveMode::LineStrip: return false; default: UNREACHABLE(); } return false; } bool IsPolygonMode(PrimitiveMode mode) { switch (mode) { case PrimitiveMode::Points: case PrimitiveMode::Lines: case PrimitiveMode::LineStrip: case PrimitiveMode::LineLoop: case PrimitiveMode::LinesAdjacency: case PrimitiveMode::LineStripAdjacency: return false; default: break; } return true; } namespace priv { const angle::PackedEnumMap gLineModes = { {{PrimitiveMode::LineLoop, true}, {PrimitiveMode::LineStrip, true}, {PrimitiveMode::LineStripAdjacency, true}, {PrimitiveMode::Lines, true}}}; } // namespace priv 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_2D_MULTISAMPLE_ARRAY: 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_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 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_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: 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: case GL_SAMPLER_VIDEO_IMAGE_WEBGL: case GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT: return 6; default: UNREACHABLE(); return 0; } } std::string ParseResourceName(const std::string &name, std::vector *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); } bool IsBuiltInName(const char *name) { return angle::BeginsWith(name, "gl_"); } std::string StripLastArrayIndex(const std::string &name) { size_t strippedNameLength = name.find_last_of('['); if (strippedNameLength != std::string::npos && name.back() == ']') { return name.substr(0, strippedNameLength); } return name; } bool SamplerNameContainsNonZeroArrayElement(const std::string &name) { constexpr char kZERO_ELEMENT[] = "[0]"; size_t start = 0; while (true) { start = name.find(kZERO_ELEMENT[0], start); if (start == std::string::npos) { break; } if (name.compare(start, strlen(kZERO_ELEMENT), kZERO_ELEMENT) != 0) { return true; } start++; } return false; } unsigned int ArraySizeProduct(const std::vector &arraySizes) { unsigned int arraySizeProduct = 1u; for (unsigned int arraySize : arraySizes) { arraySizeProduct *= arraySize; } return arraySizeProduct; } unsigned int InnerArraySizeProduct(const std::vector &arraySizes) { unsigned int arraySizeProduct = 1u; for (size_t index = 0; index + 1 < arraySizes.size(); ++index) { arraySizeProduct *= arraySizes[index]; } return arraySizeProduct; } unsigned int OutermostArraySize(const std::vector &arraySizes) { return arraySizes.empty() || arraySizes.back() == 0 ? 1 : arraySizes.back(); } 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; } // Leading zeroes are invalid if ((i == (open + 1)) && (name[i] == '0') && (name[i + 1] != ']')) { 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 (angle::base::IsValueInRangeForNumericType(subscript) && !(subscript == ULONG_MAX && errno == ERANGE) && !(errno != 0 && subscript == 0)) { *nameLengthWithoutArrayIndexOut = open; return static_cast(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; } } bool IsMipmapFiltered(GLenum minFilterMode) { switch (minFilterMode) { case GL_NEAREST: case GL_LINEAR: return false; case GL_NEAREST_MIPMAP_NEAREST: case GL_LINEAR_MIPMAP_NEAREST: case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: return true; default: UNREACHABLE(); return false; } } PipelineType GetPipelineType(ShaderType type) { switch (type) { case ShaderType::Vertex: case ShaderType::Fragment: case ShaderType::Geometry: return PipelineType::GraphicsPipeline; case ShaderType::Compute: return PipelineType::ComputePipeline; default: UNREACHABLE(); return PipelineType::GraphicsPipeline; } } const char *GetDebugMessageSourceString(GLenum source) { switch (source) { case GL_DEBUG_SOURCE_API: return "API"; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "Window System"; case GL_DEBUG_SOURCE_SHADER_COMPILER: return "Shader Compiler"; case GL_DEBUG_SOURCE_THIRD_PARTY: return "Third Party"; case GL_DEBUG_SOURCE_APPLICATION: return "Application"; case GL_DEBUG_SOURCE_OTHER: return "Other"; default: return "Unknown Source"; } } const char *GetDebugMessageTypeString(GLenum type) { switch (type) { case GL_DEBUG_TYPE_ERROR: return "Error"; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "Deprecated behavior"; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "Undefined behavior"; case GL_DEBUG_TYPE_PORTABILITY: return "Portability"; case GL_DEBUG_TYPE_PERFORMANCE: return "Performance"; case GL_DEBUG_TYPE_OTHER: return "Other"; case GL_DEBUG_TYPE_MARKER: return "Marker"; default: return "Unknown Type"; } } const char *GetDebugMessageSeverityString(GLenum severity) { switch (severity) { case GL_DEBUG_SEVERITY_HIGH: return "High"; case GL_DEBUG_SEVERITY_MEDIUM: return "Medium"; case GL_DEBUG_SEVERITY_LOW: return "Low"; case GL_DEBUG_SEVERITY_NOTIFICATION: return "Notification"; default: return "Unknown Severity"; } } ShaderType GetShaderTypeFromBitfield(size_t singleShaderType) { switch (singleShaderType) { case GL_VERTEX_SHADER_BIT: return ShaderType::Vertex; case GL_FRAGMENT_SHADER_BIT: return ShaderType::Fragment; case GL_COMPUTE_SHADER_BIT: return ShaderType::Compute; case GL_GEOMETRY_SHADER_BIT: return ShaderType::Geometry; case GL_TESS_CONTROL_SHADER_BIT: return ShaderType::TessControl; case GL_TESS_EVALUATION_SHADER_BIT: return ShaderType::TessEvaluation; default: return ShaderType::InvalidEnum; } } GLbitfield GetBitfieldFromShaderType(ShaderType shaderType) { switch (shaderType) { case ShaderType::Vertex: return GL_VERTEX_SHADER_BIT; case ShaderType::Fragment: return GL_FRAGMENT_SHADER_BIT; case ShaderType::Compute: return GL_COMPUTE_SHADER_BIT; case ShaderType::Geometry: return GL_GEOMETRY_SHADER_BIT; case ShaderType::TessControl: return GL_TESS_CONTROL_SHADER_BIT; case ShaderType::TessEvaluation: return GL_TESS_EVALUATION_SHADER_BIT; default: UNREACHABLE(); return GL_ZERO; } } bool ShaderTypeSupportsTransformFeedback(ShaderType shaderType) { switch (shaderType) { case ShaderType::Vertex: case ShaderType::Geometry: case ShaderType::TessEvaluation: return true; default: return false; } } ShaderType GetLastPreFragmentStage(ShaderBitSet shaderTypes) { shaderTypes.reset(ShaderType::Fragment); shaderTypes.reset(ShaderType::Compute); return shaderTypes.any() ? shaderTypes.last() : ShaderType::InvalidEnum; } } // 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(FirstCubeMapTextureTarget); } EGLenum LayerIndexToCubeMapTextureTarget(size_t index) { ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget)); return FirstCubeMapTextureTarget + static_cast(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; } bool IsExternalImageTarget(EGLenum target) { switch (target) { case EGL_NATIVE_BUFFER_ANDROID: case EGL_D3D11_TEXTURE_ANGLE: case EGL_LINUX_DMA_BUF_EXT: case EGL_METAL_TEXTURE_ANGLE: case EGL_VULKAN_IMAGE_ANGLE: return true; default: return false; } } 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_NATIVE_PIXMAP: return "Bad native pixmap."; 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(reinterpret_cast(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; } } EGLClientBuffer GLObjectHandleToEGLClientBuffer(GLuint handle) { return reinterpret_cast(static_cast(handle)); } } // namespace gl_egl namespace angle { bool IsDrawEntryPoint(EntryPoint entryPoint) { switch (entryPoint) { case EntryPoint::GLDrawArrays: case EntryPoint::GLDrawArraysIndirect: case EntryPoint::GLDrawArraysInstanced: case EntryPoint::GLDrawArraysInstancedANGLE: case EntryPoint::GLDrawArraysInstancedBaseInstance: case EntryPoint::GLDrawArraysInstancedBaseInstanceANGLE: case EntryPoint::GLDrawArraysInstancedEXT: case EntryPoint::GLDrawElements: case EntryPoint::GLDrawElementsBaseVertex: case EntryPoint::GLDrawElementsBaseVertexEXT: case EntryPoint::GLDrawElementsBaseVertexOES: case EntryPoint::GLDrawElementsIndirect: case EntryPoint::GLDrawElementsInstanced: case EntryPoint::GLDrawElementsInstancedANGLE: case EntryPoint::GLDrawElementsInstancedBaseInstance: case EntryPoint::GLDrawElementsInstancedBaseVertex: case EntryPoint::GLDrawElementsInstancedBaseVertexBaseInstance: case EntryPoint::GLDrawElementsInstancedBaseVertexBaseInstanceANGLE: case EntryPoint::GLDrawElementsInstancedBaseVertexEXT: case EntryPoint::GLDrawElementsInstancedBaseVertexOES: case EntryPoint::GLDrawElementsInstancedEXT: case EntryPoint::GLDrawPixels: case EntryPoint::GLDrawRangeElements: case EntryPoint::GLDrawRangeElementsBaseVertex: case EntryPoint::GLDrawRangeElementsBaseVertexEXT: case EntryPoint::GLDrawRangeElementsBaseVertexOES: case EntryPoint::GLDrawTexfOES: case EntryPoint::GLDrawTexfvOES: case EntryPoint::GLDrawTexiOES: case EntryPoint::GLDrawTexivOES: case EntryPoint::GLDrawTexsOES: case EntryPoint::GLDrawTexsvOES: case EntryPoint::GLDrawTexxOES: case EntryPoint::GLDrawTexxvOES: case EntryPoint::GLDrawTransformFeedback: case EntryPoint::GLDrawTransformFeedbackInstanced: case EntryPoint::GLDrawTransformFeedbackStream: case EntryPoint::GLDrawTransformFeedbackStreamInstanced: return true; default: return false; } } bool IsDispatchEntryPoint(EntryPoint entryPoint) { switch (entryPoint) { case EntryPoint::GLDispatchCompute: case EntryPoint::GLDispatchComputeIndirect: return true; default: return false; } } bool IsClearEntryPoint(EntryPoint entryPoint) { switch (entryPoint) { case EntryPoint::GLClear: case EntryPoint::GLClearBufferfi: case EntryPoint::GLClearBufferfv: case EntryPoint::GLClearBufferiv: case EntryPoint::GLClearBufferuiv: return true; default: return false; } } bool IsQueryEntryPoint(EntryPoint entryPoint) { switch (entryPoint) { case EntryPoint::GLBeginQuery: case EntryPoint::GLBeginQueryEXT: case EntryPoint::GLBeginQueryIndexed: case EntryPoint::GLEndQuery: case EntryPoint::GLEndQueryEXT: case EntryPoint::GLEndQueryIndexed: return true; default: return false; } } } // namespace angle #if !defined(ANGLE_ENABLE_WINDOWS_UWP) 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_UWP #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