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