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