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