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 #ifndef LIBANGLE_RENDERER_RENDERER_UTILS_H_
11 #define LIBANGLE_RENDERER_RENDERER_UTILS_H_
12
13 #include <cstdint>
14
15 #include <limits>
16 #include <map>
17
18 #include "GLSLANG/ShaderLang.h"
19 #include "common/angleutils.h"
20 #include "common/utilities.h"
21 #include "libANGLE/ImageIndex.h"
22 #include "libANGLE/angletypes.h"
23
24 namespace angle
25 {
26 struct FeatureSetBase;
27 struct Format;
28 struct ImageLoadContext;
29 enum class FormatID;
30 } // namespace angle
31
32 namespace gl
33 {
34 struct FormatType;
35 struct InternalFormat;
36 class ProgramExecutable;
37 class State;
38 } // namespace gl
39
40 namespace egl
41 {
42 class AttributeMap;
43 struct DisplayState;
44 } // namespace egl
45
46 namespace rx
47 {
48 class ContextImpl;
49
50 // The possible rotations of the surface/draw framebuffer, particularly for the Vulkan back-end on
51 // Android.
52 enum class SurfaceRotation
53 {
54 Identity,
55 Rotated90Degrees,
56 Rotated180Degrees,
57 Rotated270Degrees,
58 FlippedIdentity,
59 FlippedRotated90Degrees,
60 FlippedRotated180Degrees,
61 FlippedRotated270Degrees,
62
63 InvalidEnum,
64 EnumCount = InvalidEnum,
65 };
66
67 bool IsRotatedAspectRatio(SurfaceRotation rotation);
68
69 using SpecConstUsageBits = angle::PackedEnumBitSet<sh::vk::SpecConstUsage, uint32_t>;
70
71 void RotateRectangle(const SurfaceRotation rotation,
72 const bool flipY,
73 const int framebufferWidth,
74 const int framebufferHeight,
75 const gl::Rectangle &incoming,
76 gl::Rectangle *outgoing);
77
78 using MipGenerationFunction = void (*)(size_t sourceWidth,
79 size_t sourceHeight,
80 size_t sourceDepth,
81 const uint8_t *sourceData,
82 size_t sourceRowPitch,
83 size_t sourceDepthPitch,
84 uint8_t *destData,
85 size_t destRowPitch,
86 size_t destDepthPitch);
87
88 typedef void (*PixelReadFunction)(const uint8_t *source, uint8_t *dest);
89 typedef void (*PixelWriteFunction)(const uint8_t *source, uint8_t *dest);
90 typedef void (*FastCopyFunction)(const uint8_t *source,
91 int srcXAxisPitch,
92 int srcYAxisPitch,
93 uint8_t *dest,
94 int destXAxisPitch,
95 int destYAxisPitch,
96 int width,
97 int height);
98
99 class FastCopyFunctionMap
100 {
101 public:
102 struct Entry
103 {
104 angle::FormatID formatID;
105 FastCopyFunction func;
106 };
107
FastCopyFunctionMap()108 constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {}
109
FastCopyFunctionMap(const Entry * data,size_t size)110 constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {}
111
112 bool has(angle::FormatID formatID) const;
113 FastCopyFunction get(angle::FormatID formatID) const;
114
115 private:
116 size_t mSize;
117 const Entry *mData;
118 };
119
120 struct PackPixelsParams
121 {
122 PackPixelsParams();
123 PackPixelsParams(const gl::Rectangle &area,
124 const angle::Format &destFormat,
125 GLuint outputPitch,
126 bool reverseRowOrderIn,
127 gl::Buffer *packBufferIn,
128 ptrdiff_t offset);
129
130 gl::Rectangle area;
131 const angle::Format *destFormat;
132 GLuint outputPitch;
133 gl::Buffer *packBuffer;
134 bool reverseRowOrder;
135 ptrdiff_t offset;
136 SurfaceRotation rotation;
137 };
138
139 void PackPixels(const PackPixelsParams ¶ms,
140 const angle::Format &sourceFormat,
141 int inputPitch,
142 const uint8_t *source,
143 uint8_t *destination);
144
145 angle::Result GetPackPixelsParams(const gl::InternalFormat &sizedFormatInfo,
146 GLuint outputPitch,
147 const gl::PixelPackState &packState,
148 gl::Buffer *packBuffer,
149 const gl::Rectangle &area,
150 const gl::Rectangle &clippedArea,
151 rx::PackPixelsParams *paramsOut,
152 GLuint *skipBytesOut);
153
154 using InitializeTextureDataFunction = void (*)(size_t width,
155 size_t height,
156 size_t depth,
157 uint8_t *output,
158 size_t outputRowPitch,
159 size_t outputDepthPitch);
160
161 using LoadImageFunction = void (*)(const angle::ImageLoadContext &context,
162 size_t width,
163 size_t height,
164 size_t depth,
165 const uint8_t *input,
166 size_t inputRowPitch,
167 size_t inputDepthPitch,
168 uint8_t *output,
169 size_t outputRowPitch,
170 size_t outputDepthPitch);
171
172 struct LoadImageFunctionInfo
173 {
LoadImageFunctionInfoLoadImageFunctionInfo174 LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {}
LoadImageFunctionInfoLoadImageFunctionInfo175 LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion)
176 : loadFunction(loadFunction), requiresConversion(requiresConversion)
177 {}
178
179 LoadImageFunction loadFunction;
180 bool requiresConversion;
181 };
182
183 using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum);
184
185 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs);
186
187 void CopyImageCHROMIUM(const uint8_t *sourceData,
188 size_t sourceRowPitch,
189 size_t sourcePixelBytes,
190 size_t sourceDepthPitch,
191 PixelReadFunction pixelReadFunction,
192 uint8_t *destData,
193 size_t destRowPitch,
194 size_t destPixelBytes,
195 size_t destDepthPitch,
196 PixelWriteFunction pixelWriteFunction,
197 GLenum destUnsizedFormat,
198 GLenum destComponentType,
199 size_t width,
200 size_t height,
201 size_t depth,
202 bool unpackFlipY,
203 bool unpackPremultiplyAlpha,
204 bool unpackUnmultiplyAlpha);
205
206 // Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete.
207 // This helper class encapsulates handling incomplete textures. Because the GL back-end
208 // can take advantage of the driver's incomplete textures, and because clearing multisample
209 // textures is so difficult, we can keep an instance of this class in the back-end instead
210 // of moving the logic to the Context front-end.
211
212 // This interface allows us to call-back to init a multisample texture.
213 class MultisampleTextureInitializer
214 {
215 public:
~MultisampleTextureInitializer()216 virtual ~MultisampleTextureInitializer() {}
217 virtual angle::Result initializeMultisampleTextureToBlack(const gl::Context *context,
218 gl::Texture *glTexture) = 0;
219 };
220
221 class IncompleteTextureSet final : angle::NonCopyable
222 {
223 public:
224 IncompleteTextureSet();
225 ~IncompleteTextureSet();
226
227 void onDestroy(const gl::Context *context);
228
229 angle::Result getIncompleteTexture(const gl::Context *context,
230 gl::TextureType type,
231 gl::SamplerFormat format,
232 MultisampleTextureInitializer *multisampleInitializer,
233 gl::Texture **textureOut);
234
235 private:
236 using TextureMapWithSamplerFormat = angle::PackedEnumMap<gl::SamplerFormat, gl::TextureMap>;
237
238 TextureMapWithSamplerFormat mIncompleteTextures;
239 };
240
241 // Helpers to set a matrix uniform value based on GLSL or HLSL semantics.
242 // The return value indicate if the data was updated or not.
243 template <int cols, int rows>
244 struct SetFloatUniformMatrixGLSL
245 {
246 static void Run(unsigned int arrayElementOffset,
247 unsigned int elementCount,
248 GLsizei countIn,
249 GLboolean transpose,
250 const GLfloat *value,
251 uint8_t *targetData);
252 };
253
254 template <int cols, int rows>
255 struct SetFloatUniformMatrixHLSL
256 {
257 static void Run(unsigned int arrayElementOffset,
258 unsigned int elementCount,
259 GLsizei countIn,
260 GLboolean transpose,
261 const GLfloat *value,
262 uint8_t *targetData);
263 };
264
265 // Helper method to de-tranpose a matrix uniform for an API query.
266 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose);
267
268 template <typename NonFloatT>
269 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose);
270
271 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type);
272
273 angle::Result ComputeStartVertex(ContextImpl *contextImpl,
274 const gl::IndexRange &indexRange,
275 GLint baseVertex,
276 GLint *firstVertexOut);
277
278 angle::Result GetVertexRangeInfo(const gl::Context *context,
279 GLint firstVertex,
280 GLsizei vertexOrIndexCount,
281 gl::DrawElementsType indexTypeOrInvalid,
282 const void *indices,
283 GLint baseVertex,
284 GLint *startVertexOut,
285 size_t *vertexCountOut);
286
287 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY);
288
289 // Helper method to intialize a FeatureSet with overrides from the DisplayState
290 void ApplyFeatureOverrides(angle::FeatureSetBase *features,
291 const angle::FeatureOverrides &overrides);
292
293 template <typename In>
LineLoopRestartIndexCountHelper(GLsizei indexCount,const uint8_t * srcPtr)294 uint32_t LineLoopRestartIndexCountHelper(GLsizei indexCount, const uint8_t *srcPtr)
295 {
296 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
297 const In *inIndices = reinterpret_cast<const In *>(srcPtr);
298 uint32_t numIndices = 0;
299 // See CopyLineLoopIndicesWithRestart() below for more info on how
300 // numIndices is calculated.
301 GLsizei loopStartIndex = 0;
302 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
303 {
304 In vertex = inIndices[curIndex];
305 if (vertex != restartIndex)
306 {
307 numIndices++;
308 }
309 else
310 {
311 if (curIndex > loopStartIndex)
312 {
313 numIndices += 2;
314 }
315 loopStartIndex = curIndex + 1;
316 }
317 }
318 if (indexCount > loopStartIndex)
319 {
320 numIndices++;
321 }
322 return numIndices;
323 }
324
GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr)325 inline uint32_t GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,
326 GLsizei indexCount,
327 const uint8_t *srcPtr)
328 {
329 switch (glIndexType)
330 {
331 case gl::DrawElementsType::UnsignedByte:
332 return LineLoopRestartIndexCountHelper<uint8_t>(indexCount, srcPtr);
333 case gl::DrawElementsType::UnsignedShort:
334 return LineLoopRestartIndexCountHelper<uint16_t>(indexCount, srcPtr);
335 case gl::DrawElementsType::UnsignedInt:
336 return LineLoopRestartIndexCountHelper<uint32_t>(indexCount, srcPtr);
337 default:
338 UNREACHABLE();
339 return 0;
340 }
341 }
342
343 // Writes the line-strip vertices for a line loop to outPtr,
344 // where outLimit is calculated as in GetPrimitiveRestartIndexCount.
345 template <typename In, typename Out>
CopyLineLoopIndicesWithRestart(GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)346 void CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, uint8_t *outPtr)
347 {
348 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
349 constexpr Out outRestartIndex = gl::GetPrimitiveRestartIndexFromType<Out>();
350 const In *inIndices = reinterpret_cast<const In *>(srcPtr);
351 Out *outIndices = reinterpret_cast<Out *>(outPtr);
352 GLsizei loopStartIndex = 0;
353 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
354 {
355 In vertex = inIndices[curIndex];
356 if (vertex != restartIndex)
357 {
358 *(outIndices++) = static_cast<Out>(vertex);
359 }
360 else
361 {
362 if (curIndex > loopStartIndex)
363 {
364 // Emit an extra vertex only if the loop is not empty.
365 *(outIndices++) = inIndices[loopStartIndex];
366 // Then restart the strip.
367 *(outIndices++) = outRestartIndex;
368 }
369 loopStartIndex = curIndex + 1;
370 }
371 }
372 if (indexCount > loopStartIndex)
373 {
374 // Close the last loop if not empty.
375 *(outIndices++) = inIndices[loopStartIndex];
376 }
377 }
378
379 void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy);
380
381 angle::Result MultiDrawArraysGeneral(ContextImpl *contextImpl,
382 const gl::Context *context,
383 gl::PrimitiveMode mode,
384 const GLint *firsts,
385 const GLsizei *counts,
386 GLsizei drawcount);
387 angle::Result MultiDrawArraysIndirectGeneral(ContextImpl *contextImpl,
388 const gl::Context *context,
389 gl::PrimitiveMode mode,
390 const void *indirect,
391 GLsizei drawcount,
392 GLsizei stride);
393 angle::Result MultiDrawArraysInstancedGeneral(ContextImpl *contextImpl,
394 const gl::Context *context,
395 gl::PrimitiveMode mode,
396 const GLint *firsts,
397 const GLsizei *counts,
398 const GLsizei *instanceCounts,
399 GLsizei drawcount);
400 angle::Result MultiDrawElementsGeneral(ContextImpl *contextImpl,
401 const gl::Context *context,
402 gl::PrimitiveMode mode,
403 const GLsizei *counts,
404 gl::DrawElementsType type,
405 const GLvoid *const *indices,
406 GLsizei drawcount);
407 angle::Result MultiDrawElementsIndirectGeneral(ContextImpl *contextImpl,
408 const gl::Context *context,
409 gl::PrimitiveMode mode,
410 gl::DrawElementsType type,
411 const void *indirect,
412 GLsizei drawcount,
413 GLsizei stride);
414 angle::Result MultiDrawElementsInstancedGeneral(ContextImpl *contextImpl,
415 const gl::Context *context,
416 gl::PrimitiveMode mode,
417 const GLsizei *counts,
418 gl::DrawElementsType type,
419 const GLvoid *const *indices,
420 const GLsizei *instanceCounts,
421 GLsizei drawcount);
422 angle::Result MultiDrawArraysInstancedBaseInstanceGeneral(ContextImpl *contextImpl,
423 const gl::Context *context,
424 gl::PrimitiveMode mode,
425 const GLint *firsts,
426 const GLsizei *counts,
427 const GLsizei *instanceCounts,
428 const GLuint *baseInstances,
429 GLsizei drawcount);
430 angle::Result MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(ContextImpl *contextImpl,
431 const gl::Context *context,
432 gl::PrimitiveMode mode,
433 const GLsizei *counts,
434 gl::DrawElementsType type,
435 const GLvoid *const *indices,
436 const GLsizei *instanceCounts,
437 const GLint *baseVertices,
438 const GLuint *baseInstances,
439 GLsizei drawcount);
440
441 // RAII object making sure reset uniforms is called no matter whether there's an error in draw calls
442 class ResetBaseVertexBaseInstance : angle::NonCopyable
443 {
444 public:
445 ResetBaseVertexBaseInstance(gl::ProgramExecutable *executable,
446 bool resetBaseVertex,
447 bool resetBaseInstance);
448
449 ~ResetBaseVertexBaseInstance();
450
451 private:
452 gl::ProgramExecutable *mExecutable;
453 bool mResetBaseVertex;
454 bool mResetBaseInstance;
455 };
456
457 angle::FormatID ConvertToSRGB(angle::FormatID formatID);
458 angle::FormatID ConvertToLinear(angle::FormatID formatID);
459 bool IsOverridableLinearFormat(angle::FormatID formatID);
460
461 template <bool swizzledLuma = true>
462 const gl::ColorGeneric AdjustBorderColor(const angle::ColorGeneric &borderColorGeneric,
463 const angle::Format &format,
464 bool stencilMode);
465
466 template <typename LargerInt>
LimitToInt(const LargerInt physicalDeviceValue)467 GLint LimitToInt(const LargerInt physicalDeviceValue)
468 {
469 static_assert(sizeof(LargerInt) >= sizeof(int32_t), "Incorrect usage of LimitToInt");
470
471 // Limit to INT_MAX / 2 instead of INT_MAX. If the limit is queried as float, the imprecision
472 // in floating point can cause the value to exceed INT_MAX. This trips dEQP up.
473 return static_cast<GLint>(std::min(
474 physicalDeviceValue, static_cast<LargerInt>(std::numeric_limits<int32_t>::max() / 2)));
475 }
476
477 bool TextureHasAnyRedefinedLevels(const gl::CubeFaceArray<gl::TexLevelMask> &redefinedLevels);
478 bool IsTextureLevelRedefined(const gl::CubeFaceArray<gl::TexLevelMask> &redefinedLevels,
479 gl::TextureType textureType,
480 gl::LevelIndex level);
481
482 enum class TextureLevelDefinition
483 {
484 Compatible = 0,
485 Incompatible = 1,
486
487 InvalidEnum = 2
488 };
489
490 enum class TextureLevelAllocation
491 {
492 WithinAllocatedImage = 0,
493 OutsideAllocatedImage = 1,
494
495 InvalidEnum = 2
496 };
497 // Returns true if the image should be released after the level is redefined, false otherwise.
498 bool TextureRedefineLevel(const TextureLevelAllocation levelAllocation,
499 const TextureLevelDefinition levelDefinition,
500 bool immutableFormat,
501 uint32_t levelCount,
502 const uint32_t layerIndex,
503 const gl::ImageIndex &index,
504 gl::LevelIndex imageFirstAllocatedLevel,
505 gl::CubeFaceArray<gl::TexLevelMask> *redefinedLevels);
506
507 void TextureRedefineGenerateMipmapLevels(gl::LevelIndex baseLevel,
508 gl::LevelIndex maxLevel,
509 gl::LevelIndex firstGeneratedLevel,
510 gl::CubeFaceArray<gl::TexLevelMask> *redefinedLevels);
511
512 enum class ImageMipLevels
513 {
514 EnabledLevels = 0,
515 FullMipChainForGenerateMipmap = 1,
516
517 InvalidEnum = 2,
518 };
519
520 enum class PipelineType
521 {
522 Graphics = 0,
523 Compute = 1,
524
525 InvalidEnum = 2,
526 EnumCount = 2,
527 };
528
529 } // namespace rx
530
531 // MultiDraw macro patterns
532 // These macros are to avoid too much code duplication as we don't want to have if detect for
533 // hasDrawID/BaseVertex/BaseInstance inside for loop in a multiDrawANGLE call Part of these are put
534 // in the header as we want to share with specialized context impl on some platforms for multidraw
535 #define ANGLE_SET_DRAW_ID_UNIFORM_0(drawID) \
536 {}
537 #define ANGLE_SET_DRAW_ID_UNIFORM_1(drawID) executable->setDrawIDUniform(drawID)
538 #define ANGLE_SET_DRAW_ID_UNIFORM(cond) ANGLE_SET_DRAW_ID_UNIFORM_##cond
539
540 #define ANGLE_SET_BASE_VERTEX_UNIFORM_0(baseVertex) \
541 {}
542 #define ANGLE_SET_BASE_VERTEX_UNIFORM_1(baseVertex) executable->setBaseVertexUniform(baseVertex);
543 #define ANGLE_SET_BASE_VERTEX_UNIFORM(cond) ANGLE_SET_BASE_VERTEX_UNIFORM_##cond
544
545 #define ANGLE_SET_BASE_INSTANCE_UNIFORM_0(baseInstance) \
546 {}
547 #define ANGLE_SET_BASE_INSTANCE_UNIFORM_1(baseInstance) \
548 executable->setBaseInstanceUniform(baseInstance)
549 #define ANGLE_SET_BASE_INSTANCE_UNIFORM(cond) ANGLE_SET_BASE_INSTANCE_UNIFORM_##cond
550
551 #define ANGLE_NOOP_DRAW_ context->noopDraw(mode, counts[drawID])
552 #define ANGLE_NOOP_DRAW_INSTANCED \
553 context->noopDrawInstanced(mode, counts[drawID], instanceCounts[drawID])
554 #define ANGLE_NOOP_DRAW(_instanced) ANGLE_NOOP_DRAW##_instanced
555
556 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE_ \
557 gl::MarkTransformFeedbackBufferUsage(context, counts[drawID], 1)
558 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE_INSTANCED \
559 gl::MarkTransformFeedbackBufferUsage(context, counts[drawID], instanceCounts[drawID])
560 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE(instanced) \
561 ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE##instanced
562
563 #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
564