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