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