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/Display.h"
20 #include "libANGLE/formatutils.h"
21 #include "libANGLE/renderer/ContextImpl.h"
22 #include "libANGLE/renderer/Format.h"
23 #include "platform/Feature.h"
24
25 #include <string.h>
26
27 namespace rx
28 {
29
30 namespace
31 {
32 // Both D3D and Vulkan support the same set of standard sample positions for 1, 2, 4, 8, and 16
33 // samples. See:
34 //
35 // - https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx
36 //
37 // -
38 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#primsrast-multisampling
39 using SamplePositionsArray = std::array<float, 32>;
40 constexpr std::array<SamplePositionsArray, 5> kSamplePositions = {
41 {{{0.5f, 0.5f}},
42 {{0.75f, 0.75f, 0.25f, 0.25f}},
43 {{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}},
44 {{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f,
45 0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}},
46 {{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f, 0.4375f,
47 0.1875f, 0.375f, 0.625f, 0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f,
48 0.375f, 0.875f, 0.5f, 0.0625f, 0.25f, 0.125f, 0.125f, 0.75f,
49 0.0f, 0.5f, 0.9375f, 0.25f, 0.875f, 0.9375f, 0.0625f, 0.0f}}}};
50
CopyColor(gl::ColorF * color)51 void CopyColor(gl::ColorF *color)
52 {
53 // No-op
54 }
55
PremultiplyAlpha(gl::ColorF * color)56 void PremultiplyAlpha(gl::ColorF *color)
57 {
58 color->red *= color->alpha;
59 color->green *= color->alpha;
60 color->blue *= color->alpha;
61 }
62
UnmultiplyAlpha(gl::ColorF * color)63 void UnmultiplyAlpha(gl::ColorF *color)
64 {
65 if (color->alpha != 0.0f)
66 {
67 float invAlpha = 1.0f / color->alpha;
68 color->red *= invAlpha;
69 color->green *= invAlpha;
70 color->blue *= invAlpha;
71 }
72 }
73
ClipChannelsR(gl::ColorF * color)74 void ClipChannelsR(gl::ColorF *color)
75 {
76 color->green = 0.0f;
77 color->blue = 0.0f;
78 color->alpha = 1.0f;
79 }
80
ClipChannelsRG(gl::ColorF * color)81 void ClipChannelsRG(gl::ColorF *color)
82 {
83 color->blue = 0.0f;
84 color->alpha = 1.0f;
85 }
86
ClipChannelsRGB(gl::ColorF * color)87 void ClipChannelsRGB(gl::ColorF *color)
88 {
89 color->alpha = 1.0f;
90 }
91
ClipChannelsLuminance(gl::ColorF * color)92 void ClipChannelsLuminance(gl::ColorF *color)
93 {
94 color->alpha = 1.0f;
95 }
96
ClipChannelsAlpha(gl::ColorF * color)97 void ClipChannelsAlpha(gl::ColorF *color)
98 {
99 color->red = 0.0f;
100 color->green = 0.0f;
101 color->blue = 0.0f;
102 }
103
ClipChannelsNoOp(gl::ColorF * color)104 void ClipChannelsNoOp(gl::ColorF *color) {}
105
WriteUintColor(const gl::ColorF & color,PixelWriteFunction colorWriteFunction,uint8_t * destPixelData)106 void WriteUintColor(const gl::ColorF &color,
107 PixelWriteFunction colorWriteFunction,
108 uint8_t *destPixelData)
109 {
110 gl::ColorUI destColor(
111 static_cast<unsigned int>(color.red * 255), static_cast<unsigned int>(color.green * 255),
112 static_cast<unsigned int>(color.blue * 255), static_cast<unsigned int>(color.alpha * 255));
113 colorWriteFunction(reinterpret_cast<const uint8_t *>(&destColor), destPixelData);
114 }
115
WriteFloatColor(const gl::ColorF & color,PixelWriteFunction colorWriteFunction,uint8_t * destPixelData)116 void WriteFloatColor(const gl::ColorF &color,
117 PixelWriteFunction colorWriteFunction,
118 uint8_t *destPixelData)
119 {
120 colorWriteFunction(reinterpret_cast<const uint8_t *>(&color), destPixelData);
121 }
122
123 template <int cols, int rows, bool IsColumnMajor>
GetFlattenedIndex(int col,int row)124 inline int GetFlattenedIndex(int col, int row)
125 {
126 if (IsColumnMajor)
127 {
128 return col * rows + row;
129 }
130 else
131 {
132 return row * cols + col;
133 }
134 }
135
136 template <typename T,
137 bool IsSrcColumnMajor,
138 int colsSrc,
139 int rowsSrc,
140 bool IsDstColumnMajor,
141 int colsDst,
142 int rowsDst>
ExpandMatrix(T * target,const GLfloat * value)143 void ExpandMatrix(T *target, const GLfloat *value)
144 {
145 static_assert(colsSrc <= colsDst && rowsSrc <= rowsDst, "Can only expand!");
146
147 constexpr int kDstFlatSize = colsDst * rowsDst;
148 T staging[kDstFlatSize] = {0};
149
150 for (int r = 0; r < rowsSrc; r++)
151 {
152 for (int c = 0; c < colsSrc; c++)
153 {
154 int srcIndex = GetFlattenedIndex<colsSrc, rowsSrc, IsSrcColumnMajor>(c, r);
155 int dstIndex = GetFlattenedIndex<colsDst, rowsDst, IsDstColumnMajor>(c, r);
156
157 staging[dstIndex] = static_cast<T>(value[srcIndex]);
158 }
159 }
160
161 memcpy(target, staging, kDstFlatSize * sizeof(T));
162 }
163
164 template <bool IsSrcColumMajor,
165 int colsSrc,
166 int rowsSrc,
167 bool IsDstColumnMajor,
168 int colsDst,
169 int rowsDst>
SetFloatUniformMatrix(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,const GLfloat * value,uint8_t * targetData)170 void SetFloatUniformMatrix(unsigned int arrayElementOffset,
171 unsigned int elementCount,
172 GLsizei countIn,
173 const GLfloat *value,
174 uint8_t *targetData)
175 {
176 unsigned int count =
177 std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
178
179 const unsigned int targetMatrixStride = colsDst * rowsDst;
180 GLfloat *target = reinterpret_cast<GLfloat *>(
181 targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride);
182
183 for (unsigned int i = 0; i < count; i++)
184 {
185 ExpandMatrix<GLfloat, IsSrcColumMajor, colsSrc, rowsSrc, IsDstColumnMajor, colsDst,
186 rowsDst>(target, value);
187
188 target += targetMatrixStride;
189 value += colsSrc * rowsSrc;
190 }
191 }
192
SetFloatUniformMatrixFast(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,size_t matrixSize,const GLfloat * value,uint8_t * targetData)193 void SetFloatUniformMatrixFast(unsigned int arrayElementOffset,
194 unsigned int elementCount,
195 GLsizei countIn,
196 size_t matrixSize,
197 const GLfloat *value,
198 uint8_t *targetData)
199 {
200 const unsigned int count =
201 std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
202
203 const uint8_t *valueData = reinterpret_cast<const uint8_t *>(value);
204 targetData = targetData + arrayElementOffset * matrixSize;
205
206 memcpy(targetData, valueData, matrixSize * count);
207 }
208 } // anonymous namespace
209
RotateRectangle(const SurfaceRotation rotation,const bool flipY,const int framebufferWidth,const int framebufferHeight,const gl::Rectangle & incoming,gl::Rectangle * outgoing)210 void RotateRectangle(const SurfaceRotation rotation,
211 const bool flipY,
212 const int framebufferWidth,
213 const int framebufferHeight,
214 const gl::Rectangle &incoming,
215 gl::Rectangle *outgoing)
216 {
217 // GLES's y-axis points up; Vulkan's points down.
218 switch (rotation)
219 {
220 case SurfaceRotation::Identity:
221 // Do not rotate gl_Position (surface matches the device's orientation):
222 outgoing->x = incoming.x;
223 outgoing->y = flipY ? framebufferHeight - incoming.y - incoming.height : incoming.y;
224 outgoing->width = incoming.width;
225 outgoing->height = incoming.height;
226 break;
227 case SurfaceRotation::Rotated90Degrees:
228 // Rotate gl_Position 90 degrees:
229 outgoing->x = incoming.y;
230 outgoing->y = flipY ? incoming.x : framebufferWidth - incoming.x - incoming.width;
231 outgoing->width = incoming.height;
232 outgoing->height = incoming.width;
233 break;
234 case SurfaceRotation::Rotated180Degrees:
235 // Rotate gl_Position 180 degrees:
236 outgoing->x = framebufferWidth - incoming.x - incoming.width;
237 outgoing->y = flipY ? incoming.y : framebufferHeight - incoming.y - incoming.height;
238 outgoing->width = incoming.width;
239 outgoing->height = incoming.height;
240 break;
241 case SurfaceRotation::Rotated270Degrees:
242 // Rotate gl_Position 270 degrees:
243 outgoing->x = framebufferHeight - incoming.y - incoming.height;
244 outgoing->y = flipY ? framebufferWidth - incoming.x - incoming.width : incoming.x;
245 outgoing->width = incoming.height;
246 outgoing->height = incoming.width;
247 break;
248 default:
249 UNREACHABLE();
250 break;
251 }
252 }
253
PackPixelsParams()254 PackPixelsParams::PackPixelsParams()
255 : destFormat(nullptr),
256 outputPitch(0),
257 packBuffer(nullptr),
258 offset(0),
259 rotation(SurfaceRotation::Identity)
260 {}
261
PackPixelsParams(const gl::Rectangle & areaIn,const angle::Format & destFormat,GLuint outputPitchIn,bool reverseRowOrderIn,gl::Buffer * packBufferIn,ptrdiff_t offsetIn)262 PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn,
263 const angle::Format &destFormat,
264 GLuint outputPitchIn,
265 bool reverseRowOrderIn,
266 gl::Buffer *packBufferIn,
267 ptrdiff_t offsetIn)
268 : area(areaIn),
269 destFormat(&destFormat),
270 outputPitch(outputPitchIn),
271 packBuffer(packBufferIn),
272 reverseRowOrder(reverseRowOrderIn),
273 offset(offsetIn),
274 rotation(SurfaceRotation::Identity)
275 {}
276
PackPixels(const PackPixelsParams & params,const angle::Format & sourceFormat,int inputPitchIn,const uint8_t * sourceIn,uint8_t * destWithoutOffset)277 void PackPixels(const PackPixelsParams ¶ms,
278 const angle::Format &sourceFormat,
279 int inputPitchIn,
280 const uint8_t *sourceIn,
281 uint8_t *destWithoutOffset)
282 {
283 uint8_t *destWithOffset = destWithoutOffset + params.offset;
284
285 const uint8_t *source = sourceIn;
286 int inputPitch = inputPitchIn;
287 int destWidth = params.area.width;
288 int destHeight = params.area.height;
289 int xAxisPitch = 0;
290 int yAxisPitch = 0;
291 switch (params.rotation)
292 {
293 case SurfaceRotation::Identity:
294 // The source image is not rotated (i.e. matches the device's orientation), and may or
295 // may not be y-flipped. The image is row-major. Each source row (one step along the
296 // y-axis for each step in the dest y-axis) is inputPitch past the previous row. Along
297 // a row, each source pixel (one step along the x-axis for each step in the dest
298 // x-axis) is sourceFormat.pixelBytes past the previous pixel.
299 xAxisPitch = sourceFormat.pixelBytes;
300 if (params.reverseRowOrder)
301 {
302 // The source image is y-flipped, which means we start at the last row, and each
303 // source row is BEFORE the previous row.
304 source += inputPitchIn * (params.area.height - 1);
305 inputPitch = -inputPitch;
306 yAxisPitch = -inputPitchIn;
307 }
308 else
309 {
310 yAxisPitch = inputPitchIn;
311 }
312 break;
313 case SurfaceRotation::Rotated90Degrees:
314 // The source image is rotated 90 degrees counter-clockwise. Y-flip is always applied
315 // to rotated images. The image is column-major. Each source column (one step along
316 // the source x-axis for each step in the dest y-axis) is inputPitch past the previous
317 // column. Along a column, each source pixel (one step along the y-axis for each step
318 // in the dest x-axis) is sourceFormat.pixelBytes past the previous pixel.
319 xAxisPitch = inputPitchIn;
320 yAxisPitch = sourceFormat.pixelBytes;
321 destWidth = params.area.height;
322 destHeight = params.area.width;
323 break;
324 case SurfaceRotation::Rotated180Degrees:
325 // The source image is rotated 180 degrees. Y-flip is always applied to rotated
326 // images. The image is row-major, but upside down. Each source row (one step along
327 // the y-axis for each step in the dest y-axis) is inputPitch after the previous row.
328 // Along a row, each source pixel (one step along the x-axis for each step in the dest
329 // x-axis) is sourceFormat.pixelBytes BEFORE the previous pixel.
330 xAxisPitch = -static_cast<int>(sourceFormat.pixelBytes);
331 yAxisPitch = inputPitchIn;
332 source += sourceFormat.pixelBytes * (params.area.width - 1);
333 break;
334 case SurfaceRotation::Rotated270Degrees:
335 // The source image is rotated 270 degrees counter-clockwise (or 90 degrees clockwise).
336 // Y-flip is always applied to rotated images. The image is column-major, where each
337 // column (one step in the source x-axis for one step in the dest y-axis) is inputPitch
338 // BEFORE the previous column. Along a column, each source pixel (one step along the
339 // y-axis for each step in the dest x-axis) is sourceFormat.pixelBytes BEFORE the
340 // previous pixel. The first pixel is at the end of the source.
341 xAxisPitch = -inputPitchIn;
342 yAxisPitch = -static_cast<int>(sourceFormat.pixelBytes);
343 destWidth = params.area.height;
344 destHeight = params.area.width;
345 source += inputPitch * (params.area.height - 1) +
346 sourceFormat.pixelBytes * (params.area.width - 1);
347 break;
348 default:
349 UNREACHABLE();
350 break;
351 }
352
353 if (params.rotation == SurfaceRotation::Identity && sourceFormat == *params.destFormat)
354 {
355 // Direct copy possible
356 for (int y = 0; y < params.area.height; ++y)
357 {
358 memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch,
359 params.area.width * sourceFormat.pixelBytes);
360 }
361 return;
362 }
363
364 PixelCopyFunction fastCopyFunc = sourceFormat.fastCopyFunctions.get(params.destFormat->id);
365
366 if (fastCopyFunc)
367 {
368 // Fast copy is possible through some special function
369 for (int y = 0; y < destHeight; ++y)
370 {
371 for (int x = 0; x < destWidth; ++x)
372 {
373 uint8_t *dest =
374 destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
375 const uint8_t *src = source + y * yAxisPitch + x * xAxisPitch;
376
377 fastCopyFunc(src, dest);
378 }
379 }
380 return;
381 }
382
383 PixelWriteFunction pixelWriteFunction = params.destFormat->pixelWriteFunction;
384 ASSERT(pixelWriteFunction != nullptr);
385
386 // Maximum size of any Color<T> type used.
387 uint8_t temp[16];
388 static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) &&
389 sizeof(temp) >= sizeof(gl::ColorI) &&
390 sizeof(temp) >= sizeof(angle::DepthStencil),
391 "Unexpected size of pixel struct.");
392
393 PixelReadFunction pixelReadFunction = sourceFormat.pixelReadFunction;
394 ASSERT(pixelReadFunction != nullptr);
395
396 for (int y = 0; y < destHeight; ++y)
397 {
398 for (int x = 0; x < destWidth; ++x)
399 {
400 uint8_t *dest =
401 destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes;
402 const uint8_t *src = source + y * yAxisPitch + x * xAxisPitch;
403
404 // readFunc and writeFunc will be using the same type of color, CopyTexImage
405 // will not allow the copy otherwise.
406 pixelReadFunction(src, temp);
407 pixelWriteFunction(temp, dest);
408 }
409 }
410 }
411
has(angle::FormatID formatID) const412 bool FastCopyFunctionMap::has(angle::FormatID formatID) const
413 {
414 return (get(formatID) != nullptr);
415 }
416
get(angle::FormatID formatID) const417 PixelCopyFunction FastCopyFunctionMap::get(angle::FormatID formatID) const
418 {
419 for (size_t index = 0; index < mSize; ++index)
420 {
421 if (mData[index].formatID == formatID)
422 {
423 return mData[index].func;
424 }
425 }
426
427 return nullptr;
428 }
429
ShouldUseDebugLayers(const egl::AttributeMap & attribs)430 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs)
431 {
432 EGLAttrib debugSetting =
433 attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE);
434
435 // Prefer to enable debug layers when available.
436 #if defined(ANGLE_ENABLE_ASSERTS)
437 return (debugSetting != EGL_FALSE);
438 #else
439 return (debugSetting == EGL_TRUE);
440 #endif // defined(ANGLE_ENABLE_ASSERTS)
441 }
442
ShouldUseVirtualizedContexts(const egl::AttributeMap & attribs,bool defaultValue)443 bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue)
444 {
445 EGLAttrib virtualizedContextRequest =
446 attribs.get(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE, EGL_DONT_CARE);
447 if (defaultValue)
448 {
449 return (virtualizedContextRequest != EGL_FALSE);
450 }
451 else
452 {
453 return (virtualizedContextRequest == EGL_TRUE);
454 }
455 }
456
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)457 void CopyImageCHROMIUM(const uint8_t *sourceData,
458 size_t sourceRowPitch,
459 size_t sourcePixelBytes,
460 size_t sourceDepthPitch,
461 PixelReadFunction pixelReadFunction,
462 uint8_t *destData,
463 size_t destRowPitch,
464 size_t destPixelBytes,
465 size_t destDepthPitch,
466 PixelWriteFunction pixelWriteFunction,
467 GLenum destUnsizedFormat,
468 GLenum destComponentType,
469 size_t width,
470 size_t height,
471 size_t depth,
472 bool unpackFlipY,
473 bool unpackPremultiplyAlpha,
474 bool unpackUnmultiplyAlpha)
475 {
476 using ConversionFunction = void (*)(gl::ColorF *);
477 ConversionFunction conversionFunction = CopyColor;
478 if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha)
479 {
480 if (unpackPremultiplyAlpha)
481 {
482 conversionFunction = PremultiplyAlpha;
483 }
484 else
485 {
486 conversionFunction = UnmultiplyAlpha;
487 }
488 }
489
490 auto clipChannelsFunction = ClipChannelsNoOp;
491 switch (destUnsizedFormat)
492 {
493 case GL_RED:
494 clipChannelsFunction = ClipChannelsR;
495 break;
496 case GL_RG:
497 clipChannelsFunction = ClipChannelsRG;
498 break;
499 case GL_RGB:
500 clipChannelsFunction = ClipChannelsRGB;
501 break;
502 case GL_LUMINANCE:
503 clipChannelsFunction = ClipChannelsLuminance;
504 break;
505 case GL_ALPHA:
506 clipChannelsFunction = ClipChannelsAlpha;
507 break;
508 }
509
510 auto writeFunction = (destComponentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor;
511
512 for (size_t z = 0; z < depth; z++)
513 {
514 for (size_t y = 0; y < height; y++)
515 {
516 for (size_t x = 0; x < width; x++)
517 {
518 const uint8_t *sourcePixelData =
519 sourceData + y * sourceRowPitch + x * sourcePixelBytes + z * sourceDepthPitch;
520
521 gl::ColorF sourceColor;
522 pixelReadFunction(sourcePixelData, reinterpret_cast<uint8_t *>(&sourceColor));
523
524 conversionFunction(&sourceColor);
525 clipChannelsFunction(&sourceColor);
526
527 size_t destY = 0;
528 if (unpackFlipY)
529 {
530 destY += (height - 1);
531 destY -= y;
532 }
533 else
534 {
535 destY += y;
536 }
537
538 uint8_t *destPixelData =
539 destData + destY * destRowPitch + x * destPixelBytes + z * destDepthPitch;
540 writeFunction(sourceColor, pixelWriteFunction, destPixelData);
541 }
542 }
543 }
544 }
545
546 // IncompleteTextureSet implementation.
IncompleteTextureSet()547 IncompleteTextureSet::IncompleteTextureSet() {}
548
~IncompleteTextureSet()549 IncompleteTextureSet::~IncompleteTextureSet() {}
550
onDestroy(const gl::Context * context)551 void IncompleteTextureSet::onDestroy(const gl::Context *context)
552 {
553 // Clear incomplete textures.
554 for (auto &incompleteTexture : mIncompleteTextures)
555 {
556 if (incompleteTexture.get() != nullptr)
557 {
558 incompleteTexture->onDestroy(context);
559 incompleteTexture.set(context, nullptr);
560 }
561 }
562 }
563
getIncompleteTexture(const gl::Context * context,gl::TextureType type,MultisampleTextureInitializer * multisampleInitializer,gl::Texture ** textureOut)564 angle::Result IncompleteTextureSet::getIncompleteTexture(
565 const gl::Context *context,
566 gl::TextureType type,
567 MultisampleTextureInitializer *multisampleInitializer,
568 gl::Texture **textureOut)
569 {
570 *textureOut = mIncompleteTextures[type].get();
571 if (*textureOut != nullptr)
572 {
573 return angle::Result::Continue;
574 }
575
576 ContextImpl *implFactory = context->getImplementation();
577
578 const GLubyte color[] = {0, 0, 0, 255};
579 const gl::Extents colorSize(1, 1, 1);
580 gl::PixelUnpackState unpack;
581 unpack.alignment = 1;
582 const gl::Box area(0, 0, 0, 1, 1, 1);
583
584 // If a texture is external use a 2D texture for the incomplete texture
585 gl::TextureType createType = (type == gl::TextureType::External) ? gl::TextureType::_2D : type;
586
587 gl::Texture *tex =
588 new gl::Texture(implFactory, {std::numeric_limits<GLuint>::max()}, createType);
589 angle::UniqueObjectPointer<gl::Texture, gl::Context> t(tex, context);
590
591 // This is a bit of a kludge but is necessary to consume the error.
592 gl::Context *mutableContext = const_cast<gl::Context *>(context);
593
594 if (createType == gl::TextureType::_2DMultisample)
595 {
596 ANGLE_TRY(
597 t->setStorageMultisample(mutableContext, createType, 1, GL_RGBA8, colorSize, true));
598 }
599 else
600 {
601 ANGLE_TRY(t->setStorage(mutableContext, createType, 1, GL_RGBA8, colorSize));
602 }
603
604 if (type == gl::TextureType::CubeMap)
605 {
606 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
607 {
608 ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr, face, 0, area, GL_RGBA,
609 GL_UNSIGNED_BYTE, color));
610 }
611 }
612 else if (type == gl::TextureType::_2DMultisample)
613 {
614 // Call a specialized clear function to init a multisample texture.
615 ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get()));
616 }
617 else
618 {
619 ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr,
620 gl::NonCubeTextureTypeToTarget(createType), 0, area, GL_RGBA,
621 GL_UNSIGNED_BYTE, color));
622 }
623
624 ANGLE_TRY(t->syncState(context));
625
626 mIncompleteTextures[type].set(context, t.release());
627 *textureOut = mIncompleteTextures[type].get();
628 return angle::Result::Continue;
629 }
630
631 #define ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \
632 template void SetFloatUniformMatrix##api<cols, rows>::Run( \
633 unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *)
634
635 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 2);
636 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 3);
637 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 3);
638 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 2);
639 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 2);
640 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 3);
641
642 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 2);
643 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 3);
644 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 3);
645 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 2);
646 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 4);
647 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 4);
648
649 #undef ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC
650
651 #define ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \
652 template void SetFloatUniformMatrix##api<cols, 4>::Run(unsigned int, unsigned int, GLsizei, \
653 GLboolean, const GLfloat *, uint8_t *)
654
655 template <int cols>
656 struct SetFloatUniformMatrixGLSL<cols, 4>
657 {
658 static void Run(unsigned int arrayElementOffset,
659 unsigned int elementCount,
660 GLsizei countIn,
661 GLboolean transpose,
662 const GLfloat *value,
663 uint8_t *targetData);
664 };
665
666 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 4);
667 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 4);
668 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 4);
669
670 #undef ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC
671
672 #define ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \
673 template void SetFloatUniformMatrix##api<4, rows>::Run(unsigned int, unsigned int, GLsizei, \
674 GLboolean, const GLfloat *, uint8_t *)
675
676 template <int rows>
677 struct SetFloatUniformMatrixHLSL<4, rows>
678 {
679 static void Run(unsigned int arrayElementOffset,
680 unsigned int elementCount,
681 GLsizei countIn,
682 GLboolean transpose,
683 const GLfloat *value,
684 uint8_t *targetData);
685 };
686
687 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 2);
688 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 3);
689 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 4);
690
691 #undef ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC
692
693 template <int cols>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)694 void SetFloatUniformMatrixGLSL<cols, 4>::Run(unsigned int arrayElementOffset,
695 unsigned int elementCount,
696 GLsizei countIn,
697 GLboolean transpose,
698 const GLfloat *value,
699 uint8_t *targetData)
700 {
701 const bool isSrcColumnMajor = !transpose;
702 if (isSrcColumnMajor)
703 {
704 // Both src and dst matrixs are has same layout,
705 // a single memcpy updates all the matrices
706 constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 4;
707 SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value,
708 targetData);
709 }
710 else
711 {
712 // fallback to general cases
713 SetFloatUniformMatrix<false, cols, 4, true, cols, 4>(arrayElementOffset, elementCount,
714 countIn, value, targetData);
715 }
716 }
717
718 template <int cols, int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)719 void SetFloatUniformMatrixGLSL<cols, rows>::Run(unsigned int arrayElementOffset,
720 unsigned int elementCount,
721 GLsizei countIn,
722 GLboolean transpose,
723 const GLfloat *value,
724 uint8_t *targetData)
725 {
726 const bool isSrcColumnMajor = !transpose;
727 // GLSL expects matrix uniforms to be column-major, and each column is padded to 4 rows.
728 if (isSrcColumnMajor)
729 {
730 SetFloatUniformMatrix<true, cols, rows, true, cols, 4>(arrayElementOffset, elementCount,
731 countIn, value, targetData);
732 }
733 else
734 {
735 SetFloatUniformMatrix<false, cols, rows, true, cols, 4>(arrayElementOffset, elementCount,
736 countIn, value, targetData);
737 }
738 }
739
740 template <int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)741 void SetFloatUniformMatrixHLSL<4, rows>::Run(unsigned int arrayElementOffset,
742 unsigned int elementCount,
743 GLsizei countIn,
744 GLboolean transpose,
745 const GLfloat *value,
746 uint8_t *targetData)
747 {
748 const bool isSrcColumnMajor = !transpose;
749 if (!isSrcColumnMajor)
750 {
751 // Both src and dst matrixs are has same layout,
752 // a single memcpy updates all the matrices
753 constexpr size_t srcMatrixSize = sizeof(GLfloat) * 4 * rows;
754 SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value,
755 targetData);
756 }
757 else
758 {
759 // fallback to general cases
760 SetFloatUniformMatrix<true, 4, rows, false, 4, rows>(arrayElementOffset, elementCount,
761 countIn, value, targetData);
762 }
763 }
764
765 template <int cols, int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)766 void SetFloatUniformMatrixHLSL<cols, rows>::Run(unsigned int arrayElementOffset,
767 unsigned int elementCount,
768 GLsizei countIn,
769 GLboolean transpose,
770 const GLfloat *value,
771 uint8_t *targetData)
772 {
773 const bool isSrcColumnMajor = !transpose;
774 // Internally store matrices as row-major to accomodate HLSL matrix indexing. Each row is
775 // padded to 4 columns.
776 if (!isSrcColumnMajor)
777 {
778 SetFloatUniformMatrix<false, cols, rows, false, 4, rows>(arrayElementOffset, elementCount,
779 countIn, value, targetData);
780 }
781 else
782 {
783 SetFloatUniformMatrix<true, cols, rows, false, 4, rows>(arrayElementOffset, elementCount,
784 countIn, value, targetData);
785 }
786 }
787
788 template void GetMatrixUniform<GLint>(GLenum, GLint *, const GLint *, bool);
789 template void GetMatrixUniform<GLuint>(GLenum, GLuint *, const GLuint *, bool);
790
GetMatrixUniform(GLenum type,GLfloat * dataOut,const GLfloat * source,bool transpose)791 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose)
792 {
793 int columns = gl::VariableColumnCount(type);
794 int rows = gl::VariableRowCount(type);
795 for (GLint col = 0; col < columns; ++col)
796 {
797 for (GLint row = 0; row < rows; ++row)
798 {
799 GLfloat *outptr = dataOut + ((col * rows) + row);
800 const GLfloat *inptr =
801 transpose ? source + ((row * 4) + col) : source + ((col * 4) + row);
802 *outptr = *inptr;
803 }
804 }
805 }
806
807 template <typename NonFloatT>
GetMatrixUniform(GLenum type,NonFloatT * dataOut,const NonFloatT * source,bool transpose)808 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose)
809 {
810 UNREACHABLE();
811 }
812
GetFormatFromFormatType(GLenum format,GLenum type)813 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type)
814 {
815 GLenum sizedInternalFormat = gl::GetInternalFormatInfo(format, type).sizedInternalFormat;
816 angle::FormatID angleFormatID = angle::Format::InternalFormatToID(sizedInternalFormat);
817 return angle::Format::Get(angleFormatID);
818 }
819
ComputeStartVertex(ContextImpl * contextImpl,const gl::IndexRange & indexRange,GLint baseVertex,GLint * firstVertexOut)820 angle::Result ComputeStartVertex(ContextImpl *contextImpl,
821 const gl::IndexRange &indexRange,
822 GLint baseVertex,
823 GLint *firstVertexOut)
824 {
825 // The entire index range should be within the limits of a 32-bit uint because the largest
826 // GL index type is GL_UNSIGNED_INT.
827 ASSERT(indexRange.start <= std::numeric_limits<uint32_t>::max() &&
828 indexRange.end <= std::numeric_limits<uint32_t>::max());
829
830 // The base vertex is only used in DrawElementsIndirect. Given the assertion above and the
831 // type of mBaseVertex (GLint), adding them both as 64-bit ints is safe.
832 int64_t startVertexInt64 =
833 static_cast<int64_t>(baseVertex) + static_cast<int64_t>(indexRange.start);
834
835 // OpenGL ES 3.2 spec section 10.5: "Behavior of DrawElementsOneInstance is undefined if the
836 // vertex ID is negative for any element"
837 ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 >= 0);
838
839 // OpenGL ES 3.2 spec section 10.5: "If the vertex ID is larger than the maximum value
840 // representable by type, it should behave as if the calculation were upconverted to 32-bit
841 // unsigned integers(with wrapping on overflow conditions)." ANGLE does not fully handle
842 // these rules, an overflow error is returned if the start vertex cannot be stored in a
843 // 32-bit signed integer.
844 ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 <= std::numeric_limits<GLint>::max());
845
846 *firstVertexOut = static_cast<GLint>(startVertexInt64);
847 return angle::Result::Continue;
848 }
849
GetVertexRangeInfo(const gl::Context * context,GLint firstVertex,GLsizei vertexOrIndexCount,gl::DrawElementsType indexTypeOrInvalid,const void * indices,GLint baseVertex,GLint * startVertexOut,size_t * vertexCountOut)850 angle::Result GetVertexRangeInfo(const gl::Context *context,
851 GLint firstVertex,
852 GLsizei vertexOrIndexCount,
853 gl::DrawElementsType indexTypeOrInvalid,
854 const void *indices,
855 GLint baseVertex,
856 GLint *startVertexOut,
857 size_t *vertexCountOut)
858 {
859 if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
860 {
861 gl::IndexRange indexRange;
862 ANGLE_TRY(context->getState().getVertexArray()->getIndexRange(
863 context, indexTypeOrInvalid, vertexOrIndexCount, indices, &indexRange));
864 ANGLE_TRY(ComputeStartVertex(context->getImplementation(), indexRange, baseVertex,
865 startVertexOut));
866 *vertexCountOut = indexRange.vertexCount();
867 }
868 else
869 {
870 *startVertexOut = firstVertex;
871 *vertexCountOut = vertexOrIndexCount;
872 }
873 return angle::Result::Continue;
874 }
875
ClipRectToScissor(const gl::State & glState,const gl::Rectangle & rect,bool invertY)876 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY)
877 {
878 // If the scissor test isn't enabled, assume it has infinite size. Its intersection with the
879 // rect would be the rect itself.
880 //
881 // Note that on Vulkan, returning this (as opposed to a fixed max-int-sized rect) could lead to
882 // unnecessary pipeline creations if two otherwise identical pipelines are used on framebuffers
883 // with different sizes. If such usage is observed in an application, we should investigate
884 // possible optimizations.
885 if (!glState.isScissorTestEnabled())
886 {
887 return rect;
888 }
889
890 gl::Rectangle clippedRect;
891 if (!gl::ClipRectangle(glState.getScissor(), rect, &clippedRect))
892 {
893 return gl::Rectangle();
894 }
895
896 if (invertY)
897 {
898 clippedRect.y = rect.height - clippedRect.y - clippedRect.height;
899 }
900
901 return clippedRect;
902 }
903
ApplyFeatureOverrides(angle::FeatureSetBase * features,const egl::DisplayState & state)904 void ApplyFeatureOverrides(angle::FeatureSetBase *features, const egl::DisplayState &state)
905 {
906 features->overrideFeatures(state.featureOverridesEnabled, true);
907 features->overrideFeatures(state.featureOverridesDisabled, false);
908
909 // Override with environment as well.
910 std::vector<std::string> overridesEnabled =
911 angle::GetStringsFromEnvironmentVar("ANGLE_FEATURE_OVERRIDES_ENABLED", ":");
912 std::vector<std::string> overridesDisabled =
913 angle::GetStringsFromEnvironmentVar("ANGLE_FEATURE_OVERRIDES_DISABLED", ":");
914 features->overrideFeatures(overridesEnabled, true);
915 features->overrideFeatures(overridesDisabled, false);
916 }
917
GetSamplePosition(GLsizei sampleCount,size_t index,GLfloat * xy)918 void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy)
919 {
920 ASSERT(gl::isPow2(sampleCount));
921 if (sampleCount > 16)
922 {
923 // Vulkan (and D3D11) doesn't have standard sample positions for 32 and 64 samples (and no
924 // drivers are known to support that many samples)
925 xy[0] = 0.5f;
926 xy[1] = 0.5f;
927 }
928 else
929 {
930 size_t indexKey = static_cast<size_t>(gl::log2(sampleCount));
931 ASSERT(indexKey < kSamplePositions.size() &&
932 (2 * index + 1) < kSamplePositions[indexKey].size());
933
934 xy[0] = kSamplePositions[indexKey][2 * index];
935 xy[1] = kSamplePositions[indexKey][2 * index + 1];
936 }
937 }
938 } // namespace rx
939