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 &params,
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