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