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