• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // renderer_utils:
7 //   Helper methods pertaining to most or all back-ends.
8 //
9 
10 #include "libANGLE/renderer/renderer_utils.h"
11 
12 #include "common/string_utils.h"
13 #include "common/system_utils.h"
14 #include "common/utilities.h"
15 #include "image_util/copyimage.h"
16 #include "image_util/imageformats.h"
17 #include "libANGLE/AttributeMap.h"
18 #include "libANGLE/Context.h"
19 #include "libANGLE/Context.inl.h"
20 #include "libANGLE/Display.h"
21 #include "libANGLE/formatutils.h"
22 #include "libANGLE/renderer/ContextImpl.h"
23 #include "libANGLE/renderer/Format.h"
24 #include "platform/Feature.h"
25 
26 #include <string.h>
27 #include <cctype>
28 
29 namespace angle
30 {
31 namespace
32 {
33 // For the sake of feature name matching, underscore is ignored, and the names are matched
34 // case-insensitive.  This allows feature names to be overriden both in snake_case (previously used
35 // by ANGLE) and camelCase.
FeatureNameMatch(const std::string & a,const std::string & b)36 bool FeatureNameMatch(const std::string &a, const std::string &b)
37 {
38     size_t ai = 0;
39     size_t bi = 0;
40 
41     while (ai < a.size() && bi < b.size())
42     {
43         if (a[ai] == '_')
44         {
45             ++ai;
46         }
47         if (b[bi] == '_')
48         {
49             ++bi;
50         }
51         if (std::tolower(a[ai++]) != std::tolower(b[bi++]))
52         {
53             return false;
54         }
55     }
56 
57     return ai == a.size() && bi == b.size();
58 }
59 
60 // Search for a feature by name, matching it loosely so that both snake_case and camelCase names are
61 // matched.
FindFeatureByName(FeatureMap * features,const std::string & name)62 FeatureInfo *FindFeatureByName(FeatureMap *features, const std::string &name)
63 {
64     for (auto iter : *features)
65     {
66         if (FeatureNameMatch(iter.first, name))
67         {
68             return iter.second;
69         }
70     }
71     return nullptr;
72 }
73 }  // anonymous namespace
74 
75 // FeatureSetBase implementation
overrideFeatures(const std::vector<std::string> & featureNames,bool enabled)76 void FeatureSetBase::overrideFeatures(const std::vector<std::string> &featureNames, bool enabled)
77 {
78     for (const std::string &name : featureNames)
79     {
80         FeatureInfo *feature = FindFeatureByName(&members, name);
81         if (feature != nullptr)
82         {
83             feature->enabled = enabled;
84         }
85     }
86 }
87 
populateFeatureList(FeatureList * features) const88 void FeatureSetBase::populateFeatureList(FeatureList *features) const
89 {
90     for (FeatureMap::const_iterator it = members.begin(); it != members.end(); it++)
91     {
92         features->push_back(it->second);
93     }
94 }
95 }  // namespace angle
96 
97 namespace rx
98 {
99 
100 namespace
101 {
102 // Both D3D and Vulkan support the same set of standard sample positions for 1, 2, 4, 8, and 16
103 // samples.  See:
104 //
105 // - https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx
106 //
107 // -
108 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#primsrast-multisampling
109 using SamplePositionsArray                                     = std::array<float, 32>;
110 constexpr std::array<SamplePositionsArray, 5> kSamplePositions = {
111     {{{0.5f, 0.5f}},
112      {{0.75f, 0.75f, 0.25f, 0.25f}},
113      {{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}},
114      {{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f,
115        0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}},
116      {{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f,  0.75f,   0.4375f,
117        0.1875f, 0.375f,  0.625f,  0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f,
118        0.375f,  0.875f,  0.5f,    0.0625f, 0.25f,   0.125f,  0.125f,  0.75f,
119        0.0f,    0.5f,    0.9375f, 0.25f,   0.875f,  0.9375f, 0.0625f, 0.0f}}}};
120 
121 struct IncompleteTextureParameters
122 {
123     GLenum sizedInternalFormat;
124     GLenum format;
125     GLenum type;
126     GLubyte clearColor[4];
127 };
128 
129 // Note that for gl::SamplerFormat::Shadow, the clearColor datatype needs to be GLushort and as such
130 // we will reinterpret GLubyte[4] as GLushort[2].
131 constexpr angle::PackedEnumMap<gl::SamplerFormat, IncompleteTextureParameters>
132     kIncompleteTextureParameters = {
133         {gl::SamplerFormat::Float, {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, {0, 0, 0, 255}}},
134         {gl::SamplerFormat::Unsigned,
135          {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, {0, 0, 0, 255}}},
136         {gl::SamplerFormat::Signed, {GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, {0, 0, 0, 127}}},
137         {gl::SamplerFormat::Shadow,
138          {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, {0, 0, 0, 0}}}};
139 
CopyColor(gl::ColorF * color)140 void CopyColor(gl::ColorF *color)
141 {
142     // No-op
143 }
144 
PremultiplyAlpha(gl::ColorF * color)145 void PremultiplyAlpha(gl::ColorF *color)
146 {
147     color->red *= color->alpha;
148     color->green *= color->alpha;
149     color->blue *= color->alpha;
150 }
151 
UnmultiplyAlpha(gl::ColorF * color)152 void UnmultiplyAlpha(gl::ColorF *color)
153 {
154     if (color->alpha != 0.0f)
155     {
156         float invAlpha = 1.0f / color->alpha;
157         color->red *= invAlpha;
158         color->green *= invAlpha;
159         color->blue *= invAlpha;
160     }
161 }
162 
ClipChannelsR(gl::ColorF * color)163 void ClipChannelsR(gl::ColorF *color)
164 {
165     color->green = 0.0f;
166     color->blue  = 0.0f;
167     color->alpha = 1.0f;
168 }
169 
ClipChannelsRG(gl::ColorF * color)170 void ClipChannelsRG(gl::ColorF *color)
171 {
172     color->blue  = 0.0f;
173     color->alpha = 1.0f;
174 }
175 
ClipChannelsRGB(gl::ColorF * color)176 void ClipChannelsRGB(gl::ColorF *color)
177 {
178     color->alpha = 1.0f;
179 }
180 
ClipChannelsLuminance(gl::ColorF * color)181 void ClipChannelsLuminance(gl::ColorF *color)
182 {
183     color->alpha = 1.0f;
184 }
185 
ClipChannelsAlpha(gl::ColorF * color)186 void ClipChannelsAlpha(gl::ColorF *color)
187 {
188     color->red   = 0.0f;
189     color->green = 0.0f;
190     color->blue  = 0.0f;
191 }
192 
ClipChannelsNoOp(gl::ColorF * color)193 void ClipChannelsNoOp(gl::ColorF *color) {}
194 
WriteUintColor(const gl::ColorF & color,PixelWriteFunction colorWriteFunction,uint8_t * destPixelData)195 void WriteUintColor(const gl::ColorF &color,
196                     PixelWriteFunction colorWriteFunction,
197                     uint8_t *destPixelData)
198 {
199     gl::ColorUI destColor(
200         static_cast<unsigned int>(color.red * 255), static_cast<unsigned int>(color.green * 255),
201         static_cast<unsigned int>(color.blue * 255), static_cast<unsigned int>(color.alpha * 255));
202     colorWriteFunction(reinterpret_cast<const uint8_t *>(&destColor), destPixelData);
203 }
204 
WriteFloatColor(const gl::ColorF & color,PixelWriteFunction colorWriteFunction,uint8_t * destPixelData)205 void WriteFloatColor(const gl::ColorF &color,
206                      PixelWriteFunction colorWriteFunction,
207                      uint8_t *destPixelData)
208 {
209     colorWriteFunction(reinterpret_cast<const uint8_t *>(&color), destPixelData);
210 }
211 
212 template <int cols, int rows, bool IsColumnMajor>
GetFlattenedIndex(int col,int row)213 inline int GetFlattenedIndex(int col, int row)
214 {
215     if (IsColumnMajor)
216     {
217         return col * rows + row;
218     }
219     else
220     {
221         return row * cols + col;
222     }
223 }
224 
225 template <typename T,
226           bool IsSrcColumnMajor,
227           int colsSrc,
228           int rowsSrc,
229           bool IsDstColumnMajor,
230           int colsDst,
231           int rowsDst>
ExpandMatrix(T * target,const GLfloat * value)232 void ExpandMatrix(T *target, const GLfloat *value)
233 {
234     static_assert(colsSrc <= colsDst && rowsSrc <= rowsDst, "Can only expand!");
235 
236     constexpr int kDstFlatSize = colsDst * rowsDst;
237     T staging[kDstFlatSize]    = {0};
238 
239     for (int r = 0; r < rowsSrc; r++)
240     {
241         for (int c = 0; c < colsSrc; c++)
242         {
243             int srcIndex = GetFlattenedIndex<colsSrc, rowsSrc, IsSrcColumnMajor>(c, r);
244             int dstIndex = GetFlattenedIndex<colsDst, rowsDst, IsDstColumnMajor>(c, r);
245 
246             staging[dstIndex] = static_cast<T>(value[srcIndex]);
247         }
248     }
249 
250     memcpy(target, staging, kDstFlatSize * sizeof(T));
251 }
252 
253 template <bool IsSrcColumMajor,
254           int colsSrc,
255           int rowsSrc,
256           bool IsDstColumnMajor,
257           int colsDst,
258           int rowsDst>
SetFloatUniformMatrix(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,const GLfloat * value,uint8_t * targetData)259 void SetFloatUniformMatrix(unsigned int arrayElementOffset,
260                            unsigned int elementCount,
261                            GLsizei countIn,
262                            const GLfloat *value,
263                            uint8_t *targetData)
264 {
265     unsigned int count =
266         std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
267 
268     const unsigned int targetMatrixStride = colsDst * rowsDst;
269     GLfloat *target                       = reinterpret_cast<GLfloat *>(
270         targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride);
271 
272     for (unsigned int i = 0; i < count; i++)
273     {
274         ExpandMatrix<GLfloat, IsSrcColumMajor, colsSrc, rowsSrc, IsDstColumnMajor, colsDst,
275                      rowsDst>(target, value);
276 
277         target += targetMatrixStride;
278         value += colsSrc * rowsSrc;
279     }
280 }
281 
SetFloatUniformMatrixFast(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,size_t matrixSize,const GLfloat * value,uint8_t * targetData)282 void SetFloatUniformMatrixFast(unsigned int arrayElementOffset,
283                                unsigned int elementCount,
284                                GLsizei countIn,
285                                size_t matrixSize,
286                                const GLfloat *value,
287                                uint8_t *targetData)
288 {
289     const unsigned int count =
290         std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
291 
292     const uint8_t *valueData = reinterpret_cast<const uint8_t *>(value);
293     targetData               = targetData + arrayElementOffset * matrixSize;
294 
295     memcpy(targetData, valueData, matrixSize * count);
296 }
297 }  // anonymous namespace
298 
RotateRectangle(const SurfaceRotation rotation,const bool flipY,const int framebufferWidth,const int framebufferHeight,const gl::Rectangle & incoming,gl::Rectangle * outgoing)299 void RotateRectangle(const SurfaceRotation rotation,
300                      const bool flipY,
301                      const int framebufferWidth,
302                      const int framebufferHeight,
303                      const gl::Rectangle &incoming,
304                      gl::Rectangle *outgoing)
305 {
306     // GLES's y-axis points up; Vulkan's points down.
307     switch (rotation)
308     {
309         case SurfaceRotation::Identity:
310             // Do not rotate gl_Position (surface matches the device's orientation):
311             outgoing->x     = incoming.x;
312             outgoing->y     = flipY ? framebufferHeight - incoming.y - incoming.height : incoming.y;
313             outgoing->width = incoming.width;
314             outgoing->height = incoming.height;
315             break;
316         case SurfaceRotation::Rotated90Degrees:
317             // Rotate gl_Position 90 degrees:
318             outgoing->x      = incoming.y;
319             outgoing->y      = flipY ? incoming.x : framebufferWidth - incoming.x - incoming.width;
320             outgoing->width  = incoming.height;
321             outgoing->height = incoming.width;
322             break;
323         case SurfaceRotation::Rotated180Degrees:
324             // Rotate gl_Position 180 degrees:
325             outgoing->x     = framebufferWidth - incoming.x - incoming.width;
326             outgoing->y     = flipY ? incoming.y : framebufferHeight - incoming.y - incoming.height;
327             outgoing->width = incoming.width;
328             outgoing->height = incoming.height;
329             break;
330         case SurfaceRotation::Rotated270Degrees:
331             // Rotate gl_Position 270 degrees:
332             outgoing->x      = framebufferHeight - incoming.y - incoming.height;
333             outgoing->y      = flipY ? framebufferWidth - incoming.x - incoming.width : incoming.x;
334             outgoing->width  = incoming.height;
335             outgoing->height = incoming.width;
336             break;
337         default:
338             UNREACHABLE();
339             break;
340     }
341 }
342 
PackPixelsParams()343 PackPixelsParams::PackPixelsParams()
344     : destFormat(nullptr),
345       outputPitch(0),
346       packBuffer(nullptr),
347       offset(0),
348       rotation(SurfaceRotation::Identity)
349 {}
350 
PackPixelsParams(const gl::Rectangle & areaIn,const angle::Format & destFormat,GLuint outputPitchIn,bool reverseRowOrderIn,gl::Buffer * packBufferIn,ptrdiff_t offsetIn)351 PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn,
352                                    const angle::Format &destFormat,
353                                    GLuint outputPitchIn,
354                                    bool reverseRowOrderIn,
355                                    gl::Buffer *packBufferIn,
356                                    ptrdiff_t offsetIn)
357     : area(areaIn),
358       destFormat(&destFormat),
359       outputPitch(outputPitchIn),
360       packBuffer(packBufferIn),
361       reverseRowOrder(reverseRowOrderIn),
362       offset(offsetIn),
363       rotation(SurfaceRotation::Identity)
364 {}
365 
PackPixels(const PackPixelsParams & params,const angle::Format & sourceFormat,int inputPitchIn,const uint8_t * sourceIn,uint8_t * destWithoutOffset)366 void PackPixels(const PackPixelsParams &params,
367                 const angle::Format &sourceFormat,
368                 int inputPitchIn,
369                 const uint8_t *sourceIn,
370                 uint8_t *destWithoutOffset)
371 {
372     uint8_t *destWithOffset = destWithoutOffset + params.offset;
373 
374     const uint8_t *source = sourceIn;
375     int inputPitch        = inputPitchIn;
376     int destWidth         = params.area.width;
377     int destHeight        = params.area.height;
378     int xAxisPitch        = 0;
379     int yAxisPitch        = 0;
380     switch (params.rotation)
381     {
382         case SurfaceRotation::Identity:
383             // The source image is not rotated (i.e. matches the device's orientation), and may or
384             // may not be y-flipped.  The image is row-major.  Each source row (one step along the
385             // y-axis for each step in the dest y-axis) is inputPitch past the previous row.  Along
386             // a row, each source pixel (one step along the x-axis for each step in the dest
387             // x-axis) is sourceFormat.pixelBytes past the previous pixel.
388             xAxisPitch = sourceFormat.pixelBytes;
389             if (params.reverseRowOrder)
390             {
391                 // The source image is y-flipped, which means we start at the last row, and each
392                 // source row is BEFORE the previous row.
393                 source += inputPitchIn * (params.area.height - 1);
394                 inputPitch = -inputPitch;
395                 yAxisPitch = -inputPitchIn;
396             }
397             else
398             {
399                 yAxisPitch = inputPitchIn;
400             }
401             break;
402         case SurfaceRotation::Rotated90Degrees:
403             // The source image is rotated 90 degrees counter-clockwise.  Y-flip is always applied
404             // to rotated images.  The image is column-major.  Each source column (one step along
405             // the source x-axis for each step in the dest y-axis) is inputPitch past the previous
406             // column.  Along a column, each source pixel (one step along the y-axis for each step
407             // in the dest x-axis) is sourceFormat.pixelBytes past the previous pixel.
408             xAxisPitch = inputPitchIn;
409             yAxisPitch = sourceFormat.pixelBytes;
410             destWidth  = params.area.height;
411             destHeight = params.area.width;
412             break;
413         case SurfaceRotation::Rotated180Degrees:
414             // The source image is rotated 180 degrees.  Y-flip is always applied to rotated
415             // images.  The image is row-major, but upside down.  Each source row (one step along
416             // the y-axis for each step in the dest y-axis) is inputPitch after the previous row.
417             // Along a row, each source pixel (one step along the x-axis for each step in the dest
418             // x-axis) is sourceFormat.pixelBytes BEFORE the previous pixel.
419             xAxisPitch = -static_cast<int>(sourceFormat.pixelBytes);
420             yAxisPitch = inputPitchIn;
421             source += sourceFormat.pixelBytes * (params.area.width - 1);
422             break;
423         case SurfaceRotation::Rotated270Degrees:
424             // The source image is rotated 270 degrees counter-clockwise (or 90 degrees clockwise).
425             // Y-flip is always applied to rotated images.  The image is column-major, where each
426             // column (one step in the source x-axis for one step in the dest y-axis) is inputPitch
427             // BEFORE the previous column.  Along a column, each source pixel (one step along the
428             // y-axis for each step in the dest x-axis) is sourceFormat.pixelBytes BEFORE the
429             // previous pixel.  The first pixel is at the end of the source.
430             xAxisPitch = -inputPitchIn;
431             yAxisPitch = -static_cast<int>(sourceFormat.pixelBytes);
432             destWidth  = params.area.height;
433             destHeight = params.area.width;
434             source += inputPitch * (params.area.height - 1) +
435                       sourceFormat.pixelBytes * (params.area.width - 1);
436             break;
437         default:
438             UNREACHABLE();
439             break;
440     }
441 
442     if (params.rotation == SurfaceRotation::Identity && sourceFormat == *params.destFormat)
443     {
444         // Direct copy possible
445         for (int y = 0; y < params.area.height; ++y)
446         {
447             memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch,
448                    params.area.width * sourceFormat.pixelBytes);
449         }
450         return;
451     }
452 
453     FastCopyFunction fastCopyFunc = sourceFormat.fastCopyFunctions.get(params.destFormat->id);
454 
455     if (fastCopyFunc)
456     {
457         // Fast copy is possible through some special function
458         fastCopyFunc(source, xAxisPitch, yAxisPitch, destWithOffset, params.destFormat->pixelBytes,
459                      params.outputPitch, destWidth, destHeight);
460         return;
461     }
462 
463     PixelWriteFunction pixelWriteFunction = params.destFormat->pixelWriteFunction;
464     ASSERT(pixelWriteFunction != nullptr);
465 
466     // Maximum size of any Color<T> type used.
467     uint8_t temp[16];
468     static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) &&
469                       sizeof(temp) >= sizeof(gl::ColorI) &&
470                       sizeof(temp) >= sizeof(angle::DepthStencil),
471                   "Unexpected size of pixel struct.");
472 
473     PixelReadFunction pixelReadFunction = sourceFormat.pixelReadFunction;
474     ASSERT(pixelReadFunction != nullptr);
475 
476     for (int y = 0; y < destHeight; ++y)
477     {
478         for (int x = 0; x < destWidth; ++x)
479         {
480             uint8_t *dest =
481                 destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
482             const uint8_t *src = source + y * yAxisPitch + x * xAxisPitch;
483 
484             // readFunc and writeFunc will be using the same type of color, CopyTexImage
485             // will not allow the copy otherwise.
486             pixelReadFunction(src, temp);
487             pixelWriteFunction(temp, dest);
488         }
489     }
490 }
491 
has(angle::FormatID formatID) const492 bool FastCopyFunctionMap::has(angle::FormatID formatID) const
493 {
494     return (get(formatID) != nullptr);
495 }
496 
497 namespace
498 {
499 
getEntry(const FastCopyFunctionMap::Entry * entry,size_t numEntries,angle::FormatID formatID)500 const FastCopyFunctionMap::Entry *getEntry(const FastCopyFunctionMap::Entry *entry,
501                                            size_t numEntries,
502                                            angle::FormatID formatID)
503 {
504     const FastCopyFunctionMap::Entry *end = entry + numEntries;
505     while (entry != end)
506     {
507         if (entry->formatID == formatID)
508         {
509             return entry;
510         }
511         ++entry;
512     }
513 
514     return nullptr;
515 }
516 
517 }  // namespace
518 
get(angle::FormatID formatID) const519 FastCopyFunction FastCopyFunctionMap::get(angle::FormatID formatID) const
520 {
521     const FastCopyFunctionMap::Entry *entry = getEntry(mData, mSize, formatID);
522     return entry ? entry->func : nullptr;
523 }
524 
ShouldUseDebugLayers(const egl::AttributeMap & attribs)525 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs)
526 {
527     EGLAttrib debugSetting =
528         attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE);
529 
530     // Prefer to enable debug layers when available.
531 #if defined(ANGLE_ENABLE_ASSERTS)
532     return (debugSetting != EGL_FALSE);
533 #else
534     return (debugSetting == EGL_TRUE);
535 #endif  // defined(ANGLE_ENABLE_ASSERTS)
536 }
537 
CopyImageCHROMIUM(const uint8_t * sourceData,size_t sourceRowPitch,size_t sourcePixelBytes,size_t sourceDepthPitch,PixelReadFunction pixelReadFunction,uint8_t * destData,size_t destRowPitch,size_t destPixelBytes,size_t destDepthPitch,PixelWriteFunction pixelWriteFunction,GLenum destUnsizedFormat,GLenum destComponentType,size_t width,size_t height,size_t depth,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)538 void CopyImageCHROMIUM(const uint8_t *sourceData,
539                        size_t sourceRowPitch,
540                        size_t sourcePixelBytes,
541                        size_t sourceDepthPitch,
542                        PixelReadFunction pixelReadFunction,
543                        uint8_t *destData,
544                        size_t destRowPitch,
545                        size_t destPixelBytes,
546                        size_t destDepthPitch,
547                        PixelWriteFunction pixelWriteFunction,
548                        GLenum destUnsizedFormat,
549                        GLenum destComponentType,
550                        size_t width,
551                        size_t height,
552                        size_t depth,
553                        bool unpackFlipY,
554                        bool unpackPremultiplyAlpha,
555                        bool unpackUnmultiplyAlpha)
556 {
557     using ConversionFunction              = void (*)(gl::ColorF *);
558     ConversionFunction conversionFunction = CopyColor;
559     if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha)
560     {
561         if (unpackPremultiplyAlpha)
562         {
563             conversionFunction = PremultiplyAlpha;
564         }
565         else
566         {
567             conversionFunction = UnmultiplyAlpha;
568         }
569     }
570 
571     auto clipChannelsFunction = ClipChannelsNoOp;
572     switch (destUnsizedFormat)
573     {
574         case GL_RED:
575             clipChannelsFunction = ClipChannelsR;
576             break;
577         case GL_RG:
578             clipChannelsFunction = ClipChannelsRG;
579             break;
580         case GL_RGB:
581             clipChannelsFunction = ClipChannelsRGB;
582             break;
583         case GL_LUMINANCE:
584             clipChannelsFunction = ClipChannelsLuminance;
585             break;
586         case GL_ALPHA:
587             clipChannelsFunction = ClipChannelsAlpha;
588             break;
589     }
590 
591     auto writeFunction = (destComponentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor;
592 
593     for (size_t z = 0; z < depth; z++)
594     {
595         for (size_t y = 0; y < height; y++)
596         {
597             for (size_t x = 0; x < width; x++)
598             {
599                 const uint8_t *sourcePixelData =
600                     sourceData + y * sourceRowPitch + x * sourcePixelBytes + z * sourceDepthPitch;
601 
602                 gl::ColorF sourceColor;
603                 pixelReadFunction(sourcePixelData, reinterpret_cast<uint8_t *>(&sourceColor));
604 
605                 conversionFunction(&sourceColor);
606                 clipChannelsFunction(&sourceColor);
607 
608                 size_t destY = 0;
609                 if (unpackFlipY)
610                 {
611                     destY += (height - 1);
612                     destY -= y;
613                 }
614                 else
615                 {
616                     destY += y;
617                 }
618 
619                 uint8_t *destPixelData =
620                     destData + destY * destRowPitch + x * destPixelBytes + z * destDepthPitch;
621                 writeFunction(sourceColor, pixelWriteFunction, destPixelData);
622             }
623         }
624     }
625 }
626 
627 // IncompleteTextureSet implementation.
IncompleteTextureSet()628 IncompleteTextureSet::IncompleteTextureSet() : mIncompleteTextureBufferAttachment(nullptr) {}
629 
~IncompleteTextureSet()630 IncompleteTextureSet::~IncompleteTextureSet() {}
631 
onDestroy(const gl::Context * context)632 void IncompleteTextureSet::onDestroy(const gl::Context *context)
633 {
634     // Clear incomplete textures.
635     for (auto &incompleteTextures : mIncompleteTextures)
636     {
637         for (auto &incompleteTexture : incompleteTextures)
638         {
639             if (incompleteTexture.get() != nullptr)
640             {
641                 incompleteTexture->onDestroy(context);
642                 incompleteTexture.set(context, nullptr);
643             }
644         }
645     }
646     if (mIncompleteTextureBufferAttachment != nullptr)
647     {
648         mIncompleteTextureBufferAttachment->onDestroy(context);
649         mIncompleteTextureBufferAttachment = nullptr;
650     }
651 }
652 
getIncompleteTexture(const gl::Context * context,gl::TextureType type,gl::SamplerFormat format,MultisampleTextureInitializer * multisampleInitializer,gl::Texture ** textureOut)653 angle::Result IncompleteTextureSet::getIncompleteTexture(
654     const gl::Context *context,
655     gl::TextureType type,
656     gl::SamplerFormat format,
657     MultisampleTextureInitializer *multisampleInitializer,
658     gl::Texture **textureOut)
659 {
660     *textureOut = mIncompleteTextures[format][type].get();
661     if (*textureOut != nullptr)
662     {
663         return angle::Result::Continue;
664     }
665 
666     ContextImpl *implFactory = context->getImplementation();
667 
668     gl::Extents colorSize(1, 1, 1);
669     gl::PixelUnpackState unpack;
670     unpack.alignment = 1;
671     gl::Box area(0, 0, 0, 1, 1, 1);
672     const IncompleteTextureParameters &incompleteTextureParam =
673         kIncompleteTextureParameters[format];
674 
675     // Cube map arrays are expected to have layer counts that are multiples of 6
676     constexpr int kCubeMapArraySize = 6;
677     if (type == gl::TextureType::CubeMapArray)
678     {
679         // From the GLES 3.2 spec:
680         //   8.18. IMMUTABLE-FORMAT TEXTURE IMAGES
681         //   TexStorage3D Errors
682         //   An INVALID_OPERATION error is generated if any of the following conditions hold:
683         //     * target is TEXTURE_CUBE_MAP_ARRAY and depth is not a multiple of 6
684         // Since ANGLE treats incomplete textures as immutable, respect that here.
685         colorSize.depth = kCubeMapArraySize;
686         area.depth      = kCubeMapArraySize;
687     }
688 
689     // If a texture is external use a 2D texture for the incomplete texture
690     gl::TextureType createType = (type == gl::TextureType::External) ? gl::TextureType::_2D : type;
691 
692     gl::Texture *tex =
693         new gl::Texture(implFactory, {std::numeric_limits<GLuint>::max()}, createType);
694     angle::UniqueObjectPointer<gl::Texture, gl::Context> t(tex, context);
695 
696     // This is a bit of a kludge but is necessary to consume the error.
697     gl::Context *mutableContext = const_cast<gl::Context *>(context);
698 
699     if (createType == gl::TextureType::Buffer)
700     {
701         constexpr uint32_t kBufferInitData = 0;
702         mIncompleteTextureBufferAttachment =
703             new gl::Buffer(implFactory, {std::numeric_limits<GLuint>::max()});
704         ANGLE_TRY(mIncompleteTextureBufferAttachment->bufferData(
705             mutableContext, gl::BufferBinding::Texture, &kBufferInitData, sizeof(kBufferInitData),
706             gl::BufferUsage::StaticDraw));
707     }
708     else if (createType == gl::TextureType::_2DMultisample)
709     {
710         ANGLE_TRY(t->setStorageMultisample(mutableContext, createType, 1,
711                                            incompleteTextureParam.sizedInternalFormat, colorSize,
712                                            true));
713     }
714     else
715     {
716         ANGLE_TRY(t->setStorage(mutableContext, createType, 1,
717                                 incompleteTextureParam.sizedInternalFormat, colorSize));
718     }
719 
720     if (type == gl::TextureType::CubeMap)
721     {
722         for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
723         {
724             ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr, face, 0, area,
725                                      incompleteTextureParam.format, incompleteTextureParam.type,
726                                      incompleteTextureParam.clearColor));
727         }
728     }
729     else if (type == gl::TextureType::CubeMapArray)
730     {
731         // We need to provide enough pixel data to fill the array of six faces
732         GLubyte incompleteCubeArrayPixels[kCubeMapArraySize][4];
733         for (int i = 0; i < kCubeMapArraySize; ++i)
734         {
735             incompleteCubeArrayPixels[i][0] = incompleteTextureParam.clearColor[0];
736             incompleteCubeArrayPixels[i][1] = incompleteTextureParam.clearColor[1];
737             incompleteCubeArrayPixels[i][2] = incompleteTextureParam.clearColor[2];
738             incompleteCubeArrayPixels[i][3] = incompleteTextureParam.clearColor[3];
739         }
740 
741         ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr,
742                                  gl::NonCubeTextureTypeToTarget(createType), 0, area,
743                                  incompleteTextureParam.format, incompleteTextureParam.type,
744                                  *incompleteCubeArrayPixels));
745     }
746     else if (type == gl::TextureType::_2DMultisample)
747     {
748         // Call a specialized clear function to init a multisample texture.
749         ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get()));
750     }
751     else if (type == gl::TextureType::Buffer)
752     {
753         ANGLE_TRY(t->setBuffer(context, mIncompleteTextureBufferAttachment,
754                                incompleteTextureParam.sizedInternalFormat));
755     }
756     else
757     {
758         ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr,
759                                  gl::NonCubeTextureTypeToTarget(createType), 0, area,
760                                  incompleteTextureParam.format, incompleteTextureParam.type,
761                                  incompleteTextureParam.clearColor));
762     }
763 
764     if (format == gl::SamplerFormat::Shadow)
765     {
766         // To avoid the undefined spec behavior for shadow samplers with a depth texture, we set the
767         // compare mode to GL_COMPARE_REF_TO_TEXTURE
768         ASSERT(!t->hasObservers());
769         t->setCompareMode(context, GL_COMPARE_REF_TO_TEXTURE);
770     }
771 
772     ANGLE_TRY(t->syncState(context, gl::Command::Other));
773 
774     mIncompleteTextures[format][type].set(context, t.release());
775     *textureOut = mIncompleteTextures[format][type].get();
776     return angle::Result::Continue;
777 }
778 
779 #define ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \
780     template void SetFloatUniformMatrix##api<cols, rows>::Run(     \
781         unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *)
782 
783 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 2);
784 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 3);
785 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 3);
786 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 2);
787 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 2);
788 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 3);
789 
790 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 2);
791 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 3);
792 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 3);
793 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 2);
794 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 4);
795 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 4);
796 
797 #undef ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC
798 
799 #define ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows)                      \
800     template void SetFloatUniformMatrix##api<cols, 4>::Run(unsigned int, unsigned int, GLsizei, \
801                                                            GLboolean, const GLfloat *, uint8_t *)
802 
803 template <int cols>
804 struct SetFloatUniformMatrixGLSL<cols, 4>
805 {
806     static void Run(unsigned int arrayElementOffset,
807                     unsigned int elementCount,
808                     GLsizei countIn,
809                     GLboolean transpose,
810                     const GLfloat *value,
811                     uint8_t *targetData);
812 };
813 
814 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 4);
815 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 4);
816 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 4);
817 
818 #undef ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC
819 
820 #define ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows)                      \
821     template void SetFloatUniformMatrix##api<4, rows>::Run(unsigned int, unsigned int, GLsizei, \
822                                                            GLboolean, const GLfloat *, uint8_t *)
823 
824 template <int rows>
825 struct SetFloatUniformMatrixHLSL<4, rows>
826 {
827     static void Run(unsigned int arrayElementOffset,
828                     unsigned int elementCount,
829                     GLsizei countIn,
830                     GLboolean transpose,
831                     const GLfloat *value,
832                     uint8_t *targetData);
833 };
834 
835 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 2);
836 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 3);
837 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 4);
838 
839 #undef ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC
840 
841 template <int cols>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)842 void SetFloatUniformMatrixGLSL<cols, 4>::Run(unsigned int arrayElementOffset,
843                                              unsigned int elementCount,
844                                              GLsizei countIn,
845                                              GLboolean transpose,
846                                              const GLfloat *value,
847                                              uint8_t *targetData)
848 {
849     const bool isSrcColumnMajor = !transpose;
850     if (isSrcColumnMajor)
851     {
852         // Both src and dst matrixs are has same layout,
853         // a single memcpy updates all the matrices
854         constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 4;
855         SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value,
856                                   targetData);
857     }
858     else
859     {
860         // fallback to general cases
861         SetFloatUniformMatrix<false, cols, 4, true, cols, 4>(arrayElementOffset, elementCount,
862                                                              countIn, value, targetData);
863     }
864 }
865 
866 template <int cols, int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)867 void SetFloatUniformMatrixGLSL<cols, rows>::Run(unsigned int arrayElementOffset,
868                                                 unsigned int elementCount,
869                                                 GLsizei countIn,
870                                                 GLboolean transpose,
871                                                 const GLfloat *value,
872                                                 uint8_t *targetData)
873 {
874     const bool isSrcColumnMajor = !transpose;
875     // GLSL expects matrix uniforms to be column-major, and each column is padded to 4 rows.
876     if (isSrcColumnMajor)
877     {
878         SetFloatUniformMatrix<true, cols, rows, true, cols, 4>(arrayElementOffset, elementCount,
879                                                                countIn, value, targetData);
880     }
881     else
882     {
883         SetFloatUniformMatrix<false, cols, rows, true, cols, 4>(arrayElementOffset, elementCount,
884                                                                 countIn, value, targetData);
885     }
886 }
887 
888 template <int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)889 void SetFloatUniformMatrixHLSL<4, rows>::Run(unsigned int arrayElementOffset,
890                                              unsigned int elementCount,
891                                              GLsizei countIn,
892                                              GLboolean transpose,
893                                              const GLfloat *value,
894                                              uint8_t *targetData)
895 {
896     const bool isSrcColumnMajor = !transpose;
897     if (!isSrcColumnMajor)
898     {
899         // Both src and dst matrixs are has same layout,
900         // a single memcpy updates all the matrices
901         constexpr size_t srcMatrixSize = sizeof(GLfloat) * 4 * rows;
902         SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value,
903                                   targetData);
904     }
905     else
906     {
907         // fallback to general cases
908         SetFloatUniformMatrix<true, 4, rows, false, 4, rows>(arrayElementOffset, elementCount,
909                                                              countIn, value, targetData);
910     }
911 }
912 
913 template <int cols, int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)914 void SetFloatUniformMatrixHLSL<cols, rows>::Run(unsigned int arrayElementOffset,
915                                                 unsigned int elementCount,
916                                                 GLsizei countIn,
917                                                 GLboolean transpose,
918                                                 const GLfloat *value,
919                                                 uint8_t *targetData)
920 {
921     const bool isSrcColumnMajor = !transpose;
922     // Internally store matrices as row-major to accomodate HLSL matrix indexing.  Each row is
923     // padded to 4 columns.
924     if (!isSrcColumnMajor)
925     {
926         SetFloatUniformMatrix<false, cols, rows, false, 4, rows>(arrayElementOffset, elementCount,
927                                                                  countIn, value, targetData);
928     }
929     else
930     {
931         SetFloatUniformMatrix<true, cols, rows, false, 4, rows>(arrayElementOffset, elementCount,
932                                                                 countIn, value, targetData);
933     }
934 }
935 
936 template void GetMatrixUniform<GLint>(GLenum, GLint *, const GLint *, bool);
937 template void GetMatrixUniform<GLuint>(GLenum, GLuint *, const GLuint *, bool);
938 
GetMatrixUniform(GLenum type,GLfloat * dataOut,const GLfloat * source,bool transpose)939 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose)
940 {
941     int columns = gl::VariableColumnCount(type);
942     int rows    = gl::VariableRowCount(type);
943     for (GLint col = 0; col < columns; ++col)
944     {
945         for (GLint row = 0; row < rows; ++row)
946         {
947             GLfloat *outptr = dataOut + ((col * rows) + row);
948             const GLfloat *inptr =
949                 transpose ? source + ((row * 4) + col) : source + ((col * 4) + row);
950             *outptr = *inptr;
951         }
952     }
953 }
954 
955 template <typename NonFloatT>
GetMatrixUniform(GLenum type,NonFloatT * dataOut,const NonFloatT * source,bool transpose)956 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose)
957 {
958     UNREACHABLE();
959 }
960 
GetFormatFromFormatType(GLenum format,GLenum type)961 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type)
962 {
963     GLenum sizedInternalFormat    = gl::GetInternalFormatInfo(format, type).sizedInternalFormat;
964     angle::FormatID angleFormatID = angle::Format::InternalFormatToID(sizedInternalFormat);
965     return angle::Format::Get(angleFormatID);
966 }
967 
ComputeStartVertex(ContextImpl * contextImpl,const gl::IndexRange & indexRange,GLint baseVertex,GLint * firstVertexOut)968 angle::Result ComputeStartVertex(ContextImpl *contextImpl,
969                                  const gl::IndexRange &indexRange,
970                                  GLint baseVertex,
971                                  GLint *firstVertexOut)
972 {
973     // The entire index range should be within the limits of a 32-bit uint because the largest
974     // GL index type is GL_UNSIGNED_INT.
975     ASSERT(indexRange.start <= std::numeric_limits<uint32_t>::max() &&
976            indexRange.end <= std::numeric_limits<uint32_t>::max());
977 
978     // The base vertex is only used in DrawElementsIndirect. Given the assertion above and the
979     // type of mBaseVertex (GLint), adding them both as 64-bit ints is safe.
980     int64_t startVertexInt64 =
981         static_cast<int64_t>(baseVertex) + static_cast<int64_t>(indexRange.start);
982 
983     // OpenGL ES 3.2 spec section 10.5: "Behavior of DrawElementsOneInstance is undefined if the
984     // vertex ID is negative for any element"
985     ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 >= 0);
986 
987     // OpenGL ES 3.2 spec section 10.5: "If the vertex ID is larger than the maximum value
988     // representable by type, it should behave as if the calculation were upconverted to 32-bit
989     // unsigned integers(with wrapping on overflow conditions)." ANGLE does not fully handle
990     // these rules, an overflow error is returned if the start vertex cannot be stored in a
991     // 32-bit signed integer.
992     ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 <= std::numeric_limits<GLint>::max());
993 
994     *firstVertexOut = static_cast<GLint>(startVertexInt64);
995     return angle::Result::Continue;
996 }
997 
GetVertexRangeInfo(const gl::Context * context,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,GLint baseVertex,GLint * startVertexOut,size_t * vertexCountOut)998 angle::Result GetVertexRangeInfo(const gl::Context *context,
999                                  GLint firstVertex,
1000                                  GLsizei vertexOrIndexCount,
1001                                  gl::DrawElementsType indexTypeOrInvalid,
1002                                  const void *indices,
1003                                  GLint baseVertex,
1004                                  GLint *startVertexOut,
1005                                  size_t *vertexCountOut)
1006 {
1007     if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
1008     {
1009         gl::IndexRange indexRange;
1010         ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(
1011             context, indexTypeOrInvalid, vertexOrIndexCount, indices, &indexRange));
1012         ANGLE_TRY(ComputeStartVertex(context->getImplementation(), indexRange, baseVertex,
1013                                      startVertexOut));
1014         *vertexCountOut = indexRange.vertexCount();
1015     }
1016     else
1017     {
1018         *startVertexOut = firstVertex;
1019         *vertexCountOut = vertexOrIndexCount;
1020     }
1021     return angle::Result::Continue;
1022 }
1023 
ClipRectToScissor(const gl::State & glState,const gl::Rectangle & rect,bool invertY)1024 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY)
1025 {
1026     // If the scissor test isn't enabled, assume it has infinite size.  Its intersection with the
1027     // rect would be the rect itself.
1028     //
1029     // Note that on Vulkan, returning this (as opposed to a fixed max-int-sized rect) could lead to
1030     // unnecessary pipeline creations if two otherwise identical pipelines are used on framebuffers
1031     // with different sizes.  If such usage is observed in an application, we should investigate
1032     // possible optimizations.
1033     if (!glState.isScissorTestEnabled())
1034     {
1035         return rect;
1036     }
1037 
1038     gl::Rectangle clippedRect;
1039     if (!gl::ClipRectangle(glState.getScissor(), rect, &clippedRect))
1040     {
1041         return gl::Rectangle();
1042     }
1043 
1044     if (invertY)
1045     {
1046         clippedRect.y = rect.height - clippedRect.y - clippedRect.height;
1047     }
1048 
1049     return clippedRect;
1050 }
1051 
LogFeatureStatus(const angle::FeatureSetBase & features,const std::vector<std::string> & featureNames,bool enabled)1052 void LogFeatureStatus(const angle::FeatureSetBase &features,
1053                       const std::vector<std::string> &featureNames,
1054                       bool enabled)
1055 {
1056     for (const std::string &name : featureNames)
1057     {
1058         if (features.getFeatures().find(name) != features.getFeatures().end())
1059         {
1060             INFO() << "Feature: " << name << (enabled ? " enabled" : " disabled");
1061         }
1062     }
1063 }
1064 
ApplyFeatureOverrides(angle::FeatureSetBase * features,const egl::DisplayState & state)1065 void ApplyFeatureOverrides(angle::FeatureSetBase *features, const egl::DisplayState &state)
1066 {
1067     features->overrideFeatures(state.featureOverridesEnabled, true);
1068     features->overrideFeatures(state.featureOverridesDisabled, false);
1069 
1070     // Override with environment as well.
1071     constexpr char kAngleFeatureOverridesEnabledEnvName[]  = "ANGLE_FEATURE_OVERRIDES_ENABLED";
1072     constexpr char kAngleFeatureOverridesDisabledEnvName[] = "ANGLE_FEATURE_OVERRIDES_DISABLED";
1073     constexpr char kAngleFeatureOverridesEnabledPropertyName[] =
1074         "debug.angle.feature_overrides_enabled";
1075     constexpr char kAngleFeatureOverridesDisabledPropertyName[] =
1076         "debug.angle.feature_overrides_disabled";
1077     std::vector<std::string> overridesEnabled =
1078         angle::GetCachedStringsFromEnvironmentVarOrAndroidProperty(
1079             kAngleFeatureOverridesEnabledEnvName, kAngleFeatureOverridesEnabledPropertyName, ":");
1080     std::vector<std::string> overridesDisabled =
1081         angle::GetCachedStringsFromEnvironmentVarOrAndroidProperty(
1082             kAngleFeatureOverridesDisabledEnvName, kAngleFeatureOverridesDisabledPropertyName, ":");
1083 
1084     features->overrideFeatures(overridesEnabled, true);
1085     LogFeatureStatus(*features, overridesEnabled, true);
1086 
1087     features->overrideFeatures(overridesDisabled, false);
1088     LogFeatureStatus(*features, overridesDisabled, false);
1089 }
1090 
GetSamplePosition(GLsizei sampleCount,size_t index,GLfloat * xy)1091 void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy)
1092 {
1093     ASSERT(gl::isPow2(sampleCount));
1094     if (sampleCount > 16)
1095     {
1096         // Vulkan (and D3D11) doesn't have standard sample positions for 32 and 64 samples (and no
1097         // drivers are known to support that many samples)
1098         xy[0] = 0.5f;
1099         xy[1] = 0.5f;
1100     }
1101     else
1102     {
1103         size_t indexKey = static_cast<size_t>(gl::log2(sampleCount));
1104         ASSERT(indexKey < kSamplePositions.size() &&
1105                (2 * index + 1) < kSamplePositions[indexKey].size());
1106 
1107         xy[0] = kSamplePositions[indexKey][2 * index];
1108         xy[1] = kSamplePositions[indexKey][2 * index + 1];
1109     }
1110 }
1111 
1112 // These macros are to avoid code too much duplication for variations of multi draw types
1113 #define DRAW_ARRAYS__ contextImpl->drawArrays(context, mode, firsts[drawID], counts[drawID])
1114 #define DRAW_ARRAYS_INSTANCED_                                                      \
1115     contextImpl->drawArraysInstanced(context, mode, firsts[drawID], counts[drawID], \
1116                                      instanceCounts[drawID])
1117 #define DRAW_ELEMENTS__ \
1118     contextImpl->drawElements(context, mode, counts[drawID], type, indices[drawID])
1119 #define DRAW_ELEMENTS_INSTANCED_                                                             \
1120     contextImpl->drawElementsInstanced(context, mode, counts[drawID], type, indices[drawID], \
1121                                        instanceCounts[drawID])
1122 #define DRAW_ARRAYS_INSTANCED_BASE_INSTANCE                                                     \
1123     contextImpl->drawArraysInstancedBaseInstance(context, mode, firsts[drawID], counts[drawID], \
1124                                                  instanceCounts[drawID], baseInstances[drawID])
1125 #define DRAW_ELEMENTS_INSTANCED_BASE_VERTEX_BASE_INSTANCE                             \
1126     contextImpl->drawElementsInstancedBaseVertexBaseInstance(                         \
1127         context, mode, counts[drawID], type, indices[drawID], instanceCounts[drawID], \
1128         baseVertices[drawID], baseInstances[drawID])
1129 #define DRAW_CALL(drawType, instanced, bvbi) DRAW_##drawType##instanced##bvbi
1130 
1131 #define MULTI_DRAW_BLOCK(drawType, instanced, bvbi, hasDrawID, hasBaseVertex, hasBaseInstance) \
1132     for (GLsizei drawID = 0; drawID < drawcount; ++drawID)                                     \
1133     {                                                                                          \
1134         if (ANGLE_NOOP_DRAW(instanced))                                                        \
1135         {                                                                                      \
1136             ANGLE_TRY(contextImpl->handleNoopDrawEvent());                                     \
1137             continue;                                                                          \
1138         }                                                                                      \
1139         ANGLE_SET_DRAW_ID_UNIFORM(hasDrawID)(drawID);                                          \
1140         ANGLE_SET_BASE_VERTEX_UNIFORM(hasBaseVertex)(baseVertices[drawID]);                    \
1141         ANGLE_SET_BASE_INSTANCE_UNIFORM(hasBaseInstance)(baseInstances[drawID]);               \
1142         ANGLE_TRY(DRAW_CALL(drawType, instanced, bvbi));                                       \
1143         ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE(instanced);                                        \
1144         gl::MarkShaderStorageUsage(context);                                                   \
1145     }
1146 
MultiDrawArraysGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,GLsizei drawcount)1147 angle::Result MultiDrawArraysGeneral(ContextImpl *contextImpl,
1148                                      const gl::Context *context,
1149                                      gl::PrimitiveMode mode,
1150                                      const GLint *firsts,
1151                                      const GLsizei *counts,
1152                                      GLsizei drawcount)
1153 {
1154     gl::Program *programObject = context->getState().getLinkedProgram(context);
1155     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
1156     if (hasDrawID)
1157     {
1158         MULTI_DRAW_BLOCK(ARRAYS, _, _, 1, 0, 0)
1159     }
1160     else
1161     {
1162         MULTI_DRAW_BLOCK(ARRAYS, _, _, 0, 0, 0)
1163     }
1164 
1165     return angle::Result::Continue;
1166 }
1167 
MultiDrawArraysIndirectGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const void * indirect,GLsizei drawcount,GLsizei stride)1168 angle::Result MultiDrawArraysIndirectGeneral(ContextImpl *contextImpl,
1169                                              const gl::Context *context,
1170                                              gl::PrimitiveMode mode,
1171                                              const void *indirect,
1172                                              GLsizei drawcount,
1173                                              GLsizei stride)
1174 {
1175     const GLubyte *indirectPtr = static_cast<const GLubyte *>(indirect);
1176 
1177     for (auto count = 0; count < drawcount; count++)
1178     {
1179         ANGLE_TRY(contextImpl->drawArraysIndirect(
1180             context, mode, reinterpret_cast<const gl::DrawArraysIndirectCommand *>(indirectPtr)));
1181         if (stride == 0)
1182         {
1183             indirectPtr += sizeof(gl::DrawArraysIndirectCommand);
1184         }
1185         else
1186         {
1187             indirectPtr += stride;
1188         }
1189     }
1190 
1191     return angle::Result::Continue;
1192 }
1193 
MultiDrawArraysInstancedGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,GLsizei drawcount)1194 angle::Result MultiDrawArraysInstancedGeneral(ContextImpl *contextImpl,
1195                                               const gl::Context *context,
1196                                               gl::PrimitiveMode mode,
1197                                               const GLint *firsts,
1198                                               const GLsizei *counts,
1199                                               const GLsizei *instanceCounts,
1200                                               GLsizei drawcount)
1201 {
1202     gl::Program *programObject = context->getState().getLinkedProgram(context);
1203     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
1204     if (hasDrawID)
1205     {
1206         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _, 1, 0, 0)
1207     }
1208     else
1209     {
1210         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _, 0, 0, 0)
1211     }
1212 
1213     return angle::Result::Continue;
1214 }
1215 
MultiDrawElementsGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,GLsizei drawcount)1216 angle::Result MultiDrawElementsGeneral(ContextImpl *contextImpl,
1217                                        const gl::Context *context,
1218                                        gl::PrimitiveMode mode,
1219                                        const GLsizei *counts,
1220                                        gl::DrawElementsType type,
1221                                        const GLvoid *const *indices,
1222                                        GLsizei drawcount)
1223 {
1224     gl::Program *programObject = context->getState().getLinkedProgram(context);
1225     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
1226     if (hasDrawID)
1227     {
1228         MULTI_DRAW_BLOCK(ELEMENTS, _, _, 1, 0, 0)
1229     }
1230     else
1231     {
1232         MULTI_DRAW_BLOCK(ELEMENTS, _, _, 0, 0, 0)
1233     }
1234 
1235     return angle::Result::Continue;
1236 }
1237 
MultiDrawElementsIndirectGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,gl::DrawElementsType type,const void * indirect,GLsizei drawcount,GLsizei stride)1238 angle::Result MultiDrawElementsIndirectGeneral(ContextImpl *contextImpl,
1239                                                const gl::Context *context,
1240                                                gl::PrimitiveMode mode,
1241                                                gl::DrawElementsType type,
1242                                                const void *indirect,
1243                                                GLsizei drawcount,
1244                                                GLsizei stride)
1245 {
1246     const GLubyte *indirectPtr = static_cast<const GLubyte *>(indirect);
1247 
1248     for (auto count = 0; count < drawcount; count++)
1249     {
1250         ANGLE_TRY(contextImpl->drawElementsIndirect(
1251             context, mode, type,
1252             reinterpret_cast<const gl::DrawElementsIndirectCommand *>(indirectPtr)));
1253         if (stride == 0)
1254         {
1255             indirectPtr += sizeof(gl::DrawElementsIndirectCommand);
1256         }
1257         else
1258         {
1259             indirectPtr += stride;
1260         }
1261     }
1262 
1263     return angle::Result::Continue;
1264 }
1265 
MultiDrawElementsInstancedGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,GLsizei drawcount)1266 angle::Result MultiDrawElementsInstancedGeneral(ContextImpl *contextImpl,
1267                                                 const gl::Context *context,
1268                                                 gl::PrimitiveMode mode,
1269                                                 const GLsizei *counts,
1270                                                 gl::DrawElementsType type,
1271                                                 const GLvoid *const *indices,
1272                                                 const GLsizei *instanceCounts,
1273                                                 GLsizei drawcount)
1274 {
1275     gl::Program *programObject = context->getState().getLinkedProgram(context);
1276     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
1277     if (hasDrawID)
1278     {
1279         MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _, 1, 0, 0)
1280     }
1281     else
1282     {
1283         MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _, 0, 0, 0)
1284     }
1285 
1286     return angle::Result::Continue;
1287 }
1288 
MultiDrawArraysInstancedBaseInstanceGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const GLint * firsts,const GLsizei * counts,const GLsizei * instanceCounts,const GLuint * baseInstances,GLsizei drawcount)1289 angle::Result MultiDrawArraysInstancedBaseInstanceGeneral(ContextImpl *contextImpl,
1290                                                           const gl::Context *context,
1291                                                           gl::PrimitiveMode mode,
1292                                                           const GLint *firsts,
1293                                                           const GLsizei *counts,
1294                                                           const GLsizei *instanceCounts,
1295                                                           const GLuint *baseInstances,
1296                                                           GLsizei drawcount)
1297 {
1298     gl::Program *programObject = context->getState().getLinkedProgram(context);
1299     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
1300     const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform();
1301     ResetBaseVertexBaseInstance resetUniforms(programObject, false, hasBaseInstance);
1302 
1303     if (hasDrawID && hasBaseInstance)
1304     {
1305         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 1, 0, 1)
1306     }
1307     else if (hasDrawID)
1308     {
1309         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 1, 0, 0)
1310     }
1311     else if (hasBaseInstance)
1312     {
1313         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 0, 0, 1)
1314     }
1315     else
1316     {
1317         MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 0, 0, 0)
1318     }
1319 
1320     return angle::Result::Continue;
1321 }
1322 
MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(ContextImpl * contextImpl,const gl::Context * context,gl::PrimitiveMode mode,const GLsizei * counts,gl::DrawElementsType type,const GLvoid * const * indices,const GLsizei * instanceCounts,const GLint * baseVertices,const GLuint * baseInstances,GLsizei drawcount)1323 angle::Result MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(ContextImpl *contextImpl,
1324                                                                       const gl::Context *context,
1325                                                                       gl::PrimitiveMode mode,
1326                                                                       const GLsizei *counts,
1327                                                                       gl::DrawElementsType type,
1328                                                                       const GLvoid *const *indices,
1329                                                                       const GLsizei *instanceCounts,
1330                                                                       const GLint *baseVertices,
1331                                                                       const GLuint *baseInstances,
1332                                                                       GLsizei drawcount)
1333 {
1334     gl::Program *programObject = context->getState().getLinkedProgram(context);
1335     const bool hasDrawID       = programObject && programObject->hasDrawIDUniform();
1336     const bool hasBaseVertex   = programObject && programObject->hasBaseVertexUniform();
1337     const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform();
1338     ResetBaseVertexBaseInstance resetUniforms(programObject, hasBaseVertex, hasBaseInstance);
1339 
1340     if (hasDrawID)
1341     {
1342         if (hasBaseVertex)
1343         {
1344             if (hasBaseInstance)
1345             {
1346                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 1, 1)
1347             }
1348             else
1349             {
1350                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 1, 0)
1351             }
1352         }
1353         else
1354         {
1355             if (hasBaseInstance)
1356             {
1357                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 0, 1)
1358             }
1359             else
1360             {
1361                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 0, 0)
1362             }
1363         }
1364     }
1365     else
1366     {
1367         if (hasBaseVertex)
1368         {
1369             if (hasBaseInstance)
1370             {
1371                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 1, 1)
1372             }
1373             else
1374             {
1375                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 1, 0)
1376             }
1377         }
1378         else
1379         {
1380             if (hasBaseInstance)
1381             {
1382                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 0, 1)
1383             }
1384             else
1385             {
1386                 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 0, 0)
1387             }
1388         }
1389     }
1390 
1391     return angle::Result::Continue;
1392 }
1393 
ResetBaseVertexBaseInstance(gl::Program * programObject,bool resetBaseVertex,bool resetBaseInstance)1394 ResetBaseVertexBaseInstance::ResetBaseVertexBaseInstance(gl::Program *programObject,
1395                                                          bool resetBaseVertex,
1396                                                          bool resetBaseInstance)
1397     : mProgramObject(programObject),
1398       mResetBaseVertex(resetBaseVertex),
1399       mResetBaseInstance(resetBaseInstance)
1400 {}
1401 
~ResetBaseVertexBaseInstance()1402 ResetBaseVertexBaseInstance::~ResetBaseVertexBaseInstance()
1403 {
1404     if (mProgramObject)
1405     {
1406         // Reset emulated uniforms to zero to avoid affecting other draw calls
1407         if (mResetBaseVertex)
1408         {
1409             mProgramObject->setBaseVertexUniform(0);
1410         }
1411 
1412         if (mResetBaseInstance)
1413         {
1414             mProgramObject->setBaseInstanceUniform(0);
1415         }
1416     }
1417 }
1418 
ConvertToSRGB(angle::FormatID formatID)1419 angle::FormatID ConvertToSRGB(angle::FormatID formatID)
1420 {
1421     switch (formatID)
1422     {
1423         case angle::FormatID::R8_UNORM:
1424             return angle::FormatID::R8_UNORM_SRGB;
1425         case angle::FormatID::R8G8_UNORM:
1426             return angle::FormatID::R8G8_UNORM_SRGB;
1427         case angle::FormatID::R8G8B8_UNORM:
1428             return angle::FormatID::R8G8B8_UNORM_SRGB;
1429         case angle::FormatID::R8G8B8A8_UNORM:
1430             return angle::FormatID::R8G8B8A8_UNORM_SRGB;
1431         case angle::FormatID::B8G8R8A8_UNORM:
1432             return angle::FormatID::B8G8R8A8_UNORM_SRGB;
1433         case angle::FormatID::BC1_RGB_UNORM_BLOCK:
1434             return angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK;
1435         case angle::FormatID::BC1_RGBA_UNORM_BLOCK:
1436             return angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK;
1437         case angle::FormatID::BC2_RGBA_UNORM_BLOCK:
1438             return angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK;
1439         case angle::FormatID::BC3_RGBA_UNORM_BLOCK:
1440             return angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK;
1441         case angle::FormatID::BC7_RGBA_UNORM_BLOCK:
1442             return angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK;
1443         case angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK:
1444             return angle::FormatID::ETC2_R8G8B8_SRGB_BLOCK;
1445         case angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK:
1446             return angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK;
1447         case angle::FormatID::ETC2_R8G8B8A8_UNORM_BLOCK:
1448             return angle::FormatID::ETC2_R8G8B8A8_SRGB_BLOCK;
1449         case angle::FormatID::ASTC_4x4_UNORM_BLOCK:
1450             return angle::FormatID::ASTC_4x4_SRGB_BLOCK;
1451         case angle::FormatID::ASTC_5x4_UNORM_BLOCK:
1452             return angle::FormatID::ASTC_5x4_SRGB_BLOCK;
1453         case angle::FormatID::ASTC_5x5_UNORM_BLOCK:
1454             return angle::FormatID::ASTC_5x5_SRGB_BLOCK;
1455         case angle::FormatID::ASTC_6x5_UNORM_BLOCK:
1456             return angle::FormatID::ASTC_6x5_SRGB_BLOCK;
1457         case angle::FormatID::ASTC_6x6_UNORM_BLOCK:
1458             return angle::FormatID::ASTC_6x6_SRGB_BLOCK;
1459         case angle::FormatID::ASTC_8x5_UNORM_BLOCK:
1460             return angle::FormatID::ASTC_8x5_SRGB_BLOCK;
1461         case angle::FormatID::ASTC_8x6_UNORM_BLOCK:
1462             return angle::FormatID::ASTC_8x6_SRGB_BLOCK;
1463         case angle::FormatID::ASTC_8x8_UNORM_BLOCK:
1464             return angle::FormatID::ASTC_8x8_SRGB_BLOCK;
1465         case angle::FormatID::ASTC_10x5_UNORM_BLOCK:
1466             return angle::FormatID::ASTC_10x5_SRGB_BLOCK;
1467         case angle::FormatID::ASTC_10x6_UNORM_BLOCK:
1468             return angle::FormatID::ASTC_10x6_SRGB_BLOCK;
1469         case angle::FormatID::ASTC_10x8_UNORM_BLOCK:
1470             return angle::FormatID::ASTC_10x8_SRGB_BLOCK;
1471         case angle::FormatID::ASTC_10x10_UNORM_BLOCK:
1472             return angle::FormatID::ASTC_10x10_SRGB_BLOCK;
1473         case angle::FormatID::ASTC_12x10_UNORM_BLOCK:
1474             return angle::FormatID::ASTC_12x10_SRGB_BLOCK;
1475         case angle::FormatID::ASTC_12x12_UNORM_BLOCK:
1476             return angle::FormatID::ASTC_12x12_SRGB_BLOCK;
1477         default:
1478             return angle::FormatID::NONE;
1479     }
1480 }
1481 
ConvertToLinear(angle::FormatID formatID)1482 angle::FormatID ConvertToLinear(angle::FormatID formatID)
1483 {
1484     switch (formatID)
1485     {
1486         case angle::FormatID::R8_UNORM_SRGB:
1487             return angle::FormatID::R8_UNORM;
1488         case angle::FormatID::R8G8_UNORM_SRGB:
1489             return angle::FormatID::R8G8_UNORM;
1490         case angle::FormatID::R8G8B8_UNORM_SRGB:
1491             return angle::FormatID::R8G8B8_UNORM;
1492         case angle::FormatID::R8G8B8A8_UNORM_SRGB:
1493             return angle::FormatID::R8G8B8A8_UNORM;
1494         case angle::FormatID::B8G8R8A8_UNORM_SRGB:
1495             return angle::FormatID::B8G8R8A8_UNORM;
1496         case angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK:
1497             return angle::FormatID::BC1_RGB_UNORM_BLOCK;
1498         case angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK:
1499             return angle::FormatID::BC1_RGBA_UNORM_BLOCK;
1500         case angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK:
1501             return angle::FormatID::BC2_RGBA_UNORM_BLOCK;
1502         case angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK:
1503             return angle::FormatID::BC3_RGBA_UNORM_BLOCK;
1504         case angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK:
1505             return angle::FormatID::BC7_RGBA_UNORM_BLOCK;
1506         case angle::FormatID::ETC2_R8G8B8_SRGB_BLOCK:
1507             return angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK;
1508         case angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK:
1509             return angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK;
1510         case angle::FormatID::ETC2_R8G8B8A8_SRGB_BLOCK:
1511             return angle::FormatID::ETC2_R8G8B8A8_UNORM_BLOCK;
1512         case angle::FormatID::ASTC_4x4_SRGB_BLOCK:
1513             return angle::FormatID::ASTC_4x4_UNORM_BLOCK;
1514         case angle::FormatID::ASTC_5x4_SRGB_BLOCK:
1515             return angle::FormatID::ASTC_5x4_UNORM_BLOCK;
1516         case angle::FormatID::ASTC_5x5_SRGB_BLOCK:
1517             return angle::FormatID::ASTC_5x5_UNORM_BLOCK;
1518         case angle::FormatID::ASTC_6x5_SRGB_BLOCK:
1519             return angle::FormatID::ASTC_6x5_UNORM_BLOCK;
1520         case angle::FormatID::ASTC_6x6_SRGB_BLOCK:
1521             return angle::FormatID::ASTC_6x6_UNORM_BLOCK;
1522         case angle::FormatID::ASTC_8x5_SRGB_BLOCK:
1523             return angle::FormatID::ASTC_8x5_UNORM_BLOCK;
1524         case angle::FormatID::ASTC_8x6_SRGB_BLOCK:
1525             return angle::FormatID::ASTC_8x6_UNORM_BLOCK;
1526         case angle::FormatID::ASTC_8x8_SRGB_BLOCK:
1527             return angle::FormatID::ASTC_8x8_UNORM_BLOCK;
1528         case angle::FormatID::ASTC_10x5_SRGB_BLOCK:
1529             return angle::FormatID::ASTC_10x5_UNORM_BLOCK;
1530         case angle::FormatID::ASTC_10x6_SRGB_BLOCK:
1531             return angle::FormatID::ASTC_10x6_UNORM_BLOCK;
1532         case angle::FormatID::ASTC_10x8_SRGB_BLOCK:
1533             return angle::FormatID::ASTC_10x8_UNORM_BLOCK;
1534         case angle::FormatID::ASTC_10x10_SRGB_BLOCK:
1535             return angle::FormatID::ASTC_10x10_UNORM_BLOCK;
1536         case angle::FormatID::ASTC_12x10_SRGB_BLOCK:
1537             return angle::FormatID::ASTC_12x10_UNORM_BLOCK;
1538         case angle::FormatID::ASTC_12x12_SRGB_BLOCK:
1539             return angle::FormatID::ASTC_12x12_UNORM_BLOCK;
1540         default:
1541             return angle::FormatID::NONE;
1542     }
1543 }
1544 
IsOverridableLinearFormat(angle::FormatID formatID)1545 bool IsOverridableLinearFormat(angle::FormatID formatID)
1546 {
1547     return ConvertToSRGB(formatID) != angle::FormatID::NONE;
1548 }
1549 }  // namespace rx
1550