| // |
| // 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. |
| |
| // Older clang versions have a false positive on this warning here. |
| #pragma clang diagnostic ignored "-Wglobal-constructors" |
| |
| #include "common/utilities.h" |
| #include <GLSLANG/ShaderVars.h> |
| #include "common/mathutil.h" |
| #include "common/platform.h" |
| |
| #include <set> |
| |
| #if defined(ANGLE_ENABLE_WINDOWS_UWP) |
| # include <windows.applicationmodel.core.h> |
| # include <windows.graphics.display.h> |
| # include <wrl.h> |
| # include <wrl/wrappers/corewrappers.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_SAMPLER_2D_MULTISAMPLE_ARRAY: |
| 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_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_SAMPLER_2D_MULTISAMPLE_ARRAY: |
| 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_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_SAMPLER_2D_MULTISAMPLE_ARRAY: |
| 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_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_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_MULTISAMPLE_ARRAY: |
| 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_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_CUBE_SHADOW: |
| case GL_SAMPLER_2D_ARRAY_SHADOW: |
| 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 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 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: |
| case GL_INT_IMAGE_CUBE: |
| case GL_UNSIGNED_INT_IMAGE_CUBE: |
| 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<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(DrawElementsType indexType, |
| const GLvoid *indices, |
| size_t count, |
| bool primitiveRestartEnabled) |
| { |
| switch (indexType) |
| { |
| case DrawElementsType::UnsignedByte: |
| return ComputeTypedIndexRange(static_cast<const GLubyte *>(indices), count, |
| primitiveRestartEnabled, |
| GetPrimitiveRestartIndex(indexType)); |
| case DrawElementsType::UnsignedShort: |
| return ComputeTypedIndexRange(static_cast<const GLushort *>(indices), count, |
| primitiveRestartEnabled, |
| GetPrimitiveRestartIndex(indexType)); |
| case DrawElementsType::UnsignedInt: |
| return ComputeTypedIndexRange(static_cast<const GLuint *>(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<PrimitiveMode, bool> 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: |
| 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); |
| } |
| |
| 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; |
| } |
| |
| const sh::ShaderVariable *FindShaderVarField(const sh::ShaderVariable &var, |
| const std::string &fullName, |
| GLuint *fieldIndexOut) |
| { |
| 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 (size_t field = 0; field < var.fields.size(); ++field) |
| { |
| if (var.fields[field].name == fieldName) |
| { |
| *fieldIndexOut = static_cast<GLuint>(field); |
| return &var.fields[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 (angle::base::IsValueInRangeForNumericType<uint32_t>(subscript) && |
| !(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; |
| } |
| } |
| |
| 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; |
| } |
| } |
| |
| } // 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; |
| } |
| |
| bool IsExternalImageTarget(EGLenum target) |
| { |
| switch (target) |
| { |
| case EGL_NATIVE_BUFFER_ANDROID: |
| case EGL_D3D11_TEXTURE_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_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; |
| } |
| } |
| |
| EGLClientBuffer GLObjectHandleToEGLClientBuffer(GLuint handle) |
| { |
| return reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(handle)); |
| } |
| |
| } // namespace gl_egl |
| |
| #if !defined(ANGLE_ENABLE_WINDOWS_UWP) |
| 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_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 |