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