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