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