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> |
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: |
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 | { |
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. |
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 | |
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. |
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 | { |
179 | angle::EnumIterator<TextureTarget> begin() const { return kCubeMapTextureTargetMin; } |
180 | 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 | { |
189 | angle::EnumIterator<ShaderType> begin() const { return kGLES2ShaderTypeMin; } |
190 | 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 | { |
199 | angle::EnumIterator<ShaderType> begin() const { return kShaderTypeMin; } |
200 | 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 | |
218 | enum 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 | |
239 | template <> |
240 | constexpr 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 | |
250 | constexpr GLenum ToGLenum(PrimitiveMode from) |
251 | { |
252 | return static_cast<GLenum>(from); |
253 | } |
254 | |
255 | static_assert(ToGLenum(PrimitiveMode::Points) == GL_POINTS, "PrimitiveMode violation" ); |
256 | static_assert(ToGLenum(PrimitiveMode::Lines) == GL_LINES, "PrimitiveMode violation" ); |
257 | static_assert(ToGLenum(PrimitiveMode::LineLoop) == GL_LINE_LOOP, "PrimitiveMode violation" ); |
258 | static_assert(ToGLenum(PrimitiveMode::LineStrip) == GL_LINE_STRIP, "PrimitiveMode violation" ); |
259 | static_assert(ToGLenum(PrimitiveMode::Triangles) == GL_TRIANGLES, "PrimitiveMode violation" ); |
260 | static_assert(ToGLenum(PrimitiveMode::TriangleStrip) == GL_TRIANGLE_STRIP, |
261 | "PrimitiveMode violation" ); |
262 | static_assert(ToGLenum(PrimitiveMode::TriangleFan) == GL_TRIANGLE_FAN, "PrimitiveMode violation" ); |
263 | static_assert(ToGLenum(PrimitiveMode::LinesAdjacency) == GL_LINES_ADJACENCY, |
264 | "PrimitiveMode violation" ); |
265 | static_assert(ToGLenum(PrimitiveMode::LineStripAdjacency) == GL_LINE_STRIP_ADJACENCY, |
266 | "PrimitiveMode violation" ); |
267 | static_assert(ToGLenum(PrimitiveMode::TrianglesAdjacency) == GL_TRIANGLES_ADJACENCY, |
268 | "PrimitiveMode violation" ); |
269 | static_assert(ToGLenum(PrimitiveMode::TriangleStripAdjacency) == GL_TRIANGLE_STRIP_ADJACENCY, |
270 | "PrimitiveMode violation" ); |
271 | |
272 | enum class DrawElementsType : size_t |
273 | { |
274 | UnsignedByte = 0, |
275 | UnsignedShort = 1, |
276 | UnsignedInt = 2, |
277 | InvalidEnum = 3, |
278 | EnumCount = 3, |
279 | }; |
280 | |
281 | template <> |
282 | constexpr 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 | |
301 | constexpr 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 | |
310 | ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedByte, GL_UNSIGNED_BYTE); |
311 | ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedShort, GL_UNSIGNED_SHORT); |
312 | ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedInt, GL_UNSIGNED_INT); |
313 | |
314 | enum 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 | |
336 | template <> |
337 | constexpr 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 | |
349 | constexpr 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 | |
359 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Byte, GL_BYTE); |
360 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedByte, GL_UNSIGNED_BYTE); |
361 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Short, GL_SHORT); |
362 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedShort, GL_UNSIGNED_SHORT); |
363 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int, GL_INT); |
364 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt, GL_UNSIGNED_INT); |
365 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Float, GL_FLOAT); |
366 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloat, GL_HALF_FLOAT); |
367 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Fixed, GL_FIXED); |
368 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int2101010, GL_INT_2_10_10_10_REV); |
369 | ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt2101010, GL_UNSIGNED_INT_2_10_10_10_REV); |
370 | } // namespace gl |
371 | |
372 | namespace egl |
373 | { |
374 | MessageType ErrorCodeToMessageType(EGLint errorCode); |
375 | } // namespace egl |
376 | |
377 | namespace egl_gl |
378 | { |
379 | gl::TextureTarget EGLCubeMapTargetToCubeMapTarget(EGLenum eglTarget); |
380 | gl::TextureTarget EGLImageTargetToTextureTarget(EGLenum eglTarget); |
381 | gl::TextureType EGLTextureTargetToTextureType(EGLenum eglTarget); |
382 | } // namespace egl_gl |
383 | |
384 | #endif // COMMON_PACKEDGLENUMS_H_ |
385 | |