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