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