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>
62struct AllEnums
63{
64 EnumIterator<E> begin() const { return {static_cast<E>(0)}; }
65 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.
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 // 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
109 void fill(const T &u) { mPrivateData.fill(u); }
110 void swap(PackedEnumMap<E, T> &a) noexcept { mPrivateData.swap(a.mPrivateData); }
111
112 // iterators:
113 iterator begin() noexcept { return mPrivateData.begin(); }
114 const_iterator begin() const noexcept { return mPrivateData.begin(); }
115 iterator end() noexcept { return mPrivateData.end(); }
116 const_iterator end() const noexcept { return mPrivateData.end(); }
117
118 reverse_iterator rbegin() noexcept { return mPrivateData.rbegin(); }
119 const_reverse_iterator rbegin() const noexcept { return mPrivateData.rbegin(); }
120 reverse_iterator rend() noexcept { return mPrivateData.rend(); }
121 const_reverse_iterator rend() const noexcept { return mPrivateData.rend(); }
122
123 // capacity:
124 constexpr size_type size() const noexcept { return mPrivateData.size(); }
125 constexpr size_type max_size() const noexcept { return mPrivateData.max_size(); }
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
141 const_reference at(E n) const { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
142 reference at(E n) { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
143
144 reference front() { return mPrivateData.front(); }
145 const_reference front() const { return mPrivateData.front(); }
146 reference back() { return mPrivateData.back(); }
147 const_reference back() const { return mPrivateData.back(); }
148
149 T *data() noexcept { return mPrivateData.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.
158template <typename E, typename DataT = uint32_t>
159using PackedEnumBitSet = BitSetT<EnumSize<E>(), DataT, E>;
160
161} // namespace angle
162
163namespace gl
164{
165
166TextureType TextureTargetToType(TextureTarget target);
167TextureTarget NonCubeTextureTypeToTarget(TextureType type);
168
169TextureTarget CubeFaceIndexToTextureTarget(size_t face);
170size_t CubeMapTextureTargetToFaceIndex(TextureTarget target);
171bool IsCubeMapFaceTarget(TextureTarget target);
172
173constexpr TextureTarget kCubeMapTextureTargetMin = TextureTarget::CubeMapPositiveX;
174constexpr TextureTarget kCubeMapTextureTargetMax = TextureTarget::CubeMapNegativeZ;
175constexpr TextureTarget kAfterCubeMapTextureTargetMax =
176 static_cast<TextureTarget>(static_cast<uint8_t>(kCubeMapTextureTargetMax) + 1);
177struct AllCubeFaceTextureTargets
178{
179 angle::EnumIterator<TextureTarget> begin() const { return kCubeMapTextureTargetMin; }
180 angle::EnumIterator<TextureTarget> end() const { return kAfterCubeMapTextureTargetMax; }
181};
182
183constexpr ShaderType kGLES2ShaderTypeMin = ShaderType::Vertex;
184constexpr ShaderType kGLES2ShaderTypeMax = ShaderType::Fragment;
185constexpr ShaderType kAfterGLES2ShaderTypeMax =
186 static_cast<ShaderType>(static_cast<uint8_t>(kGLES2ShaderTypeMax) + 1);
187struct AllGLES2ShaderTypes
188{
189 angle::EnumIterator<ShaderType> begin() const { return kGLES2ShaderTypeMin; }
190 angle::EnumIterator<ShaderType> end() const { return kAfterGLES2ShaderTypeMax; }
191};
192
193constexpr ShaderType kShaderTypeMin = ShaderType::Vertex;
194constexpr ShaderType kShaderTypeMax = ShaderType::Compute;
195constexpr ShaderType kAfterShaderTypeMax =
196 static_cast<ShaderType>(static_cast<uint8_t>(kShaderTypeMax) + 1);
197struct AllShaderTypes
198{
199 angle::EnumIterator<ShaderType> begin() const { return kShaderTypeMin; }
200 angle::EnumIterator<ShaderType> end() const { return kAfterShaderTypeMax; }
201};
202
203constexpr size_t kGraphicsShaderCount = static_cast<size_t>(ShaderType::EnumCount) - 1u;
204// Arrange the shader types in the order of rendering pipeline
205constexpr std::array<ShaderType, kGraphicsShaderCount> kAllGraphicsShaderTypes = {
206 ShaderType::Vertex, ShaderType::Geometry, ShaderType::Fragment};
207
208using ShaderBitSet = angle::PackedEnumBitSet<ShaderType, uint8_t>;
209static_assert(sizeof(ShaderBitSet) == sizeof(uint8_t), "Unexpected size");
210
211template <typename T>
212using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
213
214TextureType SamplerTypeToTextureType(GLenum samplerType);
215
216bool IsMultisampled(gl::TextureType type);
217
218enum class PrimitiveMode : uint8_t
219{
220 Points = 0x0,
221 Lines = 0x1,
222 LineLoop = 0x2,
223 LineStrip = 0x3,
224 Triangles = 0x4,
225 TriangleStrip = 0x5,
226 TriangleFan = 0x6,
227 Unused1 = 0x7,
228 Unused2 = 0x8,
229 Unused3 = 0x9,
230 LinesAdjacency = 0xA,
231 LineStripAdjacency = 0xB,
232 TrianglesAdjacency = 0xC,
233 TriangleStripAdjacency = 0xD,
234
235 InvalidEnum = 0xE,
236 EnumCount = 0xE,
237};
238
239template <>
240constexpr PrimitiveMode FromGLenum<PrimitiveMode>(GLenum from)
241{
242 if (from >= static_cast<GLenum>(PrimitiveMode::EnumCount))
243 {
244 return PrimitiveMode::InvalidEnum;
245 }
246
247 return static_cast<PrimitiveMode>(from);
248}
249
250constexpr GLenum ToGLenum(PrimitiveMode from)
251{
252 return static_cast<GLenum>(from);
253}
254
255static_assert(ToGLenum(PrimitiveMode::Points) == GL_POINTS, "PrimitiveMode violation");
256static_assert(ToGLenum(PrimitiveMode::Lines) == GL_LINES, "PrimitiveMode violation");
257static_assert(ToGLenum(PrimitiveMode::LineLoop) == GL_LINE_LOOP, "PrimitiveMode violation");
258static_assert(ToGLenum(PrimitiveMode::LineStrip) == GL_LINE_STRIP, "PrimitiveMode violation");
259static_assert(ToGLenum(PrimitiveMode::Triangles) == GL_TRIANGLES, "PrimitiveMode violation");
260static_assert(ToGLenum(PrimitiveMode::TriangleStrip) == GL_TRIANGLE_STRIP,
261 "PrimitiveMode violation");
262static_assert(ToGLenum(PrimitiveMode::TriangleFan) == GL_TRIANGLE_FAN, "PrimitiveMode violation");
263static_assert(ToGLenum(PrimitiveMode::LinesAdjacency) == GL_LINES_ADJACENCY,
264 "PrimitiveMode violation");
265static_assert(ToGLenum(PrimitiveMode::LineStripAdjacency) == GL_LINE_STRIP_ADJACENCY,
266 "PrimitiveMode violation");
267static_assert(ToGLenum(PrimitiveMode::TrianglesAdjacency) == GL_TRIANGLES_ADJACENCY,
268 "PrimitiveMode violation");
269static_assert(ToGLenum(PrimitiveMode::TriangleStripAdjacency) == GL_TRIANGLE_STRIP_ADJACENCY,
270 "PrimitiveMode violation");
271
272enum class DrawElementsType : size_t
273{
274 UnsignedByte = 0,
275 UnsignedShort = 1,
276 UnsignedInt = 2,
277 InvalidEnum = 3,
278 EnumCount = 3,
279};
280
281template <>
282constexpr DrawElementsType FromGLenum<DrawElementsType>(GLenum from)
283{
284
285 GLenum scaled = (from - GL_UNSIGNED_BYTE);
286 // This code sequence generates a ROR instruction on x86/arm. We want to check if the lowest bit
287 // of scaled is set and if (scaled >> 1) is greater than a non-pot value. If we rotate the
288 // lowest bit to the hightest bit both conditions can be checked with a single test.
289 static_assert(sizeof(GLenum) == 4, "Update (scaled << 31) to sizeof(GLenum) * 8 - 1");
290 GLenum packed = (scaled >> 1) | (scaled << 31);
291
292 // operator ? with a simple assignment usually translates to a cmov instruction and thus avoids
293 // a branch.
294 packed = (packed >= static_cast<GLenum>(DrawElementsType::EnumCount))
295 ? static_cast<GLenum>(DrawElementsType::InvalidEnum)
296 : packed;
297
298 return static_cast<DrawElementsType>(packed);
299}
300
301constexpr GLenum ToGLenum(DrawElementsType from)
302{
303 return ((static_cast<GLenum>(from) << 1) + GL_UNSIGNED_BYTE);
304}
305
306#define ANGLE_VALIDATE_PACKED_ENUM(type, packed, glenum) \
307 static_assert(ToGLenum(type::packed) == glenum, #type " violation"); \
308 static_assert(FromGLenum<type>(glenum) == type::packed, #type " violation")
309
310ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedByte, GL_UNSIGNED_BYTE);
311ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedShort, GL_UNSIGNED_SHORT);
312ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedInt, GL_UNSIGNED_INT);
313
314enum class VertexAttribType
315{
316 Byte = 0, // GLenum == 0x1400
317 UnsignedByte = 1, // GLenum == 0x1401
318 Short = 2, // GLenum == 0x1402
319 UnsignedShort = 3, // GLenum == 0x1403
320 Int = 4, // GLenum == 0x1404
321 UnsignedInt = 5, // GLenum == 0x1405
322 Float = 6, // GLenum == 0x1406
323 Unused1 = 7, // GLenum == 0x1407
324 Unused2 = 8, // GLenum == 0x1408
325 Unused3 = 9, // GLenum == 0x1409
326 Unused4 = 10, // GLenum == 0x140A
327 HalfFloat = 11, // GLenum == 0x140B
328 Fixed = 12, // GLenum == 0x140C
329 MaxBasicType = 12,
330 UnsignedInt2101010 = 13, // GLenum == 0x8368
331 Int2101010 = 14, // GLenum == 0x8D9F
332 InvalidEnum = 15,
333 EnumCount = 15,
334};
335
336template <>
337constexpr VertexAttribType FromGLenum<VertexAttribType>(GLenum from)
338{
339 GLenum packed = from - GL_BYTE;
340 if (packed <= static_cast<GLenum>(VertexAttribType::MaxBasicType))
341 return static_cast<VertexAttribType>(packed);
342 if (from == GL_UNSIGNED_INT_2_10_10_10_REV)
343 return VertexAttribType::UnsignedInt2101010;
344 if (from == GL_INT_2_10_10_10_REV)
345 return VertexAttribType::Int2101010;
346 return VertexAttribType::InvalidEnum;
347}
348
349constexpr GLenum ToGLenum(VertexAttribType from)
350{
351 // This could be optimized using a constexpr table.
352 if (from == VertexAttribType::Int2101010)
353 return GL_INT_2_10_10_10_REV;
354 if (from == VertexAttribType::UnsignedInt2101010)
355 return GL_UNSIGNED_INT_2_10_10_10_REV;
356 return static_cast<GLenum>(from) + GL_BYTE;
357}
358
359ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Byte, GL_BYTE);
360ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedByte, GL_UNSIGNED_BYTE);
361ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Short, GL_SHORT);
362ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedShort, GL_UNSIGNED_SHORT);
363ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int, GL_INT);
364ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt, GL_UNSIGNED_INT);
365ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Float, GL_FLOAT);
366ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloat, GL_HALF_FLOAT);
367ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Fixed, GL_FIXED);
368ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int2101010, GL_INT_2_10_10_10_REV);
369ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt2101010, GL_UNSIGNED_INT_2_10_10_10_REV);
370} // namespace gl
371
372namespace egl
373{
374MessageType ErrorCodeToMessageType(EGLint errorCode);
375} // namespace egl
376
377namespace egl_gl
378{
379gl::TextureTarget EGLCubeMapTargetToCubeMapTarget(EGLenum eglTarget);
380gl::TextureTarget EGLImageTargetToTextureTarget(EGLenum eglTarget);
381gl::TextureType EGLTextureTargetToTextureType(EGLenum eglTarget);
382} // namespace egl_gl
383
384#endif // COMMON_PACKEDGLENUMS_H_
385