• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2012 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2
8 
9 #ifndef LIBANGLE_ANGLETYPES_H_
10 #define LIBANGLE_ANGLETYPES_H_
11 
12 #include "common/Color.h"
13 #include "common/FixedVector.h"
14 #include "common/PackedEnums.h"
15 #include "common/bitset_utils.h"
16 #include "common/vector_utils.h"
17 #include "libANGLE/Constants.h"
18 #include "libANGLE/Error.h"
19 #include "libANGLE/RefCountObject.h"
20 
21 #include <inttypes.h>
22 #include <stdint.h>
23 
24 #include <bitset>
25 #include <map>
26 #include <unordered_map>
27 
28 namespace gl
29 {
30 class Buffer;
31 class Texture;
32 
33 struct Rectangle
34 {
RectangleRectangle35     Rectangle() : x(0), y(0), width(0), height(0) {}
RectangleRectangle36     constexpr Rectangle(int x_in, int y_in, int width_in, int height_in)
37         : x(x_in), y(y_in), width(width_in), height(height_in)
38     {}
39 
x0Rectangle40     int x0() const { return x; }
y0Rectangle41     int y0() const { return y; }
x1Rectangle42     int x1() const { return x + width; }
y1Rectangle43     int y1() const { return y + height; }
44 
isReversedXRectangle45     bool isReversedX() const { return width < 0; }
isReversedYRectangle46     bool isReversedY() const { return height < 0; }
47 
48     // Returns a rectangle with the same area but flipped in X, Y, neither or both.
49     Rectangle flip(bool flipX, bool flipY) const;
50 
51     // Returns a rectangle with the same area but with height and width guaranteed to be positive.
52     Rectangle removeReversal() const;
53 
54     bool encloses(const gl::Rectangle &inside) const;
55 
56     int x;
57     int y;
58     int width;
59     int height;
60 };
61 
62 bool operator==(const Rectangle &a, const Rectangle &b);
63 bool operator!=(const Rectangle &a, const Rectangle &b);
64 
65 bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection);
66 
67 struct Offset
68 {
OffsetOffset69     constexpr Offset() : x(0), y(0), z(0) {}
OffsetOffset70     constexpr Offset(int x_in, int y_in, int z_in) : x(x_in), y(y_in), z(z_in) {}
71 
72     int x;
73     int y;
74     int z;
75 };
76 
77 constexpr Offset kOffsetZero(0, 0, 0);
78 
79 bool operator==(const Offset &a, const Offset &b);
80 bool operator!=(const Offset &a, const Offset &b);
81 
82 struct Extents
83 {
ExtentsExtents84     Extents() : width(0), height(0), depth(0) {}
ExtentsExtents85     Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) {}
86 
87     Extents(const Extents &other) = default;
88     Extents &operator=(const Extents &other) = default;
89 
emptyExtents90     bool empty() const { return (width * height * depth) == 0; }
91 
92     int width;
93     int height;
94     int depth;
95 };
96 
97 bool operator==(const Extents &lhs, const Extents &rhs);
98 bool operator!=(const Extents &lhs, const Extents &rhs);
99 
100 struct Box
101 {
BoxBox102     Box() : x(0), y(0), z(0), width(0), height(0), depth(0) {}
BoxBox103     Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in)
104         : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in)
105     {}
BoxBox106     Box(const Offset &offset, const Extents &size)
107         : x(offset.x),
108           y(offset.y),
109           z(offset.z),
110           width(size.width),
111           height(size.height),
112           depth(size.depth)
113     {}
114     bool operator==(const Box &other) const;
115     bool operator!=(const Box &other) const;
116     Rectangle toRect() const;
117 
118     int x;
119     int y;
120     int z;
121     int width;
122     int height;
123     int depth;
124 };
125 
126 struct RasterizerState final
127 {
128     // This will zero-initialize the struct, including padding.
129     RasterizerState();
130 
131     bool cullFace;
132     CullFaceMode cullMode;
133     GLenum frontFace;
134 
135     bool polygonOffsetFill;
136     GLfloat polygonOffsetFactor;
137     GLfloat polygonOffsetUnits;
138 
139     bool pointDrawMode;
140     bool multiSample;
141 
142     bool rasterizerDiscard;
143 };
144 
145 bool operator==(const RasterizerState &a, const RasterizerState &b);
146 bool operator!=(const RasterizerState &a, const RasterizerState &b);
147 
148 struct BlendState final
149 {
150     // This will zero-initialize the struct, including padding.
151     BlendState();
152     BlendState(const BlendState &other);
153 
154     bool allChannelsMasked() const;
155 
156     bool blend;
157     GLenum sourceBlendRGB;
158     GLenum destBlendRGB;
159     GLenum sourceBlendAlpha;
160     GLenum destBlendAlpha;
161     GLenum blendEquationRGB;
162     GLenum blendEquationAlpha;
163 
164     bool colorMaskRed;
165     bool colorMaskGreen;
166     bool colorMaskBlue;
167     bool colorMaskAlpha;
168 
169     bool sampleAlphaToCoverage;
170 
171     bool dither;
172 };
173 
174 bool operator==(const BlendState &a, const BlendState &b);
175 bool operator!=(const BlendState &a, const BlendState &b);
176 
177 struct DepthStencilState final
178 {
179     // This will zero-initialize the struct, including padding.
180     DepthStencilState();
181     DepthStencilState(const DepthStencilState &other);
182 
183     bool depthTest;
184     GLenum depthFunc;
185     bool depthMask;
186 
187     bool stencilTest;
188     GLenum stencilFunc;
189     GLuint stencilMask;
190     GLenum stencilFail;
191     GLenum stencilPassDepthFail;
192     GLenum stencilPassDepthPass;
193     GLuint stencilWritemask;
194     GLenum stencilBackFunc;
195     GLuint stencilBackMask;
196     GLenum stencilBackFail;
197     GLenum stencilBackPassDepthFail;
198     GLenum stencilBackPassDepthPass;
199     GLuint stencilBackWritemask;
200 };
201 
202 bool operator==(const DepthStencilState &a, const DepthStencilState &b);
203 bool operator!=(const DepthStencilState &a, const DepthStencilState &b);
204 
205 // Packs a sampler state for completeness checks:
206 // * minFilter: 5 values (3 bits)
207 // * magFilter: 2 values (1 bit)
208 // * wrapS:     3 values (2 bits)
209 // * wrapT:     3 values (2 bits)
210 // * compareMode: 1 bit (for == GL_NONE).
211 // This makes a total of 9 bits. We can pack this easily into 32 bits:
212 // * minFilter: 8 bits
213 // * magFilter: 8 bits
214 // * wrapS:     8 bits
215 // * wrapT:     4 bits
216 // * compareMode: 4 bits
217 
218 struct PackedSamplerCompleteness
219 {
220     uint8_t minFilter;
221     uint8_t magFilter;
222     uint8_t wrapS;
223     uint8_t wrapTCompareMode;
224 };
225 
226 static_assert(sizeof(PackedSamplerCompleteness) == sizeof(uint32_t), "Unexpected size");
227 
228 // State from Table 6.10 (state per sampler object)
229 class SamplerState final
230 {
231   public:
232     // This will zero-initialize the struct, including padding.
233     SamplerState();
234     SamplerState(const SamplerState &other);
235 
236     static SamplerState CreateDefaultForTarget(TextureType type);
237 
getMinFilter()238     GLenum getMinFilter() const { return mMinFilter; }
239 
240     void setMinFilter(GLenum minFilter);
241 
getMagFilter()242     GLenum getMagFilter() const { return mMagFilter; }
243 
244     void setMagFilter(GLenum magFilter);
245 
getWrapS()246     GLenum getWrapS() const { return mWrapS; }
247 
248     void setWrapS(GLenum wrapS);
249 
getWrapT()250     GLenum getWrapT() const { return mWrapT; }
251 
252     void setWrapT(GLenum wrapT);
253 
getWrapR()254     GLenum getWrapR() const { return mWrapR; }
255 
256     void setWrapR(GLenum wrapR);
257 
getMaxAnisotropy()258     float getMaxAnisotropy() const { return mMaxAnisotropy; }
259 
260     void setMaxAnisotropy(float maxAnisotropy);
261 
getMinLod()262     GLfloat getMinLod() const { return mMinLod; }
263 
264     void setMinLod(GLfloat minLod);
265 
getMaxLod()266     GLfloat getMaxLod() const { return mMaxLod; }
267 
268     void setMaxLod(GLfloat maxLod);
269 
getCompareMode()270     GLenum getCompareMode() const { return mCompareMode; }
271 
272     void setCompareMode(GLenum compareMode);
273 
getCompareFunc()274     GLenum getCompareFunc() const { return mCompareFunc; }
275 
276     void setCompareFunc(GLenum compareFunc);
277 
getSRGBDecode()278     GLenum getSRGBDecode() const { return mSRGBDecode; }
279 
280     void setSRGBDecode(GLenum sRGBDecode);
281 
282     void setBorderColor(const ColorGeneric &color);
283 
getBorderColor()284     const ColorGeneric &getBorderColor() const { return mBorderColor; }
285 
sameCompleteness(const SamplerState & samplerState)286     bool sameCompleteness(const SamplerState &samplerState) const
287     {
288         return mCompleteness.packed == samplerState.mCompleteness.packed;
289     }
290 
291   private:
292     void updateWrapTCompareMode();
293 
294     GLenum mMinFilter;
295     GLenum mMagFilter;
296 
297     GLenum mWrapS;
298     GLenum mWrapT;
299     GLenum mWrapR;
300 
301     // From EXT_texture_filter_anisotropic
302     float mMaxAnisotropy;
303 
304     GLfloat mMinLod;
305     GLfloat mMaxLod;
306 
307     GLenum mCompareMode;
308     GLenum mCompareFunc;
309 
310     GLenum mSRGBDecode;
311 
312     ColorGeneric mBorderColor;
313 
314     union Completeness
315     {
316         uint32_t packed;
317         PackedSamplerCompleteness typed;
318     };
319 
320     Completeness mCompleteness;
321 };
322 
323 bool operator==(const SamplerState &a, const SamplerState &b);
324 bool operator!=(const SamplerState &a, const SamplerState &b);
325 
326 struct DrawArraysIndirectCommand
327 {
328     GLuint count;
329     GLuint instanceCount;
330     GLuint first;
331     GLuint baseInstance;
332 };
333 static_assert(sizeof(DrawArraysIndirectCommand) == 16,
334               "Unexpected size of DrawArraysIndirectCommand");
335 
336 struct DrawElementsIndirectCommand
337 {
338     GLuint count;
339     GLuint primCount;
340     GLuint firstIndex;
341     GLint baseVertex;
342     GLuint baseInstance;
343 };
344 static_assert(sizeof(DrawElementsIndirectCommand) == 20,
345               "Unexpected size of DrawElementsIndirectCommand");
346 
347 struct ImageUnit
348 {
349     ImageUnit();
350     ImageUnit(const ImageUnit &other);
351     ~ImageUnit();
352 
353     BindingPointer<Texture> texture;
354     GLint level;
355     GLboolean layered;
356     GLint layer;
357     GLenum access;
358     GLenum format;
359 };
360 
361 using ImageUnitTextureTypeMap = std::map<unsigned int, gl::TextureType>;
362 
363 struct PixelStoreStateBase
364 {
365     GLint alignment   = 4;
366     GLint rowLength   = 0;
367     GLint skipRows    = 0;
368     GLint skipPixels  = 0;
369     GLint imageHeight = 0;
370     GLint skipImages  = 0;
371 };
372 
373 struct PixelUnpackState : PixelStoreStateBase
374 {};
375 
376 struct PixelPackState : PixelStoreStateBase
377 {
378     bool reverseRowOrder = false;
379 };
380 
381 // Used in Program and VertexArray.
382 using AttributesMask = angle::BitSet<MAX_VERTEX_ATTRIBS>;
383 
384 // Used in Program
385 using UniformBlockBindingMask = angle::BitSet<IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS>;
386 
387 // Used in Framebuffer / Program
388 using DrawBufferMask = angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS>;
389 
390 // Used in StateCache
391 using StorageBuffersMask = angle::BitSet<IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>;
392 
393 template <typename T>
394 using TexLevelArray = std::array<T, IMPLEMENTATION_MAX_TEXTURE_LEVELS>;
395 
396 enum class ComponentType
397 {
398     Float       = 0,
399     Int         = 1,
400     UnsignedInt = 2,
401     NoType      = 3,
402     EnumCount   = 4,
403     InvalidEnum = 4,
404 };
405 
GLenumToComponentType(GLenum componentType)406 constexpr ComponentType GLenumToComponentType(GLenum componentType)
407 {
408     switch (componentType)
409     {
410         case GL_FLOAT:
411             return ComponentType::Float;
412         case GL_INT:
413             return ComponentType::Int;
414         case GL_UNSIGNED_INT:
415             return ComponentType::UnsignedInt;
416         case GL_NONE:
417             return ComponentType::NoType;
418         default:
419             return ComponentType::InvalidEnum;
420     }
421 }
422 
423 constexpr angle::PackedEnumMap<ComponentType, uint32_t> kComponentMasks = {{
424     {ComponentType::Float, 0x10001},
425     {ComponentType::Int, 0x00001},
426     {ComponentType::UnsignedInt, 0x10000},
427 }};
428 
429 constexpr size_t kMaxComponentTypeMaskIndex = 16;
430 using ComponentTypeMask                     = angle::BitSet<kMaxComponentTypeMaskIndex * 2>;
431 
SetComponentTypeMask(ComponentType type,size_t index,ComponentTypeMask * mask)432 ANGLE_INLINE void SetComponentTypeMask(ComponentType type, size_t index, ComponentTypeMask *mask)
433 {
434     ASSERT(index <= kMaxComponentTypeMaskIndex);
435     *mask &= ~(0x10001 << index);
436     *mask |= kComponentMasks[type] << index;
437 }
438 
GetComponentTypeMask(const ComponentTypeMask & mask,size_t index)439 ANGLE_INLINE ComponentType GetComponentTypeMask(const ComponentTypeMask &mask, size_t index)
440 {
441     ASSERT(index <= kMaxComponentTypeMaskIndex);
442     uint32_t mask_bits = static_cast<uint32_t>((mask.to_ulong() >> index) & 0x10001);
443     switch (mask_bits)
444     {
445         case 0x10001:
446             return ComponentType::Float;
447         case 0x00001:
448             return ComponentType::Int;
449         case 0x10000:
450             return ComponentType::UnsignedInt;
451         default:
452             return ComponentType::InvalidEnum;
453     }
454 }
455 
456 bool ValidateComponentTypeMasks(unsigned long outputTypes,
457                                 unsigned long inputTypes,
458                                 unsigned long outputMask,
459                                 unsigned long inputMask);
460 
461 using ContextID = uintptr_t;
462 
463 constexpr size_t kCubeFaceCount = 6;
464 
465 using TextureMap = angle::PackedEnumMap<TextureType, BindingPointer<Texture>>;
466 
467 // ShaderVector can contain one item per shader.  It differs from ShaderMap in that the values are
468 // not indexed by ShaderType.
469 template <typename T>
470 using ShaderVector = angle::FixedVector<T, static_cast<size_t>(ShaderType::EnumCount)>;
471 
472 template <typename T>
473 using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
474 
475 template <typename T>
476 using DrawBuffersArray = std::array<T, IMPLEMENTATION_MAX_DRAW_BUFFERS>;
477 
478 template <typename T>
479 using DrawBuffersVector = angle::FixedVector<T, IMPLEMENTATION_MAX_DRAW_BUFFERS>;
480 
481 template <typename T>
482 using AttribArray = std::array<T, MAX_VERTEX_ATTRIBS>;
483 
484 using ActiveTextureMask = angle::BitSet<IMPLEMENTATION_MAX_ACTIVE_TEXTURES>;
485 
486 template <typename T>
487 using ActiveTextureArray = std::array<T, IMPLEMENTATION_MAX_ACTIVE_TEXTURES>;
488 
489 using ActiveTexturePointerArray = ActiveTextureArray<Texture *>;
490 using ActiveTextureTypeArray    = ActiveTextureArray<TextureType>;
491 
492 template <typename T>
493 using UniformBuffersArray = std::array<T, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS>;
494 template <typename T>
495 using StorageBuffersArray = std::array<T, IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>;
496 template <typename T>
497 using AtomicCounterBuffersArray = std::array<T, IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS>;
498 using AtomicCounterBufferMask   = angle::BitSet<IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS>;
499 
500 using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
501 
502 using SupportedSampleSet = std::set<GLuint>;
503 
504 template <typename T>
505 using TransformFeedbackBuffersArray =
506     std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>;
507 
508 constexpr size_t kBarrierVectorDefaultSize = 16;
509 
510 template <typename T>
511 using BarrierVector = angle::FastVector<T, kBarrierVectorDefaultSize>;
512 
513 using BufferBarrierVector = BarrierVector<Buffer *>;
514 
515 struct TextureAndLayout
516 {
517     Texture *texture;
518     GLenum layout;
519 };
520 using TextureBarrierVector = BarrierVector<TextureAndLayout>;
521 
522 // OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than
523 // the size of the bound buffer. This function reduces the returned size to fit the bound buffer if
524 // necessary. Returns 0 if no buffer is bound or if integer overflow occurs.
525 GLsizeiptr GetBoundBufferAvailableSize(const OffsetBindingPointer<Buffer> &binding);
526 
527 }  // namespace gl
528 
529 namespace rx
530 {
531 // A macro that determines whether an object has a given runtime type.
532 #if defined(__clang__)
533 #    if __has_feature(cxx_rtti)
534 #        define ANGLE_HAS_DYNAMIC_CAST 1
535 #    endif
536 #elif !defined(NDEBUG) && (!defined(_MSC_VER) || defined(_CPPRTTI)) &&              \
537     (!defined(__GNUC__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || \
538      defined(__GXX_RTTI))
539 #    define ANGLE_HAS_DYNAMIC_CAST 1
540 #endif
541 
542 #ifdef ANGLE_HAS_DYNAMIC_CAST
543 #    define ANGLE_HAS_DYNAMIC_TYPE(type, obj) (dynamic_cast<type>(obj) != nullptr)
544 #    undef ANGLE_HAS_DYNAMIC_CAST
545 #else
546 #    define ANGLE_HAS_DYNAMIC_TYPE(type, obj) (obj != nullptr)
547 #endif
548 
549 // Downcast a base implementation object (EG TextureImpl to TextureD3D)
550 template <typename DestT, typename SrcT>
GetAs(SrcT * src)551 inline DestT *GetAs(SrcT *src)
552 {
553     ASSERT(ANGLE_HAS_DYNAMIC_TYPE(DestT *, src));
554     return static_cast<DestT *>(src);
555 }
556 
557 template <typename DestT, typename SrcT>
GetAs(const SrcT * src)558 inline const DestT *GetAs(const SrcT *src)
559 {
560     ASSERT(ANGLE_HAS_DYNAMIC_TYPE(const DestT *, src));
561     return static_cast<const DestT *>(src);
562 }
563 
564 #undef ANGLE_HAS_DYNAMIC_TYPE
565 
566 // Downcast a GL object to an Impl (EG gl::Texture to rx::TextureD3D)
567 template <typename DestT, typename SrcT>
GetImplAs(SrcT * src)568 inline DestT *GetImplAs(SrcT *src)
569 {
570     return GetAs<DestT>(src->getImplementation());
571 }
572 
573 template <typename DestT, typename SrcT>
SafeGetImplAs(SrcT * src)574 inline DestT *SafeGetImplAs(SrcT *src)
575 {
576     return src != nullptr ? GetAs<DestT>(src->getImplementation()) : nullptr;
577 }
578 
579 }  // namespace rx
580 
581 #include "angletypes.inc"
582 
583 namespace angle
584 {
585 // Zero-based for better array indexing
586 enum FramebufferBinding
587 {
588     FramebufferBindingRead = 0,
589     FramebufferBindingDraw,
590     FramebufferBindingSingletonMax,
591     FramebufferBindingBoth = FramebufferBindingSingletonMax,
592     FramebufferBindingMax,
593     FramebufferBindingUnknown = FramebufferBindingMax,
594 };
595 
EnumToFramebufferBinding(GLenum enumValue)596 inline FramebufferBinding EnumToFramebufferBinding(GLenum enumValue)
597 {
598     switch (enumValue)
599     {
600         case GL_READ_FRAMEBUFFER:
601             return FramebufferBindingRead;
602         case GL_DRAW_FRAMEBUFFER:
603             return FramebufferBindingDraw;
604         case GL_FRAMEBUFFER:
605             return FramebufferBindingBoth;
606         default:
607             UNREACHABLE();
608             return FramebufferBindingUnknown;
609     }
610 }
611 
FramebufferBindingToEnum(FramebufferBinding binding)612 inline GLenum FramebufferBindingToEnum(FramebufferBinding binding)
613 {
614     switch (binding)
615     {
616         case FramebufferBindingRead:
617             return GL_READ_FRAMEBUFFER;
618         case FramebufferBindingDraw:
619             return GL_DRAW_FRAMEBUFFER;
620         case FramebufferBindingBoth:
621             return GL_FRAMEBUFFER;
622         default:
623             UNREACHABLE();
624             return GL_NONE;
625     }
626 }
627 
628 template <typename ObjT, typename ContextT>
629 class DestroyThenDelete
630 {
631   public:
DestroyThenDelete(const ContextT * context)632     DestroyThenDelete(const ContextT *context) : mContext(context) {}
633 
operator()634     void operator()(ObjT *obj)
635     {
636         (void)(obj->onDestroy(mContext));
637         delete obj;
638     }
639 
640   private:
641     const ContextT *mContext;
642 };
643 
644 // Helper class for wrapping an onDestroy function.
645 template <typename ObjT, typename DeleterT>
646 class UniqueObjectPointerBase : angle::NonCopyable
647 {
648   public:
649     template <typename ContextT>
UniqueObjectPointerBase(const ContextT * context)650     UniqueObjectPointerBase(const ContextT *context) : mObject(nullptr), mDeleter(context)
651     {}
652 
653     template <typename ContextT>
UniqueObjectPointerBase(ObjT * obj,const ContextT * context)654     UniqueObjectPointerBase(ObjT *obj, const ContextT *context) : mObject(obj), mDeleter(context)
655     {}
656 
~UniqueObjectPointerBase()657     ~UniqueObjectPointerBase()
658     {
659         if (mObject)
660         {
661             mDeleter(mObject);
662         }
663     }
664 
665     ObjT *operator->() const { return mObject; }
666 
release()667     ObjT *release()
668     {
669         auto obj = mObject;
670         mObject  = nullptr;
671         return obj;
672     }
673 
get()674     ObjT *get() const { return mObject; }
675 
reset(ObjT * obj)676     void reset(ObjT *obj)
677     {
678         if (mObject)
679         {
680             mDeleter(mObject);
681         }
682         mObject = obj;
683     }
684 
685   private:
686     ObjT *mObject;
687     DeleterT mDeleter;
688 };
689 
690 template <typename ObjT, typename ContextT>
691 using UniqueObjectPointer = UniqueObjectPointerBase<ObjT, DestroyThenDelete<ObjT, ContextT>>;
692 
693 }  // namespace angle
694 
695 namespace gl
696 {
697 class State;
698 }  // namespace gl
699 
700 #endif  // LIBANGLE_ANGLETYPES_H_
701