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