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