• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params,
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