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