| 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 | |