• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2013 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 #include "libANGLE/angletypes.h"
10 #include "libANGLE/Program.h"
11 #include "libANGLE/State.h"
12 #include "libANGLE/VertexArray.h"
13 #include "libANGLE/VertexAttribute.h"
14 
15 #include <limits>
16 
17 #define USE_SYSTEM_ZLIB
18 #include "compression_utils_portable.h"
19 
20 namespace gl
21 {
22 namespace
23 {
IsStencilNoOp(GLenum stencilFunc,GLenum stencilFail,GLenum stencilPassDepthFail,GLenum stencilPassDepthPass)24 bool IsStencilNoOp(GLenum stencilFunc,
25                    GLenum stencilFail,
26                    GLenum stencilPassDepthFail,
27                    GLenum stencilPassDepthPass)
28 {
29     const bool isNeverAndKeep           = stencilFunc == GL_NEVER && stencilFail == GL_KEEP;
30     const bool isAlwaysAndKeepOrAllKeep = (stencilFunc == GL_ALWAYS || stencilFail == GL_KEEP) &&
31                                           stencilPassDepthFail == GL_KEEP &&
32                                           stencilPassDepthPass == GL_KEEP;
33 
34     return isNeverAndKeep || isAlwaysAndKeepOrAllKeep;
35 }
36 
37 // Calculate whether the range [outsideLow, outsideHigh] encloses the range [insideLow, insideHigh]
EnclosesRange(int outsideLow,int outsideHigh,int insideLow,int insideHigh)38 bool EnclosesRange(int outsideLow, int outsideHigh, int insideLow, int insideHigh)
39 {
40     return outsideLow <= insideLow && outsideHigh >= insideHigh;
41 }
42 
IsAdvancedBlendEquation(gl::BlendEquationType blendEquation)43 bool IsAdvancedBlendEquation(gl::BlendEquationType blendEquation)
44 {
45     return blendEquation >= gl::BlendEquationType::Multiply &&
46            blendEquation <= gl::BlendEquationType::HslLuminosity;
47 }
48 
IsExtendedBlendFactor(gl::BlendFactorType blendFactor)49 bool IsExtendedBlendFactor(gl::BlendFactorType blendFactor)
50 {
51     return blendFactor >= gl::BlendFactorType::Src1Alpha &&
52            blendFactor <= gl::BlendFactorType::OneMinusSrc1Alpha;
53 }
54 }  // anonymous namespace
55 
RasterizerState()56 RasterizerState::RasterizerState()
57 {
58     memset(this, 0, sizeof(RasterizerState));
59 
60     cullFace            = false;
61     cullMode            = CullFaceMode::Back;
62     frontFace           = GL_CCW;
63     polygonMode         = PolygonMode::Fill;
64     polygonOffsetPoint  = false;
65     polygonOffsetLine   = false;
66     polygonOffsetFill   = false;
67     polygonOffsetFactor = 0.0f;
68     polygonOffsetUnits  = 0.0f;
69     polygonOffsetClamp  = 0.0f;
70     depthClamp          = false;
71     pointDrawMode       = false;
72     multiSample         = false;
73     rasterizerDiscard   = false;
74     dither              = true;
75 }
76 
RasterizerState(const RasterizerState & other)77 RasterizerState::RasterizerState(const RasterizerState &other)
78 {
79     memcpy(this, &other, sizeof(RasterizerState));
80 }
81 
operator =(const RasterizerState & other)82 RasterizerState &RasterizerState::operator=(const RasterizerState &other)
83 {
84     memcpy(this, &other, sizeof(RasterizerState));
85     return *this;
86 }
87 
operator ==(const RasterizerState & a,const RasterizerState & b)88 bool operator==(const RasterizerState &a, const RasterizerState &b)
89 {
90     return memcmp(&a, &b, sizeof(RasterizerState)) == 0;
91 }
92 
operator !=(const RasterizerState & a,const RasterizerState & b)93 bool operator!=(const RasterizerState &a, const RasterizerState &b)
94 {
95     return !(a == b);
96 }
97 
BlendState()98 BlendState::BlendState()
99 {
100     memset(this, 0, sizeof(BlendState));
101 
102     blend              = false;
103     sourceBlendRGB     = GL_ONE;
104     sourceBlendAlpha   = GL_ONE;
105     destBlendRGB       = GL_ZERO;
106     destBlendAlpha     = GL_ZERO;
107     blendEquationRGB   = GL_FUNC_ADD;
108     blendEquationAlpha = GL_FUNC_ADD;
109     colorMaskRed       = true;
110     colorMaskGreen     = true;
111     colorMaskBlue      = true;
112     colorMaskAlpha     = true;
113 }
114 
BlendState(const BlendState & other)115 BlendState::BlendState(const BlendState &other)
116 {
117     memcpy(this, &other, sizeof(BlendState));
118 }
119 
operator ==(const BlendState & a,const BlendState & b)120 bool operator==(const BlendState &a, const BlendState &b)
121 {
122     return memcmp(&a, &b, sizeof(BlendState)) == 0;
123 }
124 
operator !=(const BlendState & a,const BlendState & b)125 bool operator!=(const BlendState &a, const BlendState &b)
126 {
127     return !(a == b);
128 }
129 
DepthStencilState()130 DepthStencilState::DepthStencilState()
131 {
132     memset(this, 0, sizeof(DepthStencilState));
133 
134     depthTest                = false;
135     depthFunc                = GL_LESS;
136     depthMask                = true;
137     stencilTest              = false;
138     stencilFunc              = GL_ALWAYS;
139     stencilMask              = static_cast<GLuint>(-1);
140     stencilWritemask         = static_cast<GLuint>(-1);
141     stencilBackFunc          = GL_ALWAYS;
142     stencilBackMask          = static_cast<GLuint>(-1);
143     stencilBackWritemask     = static_cast<GLuint>(-1);
144     stencilFail              = GL_KEEP;
145     stencilPassDepthFail     = GL_KEEP;
146     stencilPassDepthPass     = GL_KEEP;
147     stencilBackFail          = GL_KEEP;
148     stencilBackPassDepthFail = GL_KEEP;
149     stencilBackPassDepthPass = GL_KEEP;
150 }
151 
DepthStencilState(const DepthStencilState & other)152 DepthStencilState::DepthStencilState(const DepthStencilState &other)
153 {
154     memcpy(this, &other, sizeof(DepthStencilState));
155 }
156 
operator =(const DepthStencilState & other)157 DepthStencilState &DepthStencilState::operator=(const DepthStencilState &other)
158 {
159     memcpy(this, &other, sizeof(DepthStencilState));
160     return *this;
161 }
162 
isDepthMaskedOut() const163 bool DepthStencilState::isDepthMaskedOut() const
164 {
165     return !depthMask;
166 }
167 
isStencilMaskedOut() const168 bool DepthStencilState::isStencilMaskedOut() const
169 {
170     return (stencilMask & stencilWritemask) == 0;
171 }
172 
isStencilNoOp() const173 bool DepthStencilState::isStencilNoOp() const
174 {
175     return isStencilMaskedOut() ||
176            IsStencilNoOp(stencilFunc, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
177 }
178 
isStencilBackNoOp() const179 bool DepthStencilState::isStencilBackNoOp() const
180 {
181     const bool isStencilBackMaskedOut = (stencilBackMask & stencilBackWritemask) == 0;
182     return isStencilBackMaskedOut ||
183            IsStencilNoOp(stencilBackFunc, stencilBackFail, stencilBackPassDepthFail,
184                          stencilBackPassDepthPass);
185 }
186 
operator ==(const DepthStencilState & a,const DepthStencilState & b)187 bool operator==(const DepthStencilState &a, const DepthStencilState &b)
188 {
189     return memcmp(&a, &b, sizeof(DepthStencilState)) == 0;
190 }
191 
operator !=(const DepthStencilState & a,const DepthStencilState & b)192 bool operator!=(const DepthStencilState &a, const DepthStencilState &b)
193 {
194     return !(a == b);
195 }
196 
SamplerState()197 SamplerState::SamplerState()
198 {
199     memset(this, 0, sizeof(SamplerState));
200 
201     setMinFilter(GL_NEAREST_MIPMAP_LINEAR);
202     setMagFilter(GL_LINEAR);
203     setWrapS(GL_REPEAT);
204     setWrapT(GL_REPEAT);
205     setWrapR(GL_REPEAT);
206     setMaxAnisotropy(1.0f);
207     setMinLod(-1000.0f);
208     setMaxLod(1000.0f);
209     setCompareMode(GL_NONE);
210     setCompareFunc(GL_LEQUAL);
211     setSRGBDecode(GL_DECODE_EXT);
212 }
213 
214 SamplerState::SamplerState(const SamplerState &other) = default;
215 
216 SamplerState &SamplerState::operator=(const SamplerState &other) = default;
217 
218 // static
CreateDefaultForTarget(TextureType type)219 SamplerState SamplerState::CreateDefaultForTarget(TextureType type)
220 {
221     SamplerState state;
222 
223     // According to OES_EGL_image_external and ARB_texture_rectangle: For external textures, the
224     // default min filter is GL_LINEAR and the default s and t wrap modes are GL_CLAMP_TO_EDGE.
225     if (type == TextureType::External || type == TextureType::Rectangle)
226     {
227         state.mMinFilter = GL_LINEAR;
228         state.mWrapS     = GL_CLAMP_TO_EDGE;
229         state.mWrapT     = GL_CLAMP_TO_EDGE;
230     }
231 
232     return state;
233 }
234 
setMinFilter(GLenum minFilter)235 bool SamplerState::setMinFilter(GLenum minFilter)
236 {
237     if (mMinFilter != minFilter)
238     {
239         mMinFilter                    = minFilter;
240         mCompleteness.typed.minFilter = static_cast<uint8_t>(FromGLenum<FilterMode>(minFilter));
241         return true;
242     }
243     return false;
244 }
245 
setMagFilter(GLenum magFilter)246 bool SamplerState::setMagFilter(GLenum magFilter)
247 {
248     if (mMagFilter != magFilter)
249     {
250         mMagFilter                    = magFilter;
251         mCompleteness.typed.magFilter = static_cast<uint8_t>(FromGLenum<FilterMode>(magFilter));
252         return true;
253     }
254     return false;
255 }
256 
setWrapS(GLenum wrapS)257 bool SamplerState::setWrapS(GLenum wrapS)
258 {
259     if (mWrapS != wrapS)
260     {
261         mWrapS                    = wrapS;
262         mCompleteness.typed.wrapS = static_cast<uint8_t>(FromGLenum<WrapMode>(wrapS));
263         return true;
264     }
265     return false;
266 }
267 
setWrapT(GLenum wrapT)268 bool SamplerState::setWrapT(GLenum wrapT)
269 {
270     if (mWrapT != wrapT)
271     {
272         mWrapT = wrapT;
273         updateWrapTCompareMode();
274         return true;
275     }
276     return false;
277 }
278 
setWrapR(GLenum wrapR)279 bool SamplerState::setWrapR(GLenum wrapR)
280 {
281     if (mWrapR != wrapR)
282     {
283         mWrapR = wrapR;
284         return true;
285     }
286     return false;
287 }
288 
setMaxAnisotropy(float maxAnisotropy)289 bool SamplerState::setMaxAnisotropy(float maxAnisotropy)
290 {
291     if (mMaxAnisotropy != maxAnisotropy)
292     {
293         mMaxAnisotropy = maxAnisotropy;
294         return true;
295     }
296     return false;
297 }
298 
setMinLod(GLfloat minLod)299 bool SamplerState::setMinLod(GLfloat minLod)
300 {
301     if (mMinLod != minLod)
302     {
303         mMinLod = minLod;
304         return true;
305     }
306     return false;
307 }
308 
setMaxLod(GLfloat maxLod)309 bool SamplerState::setMaxLod(GLfloat maxLod)
310 {
311     if (mMaxLod != maxLod)
312     {
313         mMaxLod = maxLod;
314         return true;
315     }
316     return false;
317 }
318 
setCompareMode(GLenum compareMode)319 bool SamplerState::setCompareMode(GLenum compareMode)
320 {
321     if (mCompareMode != compareMode)
322     {
323         mCompareMode = compareMode;
324         updateWrapTCompareMode();
325         return true;
326     }
327     return false;
328 }
329 
setCompareFunc(GLenum compareFunc)330 bool SamplerState::setCompareFunc(GLenum compareFunc)
331 {
332     if (mCompareFunc != compareFunc)
333     {
334         mCompareFunc = compareFunc;
335         return true;
336     }
337     return false;
338 }
339 
setSRGBDecode(GLenum sRGBDecode)340 bool SamplerState::setSRGBDecode(GLenum sRGBDecode)
341 {
342     if (mSRGBDecode != sRGBDecode)
343     {
344         mSRGBDecode = sRGBDecode;
345         return true;
346     }
347     return false;
348 }
349 
setBorderColor(const ColorGeneric & color)350 bool SamplerState::setBorderColor(const ColorGeneric &color)
351 {
352     if (mBorderColor != color)
353     {
354         mBorderColor = color;
355         return true;
356     }
357     return false;
358 }
359 
updateWrapTCompareMode()360 void SamplerState::updateWrapTCompareMode()
361 {
362     uint8_t wrap    = static_cast<uint8_t>(FromGLenum<WrapMode>(mWrapT));
363     uint8_t compare = static_cast<uint8_t>(mCompareMode == GL_NONE ? 0x10 : 0x00);
364     mCompleteness.typed.wrapTCompareMode = wrap | compare;
365 }
366 
ImageUnit()367 ImageUnit::ImageUnit()
368     : texture(), level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI)
369 {}
370 
371 ImageUnit::ImageUnit(const ImageUnit &other) = default;
372 
373 ImageUnit::~ImageUnit() = default;
374 
BlendStateExt(const size_t drawBufferCount)375 BlendStateExt::BlendStateExt(const size_t drawBufferCount)
376     : mParameterMask(FactorStorage::GetMask(drawBufferCount)),
377       mSrcColor(FactorStorage::GetReplicatedValue(BlendFactorType::One, mParameterMask)),
378       mDstColor(FactorStorage::GetReplicatedValue(BlendFactorType::Zero, mParameterMask)),
379       mSrcAlpha(FactorStorage::GetReplicatedValue(BlendFactorType::One, mParameterMask)),
380       mDstAlpha(FactorStorage::GetReplicatedValue(BlendFactorType::Zero, mParameterMask)),
381       mEquationColor(EquationStorage::GetReplicatedValue(BlendEquationType::Add, mParameterMask)),
382       mEquationAlpha(EquationStorage::GetReplicatedValue(BlendEquationType::Add, mParameterMask)),
383       mAllColorMask(
384           ColorMaskStorage::GetReplicatedValue(PackColorMask(true, true, true, true),
385                                                ColorMaskStorage::GetMask(drawBufferCount))),
386       mColorMask(mAllColorMask),
387       mAllEnabledMask(0xFF >> (8 - drawBufferCount)),
388       mDrawBufferCount(drawBufferCount)
389 {}
390 
391 BlendStateExt::BlendStateExt(const BlendStateExt &other) = default;
392 
393 BlendStateExt &BlendStateExt::operator=(const BlendStateExt &other) = default;
394 
setEnabled(const bool enabled)395 void BlendStateExt::setEnabled(const bool enabled)
396 {
397     mEnabledMask = enabled ? mAllEnabledMask : DrawBufferMask::Zero();
398 }
399 
setEnabledIndexed(const size_t index,const bool enabled)400 void BlendStateExt::setEnabledIndexed(const size_t index, const bool enabled)
401 {
402     ASSERT(index < mDrawBufferCount);
403     mEnabledMask.set(index, enabled);
404 }
405 
expandColorMaskValue(const bool red,const bool green,const bool blue,const bool alpha) const406 BlendStateExt::ColorMaskStorage::Type BlendStateExt::expandColorMaskValue(const bool red,
407                                                                           const bool green,
408                                                                           const bool blue,
409                                                                           const bool alpha) const
410 {
411     return BlendStateExt::ColorMaskStorage::GetReplicatedValue(
412         PackColorMask(red, green, blue, alpha), mAllColorMask);
413 }
414 
expandColorMaskIndexed(const size_t index) const415 BlendStateExt::ColorMaskStorage::Type BlendStateExt::expandColorMaskIndexed(
416     const size_t index) const
417 {
418     return ColorMaskStorage::GetReplicatedValue(
419         ColorMaskStorage::GetValueIndexed(index, mColorMask), mAllColorMask);
420 }
421 
setColorMask(const bool red,const bool green,const bool blue,const bool alpha)422 void BlendStateExt::setColorMask(const bool red,
423                                  const bool green,
424                                  const bool blue,
425                                  const bool alpha)
426 {
427     mColorMask = expandColorMaskValue(red, green, blue, alpha);
428 }
429 
setColorMaskIndexed(const size_t index,const uint8_t value)430 void BlendStateExt::setColorMaskIndexed(const size_t index, const uint8_t value)
431 {
432     ASSERT(index < mDrawBufferCount);
433     ASSERT(value <= 0xF);
434     ColorMaskStorage::SetValueIndexed(index, value, &mColorMask);
435 }
436 
setColorMaskIndexed(const size_t index,const bool red,const bool green,const bool blue,const bool alpha)437 void BlendStateExt::setColorMaskIndexed(const size_t index,
438                                         const bool red,
439                                         const bool green,
440                                         const bool blue,
441                                         const bool alpha)
442 {
443     ASSERT(index < mDrawBufferCount);
444     ColorMaskStorage::SetValueIndexed(index, PackColorMask(red, green, blue, alpha), &mColorMask);
445 }
446 
getColorMaskIndexed(const size_t index) const447 uint8_t BlendStateExt::getColorMaskIndexed(const size_t index) const
448 {
449     ASSERT(index < mDrawBufferCount);
450     return ColorMaskStorage::GetValueIndexed(index, mColorMask);
451 }
452 
getColorMaskIndexed(const size_t index,bool * red,bool * green,bool * blue,bool * alpha) const453 void BlendStateExt::getColorMaskIndexed(const size_t index,
454                                         bool *red,
455                                         bool *green,
456                                         bool *blue,
457                                         bool *alpha) const
458 {
459     ASSERT(index < mDrawBufferCount);
460     UnpackColorMask(ColorMaskStorage::GetValueIndexed(index, mColorMask), red, green, blue, alpha);
461 }
462 
compareColorMask(ColorMaskStorage::Type other) const463 DrawBufferMask BlendStateExt::compareColorMask(ColorMaskStorage::Type other) const
464 {
465     return ColorMaskStorage::GetDiffMask(mColorMask, other);
466 }
467 
expandEquationValue(const GLenum mode) const468 BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationValue(const GLenum mode) const
469 {
470     return EquationStorage::GetReplicatedValue(FromGLenum<BlendEquationType>(mode), mParameterMask);
471 }
472 
expandEquationValue(const gl::BlendEquationType equation) const473 BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationValue(
474     const gl::BlendEquationType equation) const
475 {
476     return EquationStorage::GetReplicatedValue(equation, mParameterMask);
477 }
478 
expandEquationColorIndexed(const size_t index) const479 BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationColorIndexed(
480     const size_t index) const
481 {
482     return EquationStorage::GetReplicatedValue(
483         EquationStorage::GetValueIndexed(index, mEquationColor), mParameterMask);
484 }
485 
expandEquationAlphaIndexed(const size_t index) const486 BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationAlphaIndexed(
487     const size_t index) const
488 {
489     return EquationStorage::GetReplicatedValue(
490         EquationStorage::GetValueIndexed(index, mEquationAlpha), mParameterMask);
491 }
492 
setEquations(const GLenum modeColor,const GLenum modeAlpha)493 void BlendStateExt::setEquations(const GLenum modeColor, const GLenum modeAlpha)
494 {
495     const gl::BlendEquationType colorEquation = FromGLenum<BlendEquationType>(modeColor);
496     const gl::BlendEquationType alphaEquation = FromGLenum<BlendEquationType>(modeAlpha);
497 
498     mEquationColor = expandEquationValue(colorEquation);
499     mEquationAlpha = expandEquationValue(alphaEquation);
500 
501     // Note that advanced blend equations cannot be independently set for color and alpha, so only
502     // the color equation can be checked.
503     if (IsAdvancedBlendEquation(colorEquation))
504     {
505         mUsesAdvancedBlendEquationMask = mAllEnabledMask;
506     }
507     else
508     {
509         mUsesAdvancedBlendEquationMask.reset();
510     }
511 }
512 
setEquationsIndexed(const size_t index,const GLenum modeColor,const GLenum modeAlpha)513 void BlendStateExt::setEquationsIndexed(const size_t index,
514                                         const GLenum modeColor,
515                                         const GLenum modeAlpha)
516 {
517     ASSERT(index < mDrawBufferCount);
518 
519     const gl::BlendEquationType colorEquation = FromGLenum<BlendEquationType>(modeColor);
520     const gl::BlendEquationType alphaEquation = FromGLenum<BlendEquationType>(modeAlpha);
521 
522     EquationStorage::SetValueIndexed(index, colorEquation, &mEquationColor);
523     EquationStorage::SetValueIndexed(index, alphaEquation, &mEquationAlpha);
524 
525     mUsesAdvancedBlendEquationMask.set(index, IsAdvancedBlendEquation(colorEquation));
526 }
527 
setEquationsIndexed(const size_t index,const size_t sourceIndex,const BlendStateExt & source)528 void BlendStateExt::setEquationsIndexed(const size_t index,
529                                         const size_t sourceIndex,
530                                         const BlendStateExt &source)
531 {
532     ASSERT(index < mDrawBufferCount);
533     ASSERT(sourceIndex < source.mDrawBufferCount);
534 
535     const gl::BlendEquationType colorEquation =
536         EquationStorage::GetValueIndexed(sourceIndex, source.mEquationColor);
537     const gl::BlendEquationType alphaEquation =
538         EquationStorage::GetValueIndexed(sourceIndex, source.mEquationAlpha);
539 
540     EquationStorage::SetValueIndexed(index, colorEquation, &mEquationColor);
541     EquationStorage::SetValueIndexed(index, alphaEquation, &mEquationAlpha);
542 
543     mUsesAdvancedBlendEquationMask.set(index, IsAdvancedBlendEquation(colorEquation));
544 }
545 
compareEquations(const EquationStorage::Type color,const EquationStorage::Type alpha) const546 DrawBufferMask BlendStateExt::compareEquations(const EquationStorage::Type color,
547                                                const EquationStorage::Type alpha) const
548 {
549     return EquationStorage::GetDiffMask(mEquationColor, color) |
550            EquationStorage::GetDiffMask(mEquationAlpha, alpha);
551 }
552 
expandFactorValue(const GLenum func) const553 BlendStateExt::FactorStorage::Type BlendStateExt::expandFactorValue(const GLenum func) const
554 {
555     return FactorStorage::GetReplicatedValue(FromGLenum<BlendFactorType>(func), mParameterMask);
556 }
557 
expandFactorValue(const gl::BlendFactorType func) const558 BlendStateExt::FactorStorage::Type BlendStateExt::expandFactorValue(
559     const gl::BlendFactorType func) const
560 {
561     return FactorStorage::GetReplicatedValue(func, mParameterMask);
562 }
563 
expandSrcColorIndexed(const size_t index) const564 BlendStateExt::FactorStorage::Type BlendStateExt::expandSrcColorIndexed(const size_t index) const
565 {
566     ASSERT(index < mDrawBufferCount);
567     return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mSrcColor),
568                                              mParameterMask);
569 }
570 
expandDstColorIndexed(const size_t index) const571 BlendStateExt::FactorStorage::Type BlendStateExt::expandDstColorIndexed(const size_t index) const
572 {
573     ASSERT(index < mDrawBufferCount);
574     return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mDstColor),
575                                              mParameterMask);
576 }
577 
expandSrcAlphaIndexed(const size_t index) const578 BlendStateExt::FactorStorage::Type BlendStateExt::expandSrcAlphaIndexed(const size_t index) const
579 {
580     ASSERT(index < mDrawBufferCount);
581     return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mSrcAlpha),
582                                              mParameterMask);
583 }
584 
expandDstAlphaIndexed(const size_t index) const585 BlendStateExt::FactorStorage::Type BlendStateExt::expandDstAlphaIndexed(const size_t index) const
586 {
587     ASSERT(index < mDrawBufferCount);
588     return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mDstAlpha),
589                                              mParameterMask);
590 }
591 
setFactors(const GLenum srcColor,const GLenum dstColor,const GLenum srcAlpha,const GLenum dstAlpha)592 void BlendStateExt::setFactors(const GLenum srcColor,
593                                const GLenum dstColor,
594                                const GLenum srcAlpha,
595                                const GLenum dstAlpha)
596 {
597     const gl::BlendFactorType srcColorFactor = FromGLenum<BlendFactorType>(srcColor);
598     const gl::BlendFactorType dstColorFactor = FromGLenum<BlendFactorType>(dstColor);
599     const gl::BlendFactorType srcAlphaFactor = FromGLenum<BlendFactorType>(srcAlpha);
600     const gl::BlendFactorType dstAlphaFactor = FromGLenum<BlendFactorType>(dstAlpha);
601 
602     mSrcColor = expandFactorValue(srcColorFactor);
603     mDstColor = expandFactorValue(dstColorFactor);
604     mSrcAlpha = expandFactorValue(srcAlphaFactor);
605     mDstAlpha = expandFactorValue(dstAlphaFactor);
606 
607     if (IsExtendedBlendFactor(srcColorFactor) || IsExtendedBlendFactor(dstColorFactor) ||
608         IsExtendedBlendFactor(srcAlphaFactor) || IsExtendedBlendFactor(dstAlphaFactor))
609     {
610         mUsesExtendedBlendFactorMask = mAllEnabledMask;
611     }
612     else
613     {
614         mUsesExtendedBlendFactorMask.reset();
615     }
616 }
617 
setFactorsIndexed(const size_t index,const gl::BlendFactorType srcColorFactor,const gl::BlendFactorType dstColorFactor,const gl::BlendFactorType srcAlphaFactor,const gl::BlendFactorType dstAlphaFactor)618 void BlendStateExt::setFactorsIndexed(const size_t index,
619                                       const gl::BlendFactorType srcColorFactor,
620                                       const gl::BlendFactorType dstColorFactor,
621                                       const gl::BlendFactorType srcAlphaFactor,
622                                       const gl::BlendFactorType dstAlphaFactor)
623 {
624     ASSERT(index < mDrawBufferCount);
625 
626     FactorStorage::SetValueIndexed(index, srcColorFactor, &mSrcColor);
627     FactorStorage::SetValueIndexed(index, dstColorFactor, &mDstColor);
628     FactorStorage::SetValueIndexed(index, srcAlphaFactor, &mSrcAlpha);
629     FactorStorage::SetValueIndexed(index, dstAlphaFactor, &mDstAlpha);
630 
631     const bool isExtended =
632         IsExtendedBlendFactor(srcColorFactor) || IsExtendedBlendFactor(dstColorFactor) ||
633         IsExtendedBlendFactor(srcAlphaFactor) || IsExtendedBlendFactor(dstAlphaFactor);
634     mUsesExtendedBlendFactorMask.set(index, isExtended);
635 }
636 
setFactorsIndexed(const size_t index,const GLenum srcColor,const GLenum dstColor,const GLenum srcAlpha,const GLenum dstAlpha)637 void BlendStateExt::setFactorsIndexed(const size_t index,
638                                       const GLenum srcColor,
639                                       const GLenum dstColor,
640                                       const GLenum srcAlpha,
641                                       const GLenum dstAlpha)
642 {
643     const gl::BlendFactorType srcColorFactor = FromGLenum<BlendFactorType>(srcColor);
644     const gl::BlendFactorType dstColorFactor = FromGLenum<BlendFactorType>(dstColor);
645     const gl::BlendFactorType srcAlphaFactor = FromGLenum<BlendFactorType>(srcAlpha);
646     const gl::BlendFactorType dstAlphaFactor = FromGLenum<BlendFactorType>(dstAlpha);
647 
648     setFactorsIndexed(index, srcColorFactor, dstColorFactor, srcAlphaFactor, dstAlphaFactor);
649 }
650 
setFactorsIndexed(const size_t index,const size_t sourceIndex,const BlendStateExt & source)651 void BlendStateExt::setFactorsIndexed(const size_t index,
652                                       const size_t sourceIndex,
653                                       const BlendStateExt &source)
654 {
655     ASSERT(index < mDrawBufferCount);
656     ASSERT(sourceIndex < source.mDrawBufferCount);
657 
658     const gl::BlendFactorType srcColorFactor =
659         FactorStorage::GetValueIndexed(sourceIndex, source.mSrcColor);
660     const gl::BlendFactorType dstColorFactor =
661         FactorStorage::GetValueIndexed(sourceIndex, source.mDstColor);
662     const gl::BlendFactorType srcAlphaFactor =
663         FactorStorage::GetValueIndexed(sourceIndex, source.mSrcAlpha);
664     const gl::BlendFactorType dstAlphaFactor =
665         FactorStorage::GetValueIndexed(sourceIndex, source.mDstAlpha);
666 
667     FactorStorage::SetValueIndexed(index, srcColorFactor, &mSrcColor);
668     FactorStorage::SetValueIndexed(index, dstColorFactor, &mDstColor);
669     FactorStorage::SetValueIndexed(index, srcAlphaFactor, &mSrcAlpha);
670     FactorStorage::SetValueIndexed(index, dstAlphaFactor, &mDstAlpha);
671 
672     const bool isExtended =
673         IsExtendedBlendFactor(srcColorFactor) || IsExtendedBlendFactor(dstColorFactor) ||
674         IsExtendedBlendFactor(srcAlphaFactor) || IsExtendedBlendFactor(dstAlphaFactor);
675     mUsesExtendedBlendFactorMask.set(index, isExtended);
676 }
677 
compareFactors(const FactorStorage::Type srcColor,const FactorStorage::Type dstColor,const FactorStorage::Type srcAlpha,const FactorStorage::Type dstAlpha) const678 DrawBufferMask BlendStateExt::compareFactors(const FactorStorage::Type srcColor,
679                                              const FactorStorage::Type dstColor,
680                                              const FactorStorage::Type srcAlpha,
681                                              const FactorStorage::Type dstAlpha) const
682 {
683     return FactorStorage::GetDiffMask(mSrcColor, srcColor) |
684            FactorStorage::GetDiffMask(mDstColor, dstColor) |
685            FactorStorage::GetDiffMask(mSrcAlpha, srcAlpha) |
686            FactorStorage::GetDiffMask(mDstAlpha, dstAlpha);
687 }
688 
MinMax(int a,int b,int * minimum,int * maximum)689 static void MinMax(int a, int b, int *minimum, int *maximum)
690 {
691     if (a < b)
692     {
693         *minimum = a;
694         *maximum = b;
695     }
696     else
697     {
698         *minimum = b;
699         *maximum = a;
700     }
701 }
702 
703 template <>
empty() const704 bool RectangleImpl<int>::empty() const
705 {
706     return width == 0 && height == 0;
707 }
708 
709 template <>
empty() const710 bool RectangleImpl<float>::empty() const
711 {
712     return std::abs(width) < std::numeric_limits<float>::epsilon() &&
713            std::abs(height) < std::numeric_limits<float>::epsilon();
714 }
715 
ClipRectangle(const Rectangle & source,const Rectangle & clip,Rectangle * intersection)716 bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection)
717 {
718     angle::CheckedNumeric<int> sourceX2(source.x);
719     sourceX2 += source.width;
720     if (!sourceX2.IsValid())
721     {
722         return false;
723     }
724     angle::CheckedNumeric<int> sourceY2(source.y);
725     sourceY2 += source.height;
726     if (!sourceY2.IsValid())
727     {
728         return false;
729     }
730 
731     int minSourceX, maxSourceX, minSourceY, maxSourceY;
732     MinMax(source.x, sourceX2.ValueOrDie(), &minSourceX, &maxSourceX);
733     MinMax(source.y, sourceY2.ValueOrDie(), &minSourceY, &maxSourceY);
734 
735     angle::CheckedNumeric<int> clipX2(clip.x);
736     clipX2 += clip.width;
737     if (!clipX2.IsValid())
738     {
739         return false;
740     }
741     angle::CheckedNumeric<int> clipY2(clip.y);
742     clipY2 += clip.height;
743     if (!clipY2.IsValid())
744     {
745         return false;
746     }
747 
748     int minClipX, maxClipX, minClipY, maxClipY;
749     MinMax(clip.x, clipX2.ValueOrDie(), &minClipX, &maxClipX);
750     MinMax(clip.y, clipY2.ValueOrDie(), &minClipY, &maxClipY);
751 
752     if (minSourceX >= maxClipX || maxSourceX <= minClipX || minSourceY >= maxClipY ||
753         maxSourceY <= minClipY)
754     {
755         return false;
756     }
757 
758     int x      = std::max(minSourceX, minClipX);
759     int y      = std::max(minSourceY, minClipY);
760     int width  = std::min(maxSourceX, maxClipX) - x;
761     int height = std::min(maxSourceY, maxClipY) - y;
762 
763     if (intersection)
764     {
765         intersection->x      = x;
766         intersection->y      = y;
767         intersection->width  = width;
768         intersection->height = height;
769     }
770     return width != 0 && height != 0;
771 }
772 
GetEnclosingRectangle(const Rectangle & rect1,const Rectangle & rect2,Rectangle * rectUnion)773 void GetEnclosingRectangle(const Rectangle &rect1, const Rectangle &rect2, Rectangle *rectUnion)
774 {
775     // All callers use non-flipped framebuffer-size-clipped rectangles, so both flip and overflow
776     // are impossible.
777     ASSERT(!rect1.isReversedX() && !rect1.isReversedY());
778     ASSERT(!rect2.isReversedX() && !rect2.isReversedY());
779     ASSERT((angle::CheckedNumeric<int>(rect1.x) + rect1.width).IsValid());
780     ASSERT((angle::CheckedNumeric<int>(rect1.y) + rect1.height).IsValid());
781     ASSERT((angle::CheckedNumeric<int>(rect2.x) + rect2.width).IsValid());
782     ASSERT((angle::CheckedNumeric<int>(rect2.y) + rect2.height).IsValid());
783 
784     // This function calculates a rectangle that covers both input rectangles:
785     //
786     //                     +---------+
787     //          rect1 -->  |         |
788     //                     |     +---+-----+
789     //                     |     |   |     | <-- rect2
790     //                     +-----+---+     |
791     //                           |         |
792     //                           +---------+
793     //
794     //   xy0 = min(rect1.xy0, rect2.xy0)
795     //                    \
796     //                     +---------+-----+
797     //          union -->  |         .     |
798     //                     |     + . + . . +
799     //                     |     .   .     |
800     //                     + . . + . +     |
801     //                     |     .         |
802     //                     +-----+---------+
803     //                                    /
804     //                         xy1 = max(rect1.xy1, rect2.xy1)
805 
806     int x0 = std::min(rect1.x0(), rect2.x0());
807     int y0 = std::min(rect1.y0(), rect2.y0());
808 
809     int x1 = std::max(rect1.x1(), rect2.x1());
810     int y1 = std::max(rect1.y1(), rect2.y1());
811 
812     rectUnion->x      = x0;
813     rectUnion->y      = y0;
814     rectUnion->width  = x1 - x0;
815     rectUnion->height = y1 - y0;
816 }
817 
ExtendRectangle(const Rectangle & source,const Rectangle & extend,Rectangle * extended)818 void ExtendRectangle(const Rectangle &source, const Rectangle &extend, Rectangle *extended)
819 {
820     // All callers use non-flipped framebuffer-size-clipped rectangles, so both flip and overflow
821     // are impossible.
822     ASSERT(!source.isReversedX() && !source.isReversedY());
823     ASSERT(!extend.isReversedX() && !extend.isReversedY());
824     ASSERT((angle::CheckedNumeric<int>(source.x) + source.width).IsValid());
825     ASSERT((angle::CheckedNumeric<int>(source.y) + source.height).IsValid());
826     ASSERT((angle::CheckedNumeric<int>(extend.x) + extend.width).IsValid());
827     ASSERT((angle::CheckedNumeric<int>(extend.y) + extend.height).IsValid());
828 
829     int x0 = source.x0();
830     int x1 = source.x1();
831     int y0 = source.y0();
832     int y1 = source.y1();
833 
834     const int extendX0 = extend.x0();
835     const int extendX1 = extend.x1();
836     const int extendY0 = extend.y0();
837     const int extendY1 = extend.y1();
838 
839     // For each side of the rectangle, calculate whether it can be extended by the second rectangle.
840     // If so, extend it and continue for the next side with the new dimensions.
841 
842     // Left: Reduce x0 if the second rectangle's vertical edge covers the source's:
843     //
844     //     +--- - - -                +--- - - -
845     //     |                         |
846     //     |  +--------------+       +-----------------+
847     //     |  |    source    |  -->  |       source    |
848     //     |  +--------------+       +-----------------+
849     //     |                         |
850     //     +--- - - -                +--- - - -
851     //
852     const bool enclosesHeight = EnclosesRange(extendY0, extendY1, y0, y1);
853     if (extendX0 < x0 && extendX1 >= x0 && enclosesHeight)
854     {
855         x0 = extendX0;
856     }
857 
858     // Right: Increase x1 simiarly.
859     if (extendX0 <= x1 && extendX1 > x1 && enclosesHeight)
860     {
861         x1 = extendX1;
862     }
863 
864     // Top: Reduce y0 if the second rectangle's horizontal edge covers the source's potentially
865     // extended edge.
866     const bool enclosesWidth = EnclosesRange(extendX0, extendX1, x0, x1);
867     if (extendY0 < y0 && extendY1 >= y0 && enclosesWidth)
868     {
869         y0 = extendY0;
870     }
871 
872     // Right: Increase y1 simiarly.
873     if (extendY0 <= y1 && extendY1 > y1 && enclosesWidth)
874     {
875         y1 = extendY1;
876     }
877 
878     extended->x      = x0;
879     extended->y      = y0;
880     extended->width  = x1 - x0;
881     extended->height = y1 - y0;
882 }
883 
valid() const884 bool Box::valid() const
885 {
886     return width != 0 && height != 0 && depth != 0;
887 }
888 
operator ==(const Box & other) const889 bool Box::operator==(const Box &other) const
890 {
891     return (x == other.x && y == other.y && z == other.z && width == other.width &&
892             height == other.height && depth == other.depth);
893 }
894 
operator !=(const Box & other) const895 bool Box::operator!=(const Box &other) const
896 {
897     return !(*this == other);
898 }
899 
toRect() const900 Rectangle Box::toRect() const
901 {
902     ASSERT(z == 0 && depth == 1);
903     return Rectangle(x, y, width, height);
904 }
905 
coversSameExtent(const Extents & size) const906 bool Box::coversSameExtent(const Extents &size) const
907 {
908     return x == 0 && y == 0 && z == 0 && width == size.width && height == size.height &&
909            depth == size.depth;
910 }
911 
contains(const Box & other) const912 bool Box::contains(const Box &other) const
913 {
914     return x <= other.x && y <= other.y && z <= other.z && x + width >= other.x + other.width &&
915            y + height >= other.y + other.height && z + depth >= other.z + other.depth;
916 }
917 
volume() const918 size_t Box::volume() const
919 {
920     return width * height * depth;
921 }
922 
extend(const Box & other)923 void Box::extend(const Box &other)
924 {
925     // This extends the logic of "ExtendRectangle" to 3 dimensions
926 
927     int x0 = x;
928     int x1 = x + width;
929     int y0 = y;
930     int y1 = y + height;
931     int z0 = z;
932     int z1 = z + depth;
933 
934     const int otherx0 = other.x;
935     const int otherx1 = other.x + other.width;
936     const int othery0 = other.y;
937     const int othery1 = other.y + other.height;
938     const int otherz0 = other.z;
939     const int otherz1 = other.z + other.depth;
940 
941     // For each side of the box, calculate whether it can be extended by the other box.
942     // If so, extend it and continue to the next side with the new dimensions.
943 
944     const bool enclosesWidth  = EnclosesRange(otherx0, otherx1, x0, x1);
945     const bool enclosesHeight = EnclosesRange(othery0, othery1, y0, y1);
946     const bool enclosesDepth  = EnclosesRange(otherz0, otherz1, z0, z1);
947 
948     // Left: Reduce x0 if the other box's Y and Z plane encloses the source
949     if (otherx0 < x0 && otherx1 >= x0 && enclosesHeight && enclosesDepth)
950     {
951         x0 = otherx0;
952     }
953 
954     // Right: Increase x1 simiarly.
955     if (otherx0 <= x1 && otherx1 > x1 && enclosesHeight && enclosesDepth)
956     {
957         x1 = otherx1;
958     }
959 
960     // Bottom: Reduce y0 if the other box's X and Z plane encloses the source
961     if (othery0 < y0 && othery1 >= y0 && enclosesWidth && enclosesDepth)
962     {
963         y0 = othery0;
964     }
965 
966     // Top: Increase y1 simiarly.
967     if (othery0 <= y1 && othery1 > y1 && enclosesWidth && enclosesDepth)
968     {
969         y1 = othery1;
970     }
971 
972     // Front: Reduce z0 if the other box's X and Y plane encloses the source
973     if (otherz0 < z0 && otherz1 >= z0 && enclosesWidth && enclosesHeight)
974     {
975         z0 = otherz0;
976     }
977 
978     // Back: Increase z1 simiarly.
979     if (otherz0 <= z1 && otherz1 > z1 && enclosesWidth && enclosesHeight)
980     {
981         z1 = otherz1;
982     }
983 
984     // Update member var with new dimensions
985     x      = x0;
986     width  = x1 - x0;
987     y      = y0;
988     height = y1 - y0;
989     z      = z0;
990     depth  = z1 - z0;
991 }
992 
operator ==(const Offset & a,const Offset & b)993 bool operator==(const Offset &a, const Offset &b)
994 {
995     return a.x == b.x && a.y == b.y && a.z == b.z;
996 }
997 
operator !=(const Offset & a,const Offset & b)998 bool operator!=(const Offset &a, const Offset &b)
999 {
1000     return !(a == b);
1001 }
1002 
operator ==(const Extents & lhs,const Extents & rhs)1003 bool operator==(const Extents &lhs, const Extents &rhs)
1004 {
1005     return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depth == rhs.depth;
1006 }
1007 
operator !=(const Extents & lhs,const Extents & rhs)1008 bool operator!=(const Extents &lhs, const Extents &rhs)
1009 {
1010     return !(lhs == rhs);
1011 }
1012 
ValidateComponentTypeMasks(unsigned long outputTypes,unsigned long inputTypes,unsigned long outputMask,unsigned long inputMask)1013 bool ValidateComponentTypeMasks(unsigned long outputTypes,
1014                                 unsigned long inputTypes,
1015                                 unsigned long outputMask,
1016                                 unsigned long inputMask)
1017 {
1018     static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS <= kMaxComponentTypeMaskIndex,
1019                   "Output/input masks should fit into 16 bits - 1 bit per draw buffer. The "
1020                   "corresponding type masks should fit into 32 bits - 2 bits per draw buffer.");
1021     static_assert(MAX_VERTEX_ATTRIBS <= kMaxComponentTypeMaskIndex,
1022                   "Output/input masks should fit into 16 bits - 1 bit per attrib. The "
1023                   "corresponding type masks should fit into 32 bits - 2 bits per attrib.");
1024 
1025     // For performance reasons, draw buffer and attribute type validation is done using bit masks.
1026     // We store two bits representing the type split, with the low bit in the lower 16 bits of the
1027     // variable, and the high bit in the upper 16 bits of the variable. This is done so we can AND
1028     // with the elswewhere used DrawBufferMask or AttributeMask.
1029 
1030     // OR the masks with themselves, shifted 16 bits. This is to match our split type bits.
1031     outputMask |= (outputMask << kMaxComponentTypeMaskIndex);
1032     inputMask |= (inputMask << kMaxComponentTypeMaskIndex);
1033 
1034     // To validate:
1035     // 1. Remove any indexes that are not enabled in the input (& inputMask)
1036     // 2. Remove any indexes that exist in output, but not in input (& outputMask)
1037     // 3. Use == to verify equality
1038     return (outputTypes & inputMask) == ((inputTypes & outputMask) & inputMask);
1039 }
1040 
GetBoundBufferAvailableSize(const OffsetBindingPointer<Buffer> & binding)1041 GLsizeiptr GetBoundBufferAvailableSize(const OffsetBindingPointer<Buffer> &binding)
1042 {
1043     Buffer *buffer = binding.get();
1044     if (buffer == nullptr)
1045     {
1046         return 0;
1047     }
1048 
1049     const GLsizeiptr bufferSize = static_cast<GLsizeiptr>(buffer->getSize());
1050 
1051     if (binding.getSize() == 0)
1052     {
1053         return bufferSize;
1054     }
1055 
1056     const GLintptr offset = binding.getOffset();
1057     const GLsizeiptr size = binding.getSize();
1058 
1059     ASSERT(offset >= 0 && bufferSize >= 0);
1060 
1061     if (bufferSize <= offset)
1062     {
1063         return 0;
1064     }
1065 
1066     return std::min(size, bufferSize - offset);
1067 }
1068 
1069 }  // namespace gl
1070    //
1071 namespace angle
1072 {
CompressBlob(const size_t cacheSize,const uint8_t * cacheData,MemoryBuffer * compressedData)1073 bool CompressBlob(const size_t cacheSize, const uint8_t *cacheData, MemoryBuffer *compressedData)
1074 {
1075     uLong uncompressedSize       = static_cast<uLong>(cacheSize);
1076     uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
1077     uLong actualCompressedSize   = expectedCompressedSize;
1078 
1079     // Allocate memory.
1080     if (!compressedData->resize(expectedCompressedSize))
1081     {
1082         ERR() << "Failed to allocate memory for compression";
1083         return false;
1084     }
1085 
1086     int zResult = zlib_internal::GzipCompressHelper(compressedData->data(), &actualCompressedSize,
1087                                                     cacheData, uncompressedSize, nullptr, nullptr);
1088 
1089     if (zResult != Z_OK)
1090     {
1091         ERR() << "Failed to compress cache data: " << zResult;
1092         return false;
1093     }
1094 
1095     // Trim to actual size.
1096     ASSERT(actualCompressedSize <= expectedCompressedSize);
1097     compressedData->trim(actualCompressedSize);
1098 
1099     return true;
1100 }
1101 
DecompressBlob(const uint8_t * compressedData,const size_t compressedSize,size_t maxUncompressedDataSize,MemoryBuffer * uncompressedData)1102 bool DecompressBlob(const uint8_t *compressedData,
1103                     const size_t compressedSize,
1104                     size_t maxUncompressedDataSize,
1105                     MemoryBuffer *uncompressedData)
1106 {
1107     // Call zlib function to decompress.
1108     uint32_t uncompressedSize =
1109         zlib_internal::GetGzipUncompressedSize(compressedData, compressedSize);
1110 
1111     if (uncompressedSize > maxUncompressedDataSize)
1112     {
1113         ERR() << "Decompressed data size is larger than the maximum supported (" << uncompressedSize
1114               << " vs " << maxUncompressedDataSize << ")";
1115         return false;
1116     }
1117 
1118     // Allocate enough memory.
1119     if (!uncompressedData->resize(uncompressedSize))
1120     {
1121         ERR() << "Failed to allocate memory for decompression";
1122         return false;
1123     }
1124 
1125     uLong destLen = uncompressedSize;
1126     int zResult   = zlib_internal::GzipUncompressHelper(
1127         uncompressedData->data(), &destLen, compressedData, static_cast<uLong>(compressedSize));
1128 
1129     if (zResult != Z_OK)
1130     {
1131         WARN() << "Failed to decompress data: " << zResult << "\n";
1132         return false;
1133     }
1134 
1135     // Trim to actual size.
1136     ASSERT(destLen <= uncompressedSize);
1137     uncompressedData->trim(destLen);
1138 
1139     return true;
1140 }
1141 
GenerateCrc(const uint8_t * data,size_t size)1142 uint32_t GenerateCrc(const uint8_t *data, size_t size)
1143 {
1144     return static_cast<uint32_t>(crc32_z(0u, data, size));
1145 }
1146 
1147 UnlockedTailCall::UnlockedTailCall() = default;
1148 
~UnlockedTailCall()1149 UnlockedTailCall::~UnlockedTailCall()
1150 {
1151     ASSERT(mCalls.empty());
1152 }
1153 
add(CallType && call)1154 void UnlockedTailCall::add(CallType &&call)
1155 {
1156     mCalls.push_back(std::move(call));
1157 }
1158 
runImpl(void * resultOut)1159 void UnlockedTailCall::runImpl(void *resultOut)
1160 {
1161     if (mCalls.empty())
1162     {
1163         return;
1164     }
1165     // Clear `mCalls` before calling, because Android sometimes calls back into ANGLE through EGL
1166     // calls which don't expect there to be any pre-existing tail calls.
1167     auto calls(std::move(mCalls));
1168     ASSERT(mCalls.empty());
1169     for (CallType &call : calls)
1170     {
1171         call(resultOut);
1172     }
1173 }
1174 }  // namespace angle
1175