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