1// Copyright 2017 The ANGLE Project Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// PackedGLEnums_autogen.h:
6//   Declares ANGLE-specific enums classes for GLEnum and functions operating
7//   on them.
8
9#ifndef COMMON_PACKEDGLENUMS_H_
10#define COMMON_PACKEDGLENUMS_H_
11
12#include "common/PackedEGLEnums_autogen.h"
13#include "common/PackedGLEnums_autogen.h"
14
15#include <array>
16#include <bitset>
17#include <cstddef>
18
19#include <EGL/egl.h>
20
21#include "common/bitset_utils.h"
22
23namespace angle
24{
25
26// Return the number of elements of a packed enum, including the InvalidEnum element.
27template <typename E>
28constexpr size_t EnumSize()
29{
30    using UnderlyingType = typename std::underlying_type<E>::type;
31    return static_cast<UnderlyingType>(E::EnumCount);
32}
33
34// Implementation of AllEnums which allows iterating over all the possible values for a packed enums
35// like so:
36//     for (auto value : AllEnums<MyPackedEnum>()) {
37//         // Do something with the enum.
38//     }
39
40template <typename E>
41class EnumIterator final
42{
43  private:
44    using UnderlyingType = typename std::underlying_type<E>::type;
45
46  public:
47    EnumIterator(E value) : mValue(static_cast<UnderlyingType>(value)) {}
48    EnumIterator &operator++()
49    {
50        mValue++;
51        return *this;
52    }
53    bool operator==(const EnumIterator &other) const { return mValue == other.mValue; }
54    bool operator!=(const EnumIterator &other) const { return mValue != other.mValue; }
55    E operator*() const { return static_cast<E>(mValue); }
56
57  private:
58    UnderlyingType mValue;
59};
60
61template <typename E, size_t MaxSize = EnumSize<E>()>
62struct AllEnums
63{
64    EnumIterator<E> begin() const { return {static_cast<E>(0)}; }
65    EnumIterator<E> end() const { return {static_cast<E>(MaxSize)}; }
66};
67
68// PackedEnumMap<E, T> is like an std::array<T, E::EnumCount> but is indexed with enum values. It
69// implements all of the std::array interface except with enum values instead of indices.
70template <typename E, typename T, size_t MaxSize = EnumSize<E>()>
71class PackedEnumMap
72{
73    using UnderlyingType = typename std::underlying_type<E>::type;
74    using Storage        = std::array<T, MaxSize>;
75
76  public:
77    using InitPair = std::pair<E, T>;
78
79    constexpr PackedEnumMap() = default;
80
81    constexpr PackedEnumMap(std::initializer_list<InitPair> init) : mPrivateData{}
82    {
83        // We use a for loop instead of range-for to work around a limitation in MSVC.
84        for (const InitPair *it = init.begin(); it != init.end(); ++it)
85        {
86#if (__cplusplus < 201703L)
87            // This horrible const_cast pattern is necessary to work around a constexpr limitation.
88            // See https://stackoverflow.com/q/34199774/ . Note that it should be fixed with C++17.
89            const_cast<T &>(const_cast<const Storage &>(
90                mPrivateData)[static_cast<UnderlyingType>(it->first)]) = it->second;
91#else
92            mPrivateData[static_cast<UnderlyingType>(it->first)] = it->second;
93#endif
94        }
95    }
96
97    // types:
98    using value_type      = T;
99    using pointer         = T *;
100    using const_pointer   = const T *;
101    using reference       = T &;
102    using const_reference = const T &;
103
104    using size_type       = size_t;
105    using difference_type = ptrdiff_t;
106
107    using iterator               = typename Storage::iterator;
108    using const_iterator         = typename Storage::const_iterator;
109    using reverse_iterator       = std::reverse_iterator<iterator>;
110    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
111
112    // No explicit construct/copy/destroy for aggregate type
113    void fill(const T &u) { mPrivateData.fill(u); }
114    void swap(PackedEnumMap<E, T, MaxSize> &a) noexcept { mPrivateData.swap(a.mPrivateData); }
115
116    // iterators:
117    iterator begin() noexcept { return mPrivateData.begin(); }
118    const_iterator begin() const noexcept { return mPrivateData.begin(); }
119    iterator end() noexcept { return mPrivateData.end(); }
120    const_iterator end() const noexcept { return mPrivateData.end(); }
121
122    reverse_iterator rbegin() noexcept { return mPrivateData.rbegin(); }
123    const_reverse_iterator rbegin() const noexcept { return mPrivateData.rbegin(); }
124    reverse_iterator rend() noexcept { return mPrivateData.rend(); }
125    const_reverse_iterator rend() const noexcept { return mPrivateData.rend(); }
126
127    // capacity:
128    constexpr size_type size() const noexcept { return mPrivateData.size(); }
129    constexpr size_type max_size() const noexcept { return mPrivateData.max_size(); }
130    constexpr bool empty() const noexcept { return mPrivateData.empty(); }
131
132    // element access:
133    reference operator[](E n)
134    {
135        ASSERT(static_cast<size_t>(n) < mPrivateData.size());
136        return mPrivateData[static_cast<UnderlyingType>(n)];
137    }
138
139    constexpr const_reference operator[](E n) const
140    {
141        ASSERT(static_cast<size_t>(n) < mPrivateData.size());
142        return mPrivateData[static_cast<UnderlyingType>(n)];
143    }
144
145    const_reference at(E n) const { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
146    reference at(E n) { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
147
148    reference front() { return mPrivateData.front(); }
149    const_reference front() const { return mPrivateData.front(); }
150    reference back() { return mPrivateData.back(); }
151    const_reference back() const { return mPrivateData.back(); }
152
153    T *data() noexcept { return mPrivateData.data(); }
154    const T *data() const noexcept { return mPrivateData.data(); }
155
156    bool operator==(const PackedEnumMap &rhs) const { return mPrivateData == rhs.mPrivateData; }
157    bool operator!=(const PackedEnumMap &rhs) const { return mPrivateData != rhs.mPrivateData; }
158
159    template <typename SubT = T>
160    typename std::enable_if<std::is_integral<SubT>::value>::type operator+=(
161        const PackedEnumMap<E, SubT, MaxSize> &rhs)
162    {
163        for (E e : AllEnums<E, MaxSize>())
164        {
165            at(e) += rhs[e];
166        }
167    }
168
169  private:
170    Storage mPrivateData;
171};
172
173// PackedEnumBitSetE> is like an std::bitset<E::EnumCount> but is indexed with enum values. It
174// implements the std::bitset interface except with enum values instead of indices.
175template <typename E, typename DataT = uint32_t>
176using PackedEnumBitSet = BitSetT<EnumSize<E>(), DataT, E>;
177
178}  // namespace angle
179
180namespace gl
181{
182
183TextureType TextureTargetToType(TextureTarget target);
184TextureTarget NonCubeTextureTypeToTarget(TextureType type);
185
186TextureTarget CubeFaceIndexToTextureTarget(size_t face);
187size_t CubeMapTextureTargetToFaceIndex(TextureTarget target);
188bool IsCubeMapFaceTarget(TextureTarget target);
189
190constexpr TextureTarget kCubeMapTextureTargetMin = TextureTarget::CubeMapPositiveX;
191constexpr TextureTarget kCubeMapTextureTargetMax = TextureTarget::CubeMapNegativeZ;
192constexpr TextureTarget kAfterCubeMapTextureTargetMax =
193    static_cast<TextureTarget>(static_cast<uint8_t>(kCubeMapTextureTargetMax) + 1);
194struct AllCubeFaceTextureTargets
195{
196    angle::EnumIterator<TextureTarget> begin() const { return kCubeMapTextureTargetMin; }
197    angle::EnumIterator<TextureTarget> end() const { return kAfterCubeMapTextureTargetMax; }
198};
199
200constexpr std::array<ShaderType, 2> kAllGLES2ShaderTypes = {ShaderType::Vertex,
201                                                            ShaderType::Fragment};
202
203constexpr ShaderType kShaderTypeMin = ShaderType::Vertex;
204constexpr ShaderType kShaderTypeMax = ShaderType::Compute;
205constexpr ShaderType kAfterShaderTypeMax =
206    static_cast<ShaderType>(static_cast<uint8_t>(kShaderTypeMax) + 1);
207struct AllShaderTypes
208{
209    angle::EnumIterator<ShaderType> begin() const { return kShaderTypeMin; }
210    angle::EnumIterator<ShaderType> end() const { return kAfterShaderTypeMax; }
211};
212
213constexpr size_t kGraphicsShaderCount = static_cast<size_t>(ShaderType::EnumCount) - 1u;
214// Arrange the shader types in the order of rendering pipeline
215constexpr std::array<ShaderType, kGraphicsShaderCount> kAllGraphicsShaderTypes = {
216    ShaderType::Vertex, ShaderType::TessControl, ShaderType::TessEvaluation, ShaderType::Geometry,
217    ShaderType::Fragment};
218
219using ShaderBitSet = angle::PackedEnumBitSet<ShaderType, uint8_t>;
220static_assert(sizeof(ShaderBitSet) == sizeof(uint8_t), "Unexpected size");
221
222template <typename T>
223using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
224
225const char *ShaderTypeToString(ShaderType shaderType);
226
227TextureType SamplerTypeToTextureType(GLenum samplerType);
228TextureType ImageTypeToTextureType(GLenum imageType);
229
230bool IsMultisampled(gl::TextureType type);
231bool IsArrayTextureType(gl::TextureType type);
232
233bool IsStaticBufferUsage(BufferUsage useage);
234
235enum class PrimitiveMode : uint8_t
236{
237    Points                 = 0x0,
238    Lines                  = 0x1,
239    LineLoop               = 0x2,
240    LineStrip              = 0x3,
241    Triangles              = 0x4,
242    TriangleStrip          = 0x5,
243    TriangleFan            = 0x6,
244    Unused1                = 0x7,
245    Unused2                = 0x8,
246    Unused3                = 0x9,
247    LinesAdjacency         = 0xA,
248    LineStripAdjacency     = 0xB,
249    TrianglesAdjacency     = 0xC,
250    TriangleStripAdjacency = 0xD,
251    Patches                = 0xE,
252
253    InvalidEnum = 0xF,
254    EnumCount   = 0xF,
255};
256
257template <>
258constexpr PrimitiveMode FromGLenum<PrimitiveMode>(GLenum from)
259{
260    if (from >= static_cast<GLenum>(PrimitiveMode::EnumCount))
261    {
262        return PrimitiveMode::InvalidEnum;
263    }
264
265    return static_cast<PrimitiveMode>(from);
266}
267
268constexpr GLenum ToGLenum(PrimitiveMode from)
269{
270    return static_cast<GLenum>(from);
271}
272
273static_assert(ToGLenum(PrimitiveMode::Points) == GL_POINTS, "PrimitiveMode violation");
274static_assert(ToGLenum(PrimitiveMode::Lines) == GL_LINES, "PrimitiveMode violation");
275static_assert(ToGLenum(PrimitiveMode::LineLoop) == GL_LINE_LOOP, "PrimitiveMode violation");
276static_assert(ToGLenum(PrimitiveMode::LineStrip) == GL_LINE_STRIP, "PrimitiveMode violation");
277static_assert(ToGLenum(PrimitiveMode::Triangles) == GL_TRIANGLES, "PrimitiveMode violation");
278static_assert(ToGLenum(PrimitiveMode::TriangleStrip) == GL_TRIANGLE_STRIP,
279              "PrimitiveMode violation");
280static_assert(ToGLenum(PrimitiveMode::TriangleFan) == GL_TRIANGLE_FAN, "PrimitiveMode violation");
281static_assert(ToGLenum(PrimitiveMode::LinesAdjacency) == GL_LINES_ADJACENCY,
282              "PrimitiveMode violation");
283static_assert(ToGLenum(PrimitiveMode::LineStripAdjacency) == GL_LINE_STRIP_ADJACENCY,
284              "PrimitiveMode violation");
285static_assert(ToGLenum(PrimitiveMode::TrianglesAdjacency) == GL_TRIANGLES_ADJACENCY,
286              "PrimitiveMode violation");
287static_assert(ToGLenum(PrimitiveMode::TriangleStripAdjacency) == GL_TRIANGLE_STRIP_ADJACENCY,
288              "PrimitiveMode violation");
289
290std::ostream &operator<<(std::ostream &os, PrimitiveMode value);
291
292enum class DrawElementsType : size_t
293{
294    UnsignedByte  = 0,
295    UnsignedShort = 1,
296    UnsignedInt   = 2,
297    InvalidEnum   = 3,
298    EnumCount     = 3,
299};
300
301template <>
302constexpr DrawElementsType FromGLenum<DrawElementsType>(GLenum from)
303{
304
305    GLenum scaled = (from - GL_UNSIGNED_BYTE);
306    // This code sequence generates a ROR instruction on x86/arm. We want to check if the lowest bit
307    // of scaled is set and if (scaled >> 1) is greater than a non-pot value. If we rotate the
308    // lowest bit to the hightest bit both conditions can be checked with a single test.
309    static_assert(sizeof(GLenum) == 4, "Update (scaled << 31) to sizeof(GLenum) * 8 - 1");
310    GLenum packed = (scaled >> 1) | (scaled << 31);
311
312    // operator ? with a simple assignment usually translates to a cmov instruction and thus avoids
313    // a branch.
314    packed = (packed >= static_cast<GLenum>(DrawElementsType::EnumCount))
315                 ? static_cast<GLenum>(DrawElementsType::InvalidEnum)
316                 : packed;
317
318    return static_cast<DrawElementsType>(packed);
319}
320
321constexpr GLenum ToGLenum(DrawElementsType from)
322{
323    return ((static_cast<GLenum>(from) << 1) + GL_UNSIGNED_BYTE);
324}
325
326#define ANGLE_VALIDATE_PACKED_ENUM(type, packed, glenum)                 \
327    static_assert(ToGLenum(type::packed) == glenum, #type " violation"); \
328    static_assert(FromGLenum<type>(glenum) == type::packed, #type " violation")
329
330ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedByte, GL_UNSIGNED_BYTE);
331ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedShort, GL_UNSIGNED_SHORT);
332ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedInt, GL_UNSIGNED_INT);
333
334std::ostream &operator<<(std::ostream &os, DrawElementsType value);
335
336enum class BlendEquationType
337{
338    Add             = 0,  // GLenum == 0x8006
339    Min             = 1,  // GLenum == 0x8007
340    Max             = 2,  // GLenum == 0x8008
341    Unused          = 3,
342    Subtract        = 4,  // GLenum == 0x800A
343    ReverseSubtract = 5,  // GLenum == 0x800B
344    InvalidEnum     = 6,
345    EnumCount       = 6
346};
347
348template <>
349constexpr BlendEquationType FromGLenum<BlendEquationType>(GLenum from)
350{
351    const GLenum scaled = (from - GL_FUNC_ADD);
352    return (scaled == static_cast<GLenum>(BlendEquationType::Unused) ||
353            scaled >= static_cast<GLenum>(BlendEquationType::EnumCount))
354               ? BlendEquationType::InvalidEnum
355               : static_cast<BlendEquationType>(scaled);
356}
357
358constexpr GLenum ToGLenum(BlendEquationType from)
359{
360    return static_cast<GLenum>(from) + GL_FUNC_ADD;
361}
362
363ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Add, GL_FUNC_ADD);
364ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Min, GL_MIN);
365ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Max, GL_MAX);
366ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Subtract, GL_FUNC_SUBTRACT);
367ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, ReverseSubtract, GL_FUNC_REVERSE_SUBTRACT);
368
369std::ostream &operator<<(std::ostream &os, BlendEquationType value);
370
371enum class BlendFactorType
372{
373    Zero = 0,  // GLenum == 0
374    One  = 1,  // GLenum == 1
375
376    MinSrcDstType    = 2,
377    SrcColor         = 2,   // GLenum == 0x0300
378    OneMinusSrcColor = 3,   // GLenum == 0x0301
379    SrcAlpha         = 4,   // GLenum == 0x0302
380    OneMinusSrcAlpha = 5,   // GLenum == 0x0303
381    DstAlpha         = 6,   // GLenum == 0x0304
382    OneMinusDstAlpha = 7,   // GLenum == 0x0305
383    DstColor         = 8,   // GLenum == 0x0306
384    OneMinusDstColor = 9,   // GLenum == 0x0307
385    SrcAlphaSaturate = 10,  // GLenum == 0x0308
386    MaxSrcDstType    = 10,
387
388    MinConstantType       = 11,
389    ConstantColor         = 11,  // GLenum == 0x8001
390    OneMinusConstantColor = 12,  // GLenum == 0x8002
391    ConstantAlpha         = 13,  // GLenum == 0x8003
392    OneMinusConstantAlpha = 14,  // GLenum == 0x8004
393    MaxConstantType       = 14,
394
395    // GL_EXT_blend_func_extended
396
397    Src1Alpha = 15,  // GLenum == 0x8589
398
399    Src1Color         = 16,  // GLenum == 0x88F9
400    OneMinusSrc1Color = 17,  // GLenum == 0x88FA
401    OneMinusSrc1Alpha = 18,  // GLenum == 0x88FB
402
403    InvalidEnum = 19,
404    EnumCount   = 19
405};
406
407template <>
408constexpr BlendFactorType FromGLenum<BlendFactorType>(GLenum from)
409{
410    if (from <= 1)
411        return static_cast<BlendFactorType>(from);
412    if (from >= GL_SRC_COLOR && from <= GL_SRC_ALPHA_SATURATE)
413        return static_cast<BlendFactorType>(from - GL_SRC_COLOR + 2);
414    if (from >= GL_CONSTANT_COLOR && from <= GL_ONE_MINUS_CONSTANT_ALPHA)
415        return static_cast<BlendFactorType>(from - GL_CONSTANT_COLOR + 11);
416    if (from == GL_SRC1_ALPHA_EXT)
417        return BlendFactorType::Src1Alpha;
418    if (from >= GL_SRC1_COLOR_EXT && from <= GL_ONE_MINUS_SRC1_ALPHA_EXT)
419        return static_cast<BlendFactorType>(from - GL_SRC1_COLOR_EXT + 16);
420    return BlendFactorType::InvalidEnum;
421}
422
423constexpr GLenum ToGLenum(BlendFactorType from)
424{
425    const GLenum value = static_cast<GLenum>(from);
426    if (value <= 1)
427        return value;
428    if (from >= BlendFactorType::MinSrcDstType && from <= BlendFactorType::MaxSrcDstType)
429        return value - 2 + GL_SRC_COLOR;
430    if (from >= BlendFactorType::MinConstantType && from <= BlendFactorType::MaxConstantType)
431        return value - 11 + GL_CONSTANT_COLOR;
432    if (from == BlendFactorType::Src1Alpha)
433        return GL_SRC1_ALPHA_EXT;
434    return value - 16 + GL_SRC1_COLOR_EXT;
435}
436
437ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, Zero, GL_ZERO);
438ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, One, GL_ONE);
439ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, SrcColor, GL_SRC_COLOR);
440ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrcColor, GL_ONE_MINUS_SRC_COLOR);
441ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, SrcAlpha, GL_SRC_ALPHA);
442ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrcAlpha, GL_ONE_MINUS_SRC_ALPHA);
443ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, DstAlpha, GL_DST_ALPHA);
444ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusDstAlpha, GL_ONE_MINUS_DST_ALPHA);
445ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, DstColor, GL_DST_COLOR);
446ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusDstColor, GL_ONE_MINUS_DST_COLOR);
447ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, SrcAlphaSaturate, GL_SRC_ALPHA_SATURATE);
448ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, ConstantColor, GL_CONSTANT_COLOR);
449ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusConstantColor, GL_ONE_MINUS_CONSTANT_COLOR);
450ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, ConstantAlpha, GL_CONSTANT_ALPHA);
451ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusConstantAlpha, GL_ONE_MINUS_CONSTANT_ALPHA);
452ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, Src1Alpha, GL_SRC1_ALPHA_EXT);
453ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, Src1Color, GL_SRC1_COLOR_EXT);
454ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrc1Color, GL_ONE_MINUS_SRC1_COLOR_EXT);
455ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrc1Alpha, GL_ONE_MINUS_SRC1_ALPHA_EXT);
456
457std::ostream &operator<<(std::ostream &os, BlendFactorType value);
458
459enum class VertexAttribType
460{
461    Byte               = 0,   // GLenum == 0x1400
462    UnsignedByte       = 1,   // GLenum == 0x1401
463    Short              = 2,   // GLenum == 0x1402
464    UnsignedShort      = 3,   // GLenum == 0x1403
465    Int                = 4,   // GLenum == 0x1404
466    UnsignedInt        = 5,   // GLenum == 0x1405
467    Float              = 6,   // GLenum == 0x1406
468    Unused1            = 7,   // GLenum == 0x1407
469    Unused2            = 8,   // GLenum == 0x1408
470    Unused3            = 9,   // GLenum == 0x1409
471    Unused4            = 10,  // GLenum == 0x140A
472    HalfFloat          = 11,  // GLenum == 0x140B
473    Fixed              = 12,  // GLenum == 0x140C
474    MaxBasicType       = 12,
475    UnsignedInt2101010 = 13,  // GLenum == 0x8368
476    HalfFloatOES       = 14,  // GLenum == 0x8D61
477    Int2101010         = 15,  // GLenum == 0x8D9F
478    UnsignedInt1010102 = 16,  // GLenum == 0x8DF6
479    Int1010102         = 17,  // GLenum == 0x8DF7
480    InvalidEnum        = 18,
481    EnumCount          = 18,
482};
483
484template <>
485constexpr VertexAttribType FromGLenum<VertexAttribType>(GLenum from)
486{
487    GLenum packed = from - GL_BYTE;
488    if (packed <= static_cast<GLenum>(VertexAttribType::MaxBasicType))
489        return static_cast<VertexAttribType>(packed);
490    if (from == GL_UNSIGNED_INT_2_10_10_10_REV)
491        return VertexAttribType::UnsignedInt2101010;
492    if (from == GL_HALF_FLOAT_OES)
493        return VertexAttribType::HalfFloatOES;
494    if (from == GL_INT_2_10_10_10_REV)
495        return VertexAttribType::Int2101010;
496    if (from == GL_UNSIGNED_INT_10_10_10_2_OES)
497        return VertexAttribType::UnsignedInt1010102;
498    if (from == GL_INT_10_10_10_2_OES)
499        return VertexAttribType::Int1010102;
500    return VertexAttribType::InvalidEnum;
501}
502
503constexpr GLenum ToGLenum(VertexAttribType from)
504{
505    // This could be optimized using a constexpr table.
506    if (from == VertexAttribType::Int2101010)
507        return GL_INT_2_10_10_10_REV;
508    if (from == VertexAttribType::HalfFloatOES)
509        return GL_HALF_FLOAT_OES;
510    if (from == VertexAttribType::UnsignedInt2101010)
511        return GL_UNSIGNED_INT_2_10_10_10_REV;
512    if (from == VertexAttribType::UnsignedInt1010102)
513        return GL_UNSIGNED_INT_10_10_10_2_OES;
514    if (from == VertexAttribType::Int1010102)
515        return GL_INT_10_10_10_2_OES;
516    return static_cast<GLenum>(from) + GL_BYTE;
517}
518
519ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Byte, GL_BYTE);
520ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedByte, GL_UNSIGNED_BYTE);
521ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Short, GL_SHORT);
522ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedShort, GL_UNSIGNED_SHORT);
523ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int, GL_INT);
524ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt, GL_UNSIGNED_INT);
525ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Float, GL_FLOAT);
526ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloat, GL_HALF_FLOAT);
527ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Fixed, GL_FIXED);
528ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int2101010, GL_INT_2_10_10_10_REV);
529ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloatOES, GL_HALF_FLOAT_OES);
530ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt2101010, GL_UNSIGNED_INT_2_10_10_10_REV);
531ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int1010102, GL_INT_10_10_10_2_OES);
532ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt1010102, GL_UNSIGNED_INT_10_10_10_2_OES);
533
534std::ostream &operator<<(std::ostream &os, VertexAttribType value);
535
536enum class TessEvaluationType
537{
538    Triangles             = 0,
539    Quads                 = 1,
540    Isolines              = 2,
541    EqualSpacing          = 3,
542    FractionalEvenSpacing = 4,
543    FractionalOddSpacing  = 5,
544    Cw                    = 6,
545    Ccw                   = 7,
546    PointMode             = 8,
547    InvalidEnum           = 9,
548    EnumCount             = 9
549};
550
551template <>
552constexpr TessEvaluationType FromGLenum<TessEvaluationType>(GLenum from)
553{
554    if (from == GL_TRIANGLES)
555        return TessEvaluationType::Triangles;
556    if (from == GL_QUADS)
557        return TessEvaluationType::Quads;
558    if (from == GL_ISOLINES)
559        return TessEvaluationType::Isolines;
560    if (from == GL_EQUAL)
561        return TessEvaluationType::EqualSpacing;
562    if (from == GL_FRACTIONAL_EVEN)
563        return TessEvaluationType::FractionalEvenSpacing;
564    if (from == GL_FRACTIONAL_ODD)
565        return TessEvaluationType::FractionalOddSpacing;
566    if (from == GL_CW)
567        return TessEvaluationType::Cw;
568    if (from == GL_CCW)
569        return TessEvaluationType::Ccw;
570    if (from == GL_TESS_GEN_POINT_MODE)
571        return TessEvaluationType::PointMode;
572    return TessEvaluationType::InvalidEnum;
573}
574
575constexpr GLenum ToGLenum(TessEvaluationType from)
576{
577    switch (from)
578    {
579        case TessEvaluationType::Triangles:
580            return GL_TRIANGLES;
581        case TessEvaluationType::Quads:
582            return GL_QUADS;
583        case TessEvaluationType::Isolines:
584            return GL_ISOLINES;
585        case TessEvaluationType::EqualSpacing:
586            return GL_EQUAL;
587        case TessEvaluationType::FractionalEvenSpacing:
588            return GL_FRACTIONAL_EVEN;
589        case TessEvaluationType::FractionalOddSpacing:
590            return GL_FRACTIONAL_ODD;
591        case TessEvaluationType::Cw:
592            return GL_CW;
593        case TessEvaluationType::Ccw:
594            return GL_CCW;
595        case TessEvaluationType::PointMode:
596            return GL_TESS_GEN_POINT_MODE;
597        default:
598            return GL_INVALID_ENUM;
599    }
600}
601
602ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Triangles, GL_TRIANGLES);
603ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Quads, GL_QUADS);
604ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Isolines, GL_ISOLINES);
605ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, EqualSpacing, GL_EQUAL);
606ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, FractionalEvenSpacing, GL_FRACTIONAL_EVEN);
607ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, FractionalOddSpacing, GL_FRACTIONAL_ODD);
608ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Cw, GL_CW);
609ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Ccw, GL_CCW);
610ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, PointMode, GL_TESS_GEN_POINT_MODE);
611
612std::ostream &operator<<(std::ostream &os, TessEvaluationType value);
613
614// Typesafe object handles.
615
616template <typename T>
617struct ResourceTypeToID;
618
619template <typename T>
620struct IsResourceIDType;
621
622// Clang Format doesn't like the following X macro.
623// clang-format off
624#define ANGLE_ID_TYPES_OP(X) \
625    X(Buffer)                \
626    X(FenceNV)               \
627    X(Framebuffer)           \
628    X(MemoryObject)          \
629    X(Path)                  \
630    X(ProgramPipeline)       \
631    X(Query)                 \
632    X(Renderbuffer)          \
633    X(Sampler)               \
634    X(Semaphore)             \
635    X(Texture)               \
636    X(TransformFeedback)     \
637    X(VertexArray)
638// clang-format on
639
640#define ANGLE_DEFINE_ID_TYPE(Type)          \
641    class Type;                             \
642    struct Type##ID                         \
643    {                                       \
644        GLuint value;                       \
645    };                                      \
646    template <>                             \
647    struct ResourceTypeToID<Type>           \
648    {                                       \
649        using IDType = Type##ID;            \
650    };                                      \
651    template <>                             \
652    struct IsResourceIDType<Type##ID>       \
653    {                                       \
654        static constexpr bool value = true; \
655    };
656
657ANGLE_ID_TYPES_OP(ANGLE_DEFINE_ID_TYPE)
658
659#undef ANGLE_DEFINE_ID_TYPE
660#undef ANGLE_ID_TYPES_OP
661
662// Shaders and programs are a bit special as they share IDs.
663struct ShaderProgramID
664{
665    GLuint value;
666};
667
668template <>
669struct IsResourceIDType<ShaderProgramID>
670{
671    constexpr static bool value = true;
672};
673
674class Shader;
675template <>
676struct ResourceTypeToID<Shader>
677{
678    using IDType = ShaderProgramID;
679};
680
681class Program;
682template <>
683struct ResourceTypeToID<Program>
684{
685    using IDType = ShaderProgramID;
686};
687
688template <typename T>
689struct ResourceTypeToID
690{
691    using IDType = void;
692};
693
694template <typename T>
695struct IsResourceIDType
696{
697    static constexpr bool value = false;
698};
699
700template <typename T>
701bool ValueEquals(T lhs, T rhs)
702{
703    return lhs.value == rhs.value;
704}
705
706// Util funcs for resourceIDs
707template <typename T>
708typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator==(const T &lhs,
709                                                                           const T &rhs)
710{
711    return lhs.value == rhs.value;
712}
713
714template <typename T>
715typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator!=(const T &lhs,
716                                                                           const T &rhs)
717{
718    return lhs.value != rhs.value;
719}
720
721template <typename T>
722typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator<(const T &lhs,
723                                                                          const T &rhs)
724{
725    return lhs.value < rhs.value;
726}
727
728// Used to unbox typed values.
729template <typename ResourceIDType>
730GLuint GetIDValue(ResourceIDType id);
731
732template <>
733inline GLuint GetIDValue(GLuint id)
734{
735    return id;
736}
737
738template <typename ResourceIDType>
739inline GLuint GetIDValue(ResourceIDType id)
740{
741    return id.value;
742}
743
744// First case: handling packed enums.
745template <typename EnumT, typename FromT>
746typename std::enable_if<std::is_enum<EnumT>::value, EnumT>::type PackParam(FromT from)
747{
748    return FromGLenum<EnumT>(from);
749}
750
751// Second case: handling non-pointer resource ids.
752template <typename EnumT, typename FromT>
753typename std::enable_if<!std::is_pointer<FromT>::value && !std::is_enum<EnumT>::value, EnumT>::type
754PackParam(FromT from)
755{
756    return {from};
757}
758
759// Third case: handling pointer resource ids.
760template <typename EnumT, typename FromT>
761typename std::enable_if<std::is_pointer<FromT>::value && !std::is_enum<EnumT>::value, EnumT>::type
762PackParam(FromT from)
763{
764    static_assert(sizeof(typename std::remove_pointer<EnumT>::type) ==
765                      sizeof(typename std::remove_pointer<FromT>::type),
766                  "Types have different sizes");
767    static_assert(
768        std::is_same<
769            decltype(std::remove_pointer<EnumT>::type::value),
770            typename std::remove_const<typename std::remove_pointer<FromT>::type>::type>::value,
771        "Data types are different");
772    return reinterpret_cast<EnumT>(from);
773}
774
775struct UniformLocation
776{
777    int value;
778};
779
780struct UniformBlockIndex
781{
782    uint32_t value;
783};
784}  // namespace gl
785
786namespace egl
787{
788MessageType ErrorCodeToMessageType(EGLint errorCode);
789}  // namespace egl
790
791namespace egl_gl
792{
793gl::TextureTarget EGLCubeMapTargetToCubeMapTarget(EGLenum eglTarget);
794gl::TextureTarget EGLImageTargetToTextureTarget(EGLenum eglTarget);
795gl::TextureType EGLTextureTargetToTextureType(EGLenum eglTarget);
796}  // namespace egl_gl
797
798#endif  // COMMON_PACKEDGLENUMS_H_
799