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/ImageIndex.h"
22 #include "libANGLE/angletypes.h"
23
24 namespace angle
25 {
26 struct FeatureSetBase;
27 struct Format;
28 struct ImageLoadContext;
29 enum class FormatID : uint8_t;
30 } // namespace angle
31
32 namespace gl
33 {
34 struct FormatType;
35 struct InternalFormat;
36 class ProgramExecutable;
37 class State;
38 } // namespace gl
39
40 namespace egl
41 {
42 class AttributeMap;
43 struct DisplayState;
44 } // namespace egl
45
46 namespace sh
47 {
48 struct BlockMemberInfo;
49 }
50
51 namespace rx
52 {
53 class ContextImpl;
54
55 // The possible rotations of the surface/draw framebuffer, particularly for the Vulkan back-end on
56 // Android.
57 enum class SurfaceRotation
58 {
59 Identity,
60 Rotated90Degrees,
61 Rotated180Degrees,
62 Rotated270Degrees,
63 FlippedIdentity,
64 FlippedRotated90Degrees,
65 FlippedRotated180Degrees,
66 FlippedRotated270Degrees,
67
68 InvalidEnum,
69 EnumCount = InvalidEnum,
70 };
71
72 bool IsRotatedAspectRatio(SurfaceRotation rotation);
73
74 using SpecConstUsageBits = angle::PackedEnumBitSet<sh::vk::SpecConstUsage, uint32_t>;
75
76 void RotateRectangle(SurfaceRotation rotation,
77 bool flipY,
78 int framebufferWidth,
79 int framebufferHeight,
80 const gl::Rectangle &incoming,
81 gl::Rectangle *outgoing);
82
83 using MipGenerationFunction = void (*)(size_t sourceWidth,
84 size_t sourceHeight,
85 size_t sourceDepth,
86 const uint8_t *sourceData,
87 size_t sourceRowPitch,
88 size_t sourceDepthPitch,
89 uint8_t *destData,
90 size_t destRowPitch,
91 size_t destDepthPitch);
92
93 typedef void (*PixelReadFunction)(const uint8_t *source, uint8_t *dest);
94 typedef void (*PixelWriteFunction)(const uint8_t *source, uint8_t *dest);
95 typedef void (*FastCopyFunction)(const uint8_t *source,
96 int srcXAxisPitch,
97 int srcYAxisPitch,
98 uint8_t *dest,
99 int destXAxisPitch,
100 int destYAxisPitch,
101 int width,
102 int height);
103
104 class FastCopyFunctionMap
105 {
106 public:
107 struct Entry
108 {
109 angle::FormatID formatID;
110 FastCopyFunction func;
111 };
112
FastCopyFunctionMap()113 constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {}
114
FastCopyFunctionMap(const Entry * data,size_t size)115 constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {}
116
117 bool has(angle::FormatID formatID) const;
118 FastCopyFunction get(angle::FormatID formatID) const;
119
120 private:
121 size_t mSize;
122 const Entry *mData;
123 };
124
125 struct PackPixelsParams
126 {
127 PackPixelsParams();
128 PackPixelsParams(const gl::Rectangle &area,
129 const angle::Format &destFormat,
130 GLuint outputPitch,
131 bool reverseRowOrderIn,
132 gl::Buffer *packBufferIn,
133 ptrdiff_t offset);
134
135 gl::Rectangle area;
136 const angle::Format *destFormat;
137 GLuint outputPitch;
138 gl::Buffer *packBuffer;
139 bool reverseRowOrder;
140 ptrdiff_t offset;
141 SurfaceRotation rotation;
142 };
143
144 void PackPixels(const PackPixelsParams ¶ms,
145 const angle::Format &sourceFormat,
146 int inputPitch,
147 const uint8_t *source,
148 uint8_t *destination);
149
150 angle::Result GetPackPixelsParams(const gl::InternalFormat &sizedFormatInfo,
151 GLuint outputPitch,
152 const gl::PixelPackState &packState,
153 gl::Buffer *packBuffer,
154 const gl::Rectangle &area,
155 const gl::Rectangle &clippedArea,
156 rx::PackPixelsParams *paramsOut,
157 GLuint *skipBytesOut);
158
159 using InitializeTextureDataFunction = void (*)(size_t width,
160 size_t height,
161 size_t depth,
162 uint8_t *output,
163 size_t outputRowPitch,
164 size_t outputDepthPitch);
165
166 using LoadImageFunction = void (*)(const angle::ImageLoadContext &context,
167 size_t width,
168 size_t height,
169 size_t depth,
170 const uint8_t *input,
171 size_t inputRowPitch,
172 size_t inputDepthPitch,
173 uint8_t *output,
174 size_t outputRowPitch,
175 size_t outputDepthPitch);
176
177 struct LoadImageFunctionInfo
178 {
LoadImageFunctionInfoLoadImageFunctionInfo179 LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {}
LoadImageFunctionInfoLoadImageFunctionInfo180 LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion)
181 : loadFunction(loadFunction), requiresConversion(requiresConversion)
182 {}
183
184 LoadImageFunction loadFunction;
185 bool requiresConversion;
186 };
187
188 using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum);
189
190 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs);
191
192 void CopyImageCHROMIUM(const uint8_t *sourceData,
193 size_t sourceRowPitch,
194 size_t sourcePixelBytes,
195 size_t sourceDepthPitch,
196 PixelReadFunction pixelReadFunction,
197 uint8_t *destData,
198 size_t destRowPitch,
199 size_t destPixelBytes,
200 size_t destDepthPitch,
201 PixelWriteFunction pixelWriteFunction,
202 GLenum destUnsizedFormat,
203 GLenum destComponentType,
204 size_t width,
205 size_t height,
206 size_t depth,
207 bool unpackFlipY,
208 bool unpackPremultiplyAlpha,
209 bool unpackUnmultiplyAlpha);
210
211 // Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete.
212 // This helper class encapsulates handling incomplete textures. Because the GL back-end
213 // can take advantage of the driver's incomplete textures, and because clearing multisample
214 // textures is so difficult, we can keep an instance of this class in the back-end instead
215 // of moving the logic to the Context front-end.
216
217 // This interface allows us to call-back to init a multisample texture.
218 class MultisampleTextureInitializer
219 {
220 public:
~MultisampleTextureInitializer()221 virtual ~MultisampleTextureInitializer() {}
222 virtual angle::Result initializeMultisampleTextureToBlack(const gl::Context *context,
223 gl::Texture *glTexture) = 0;
224 };
225
226 class IncompleteTextureSet final : angle::NonCopyable
227 {
228 public:
229 IncompleteTextureSet() = default;
230 ~IncompleteTextureSet() = default;
231
232 void onDestroy(const gl::Context *context);
233
234 angle::Result getIncompleteTexture(const gl::Context *context,
235 gl::TextureType type,
236 gl::SamplerFormat format,
237 MultisampleTextureInitializer *multisampleInitializer,
238 gl::Texture **textureOut);
239
240 private:
241 using TextureMapWithSamplerFormat = angle::PackedEnumMap<gl::SamplerFormat, gl::TextureMap>;
242
243 TextureMapWithSamplerFormat mIncompleteTextures;
244 };
245
246 // Helpers to set a matrix uniform value based on GLSL or HLSL semantics.
247 // The return value indicate if the data was updated or not.
248 template <int cols, int rows>
249 struct SetFloatUniformMatrixGLSL
250 {
251 static void Run(unsigned int arrayElementOffset,
252 unsigned int elementCount,
253 GLsizei countIn,
254 GLboolean transpose,
255 const GLfloat *value,
256 uint8_t *targetData);
257 };
258
259 template <int cols, int rows>
260 struct SetFloatUniformMatrixHLSL
261 {
262 static void Run(unsigned int arrayElementOffset,
263 unsigned int elementCount,
264 GLsizei countIn,
265 GLboolean transpose,
266 const GLfloat *value,
267 uint8_t *targetData);
268 };
269
270 // Helper method to de-tranpose a matrix uniform for an API query.
271 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose);
272
273 template <typename NonFloatT>
274 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose);
275
276 // Contains a CPU-side buffer and its data layout, used as a shadow buffer for default uniform
277 // blocks in VK and WGPU backends.
278 struct BufferAndLayout final : private angle::NonCopyable
279 {
280 BufferAndLayout();
281 ~BufferAndLayout();
282
283 // Shadow copies of the shader uniform data.
284 angle::MemoryBuffer uniformData;
285
286 // Tells us where to write on a call to a setUniform method. They are arranged in uniform
287 // location order.
288 std::vector<sh::BlockMemberInfo> uniformLayout;
289 };
290
291 template <typename T>
292 void UpdateBufferWithLayout(GLsizei count,
293 uint32_t arrayIndex,
294 int componentCount,
295 const T *v,
296 const sh::BlockMemberInfo &layoutInfo,
297 angle::MemoryBuffer *uniformData);
298
299 template <typename T>
300 void ReadFromBufferWithLayout(int componentCount,
301 uint32_t arrayIndex,
302 T *dst,
303 const sh::BlockMemberInfo &layoutInfo,
304 const angle::MemoryBuffer *uniformData);
305
306 using DefaultUniformBlockMap = gl::ShaderMap<std::shared_ptr<BufferAndLayout>>;
307
308 template <typename T>
309 void SetUniform(const gl::ProgramExecutable *executable,
310 GLint location,
311 GLsizei count,
312 const T *v,
313 GLenum entryPointType,
314 DefaultUniformBlockMap *defaultUniformBlocks,
315 gl::ShaderBitSet *defaultUniformBlocksDirty);
316
317 template <int cols, int rows>
318 void SetUniformMatrixfv(const gl::ProgramExecutable *executable,
319 GLint location,
320 GLsizei count,
321 GLboolean transpose,
322 const GLfloat *value,
323 DefaultUniformBlockMap *defaultUniformBlocks,
324 gl::ShaderBitSet *defaultUniformBlocksDirty);
325
326 template <typename T>
327 void GetUniform(const gl::ProgramExecutable *executable,
328 GLint location,
329 T *v,
330 GLenum entryPointType,
331 const DefaultUniformBlockMap *defaultUniformBlocks);
332
333 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type);
334
335 angle::Result ComputeStartVertex(ContextImpl *contextImpl,
336 const gl::IndexRange &indexRange,
337 GLint baseVertex,
338 GLint *firstVertexOut);
339
340 angle::Result GetVertexRangeInfo(const gl::Context *context,
341 GLint firstVertex,
342 GLsizei vertexOrIndexCount,
343 gl::DrawElementsType indexTypeOrInvalid,
344 const void *indices,
345 GLint baseVertex,
346 GLint *startVertexOut,
347 size_t *vertexCountOut);
348
349 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY);
350
351 // Helper method to intialize a FeatureSet with overrides from the DisplayState
352 void ApplyFeatureOverrides(angle::FeatureSetBase *features,
353 const angle::FeatureOverrides &overrides);
354
355 template <typename In>
LineLoopRestartIndexCountHelper(GLsizei indexCount,const uint8_t * srcPtr)356 uint32_t LineLoopRestartIndexCountHelper(GLsizei indexCount, const uint8_t *srcPtr)
357 {
358 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
359 const In *inIndices = reinterpret_cast<const In *>(srcPtr);
360 uint32_t numIndices = 0;
361 // See CopyLineLoopIndicesWithRestart() below for more info on how
362 // numIndices is calculated.
363 GLsizei loopStartIndex = 0;
364 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
365 {
366 In vertex = inIndices[curIndex];
367 if (vertex != restartIndex)
368 {
369 numIndices++;
370 }
371 else
372 {
373 if (curIndex > loopStartIndex)
374 {
375 if (curIndex > (loopStartIndex + 1))
376 {
377 numIndices += 1;
378 }
379 numIndices += 1;
380 }
381 loopStartIndex = curIndex + 1;
382 }
383 }
384 if (indexCount > (loopStartIndex + 1))
385 {
386 numIndices++;
387 }
388 return numIndices;
389 }
390
GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr)391 inline uint32_t GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,
392 GLsizei indexCount,
393 const uint8_t *srcPtr)
394 {
395 switch (glIndexType)
396 {
397 case gl::DrawElementsType::UnsignedByte:
398 return LineLoopRestartIndexCountHelper<uint8_t>(indexCount, srcPtr);
399 case gl::DrawElementsType::UnsignedShort:
400 return LineLoopRestartIndexCountHelper<uint16_t>(indexCount, srcPtr);
401 case gl::DrawElementsType::UnsignedInt:
402 return LineLoopRestartIndexCountHelper<uint32_t>(indexCount, srcPtr);
403 default:
404 UNREACHABLE();
405 return 0;
406 }
407 }
408
409 // Writes the line-strip vertices for a line loop to outPtr,
410 // where outLimit is calculated as in GetPrimitiveRestartIndexCount.
411 // Returns number of vertices written.
412 template <typename In, typename Out>
CopyLineLoopIndicesWithRestart(GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)413 size_t CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, uint8_t *outPtr)
414 {
415 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
416 constexpr Out outRestartIndex = gl::GetPrimitiveRestartIndexFromType<Out>();
417 const In *inIndices = reinterpret_cast<const In *>(srcPtr);
418 Out *outIndices = reinterpret_cast<Out *>(outPtr);
419 GLsizei loopStartIndex = 0;
420 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
421 {
422 In vertex = inIndices[curIndex];
423 if (vertex != restartIndex)
424 {
425 *(outIndices++) = static_cast<Out>(vertex);
426 }
427 else
428 {
429 if (curIndex > loopStartIndex)
430 {
431 if (curIndex > (loopStartIndex + 1))
432 {
433 // Emit an extra vertex only if the loop has more than one vertex.
434 *(outIndices++) = inIndices[loopStartIndex];
435 }
436 // Then restart the strip.
437 *(outIndices++) = outRestartIndex;
438 }
439 loopStartIndex = curIndex + 1;
440 }
441 }
442 if (indexCount > (loopStartIndex + 1))
443 {
444 // Close the last loop if it has more than one vertex.
445 *(outIndices++) = inIndices[loopStartIndex];
446 }
447 return static_cast<size_t>(outIndices - reinterpret_cast<Out *>(outPtr));
448 }
449
450 void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy);
451
452 angle::Result MultiDrawArraysGeneral(ContextImpl *contextImpl,
453 const gl::Context *context,
454 gl::PrimitiveMode mode,
455 const GLint *firsts,
456 const GLsizei *counts,
457 GLsizei drawcount);
458 angle::Result MultiDrawArraysIndirectGeneral(ContextImpl *contextImpl,
459 const gl::Context *context,
460 gl::PrimitiveMode mode,
461 const void *indirect,
462 GLsizei drawcount,
463 GLsizei stride);
464 angle::Result MultiDrawArraysInstancedGeneral(ContextImpl *contextImpl,
465 const gl::Context *context,
466 gl::PrimitiveMode mode,
467 const GLint *firsts,
468 const GLsizei *counts,
469 const GLsizei *instanceCounts,
470 GLsizei drawcount);
471 angle::Result MultiDrawElementsGeneral(ContextImpl *contextImpl,
472 const gl::Context *context,
473 gl::PrimitiveMode mode,
474 const GLsizei *counts,
475 gl::DrawElementsType type,
476 const GLvoid *const *indices,
477 GLsizei drawcount);
478 angle::Result MultiDrawElementsIndirectGeneral(ContextImpl *contextImpl,
479 const gl::Context *context,
480 gl::PrimitiveMode mode,
481 gl::DrawElementsType type,
482 const void *indirect,
483 GLsizei drawcount,
484 GLsizei stride);
485 angle::Result MultiDrawElementsInstancedGeneral(ContextImpl *contextImpl,
486 const gl::Context *context,
487 gl::PrimitiveMode mode,
488 const GLsizei *counts,
489 gl::DrawElementsType type,
490 const GLvoid *const *indices,
491 const GLsizei *instanceCounts,
492 GLsizei drawcount);
493 angle::Result MultiDrawArraysInstancedBaseInstanceGeneral(ContextImpl *contextImpl,
494 const gl::Context *context,
495 gl::PrimitiveMode mode,
496 const GLint *firsts,
497 const GLsizei *counts,
498 const GLsizei *instanceCounts,
499 const GLuint *baseInstances,
500 GLsizei drawcount);
501 angle::Result MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(ContextImpl *contextImpl,
502 const gl::Context *context,
503 gl::PrimitiveMode mode,
504 const GLsizei *counts,
505 gl::DrawElementsType type,
506 const GLvoid *const *indices,
507 const GLsizei *instanceCounts,
508 const GLint *baseVertices,
509 const GLuint *baseInstances,
510 GLsizei drawcount);
511
512 // RAII object making sure reset uniforms is called no matter whether there's an error in draw calls
513 class ResetBaseVertexBaseInstance : angle::NonCopyable
514 {
515 public:
516 ResetBaseVertexBaseInstance(gl::ProgramExecutable *executable,
517 bool resetBaseVertex,
518 bool resetBaseInstance);
519
520 ~ResetBaseVertexBaseInstance();
521
522 private:
523 gl::ProgramExecutable *mExecutable;
524 bool mResetBaseVertex;
525 bool mResetBaseInstance;
526 };
527
528 angle::FormatID ConvertToSRGB(angle::FormatID formatID);
529 angle::FormatID ConvertToLinear(angle::FormatID formatID);
530 bool IsOverridableLinearFormat(angle::FormatID formatID);
531
532 template <bool swizzledLuma = true>
533 const gl::ColorGeneric AdjustBorderColor(const angle::ColorGeneric &borderColorGeneric,
534 const angle::Format &format,
535 bool stencilMode);
536
537 template <typename LargerInt>
LimitToInt(const LargerInt physicalDeviceValue)538 GLint LimitToInt(const LargerInt physicalDeviceValue)
539 {
540 static_assert(sizeof(LargerInt) >= sizeof(int32_t), "Incorrect usage of LimitToInt");
541 return static_cast<GLint>(
542 std::min(physicalDeviceValue, static_cast<LargerInt>(std::numeric_limits<int32_t>::max())));
543 }
544
545 template <typename LargerInt>
LimitToIntAnd(const LargerInt physicalDeviceValue,const uint64_t cap)546 GLint LimitToIntAnd(const LargerInt physicalDeviceValue, const uint64_t cap)
547 {
548 LargerInt result = LimitToInt(physicalDeviceValue);
549 return static_cast<GLint>(std::min(static_cast<uint64_t>(result), cap));
550 }
551
552 bool TextureHasAnyRedefinedLevels(const gl::CubeFaceArray<gl::TexLevelMask> &redefinedLevels);
553 bool IsTextureLevelRedefined(const gl::CubeFaceArray<gl::TexLevelMask> &redefinedLevels,
554 gl::TextureType textureType,
555 gl::LevelIndex level);
556
557 enum class TextureLevelDefinition
558 {
559 Compatible = 0,
560 Incompatible = 1,
561
562 InvalidEnum = 2
563 };
564
565 enum class TextureLevelAllocation
566 {
567 WithinAllocatedImage = 0,
568 OutsideAllocatedImage = 1,
569
570 InvalidEnum = 2
571 };
572 // Returns true if the image should be released after the level is redefined, false otherwise.
573 bool TextureRedefineLevel(const TextureLevelAllocation levelAllocation,
574 const TextureLevelDefinition levelDefinition,
575 bool immutableFormat,
576 uint32_t levelCount,
577 const uint32_t layerIndex,
578 const gl::ImageIndex &index,
579 gl::LevelIndex imageFirstAllocatedLevel,
580 gl::CubeFaceArray<gl::TexLevelMask> *redefinedLevels);
581
582 void TextureRedefineGenerateMipmapLevels(gl::LevelIndex baseLevel,
583 gl::LevelIndex maxLevel,
584 gl::LevelIndex firstGeneratedLevel,
585 gl::CubeFaceArray<gl::TexLevelMask> *redefinedLevels);
586
587 enum class ImageMipLevels
588 {
589 EnabledLevels = 0,
590 FullMipChainForGenerateMipmap = 1,
591
592 InvalidEnum = 2,
593 };
594
595 enum class PipelineType
596 {
597 Graphics = 0,
598 Compute = 1,
599
600 InvalidEnum = 2,
601 EnumCount = 2,
602 };
603
604 // Return the log of samples. Assumes |sampleCount| is a power of 2. The result can be used to
605 // index an array based on sample count.
PackSampleCount(int32_t sampleCount)606 inline size_t PackSampleCount(int32_t sampleCount)
607 {
608 if (sampleCount == 0)
609 {
610 sampleCount = 1;
611 }
612
613 // We currently only support up to 16xMSAA.
614 ASSERT(1 <= sampleCount && sampleCount <= 16);
615 ASSERT(gl::isPow2(sampleCount));
616 return gl::ScanForward(static_cast<uint32_t>(sampleCount));
617 }
618
619 } // namespace rx
620
621 // MultiDraw macro patterns
622 // These macros are to avoid too much code duplication as we don't want to have if detect for
623 // hasDrawID/BaseVertex/BaseInstance inside for loop in a multiDrawANGLE call Part of these are put
624 // in the header as we want to share with specialized context impl on some platforms for multidraw
625 #define ANGLE_SET_DRAW_ID_UNIFORM_0(drawID) \
626 {}
627 #define ANGLE_SET_DRAW_ID_UNIFORM_1(drawID) executable->setDrawIDUniform(drawID)
628 #define ANGLE_SET_DRAW_ID_UNIFORM(cond) ANGLE_SET_DRAW_ID_UNIFORM_##cond
629
630 #define ANGLE_SET_BASE_VERTEX_UNIFORM_0(baseVertex) \
631 {}
632 #define ANGLE_SET_BASE_VERTEX_UNIFORM_1(baseVertex) executable->setBaseVertexUniform(baseVertex);
633 #define ANGLE_SET_BASE_VERTEX_UNIFORM(cond) ANGLE_SET_BASE_VERTEX_UNIFORM_##cond
634
635 #define ANGLE_SET_BASE_INSTANCE_UNIFORM_0(baseInstance) \
636 {}
637 #define ANGLE_SET_BASE_INSTANCE_UNIFORM_1(baseInstance) \
638 executable->setBaseInstanceUniform(baseInstance)
639 #define ANGLE_SET_BASE_INSTANCE_UNIFORM(cond) ANGLE_SET_BASE_INSTANCE_UNIFORM_##cond
640
641 #define ANGLE_NOOP_DRAW_ context->noopDraw(mode, counts[drawID])
642 #define ANGLE_NOOP_DRAW_INSTANCED \
643 context->noopDrawInstanced(mode, counts[drawID], instanceCounts[drawID])
644 #define ANGLE_NOOP_DRAW(_instanced) ANGLE_NOOP_DRAW##_instanced
645
646 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE_ \
647 gl::MarkTransformFeedbackBufferUsage(context, counts[drawID], 1)
648 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE_INSTANCED \
649 gl::MarkTransformFeedbackBufferUsage(context, counts[drawID], instanceCounts[drawID])
650 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE(instanced) \
651 ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE##instanced
652
653 #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
654