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