• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
23 namespace angle
24 {
25 
26 // Return the number of elements of a packed enum, including the InvalidEnum element.
27 template <typename E>
EnumSize()28 constexpr 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 
40 template <typename E>
41 class EnumIterator final
42 {
43   private:
44     using UnderlyingType = typename std::underlying_type<E>::type;
45 
46   public:
EnumIterator(E value)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 
61 template <typename E>
62 struct AllEnums
63 {
beginAllEnums64     EnumIterator<E> begin() const { return {static_cast<E>(0)}; }
endAllEnums65     EnumIterator<E> end() const { return {E::InvalidEnum}; }
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.
70 template <typename E, typename T, size_t MaxSize = EnumSize<E>()>
71 class 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 
PackedEnumMap(std::initializer_list<InitPair> init)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             // This horrible const_cast pattern is necessary to work around a constexpr limitation.
87             // See https://stackoverflow.com/q/34199774/ . Note that it should be fixed with C++17.
88             const_cast<T &>(const_cast<const Storage &>(
89                 mPrivateData)[static_cast<UnderlyingType>(it->first)]) = it->second;
90         }
91     }
92 
93     // types:
94     using value_type      = T;
95     using pointer         = T *;
96     using const_pointer   = const T *;
97     using reference       = T &;
98     using const_reference = const T &;
99 
100     using size_type       = size_t;
101     using difference_type = ptrdiff_t;
102 
103     using iterator               = typename Storage::iterator;
104     using const_iterator         = typename Storage::const_iterator;
105     using reverse_iterator       = std::reverse_iterator<iterator>;
106     using const_reverse_iterator = std::reverse_iterator<const_iterator>;
107 
108     // No explicit construct/copy/destroy for aggregate type
fill(const T & u)109     void fill(const T &u) { mPrivateData.fill(u); }
swap(PackedEnumMap<E,T> & a)110     void swap(PackedEnumMap<E, T> &a) noexcept { mPrivateData.swap(a.mPrivateData); }
111 
112     // iterators:
begin()113     iterator begin() noexcept { return mPrivateData.begin(); }
begin()114     const_iterator begin() const noexcept { return mPrivateData.begin(); }
end()115     iterator end() noexcept { return mPrivateData.end(); }
end()116     const_iterator end() const noexcept { return mPrivateData.end(); }
117 
rbegin()118     reverse_iterator rbegin() noexcept { return mPrivateData.rbegin(); }
rbegin()119     const_reverse_iterator rbegin() const noexcept { return mPrivateData.rbegin(); }
rend()120     reverse_iterator rend() noexcept { return mPrivateData.rend(); }
rend()121     const_reverse_iterator rend() const noexcept { return mPrivateData.rend(); }
122 
123     // capacity:
size()124     constexpr size_type size() const noexcept { return mPrivateData.size(); }
max_size()125     constexpr size_type max_size() const noexcept { return mPrivateData.max_size(); }
empty()126     constexpr bool empty() const noexcept { return mPrivateData.empty(); }
127 
128     // element access:
129     reference operator[](E n)
130     {
131         ASSERT(static_cast<size_t>(n) < mPrivateData.size());
132         return mPrivateData[static_cast<UnderlyingType>(n)];
133     }
134 
135     constexpr const_reference operator[](E n) const
136     {
137         ASSERT(static_cast<size_t>(n) < mPrivateData.size());
138         return mPrivateData[static_cast<UnderlyingType>(n)];
139     }
140 
at(E n)141     const_reference at(E n) const { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
at(E n)142     reference at(E n) { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
143 
front()144     reference front() { return mPrivateData.front(); }
front()145     const_reference front() const { return mPrivateData.front(); }
back()146     reference back() { return mPrivateData.back(); }
back()147     const_reference back() const { return mPrivateData.back(); }
148 
data()149     T *data() noexcept { return mPrivateData.data(); }
data()150     const T *data() const noexcept { return mPrivateData.data(); }
151 
152   private:
153     Storage mPrivateData;
154 };
155 
156 // PackedEnumBitSetE> is like an std::bitset<E::EnumCount> but is indexed with enum values. It
157 // implements the std::bitset interface except with enum values instead of indices.
158 template <typename E, typename DataT = uint32_t>
159 using PackedEnumBitSet = BitSetT<EnumSize<E>(), DataT, E>;
160 
161 }  // namespace angle
162 
163 namespace gl
164 {
165 
166 TextureType TextureTargetToType(TextureTarget target);
167 TextureTarget NonCubeTextureTypeToTarget(TextureType type);
168 
169 TextureTarget CubeFaceIndexToTextureTarget(size_t face);
170 size_t CubeMapTextureTargetToFaceIndex(TextureTarget target);
171 bool IsCubeMapFaceTarget(TextureTarget target);
172 
173 constexpr TextureTarget kCubeMapTextureTargetMin = TextureTarget::CubeMapPositiveX;
174 constexpr TextureTarget kCubeMapTextureTargetMax = TextureTarget::CubeMapNegativeZ;
175 constexpr TextureTarget kAfterCubeMapTextureTargetMax =
176     static_cast<TextureTarget>(static_cast<uint8_t>(kCubeMapTextureTargetMax) + 1);
177 struct AllCubeFaceTextureTargets
178 {
beginAllCubeFaceTextureTargets179     angle::EnumIterator<TextureTarget> begin() const { return kCubeMapTextureTargetMin; }
endAllCubeFaceTextureTargets180     angle::EnumIterator<TextureTarget> end() const { return kAfterCubeMapTextureTargetMax; }
181 };
182 
183 constexpr ShaderType kGLES2ShaderTypeMin = ShaderType::Vertex;
184 constexpr ShaderType kGLES2ShaderTypeMax = ShaderType::Fragment;
185 constexpr ShaderType kAfterGLES2ShaderTypeMax =
186     static_cast<ShaderType>(static_cast<uint8_t>(kGLES2ShaderTypeMax) + 1);
187 struct AllGLES2ShaderTypes
188 {
beginAllGLES2ShaderTypes189     angle::EnumIterator<ShaderType> begin() const { return kGLES2ShaderTypeMin; }
endAllGLES2ShaderTypes190     angle::EnumIterator<ShaderType> end() const { return kAfterGLES2ShaderTypeMax; }
191 };
192 
193 constexpr ShaderType kShaderTypeMin = ShaderType::Vertex;
194 constexpr ShaderType kShaderTypeMax = ShaderType::Compute;
195 constexpr ShaderType kAfterShaderTypeMax =
196     static_cast<ShaderType>(static_cast<uint8_t>(kShaderTypeMax) + 1);
197 struct AllShaderTypes
198 {
beginAllShaderTypes199     angle::EnumIterator<ShaderType> begin() const { return kShaderTypeMin; }
endAllShaderTypes200     angle::EnumIterator<ShaderType> end() const { return kAfterShaderTypeMax; }
201 };
202 
203 constexpr size_t kGraphicsShaderCount = static_cast<size_t>(ShaderType::EnumCount) - 1u;
204 // Arrange the shader types in the order of rendering pipeline
205 constexpr std::array<ShaderType, kGraphicsShaderCount> kAllGraphicsShaderTypes = {
206     ShaderType::Vertex, ShaderType::Geometry, ShaderType::Fragment};
207 
208 using ShaderBitSet = angle::PackedEnumBitSet<ShaderType, uint8_t>;
209 static_assert(sizeof(ShaderBitSet) == sizeof(uint8_t), "Unexpected size");
210 
211 template <typename T>
212 using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
213 
214 TextureType SamplerTypeToTextureType(GLenum samplerType);
215 
216 bool IsMultisampled(gl::TextureType type);
217 bool IsArrayTextureType(gl::TextureType type);
218 
219 enum class PrimitiveMode : uint8_t
220 {
221     Points                 = 0x0,
222     Lines                  = 0x1,
223     LineLoop               = 0x2,
224     LineStrip              = 0x3,
225     Triangles              = 0x4,
226     TriangleStrip          = 0x5,
227     TriangleFan            = 0x6,
228     Unused1                = 0x7,
229     Unused2                = 0x8,
230     Unused3                = 0x9,
231     LinesAdjacency         = 0xA,
232     LineStripAdjacency     = 0xB,
233     TrianglesAdjacency     = 0xC,
234     TriangleStripAdjacency = 0xD,
235 
236     InvalidEnum = 0xE,
237     EnumCount   = 0xE,
238 };
239 
240 template <>
241 constexpr PrimitiveMode FromGLenum<PrimitiveMode>(GLenum from)
242 {
243     if (from >= static_cast<GLenum>(PrimitiveMode::EnumCount))
244     {
245         return PrimitiveMode::InvalidEnum;
246     }
247 
248     return static_cast<PrimitiveMode>(from);
249 }
250 
ToGLenum(PrimitiveMode from)251 constexpr GLenum ToGLenum(PrimitiveMode from)
252 {
253     return static_cast<GLenum>(from);
254 }
255 
256 static_assert(ToGLenum(PrimitiveMode::Points) == GL_POINTS, "PrimitiveMode violation");
257 static_assert(ToGLenum(PrimitiveMode::Lines) == GL_LINES, "PrimitiveMode violation");
258 static_assert(ToGLenum(PrimitiveMode::LineLoop) == GL_LINE_LOOP, "PrimitiveMode violation");
259 static_assert(ToGLenum(PrimitiveMode::LineStrip) == GL_LINE_STRIP, "PrimitiveMode violation");
260 static_assert(ToGLenum(PrimitiveMode::Triangles) == GL_TRIANGLES, "PrimitiveMode violation");
261 static_assert(ToGLenum(PrimitiveMode::TriangleStrip) == GL_TRIANGLE_STRIP,
262               "PrimitiveMode violation");
263 static_assert(ToGLenum(PrimitiveMode::TriangleFan) == GL_TRIANGLE_FAN, "PrimitiveMode violation");
264 static_assert(ToGLenum(PrimitiveMode::LinesAdjacency) == GL_LINES_ADJACENCY,
265               "PrimitiveMode violation");
266 static_assert(ToGLenum(PrimitiveMode::LineStripAdjacency) == GL_LINE_STRIP_ADJACENCY,
267               "PrimitiveMode violation");
268 static_assert(ToGLenum(PrimitiveMode::TrianglesAdjacency) == GL_TRIANGLES_ADJACENCY,
269               "PrimitiveMode violation");
270 static_assert(ToGLenum(PrimitiveMode::TriangleStripAdjacency) == GL_TRIANGLE_STRIP_ADJACENCY,
271               "PrimitiveMode violation");
272 
273 std::ostream &operator<<(std::ostream &os, PrimitiveMode value);
274 
275 enum class DrawElementsType : size_t
276 {
277     UnsignedByte  = 0,
278     UnsignedShort = 1,
279     UnsignedInt   = 2,
280     InvalidEnum   = 3,
281     EnumCount     = 3,
282 };
283 
284 template <>
285 constexpr DrawElementsType FromGLenum<DrawElementsType>(GLenum from)
286 {
287 
288     GLenum scaled = (from - GL_UNSIGNED_BYTE);
289     // This code sequence generates a ROR instruction on x86/arm. We want to check if the lowest bit
290     // of scaled is set and if (scaled >> 1) is greater than a non-pot value. If we rotate the
291     // lowest bit to the hightest bit both conditions can be checked with a single test.
292     static_assert(sizeof(GLenum) == 4, "Update (scaled << 31) to sizeof(GLenum) * 8 - 1");
293     GLenum packed = (scaled >> 1) | (scaled << 31);
294 
295     // operator ? with a simple assignment usually translates to a cmov instruction and thus avoids
296     // a branch.
297     packed = (packed >= static_cast<GLenum>(DrawElementsType::EnumCount))
298                  ? static_cast<GLenum>(DrawElementsType::InvalidEnum)
299                  : packed;
300 
301     return static_cast<DrawElementsType>(packed);
302 }
303 
ToGLenum(DrawElementsType from)304 constexpr GLenum ToGLenum(DrawElementsType from)
305 {
306     return ((static_cast<GLenum>(from) << 1) + GL_UNSIGNED_BYTE);
307 }
308 
309 #define ANGLE_VALIDATE_PACKED_ENUM(type, packed, glenum)                 \
310     static_assert(ToGLenum(type::packed) == glenum, #type " violation"); \
311     static_assert(FromGLenum<type>(glenum) == type::packed, #type " violation")
312 
313 ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedByte, GL_UNSIGNED_BYTE);
314 ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedShort, GL_UNSIGNED_SHORT);
315 ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedInt, GL_UNSIGNED_INT);
316 
317 std::ostream &operator<<(std::ostream &os, DrawElementsType value);
318 
319 enum class VertexAttribType
320 {
321     Byte               = 0,   // GLenum == 0x1400
322     UnsignedByte       = 1,   // GLenum == 0x1401
323     Short              = 2,   // GLenum == 0x1402
324     UnsignedShort      = 3,   // GLenum == 0x1403
325     Int                = 4,   // GLenum == 0x1404
326     UnsignedInt        = 5,   // GLenum == 0x1405
327     Float              = 6,   // GLenum == 0x1406
328     Unused1            = 7,   // GLenum == 0x1407
329     Unused2            = 8,   // GLenum == 0x1408
330     Unused3            = 9,   // GLenum == 0x1409
331     Unused4            = 10,  // GLenum == 0x140A
332     HalfFloat          = 11,  // GLenum == 0x140B
333     Fixed              = 12,  // GLenum == 0x140C
334     MaxBasicType       = 12,
335     UnsignedInt2101010 = 13,  // GLenum == 0x8368
336     Int2101010         = 14,  // GLenum == 0x8D9F
337     InvalidEnum        = 15,
338     EnumCount          = 15,
339 };
340 
341 template <>
342 constexpr VertexAttribType FromGLenum<VertexAttribType>(GLenum from)
343 {
344     GLenum packed = from - GL_BYTE;
345     if (packed <= static_cast<GLenum>(VertexAttribType::MaxBasicType))
346         return static_cast<VertexAttribType>(packed);
347     if (from == GL_UNSIGNED_INT_2_10_10_10_REV)
348         return VertexAttribType::UnsignedInt2101010;
349     if (from == GL_INT_2_10_10_10_REV)
350         return VertexAttribType::Int2101010;
351     return VertexAttribType::InvalidEnum;
352 }
353 
ToGLenum(VertexAttribType from)354 constexpr GLenum ToGLenum(VertexAttribType from)
355 {
356     // This could be optimized using a constexpr table.
357     if (from == VertexAttribType::Int2101010)
358         return GL_INT_2_10_10_10_REV;
359     if (from == VertexAttribType::UnsignedInt2101010)
360         return GL_UNSIGNED_INT_2_10_10_10_REV;
361     return static_cast<GLenum>(from) + GL_BYTE;
362 }
363 
364 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Byte, GL_BYTE);
365 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedByte, GL_UNSIGNED_BYTE);
366 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Short, GL_SHORT);
367 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedShort, GL_UNSIGNED_SHORT);
368 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int, GL_INT);
369 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt, GL_UNSIGNED_INT);
370 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Float, GL_FLOAT);
371 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloat, GL_HALF_FLOAT);
372 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Fixed, GL_FIXED);
373 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int2101010, GL_INT_2_10_10_10_REV);
374 ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt2101010, GL_UNSIGNED_INT_2_10_10_10_REV);
375 
376 std::ostream &operator<<(std::ostream &os, VertexAttribType value);
377 
378 // Typesafe object handles.
379 struct BufferID
380 {
381     GLuint value;
382 };
383 
384 struct RenderbufferID
385 {
386     GLuint value;
387 };
388 
389 struct TextureID
390 {
391     GLuint value;
392 };
393 
394 // Used to unbox typed values.
395 template <typename ResourceIDType>
396 GLuint GetIDValue(ResourceIDType id);
397 
398 template <>
GetIDValue(GLuint id)399 inline GLuint GetIDValue(GLuint id)
400 {
401     return id;
402 }
403 
404 template <typename ResourceIDType>
GetIDValue(ResourceIDType id)405 inline GLuint GetIDValue(ResourceIDType id)
406 {
407     return id.value;
408 }
409 
410 // First case: handling packed enums.
411 template <typename EnumT, typename FromT>
FromGL(FromT from)412 typename std::enable_if<std::is_enum<EnumT>::value, EnumT>::type FromGL(FromT from)
413 {
414     return FromGLenum<EnumT>(from);
415 }
416 
417 // Second case: handling non-pointer resource ids.
418 template <typename EnumT, typename FromT>
419 typename std::enable_if<!std::is_pointer<FromT>::value && !std::is_enum<EnumT>::value, EnumT>::type
FromGL(FromT from)420 FromGL(FromT from)
421 {
422     return {from};
423 }
424 
425 // Third case: handling pointer resource ids.
426 template <typename EnumT, typename FromT>
427 typename std::enable_if<std::is_pointer<FromT>::value && !std::is_enum<EnumT>::value, EnumT>::type
FromGL(FromT from)428 FromGL(FromT from)
429 {
430     return reinterpret_cast<EnumT>(from);
431 }
432 }  // namespace gl
433 
434 namespace egl
435 {
436 MessageType ErrorCodeToMessageType(EGLint errorCode);
437 }  // namespace egl
438 
439 namespace egl_gl
440 {
441 gl::TextureTarget EGLCubeMapTargetToCubeMapTarget(EGLenum eglTarget);
442 gl::TextureTarget EGLImageTargetToTextureTarget(EGLenum eglTarget);
443 gl::TextureType EGLTextureTargetToTextureType(EGLenum eglTarget);
444 }  // namespace egl_gl
445 
446 #endif  // COMMON_PACKEDGLENUMS_H_
447