• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 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 // frame_capture_utils.cpp:
7 //   ANGLE frame capture util implementation.
8 //
9 
10 #include "libANGLE/capture/frame_capture_utils.h"
11 
12 #include <vector>
13 
14 #include "common/Color.h"
15 #include "common/MemoryBuffer.h"
16 #include "common/angleutils.h"
17 
18 #include "libANGLE/capture/gl_enum_utils.h"
19 
20 #include "libANGLE/Buffer.h"
21 #include "libANGLE/Caps.h"
22 #include "libANGLE/Context.h"
23 #include "libANGLE/Framebuffer.h"
24 #include "libANGLE/Query.h"
25 #include "libANGLE/RefCountObject.h"
26 #include "libANGLE/ResourceMap.h"
27 #include "libANGLE/Sampler.h"
28 #include "libANGLE/State.h"
29 
30 #include "libANGLE/TransformFeedback.h"
31 #include "libANGLE/VertexAttribute.h"
32 #include "libANGLE/angletypes.h"
33 #include "libANGLE/renderer/FramebufferImpl.h"
34 #include "libANGLE/renderer/RenderbufferImpl.h"
35 #include "libANGLE/serializer/JsonSerializer.h"
36 
37 #if !ANGLE_CAPTURE_ENABLED
38 #    error Frame capture must be enabled to build this file.
39 #endif  // !ANGLE_CAPTURE_ENABLED
40 
41 // Note: when diagnosing serialization comparison failures, you can disable the unused function
42 // compiler warning to allow bisecting the comparison function. One first check is to disable
43 // Framebuffer Attachment pixel comparison which includes the pixel contents of the default FBO.
44 // ANGLE_DISABLE_UNUSED_FUNCTION_WARNING
45 
46 namespace angle
47 {
48 
49 namespace
50 {
51 
TextureTypeToString(gl::TextureType type)52 static const char *TextureTypeToString(gl::TextureType type)
53 {
54     switch (type)
55     {
56         case gl::TextureType::_2D:
57             return "TEXTURE_2D";
58         case gl::TextureType::_2DArray:
59             return "TEXTURE_2D_ARRAY";
60         case gl::TextureType::_2DMultisample:
61             return "TEXTURE_2DMS";
62         case gl::TextureType::_2DMultisampleArray:
63             return "TEXTURE_2DMS_ARRAY";
64         case gl::TextureType::_3D:
65             return "TEXTURE_3D";
66         case gl::TextureType::External:
67             return "TEXTURE_EXTERNAL";
68         case gl::TextureType::Rectangle:
69             return "TEXTURE_RECT";
70         case gl::TextureType::CubeMap:
71             return "TEXTURE_CUBE_MAP";
72         case gl::TextureType::CubeMapArray:
73             return "TEXTURE_CUBE_MAP_ARRAY";
74         case gl::TextureType::VideoImage:
75             return "TEXTURE_VIDEO_IMAGE";
76         case gl::TextureType::Buffer:
77             return "TEXTURE_BUFFER";
78         default:
79             return "invalid";
80     }
81 }
82 
CullFaceModeToString(gl::CullFaceMode mode)83 static const char *CullFaceModeToString(gl::CullFaceMode mode)
84 {
85     switch (mode)
86     {
87         case gl::CullFaceMode::Back:
88             return "CULL_BACK";
89         case gl::CullFaceMode::Front:
90             return "CULL_FRONT";
91         case gl::CullFaceMode::FrontAndBack:
92             return "CULL_FRONT_AND_BACK";
93         default:
94             return "invalid";
95     }
96 }
97 
ProvokingVertexConventionToString(gl::ProvokingVertexConvention mode)98 static const char *ProvokingVertexConventionToString(gl::ProvokingVertexConvention mode)
99 {
100     switch (mode)
101     {
102         case gl::ProvokingVertexConvention::FirstVertexConvention:
103             return "First";
104         case gl::ProvokingVertexConvention::LastVertexConvention:
105             return "Last";
106         default:
107             return "invalid";
108     }
109 }
110 
InitStateToString(gl::InitState state)111 static const char *InitStateToString(gl::InitState state)
112 {
113     return state == gl::InitState::Initialized ? "Initialized" : "MayNeedInit";
114 }
115 
BlockLayoutTypeToString(sh::BlockLayoutType type)116 static const char *BlockLayoutTypeToString(sh::BlockLayoutType type)
117 {
118     switch (type)
119     {
120         case sh::BlockLayoutType::BLOCKLAYOUT_STD140:
121             return "std140";
122         case sh::BlockLayoutType::BLOCKLAYOUT_STD430:
123             return "std430";
124         case sh::BlockLayoutType::BLOCKLAYOUT_PACKED:
125             return "packed";
126         case sh::BlockLayoutType::BLOCKLAYOUT_SHARED:
127             return "shared";
128         default:
129             return "invalid";
130     }
131 }
132 
BlockTypeToString(sh::BlockType type)133 static const char *BlockTypeToString(sh::BlockType type)
134 {
135     return type == sh::BlockType::BLOCK_BUFFER ? "buffer" : "uniform";
136 }
137 
InterpolationTypeToString(sh::InterpolationType type)138 static const char *InterpolationTypeToString(sh::InterpolationType type)
139 {
140     switch (type)
141     {
142         case sh::InterpolationType::INTERPOLATION_SMOOTH:
143             return "smooth";
144         case sh::InterpolationType::INTERPOLATION_CENTROID:
145             return "centroid";
146         case sh::InterpolationType::INTERPOLATION_SAMPLE:
147             return "sample";
148         case sh::InterpolationType::INTERPOLATION_FLAT:
149             return "flat";
150         case sh::InterpolationType::INTERPOLATION_NOPERSPECTIVE:
151             return "noperspective";
152         default:
153             return "invalid";
154     }
155 }
156 
157 #define ENUM_TO_STRING(C, M) \
158     case C ::M:              \
159         return #M
160 
PrimitiveModeToString(gl::PrimitiveMode mode)161 static const char *PrimitiveModeToString(gl::PrimitiveMode mode)
162 {
163     switch (mode)
164     {
165         ENUM_TO_STRING(gl::PrimitiveMode, Points);
166         ENUM_TO_STRING(gl::PrimitiveMode, Lines);
167         ENUM_TO_STRING(gl::PrimitiveMode, LineLoop);
168         ENUM_TO_STRING(gl::PrimitiveMode, LineStrip);
169         ENUM_TO_STRING(gl::PrimitiveMode, Triangles);
170         ENUM_TO_STRING(gl::PrimitiveMode, TriangleStrip);
171         ENUM_TO_STRING(gl::PrimitiveMode, TriangleFan);
172         ENUM_TO_STRING(gl::PrimitiveMode, Unused1);
173         ENUM_TO_STRING(gl::PrimitiveMode, Unused2);
174         ENUM_TO_STRING(gl::PrimitiveMode, Unused3);
175         ENUM_TO_STRING(gl::PrimitiveMode, LinesAdjacency);
176         ENUM_TO_STRING(gl::PrimitiveMode, LineStripAdjacency);
177         ENUM_TO_STRING(gl::PrimitiveMode, TrianglesAdjacency);
178         ENUM_TO_STRING(gl::PrimitiveMode, TriangleStripAdjacency);
179         ENUM_TO_STRING(gl::PrimitiveMode, Patches);
180         default:
181             return "invalid";
182     }
183 }
184 
BufferUsageToString(gl::BufferUsage usage)185 static const char *BufferUsageToString(gl::BufferUsage usage)
186 {
187     switch (usage)
188     {
189         ENUM_TO_STRING(gl::BufferUsage, DynamicCopy);
190         ENUM_TO_STRING(gl::BufferUsage, DynamicDraw);
191         ENUM_TO_STRING(gl::BufferUsage, DynamicRead);
192         ENUM_TO_STRING(gl::BufferUsage, StaticCopy);
193         ENUM_TO_STRING(gl::BufferUsage, StaticDraw);
194         ENUM_TO_STRING(gl::BufferUsage, StaticRead);
195         ENUM_TO_STRING(gl::BufferUsage, StreamCopy);
196         ENUM_TO_STRING(gl::BufferUsage, StreamDraw);
197         ENUM_TO_STRING(gl::BufferUsage, StreamRead);
198         default:
199             return "invalid";
200     }
201 }
202 
SrgbOverrideToString(gl::SrgbOverride value)203 static const char *SrgbOverrideToString(gl::SrgbOverride value)
204 {
205     switch (value)
206     {
207         ENUM_TO_STRING(gl::SrgbOverride, Default);
208         ENUM_TO_STRING(gl::SrgbOverride, SRGB);
209         ENUM_TO_STRING(gl::SrgbOverride, Linear);
210         default:
211             return "invalid";
212     }
213 }
214 
ColorGenericTypeToString(gl::ColorGeneric::Type type)215 static const char *ColorGenericTypeToString(gl::ColorGeneric::Type type)
216 {
217     switch (type)
218     {
219         ENUM_TO_STRING(gl::ColorGeneric::Type, Float);
220         ENUM_TO_STRING(gl::ColorGeneric::Type, Int);
221         ENUM_TO_STRING(gl::ColorGeneric::Type, UInt);
222         default:
223             return "invalid";
224     }
225 }
226 
CompileStatusToString(gl::CompileStatus status)227 static const char *CompileStatusToString(gl::CompileStatus status)
228 {
229     switch (status)
230     {
231         ENUM_TO_STRING(gl::CompileStatus, NOT_COMPILED);
232         ENUM_TO_STRING(gl::CompileStatus, COMPILE_REQUESTED);
233         ENUM_TO_STRING(gl::CompileStatus, COMPILED);
234         default:
235             return "invalid";
236     }
237 }
238 
239 #undef ENUM_TO_STRING
240 
241 class ANGLE_NO_DISCARD GroupScope
242 {
243   public:
GroupScope(JsonSerializer * json,const std::string & name)244     GroupScope(JsonSerializer *json, const std::string &name) : mJson(json)
245     {
246         mJson->startGroup(name);
247     }
248 
GroupScope(JsonSerializer * json,const std::string & name,int index)249     GroupScope(JsonSerializer *json, const std::string &name, int index) : mJson(json)
250     {
251         constexpr size_t kBufSize = 255;
252         char buf[kBufSize + 1]    = {};
253         snprintf(buf, kBufSize, "%s%s%02d", name.c_str(), name.empty() ? "" : " ", index);
254         mJson->startGroup(buf);
255     }
256 
GroupScope(JsonSerializer * json,int index)257     GroupScope(JsonSerializer *json, int index) : GroupScope(json, "", index) {}
258 
~GroupScope()259     ~GroupScope() { mJson->endGroup(); }
260 
261   private:
262     JsonSerializer *mJson;
263 };
264 
SerializeColorF(JsonSerializer * json,const ColorF & color)265 void SerializeColorF(JsonSerializer *json, const ColorF &color)
266 {
267     json->addScalar("red", color.red);
268     json->addScalar("green", color.green);
269     json->addScalar("blue", color.blue);
270     json->addScalar("alpha", color.alpha);
271 }
272 
SerializeColorFWithGroup(JsonSerializer * json,const char * groupName,const ColorF & color)273 void SerializeColorFWithGroup(JsonSerializer *json, const char *groupName, const ColorF &color)
274 {
275     GroupScope group(json, groupName);
276     SerializeColorF(json, color);
277 }
278 
SerializeColorI(JsonSerializer * json,const ColorI & color)279 void SerializeColorI(JsonSerializer *json, const ColorI &color)
280 {
281     json->addScalar("Red", color.red);
282     json->addScalar("Green", color.green);
283     json->addScalar("Blue", color.blue);
284     json->addScalar("Alpha", color.alpha);
285 }
286 
SerializeColorUI(JsonSerializer * json,const ColorUI & color)287 void SerializeColorUI(JsonSerializer *json, const ColorUI &color)
288 {
289     json->addScalar("Red", color.red);
290     json->addScalar("Green", color.green);
291     json->addScalar("Blue", color.blue);
292     json->addScalar("Alpha", color.alpha);
293 }
294 
SerializeExtents(JsonSerializer * json,const gl::Extents & extents)295 void SerializeExtents(JsonSerializer *json, const gl::Extents &extents)
296 {
297     json->addScalar("Width", extents.width);
298     json->addScalar("Height", extents.height);
299     json->addScalar("Depth", extents.depth);
300 }
301 
302 template <class ObjectType>
SerializeOffsetBindingPointerVector(JsonSerializer * json,const char * groupName,const std::vector<gl::OffsetBindingPointer<ObjectType>> & offsetBindingPointerVector)303 void SerializeOffsetBindingPointerVector(
304     JsonSerializer *json,
305     const char *groupName,
306     const std::vector<gl::OffsetBindingPointer<ObjectType>> &offsetBindingPointerVector)
307 {
308     GroupScope vectorGroup(json, groupName);
309 
310     for (size_t i = 0; i < offsetBindingPointerVector.size(); i++)
311     {
312         GroupScope itemGroup(json, static_cast<int>(i));
313         json->addScalar("Value", offsetBindingPointerVector[i].id().value);
314         json->addScalar("Offset", offsetBindingPointerVector[i].getOffset());
315         json->addScalar("Size", offsetBindingPointerVector[i].getSize());
316     }
317 }
318 
319 template <class ObjectType>
SerializeBindingPointerVector(JsonSerializer * json,const std::vector<gl::BindingPointer<ObjectType>> & bindingPointerVector)320 void SerializeBindingPointerVector(
321     JsonSerializer *json,
322     const std::vector<gl::BindingPointer<ObjectType>> &bindingPointerVector)
323 {
324     for (size_t i = 0; i < bindingPointerVector.size(); i++)
325     {
326         // Do not serialize zero bindings, as this will create unwanted diffs
327         if (bindingPointerVector[i].id().value != 0)
328         {
329             std::ostringstream s;
330             s << i;
331             json->addScalar(s.str().c_str(), bindingPointerVector[i].id().value);
332         }
333     }
334 }
335 
336 template <class T>
SerializeRange(JsonSerializer * json,const gl::Range<T> & range)337 void SerializeRange(JsonSerializer *json, const gl::Range<T> &range)
338 {
339     GroupScope group(json, "Range");
340     json->addScalar("Low", range.low());
341     json->addScalar("High", range.high());
342 }
343 
IsValidColorAttachmentBinding(GLenum binding,size_t colorAttachmentsCount)344 bool IsValidColorAttachmentBinding(GLenum binding, size_t colorAttachmentsCount)
345 {
346     return binding == GL_BACK || (binding >= GL_COLOR_ATTACHMENT0 &&
347                                   (binding - GL_COLOR_ATTACHMENT0) < colorAttachmentsCount);
348 }
349 
ReadPixelsFromAttachment(const gl::Context * context,gl::Framebuffer * framebuffer,const gl::FramebufferAttachment & framebufferAttachment,ScratchBuffer * scratchBuffer,MemoryBuffer ** pixels)350 Result ReadPixelsFromAttachment(const gl::Context *context,
351                                 gl::Framebuffer *framebuffer,
352                                 const gl::FramebufferAttachment &framebufferAttachment,
353                                 ScratchBuffer *scratchBuffer,
354                                 MemoryBuffer **pixels)
355 {
356     gl::Extents extents       = framebufferAttachment.getSize();
357     GLenum binding            = framebufferAttachment.getBinding();
358     gl::InternalFormat format = *framebufferAttachment.getFormat().info;
359     if (IsValidColorAttachmentBinding(binding,
360                                       framebuffer->getState().getColorAttachments().size()))
361     {
362         format = framebuffer->getImplementation()->getImplementationColorReadFormat(context);
363     }
364     ANGLE_CHECK_GL_ALLOC(const_cast<gl::Context *>(context),
365                          scratchBuffer->getInitialized(
366                              format.pixelBytes * extents.width * extents.height, pixels, 0));
367     ANGLE_TRY(framebuffer->readPixels(context, gl::Rectangle{0, 0, extents.width, extents.height},
368                                       format.format, format.type, gl::PixelPackState{}, nullptr,
369                                       (*pixels)->data()));
370     return Result::Continue;
371 }
SerializeImageIndex(JsonSerializer * json,const gl::ImageIndex & imageIndex)372 void SerializeImageIndex(JsonSerializer *json, const gl::ImageIndex &imageIndex)
373 {
374     GroupScope group(json, "Image");
375     json->addCString("ImageType", TextureTypeToString(imageIndex.getType()));
376     json->addScalar("LevelIndex", imageIndex.getLevelIndex());
377     json->addScalar("LayerIndex", imageIndex.getLayerIndex());
378     json->addScalar("LayerCount", imageIndex.getLayerCount());
379 }
380 
SerializeFramebufferAttachment(const gl::Context * context,JsonSerializer * json,ScratchBuffer * scratchBuffer,gl::Framebuffer * framebuffer,const gl::FramebufferAttachment & framebufferAttachment,gl::GLenumGroup enumGroup)381 Result SerializeFramebufferAttachment(const gl::Context *context,
382                                       JsonSerializer *json,
383                                       ScratchBuffer *scratchBuffer,
384                                       gl::Framebuffer *framebuffer,
385                                       const gl::FramebufferAttachment &framebufferAttachment,
386                                       gl::GLenumGroup enumGroup)
387 {
388     if (framebufferAttachment.type() == GL_TEXTURE ||
389         framebufferAttachment.type() == GL_RENDERBUFFER)
390     {
391         json->addScalar("ID", framebufferAttachment.id());
392     }
393     json->addScalar("Type", framebufferAttachment.type());
394     // serialize target variable
395     json->addString("Binding", gl::GLenumToString(enumGroup, framebufferAttachment.getBinding()));
396     if (framebufferAttachment.type() == GL_TEXTURE)
397     {
398         SerializeImageIndex(json, framebufferAttachment.getTextureImageIndex());
399     }
400     json->addScalar("NumViews", framebufferAttachment.getNumViews());
401     json->addScalar("Multiview", framebufferAttachment.isMultiview());
402     json->addScalar("ViewIndex", framebufferAttachment.getBaseViewIndex());
403     json->addScalar("Samples", framebufferAttachment.getRenderToTextureSamples());
404 
405     {
406         GroupScope extentsGroup(json, "Extents");
407         SerializeExtents(json, framebufferAttachment.getSize());
408     }
409 
410     if (framebufferAttachment.type() != GL_TEXTURE &&
411         framebufferAttachment.type() != GL_RENDERBUFFER)
412     {
413         GLenum prevReadBufferState = framebuffer->getReadBufferState();
414         GLenum binding             = framebufferAttachment.getBinding();
415         if (IsValidColorAttachmentBinding(binding,
416                                           framebuffer->getState().getColorAttachments().size()))
417         {
418             framebuffer->setReadBuffer(framebufferAttachment.getBinding());
419             ANGLE_TRY(framebuffer->syncState(context, GL_FRAMEBUFFER, gl::Command::Other));
420         }
421 
422         if (framebufferAttachment.initState() == gl::InitState::Initialized)
423         {
424             MemoryBuffer *pixelsPtr = nullptr;
425             ANGLE_TRY(ReadPixelsFromAttachment(context, framebuffer, framebufferAttachment,
426                                                scratchBuffer, &pixelsPtr));
427             json->addBlob("Data", pixelsPtr->data(), pixelsPtr->size());
428         }
429         else
430         {
431             json->addCString("Data", "Not initialized");
432         }
433         // Reset framebuffer state
434         framebuffer->setReadBuffer(prevReadBufferState);
435     }
436     return Result::Continue;
437 }
438 
SerializeFramebufferState(const gl::Context * context,JsonSerializer * json,ScratchBuffer * scratchBuffer,gl::Framebuffer * framebuffer,const gl::FramebufferState & framebufferState)439 Result SerializeFramebufferState(const gl::Context *context,
440                                  JsonSerializer *json,
441                                  ScratchBuffer *scratchBuffer,
442                                  gl::Framebuffer *framebuffer,
443                                  const gl::FramebufferState &framebufferState)
444 {
445     GroupScope group(json, "Framebuffer", framebufferState.id().value);
446 
447     json->addString("Label", framebufferState.getLabel());
448     json->addVector("DrawStates", framebufferState.getDrawBufferStates());
449     json->addScalar("ReadBufferState", framebufferState.getReadBufferState());
450     json->addScalar("DefaultWidth", framebufferState.getDefaultWidth());
451     json->addScalar("DefaultHeight", framebufferState.getDefaultHeight());
452     json->addScalar("DefaultSamples", framebufferState.getDefaultSamples());
453     json->addScalar("DefaultFixedSampleLocation",
454                     framebufferState.getDefaultFixedSampleLocations());
455     json->addScalar("DefaultLayers", framebufferState.getDefaultLayers());
456 
457     const std::vector<gl::FramebufferAttachment> &colorAttachments =
458         framebufferState.getColorAttachments();
459     for (const gl::FramebufferAttachment &colorAttachment : colorAttachments)
460     {
461         if (colorAttachment.isAttached())
462         {
463             GroupScope colorAttachmentgroup(json, "ColorAttachment");
464             ANGLE_TRY(SerializeFramebufferAttachment(context, json, scratchBuffer, framebuffer,
465                                                      colorAttachment,
466                                                      gl::GLenumGroup::ColorBuffer));
467         }
468     }
469     if (framebuffer->getDepthStencilAttachment())
470     {
471         GroupScope dsAttachmentgroup(json, "DepthStencilAttachment");
472         ANGLE_TRY(SerializeFramebufferAttachment(context, json, scratchBuffer, framebuffer,
473                                                  *framebuffer->getDepthStencilAttachment(),
474                                                  gl::GLenumGroup::DefaultGroup));
475     }
476     else
477     {
478         if (framebuffer->getDepthAttachment())
479         {
480             GroupScope depthAttachmentgroup(json, "DepthAttachment");
481             ANGLE_TRY(SerializeFramebufferAttachment(context, json, scratchBuffer, framebuffer,
482                                                      *framebuffer->getDepthAttachment(),
483                                                      gl::GLenumGroup::FramebufferAttachment));
484         }
485         if (framebuffer->getStencilAttachment())
486         {
487             GroupScope stencilAttachmengroup(json, "StencilAttachment");
488             ANGLE_TRY(SerializeFramebufferAttachment(context, json, scratchBuffer, framebuffer,
489                                                      *framebuffer->getStencilAttachment(),
490                                                      gl::GLenumGroup::DefaultGroup));
491         }
492     }
493     return Result::Continue;
494 }
495 
SerializeFramebuffer(const gl::Context * context,JsonSerializer * json,ScratchBuffer * scratchBuffer,gl::Framebuffer * framebuffer)496 Result SerializeFramebuffer(const gl::Context *context,
497                             JsonSerializer *json,
498                             ScratchBuffer *scratchBuffer,
499                             gl::Framebuffer *framebuffer)
500 {
501     return SerializeFramebufferState(context, json, scratchBuffer, framebuffer,
502                                      framebuffer->getState());
503 }
504 
SerializeRasterizerState(JsonSerializer * json,const gl::RasterizerState & rasterizerState)505 void SerializeRasterizerState(JsonSerializer *json, const gl::RasterizerState &rasterizerState)
506 {
507     GroupScope group(json, "Rasterizer");
508     json->addScalar("CullFace", rasterizerState.cullFace);
509     json->addCString("CullMode", CullFaceModeToString(rasterizerState.cullMode));
510     json->addScalar("FrontFace", rasterizerState.frontFace);
511     json->addScalar("PolygonOffsetFill", rasterizerState.polygonOffsetFill);
512     json->addScalar("PolygonOffsetFactor", rasterizerState.polygonOffsetFactor);
513     json->addScalar("PolygonOffsetUnits", rasterizerState.polygonOffsetUnits);
514     json->addScalar("PointDrawMode", rasterizerState.pointDrawMode);
515     json->addScalar("MultiSample", rasterizerState.multiSample);
516     json->addScalar("RasterizerDiscard", rasterizerState.rasterizerDiscard);
517     json->addScalar("Dither", rasterizerState.dither);
518 }
519 
SerializeRectangle(JsonSerializer * json,const std::string & name,const gl::Rectangle & rectangle)520 void SerializeRectangle(JsonSerializer *json,
521                         const std::string &name,
522                         const gl::Rectangle &rectangle)
523 {
524     GroupScope group(json, name);
525     json->addScalar("x", rectangle.x);
526     json->addScalar("y", rectangle.y);
527     json->addScalar("w", rectangle.width);
528     json->addScalar("h", rectangle.height);
529 }
530 
SerializeBlendStateExt(JsonSerializer * json,const gl::BlendStateExt & blendStateExt)531 void SerializeBlendStateExt(JsonSerializer *json, const gl::BlendStateExt &blendStateExt)
532 {
533     GroupScope group(json, "BlendStateExt");
534     json->addScalar("MaxDrawBuffers", blendStateExt.mMaxDrawBuffers);
535     json->addScalar("enableMask", blendStateExt.mEnabledMask.bits());
536     json->addScalar("DstColor", blendStateExt.mDstColor);
537     json->addScalar("DstAlpha", blendStateExt.mDstAlpha);
538     json->addScalar("SrcColor", blendStateExt.mSrcColor);
539     json->addScalar("SrcAlpha", blendStateExt.mSrcAlpha);
540     json->addScalar("EquationColor", blendStateExt.mEquationColor);
541     json->addScalar("EquationAlpha", blendStateExt.mEquationAlpha);
542     json->addScalar("ColorMask", blendStateExt.mColorMask);
543 }
544 
SerializeDepthStencilState(JsonSerializer * json,const gl::DepthStencilState & depthStencilState)545 void SerializeDepthStencilState(JsonSerializer *json,
546                                 const gl::DepthStencilState &depthStencilState)
547 {
548     GroupScope group(json, "DepthStencilState");
549     json->addScalar("DepthTest", depthStencilState.depthTest);
550     json->addScalar("DepthFunc", depthStencilState.depthFunc);
551     json->addScalar("DepthMask", depthStencilState.depthMask);
552     json->addScalar("StencilTest", depthStencilState.stencilTest);
553     json->addScalar("StencilFunc", depthStencilState.stencilFunc);
554     json->addScalar("StencilMask", depthStencilState.stencilMask);
555     json->addScalar("StencilFail", depthStencilState.stencilFail);
556     json->addScalar("StencilPassDepthFail", depthStencilState.stencilPassDepthFail);
557     json->addScalar("StencilPassDepthPass", depthStencilState.stencilPassDepthPass);
558     json->addScalar("StencilWritemask", depthStencilState.stencilWritemask);
559     json->addScalar("StencilBackFunc", depthStencilState.stencilBackFunc);
560     json->addScalar("StencilBackMask", depthStencilState.stencilBackMask);
561     json->addScalar("StencilBackFail", depthStencilState.stencilBackFail);
562     json->addScalar("StencilBackPassDepthFail", depthStencilState.stencilBackPassDepthFail);
563     json->addScalar("StencilBackPassDepthPass", depthStencilState.stencilBackPassDepthPass);
564     json->addScalar("StencilBackWritemask", depthStencilState.stencilBackWritemask);
565 }
566 
SerializeVertexAttribCurrentValueData(JsonSerializer * json,const gl::VertexAttribCurrentValueData & vertexAttribCurrentValueData)567 void SerializeVertexAttribCurrentValueData(
568     JsonSerializer *json,
569     const gl::VertexAttribCurrentValueData &vertexAttribCurrentValueData)
570 {
571     ASSERT(vertexAttribCurrentValueData.Type == gl::VertexAttribType::Float ||
572            vertexAttribCurrentValueData.Type == gl::VertexAttribType::Int ||
573            vertexAttribCurrentValueData.Type == gl::VertexAttribType::UnsignedInt);
574     if (vertexAttribCurrentValueData.Type == gl::VertexAttribType::Float)
575     {
576         json->addScalar("0", vertexAttribCurrentValueData.Values.FloatValues[0]);
577         json->addScalar("1", vertexAttribCurrentValueData.Values.FloatValues[1]);
578         json->addScalar("2", vertexAttribCurrentValueData.Values.FloatValues[2]);
579         json->addScalar("3", vertexAttribCurrentValueData.Values.FloatValues[3]);
580     }
581     else if (vertexAttribCurrentValueData.Type == gl::VertexAttribType::Int)
582     {
583         json->addScalar("0", vertexAttribCurrentValueData.Values.IntValues[0]);
584         json->addScalar("1", vertexAttribCurrentValueData.Values.IntValues[1]);
585         json->addScalar("2", vertexAttribCurrentValueData.Values.IntValues[2]);
586         json->addScalar("3", vertexAttribCurrentValueData.Values.IntValues[3]);
587     }
588     else
589     {
590         json->addScalar("0", vertexAttribCurrentValueData.Values.UnsignedIntValues[0]);
591         json->addScalar("1", vertexAttribCurrentValueData.Values.UnsignedIntValues[1]);
592         json->addScalar("2", vertexAttribCurrentValueData.Values.UnsignedIntValues[2]);
593         json->addScalar("3", vertexAttribCurrentValueData.Values.UnsignedIntValues[3]);
594     }
595 }
596 
SerializePixelPackState(JsonSerializer * json,const gl::PixelPackState & pixelPackState)597 void SerializePixelPackState(JsonSerializer *json, const gl::PixelPackState &pixelPackState)
598 {
599     GroupScope group(json, "PixelPackState");
600     json->addScalar("Alignment", pixelPackState.alignment);
601     json->addScalar("RowLength", pixelPackState.rowLength);
602     json->addScalar("SkipRows", pixelPackState.skipRows);
603     json->addScalar("SkipPixels", pixelPackState.skipPixels);
604     json->addScalar("ImageHeight", pixelPackState.imageHeight);
605     json->addScalar("SkipImages", pixelPackState.skipImages);
606     json->addScalar("ReverseRowOrder", pixelPackState.reverseRowOrder);
607 }
608 
SerializePixelUnpackState(JsonSerializer * json,const gl::PixelUnpackState & pixelUnpackState)609 void SerializePixelUnpackState(JsonSerializer *json, const gl::PixelUnpackState &pixelUnpackState)
610 {
611     GroupScope group(json, "PixelUnpackState");
612     json->addScalar("Alignment", pixelUnpackState.alignment);
613     json->addScalar("RowLength", pixelUnpackState.rowLength);
614     json->addScalar("SkipRows", pixelUnpackState.skipRows);
615     json->addScalar("SkipPixels", pixelUnpackState.skipPixels);
616     json->addScalar("ImageHeight", pixelUnpackState.imageHeight);
617     json->addScalar("SkipImages", pixelUnpackState.skipImages);
618 }
619 
SerializeImageUnit(JsonSerializer * json,const gl::ImageUnit & imageUnit)620 void SerializeImageUnit(JsonSerializer *json, const gl::ImageUnit &imageUnit)
621 {
622     GroupScope group(json, "ImageUnit");
623     json->addScalar("Level", imageUnit.level);
624     json->addScalar("Layered", imageUnit.layered);
625     json->addScalar("Layer", imageUnit.layer);
626     json->addScalar("Access", imageUnit.access);
627     json->addScalar("Format", imageUnit.format);
628     json->addScalar("Texid", imageUnit.texture.id().value);
629 }
630 
SerializeContextState(JsonSerializer * json,const gl::State & state)631 void SerializeContextState(JsonSerializer *json, const gl::State &state)
632 {
633     GroupScope group(json, "ContextState");
634     json->addScalar("ClientType", state.getClientType());
635     json->addScalar("Priority", state.getContextPriority());
636     json->addScalar("Major", state.getClientMajorVersion());
637     json->addScalar("Minor", state.getClientMinorVersion());
638     SerializeColorFWithGroup(json, "ColorClearValue", state.getColorClearValue());
639     json->addScalar("DepthClearValue", state.getDepthClearValue());
640     json->addScalar("StencilClearValue", state.getStencilClearValue());
641     SerializeRasterizerState(json, state.getRasterizerState());
642     json->addScalar("ScissorTestEnabled", state.isScissorTestEnabled());
643     SerializeRectangle(json, "Scissors", state.getScissor());
644     SerializeBlendStateExt(json, state.getBlendStateExt());
645     SerializeColorFWithGroup(json, "BlendColor", state.getBlendColor());
646     json->addScalar("SampleAlphaToCoverageEnabled", state.isSampleAlphaToCoverageEnabled());
647     json->addScalar("SampleCoverageEnabled", state.isSampleCoverageEnabled());
648     json->addScalar("SampleCoverageValue", state.getSampleCoverageValue());
649     json->addScalar("SampleCoverageInvert", state.getSampleCoverageInvert());
650     json->addScalar("SampleMaskEnabled", state.isSampleMaskEnabled());
651     json->addScalar("MaxSampleMaskWords", state.getMaxSampleMaskWords());
652     {
653         const auto &sampleMaskValues = state.getSampleMaskValues();
654         GroupScope maskGroup(json, "SampleMaskValues");
655         for (size_t i = 0; i < sampleMaskValues.size(); i++)
656         {
657             std::ostringstream os;
658             os << i;
659             json->addScalar(os.str(), sampleMaskValues[i]);
660         }
661     }
662     SerializeDepthStencilState(json, state.getDepthStencilState());
663     json->addScalar("StencilRef", state.getStencilRef());
664     json->addScalar("StencilBackRef", state.getStencilBackRef());
665     json->addScalar("LineWidth", state.getLineWidth());
666     json->addScalar("GenerateMipmapHint", state.getGenerateMipmapHint());
667     json->addScalar("TextureFilteringHint", state.getTextureFilteringHint());
668     json->addScalar("FragmentShaderDerivativeHint", state.getFragmentShaderDerivativeHint());
669     json->addScalar("BindGeneratesResourceEnabled", state.isBindGeneratesResourceEnabled());
670     json->addScalar("ClientArraysEnabled", state.areClientArraysEnabled());
671     SerializeRectangle(json, "Viewport", state.getViewport());
672     json->addScalar("Near", state.getNearPlane());
673     json->addScalar("Far", state.getFarPlane());
674     if (state.getReadFramebuffer())
675     {
676         json->addScalar("Framebuffer ID", state.getReadFramebuffer()->id().value);
677     }
678     if (state.getDrawFramebuffer())
679     {
680         json->addScalar("Draw Framebuffer ID", state.getDrawFramebuffer()->id().value);
681     }
682     json->addScalar("Renderbuffer ID", state.getRenderbufferId().value);
683     if (state.getProgram())
684     {
685         json->addScalar("ProgramID", state.getProgram()->id().value);
686     }
687     if (state.getProgramPipeline())
688     {
689         json->addScalar("ProgramPipelineID", state.getProgramPipeline()->id().value);
690     }
691     json->addCString("ProvokingVertex",
692                      ProvokingVertexConventionToString(state.getProvokingVertex()));
693     const std::vector<gl::VertexAttribCurrentValueData> &vertexAttribCurrentValues =
694         state.getVertexAttribCurrentValues();
695     for (size_t i = 0; i < vertexAttribCurrentValues.size(); i++)
696     {
697         GroupScope vagroup(json, "VertexAttribCurrentValue", static_cast<int>(i));
698         SerializeVertexAttribCurrentValueData(json, vertexAttribCurrentValues[i]);
699     }
700     if (state.getVertexArray())
701     {
702         json->addScalar("VertexArrayID", state.getVertexArray()->id().value);
703     }
704     json->addScalar("CurrentValuesTypeMask", state.getCurrentValuesTypeMask().to_ulong());
705     json->addScalar("ActiveSampler", state.getActiveSampler());
706     {
707         GroupScope boundTexturesGroup(json, "BoundTextures");
708         for (const auto &textures : state.getBoundTexturesForCapture())
709         {
710             SerializeBindingPointerVector<gl::Texture>(json, textures);
711         }
712     }
713     json->addScalar("TexturesIncompatibleWithSamplers",
714                     state.getTexturesIncompatibleWithSamplers().to_ulong());
715     SerializeBindingPointerVector<gl::Sampler>(json, state.getSamplers());
716 
717     {
718         GroupScope imageUnitsGroup(json, "BoundImageUnits");
719         for (const gl::ImageUnit &imageUnit : state.getImageUnits())
720         {
721             SerializeImageUnit(json, imageUnit);
722         }
723     }
724 
725     {
726         const gl::ActiveQueryMap &activeQueries = state.getActiveQueriesForCapture();
727         GroupScope activeQueriesGroup(json, "ActiveQueries");
728         for (gl::QueryType queryType : AllEnums<gl::QueryType>())
729         {
730             const gl::BindingPointer<gl::Query> &query = activeQueries[queryType];
731             std::stringstream strstr;
732             strstr << queryType;
733             json->addScalar(strstr.str(), query.id().value);
734         }
735     }
736 
737     {
738         const gl::BoundBufferMap &boundBuffers = state.getBoundBuffersForCapture();
739         GroupScope boundBuffersGroup(json, "BoundBuffers");
740         for (gl::BufferBinding bufferBinding : AllEnums<gl::BufferBinding>())
741         {
742             const gl::BindingPointer<gl::Buffer> &buffer = boundBuffers[bufferBinding];
743             std::stringstream strstr;
744             strstr << bufferBinding;
745             json->addScalar(strstr.str(), buffer.id().value);
746         }
747     }
748 
749     SerializeOffsetBindingPointerVector<gl::Buffer>(json, "UniformBufferBindings",
750                                                     state.getOffsetBindingPointerUniformBuffers());
751     SerializeOffsetBindingPointerVector<gl::Buffer>(
752         json, "AtomicCounterBufferBindings", state.getOffsetBindingPointerAtomicCounterBuffers());
753     SerializeOffsetBindingPointerVector<gl::Buffer>(
754         json, "ShaderStorageBufferBindings", state.getOffsetBindingPointerShaderStorageBuffers());
755     if (state.getCurrentTransformFeedback())
756     {
757         json->addScalar("CurrentTransformFeedback",
758                         state.getCurrentTransformFeedback()->id().value);
759     }
760     SerializePixelUnpackState(json, state.getUnpackState());
761     SerializePixelPackState(json, state.getPackState());
762     json->addScalar("PrimitiveRestartEnabled", state.isPrimitiveRestartEnabled());
763     json->addScalar("MultisamplingEnabled", state.isMultisamplingEnabled());
764     json->addScalar("SampleAlphaToOneEnabled", state.isSampleAlphaToOneEnabled());
765     json->addScalar("CoverageModulation", state.getCoverageModulation());
766     json->addScalar("FramebufferSRGB", state.getFramebufferSRGB());
767     json->addScalar("RobustResourceInitEnabled", state.isRobustResourceInitEnabled());
768     json->addScalar("ProgramBinaryCacheEnabled", state.isProgramBinaryCacheEnabled());
769     json->addScalar("TextureRectangleEnabled", state.isTextureRectangleEnabled());
770     json->addScalar("MaxShaderCompilerThreads", state.getMaxShaderCompilerThreads());
771     json->addScalar("EnabledClipDistances", state.getEnabledClipDistances().to_ulong());
772     json->addScalar("BlendFuncConstantAlphaDrawBuffers",
773                     state.getBlendFuncConstantAlphaDrawBuffers().to_ulong());
774     json->addScalar("BlendFuncConstantColorDrawBuffers",
775                     state.getBlendFuncConstantColorDrawBuffers().to_ulong());
776     json->addScalar("SimultaneousConstantColorAndAlphaBlendFunc",
777                     state.noSimultaneousConstantColorAndAlphaBlendFunc());
778 }
779 
SerializeBufferState(JsonSerializer * json,const gl::BufferState & bufferState)780 void SerializeBufferState(JsonSerializer *json, const gl::BufferState &bufferState)
781 {
782     json->addString("Label", bufferState.getLabel());
783     json->addCString("Usage", BufferUsageToString(bufferState.getUsage()));
784     json->addScalar("Size", bufferState.getSize());
785     json->addScalar("AccessFlags", bufferState.getAccessFlags());
786     json->addScalar("Access", bufferState.getAccess());
787     json->addScalar("Mapped", bufferState.isMapped());
788     json->addScalar("MapOffset", bufferState.getMapOffset());
789     json->addScalar("MapLength", bufferState.getMapLength());
790 }
791 
SerializeBuffer(const gl::Context * context,JsonSerializer * json,ScratchBuffer * scratchBuffer,gl::Buffer * buffer)792 Result SerializeBuffer(const gl::Context *context,
793                        JsonSerializer *json,
794                        ScratchBuffer *scratchBuffer,
795                        gl::Buffer *buffer)
796 {
797     GroupScope group(json, "Buffer", buffer->id().value);
798     SerializeBufferState(json, buffer->getState());
799     if (buffer->getSize())
800     {
801         MemoryBuffer *dataPtr = nullptr;
802         ANGLE_CHECK_GL_ALLOC(
803             const_cast<gl::Context *>(context),
804             scratchBuffer->getInitialized(static_cast<size_t>(buffer->getSize()), &dataPtr, 0));
805         ANGLE_TRY(buffer->getSubData(context, 0, dataPtr->size(), dataPtr->data()));
806         json->addBlob("data", dataPtr->data(), dataPtr->size());
807     }
808     else
809     {
810         json->addCString("data", "null");
811     }
812     return Result::Continue;
813 }
SerializeColorGeneric(JsonSerializer * json,const std::string & name,const ColorGeneric & colorGeneric)814 void SerializeColorGeneric(JsonSerializer *json,
815                            const std::string &name,
816                            const ColorGeneric &colorGeneric)
817 {
818     GroupScope group(json, name);
819     ASSERT(colorGeneric.type == ColorGeneric::Type::Float ||
820            colorGeneric.type == ColorGeneric::Type::Int ||
821            colorGeneric.type == ColorGeneric::Type::UInt);
822     json->addCString("Type", ColorGenericTypeToString(colorGeneric.type));
823     if (colorGeneric.type == ColorGeneric::Type::Float)
824     {
825         SerializeColorF(json, colorGeneric.colorF);
826     }
827     else if (colorGeneric.type == ColorGeneric::Type::Int)
828     {
829         SerializeColorI(json, colorGeneric.colorI);
830     }
831     else
832     {
833         SerializeColorUI(json, colorGeneric.colorUI);
834     }
835 }
836 
SerializeSamplerState(JsonSerializer * json,const gl::SamplerState & samplerState)837 void SerializeSamplerState(JsonSerializer *json, const gl::SamplerState &samplerState)
838 {
839     json->addScalar("MinFilter", samplerState.getMinFilter());
840     json->addScalar("MagFilter", samplerState.getMagFilter());
841     json->addScalar("WrapS", samplerState.getWrapS());
842     json->addScalar("WrapT", samplerState.getWrapT());
843     json->addScalar("WrapR", samplerState.getWrapR());
844     json->addScalar("MaxAnisotropy", samplerState.getMaxAnisotropy());
845     json->addScalar("MinLod", samplerState.getMinLod());
846     json->addScalar("MaxLod", samplerState.getMaxLod());
847     json->addScalar("CompareMode", samplerState.getCompareMode());
848     json->addScalar("CompareFunc", samplerState.getCompareFunc());
849     json->addScalar("SRGBDecode", samplerState.getSRGBDecode());
850     SerializeColorGeneric(json, "BorderColor", samplerState.getBorderColor());
851 }
852 
SerializeSampler(JsonSerializer * json,gl::Sampler * sampler)853 void SerializeSampler(JsonSerializer *json, gl::Sampler *sampler)
854 {
855     GroupScope group(json, "Sampler", sampler->id().value);
856     json->addString("Label", sampler->getLabel());
857     SerializeSamplerState(json, sampler->getSamplerState());
858 }
859 
SerializeSwizzleState(JsonSerializer * json,const gl::SwizzleState & swizzleState)860 void SerializeSwizzleState(JsonSerializer *json, const gl::SwizzleState &swizzleState)
861 {
862     json->addScalar("SwizzleRed", swizzleState.swizzleRed);
863     json->addScalar("SwizzleGreen", swizzleState.swizzleGreen);
864     json->addScalar("SwizzleBlue", swizzleState.swizzleBlue);
865     json->addScalar("SwizzleAlpha", swizzleState.swizzleAlpha);
866 }
867 
SerializeInternalFormat(JsonSerializer * json,const gl::InternalFormat * internalFormat)868 void SerializeInternalFormat(JsonSerializer *json, const gl::InternalFormat *internalFormat)
869 {
870     json->addScalar("InternalFormat", internalFormat->internalFormat);
871 }
872 
SerializeFormat(JsonSerializer * json,const gl::Format & format)873 void SerializeFormat(JsonSerializer *json, const gl::Format &format)
874 {
875     SerializeInternalFormat(json, format.info);
876 }
877 
SerializeRenderbufferState(JsonSerializer * json,const gl::RenderbufferState & renderbufferState)878 void SerializeRenderbufferState(JsonSerializer *json,
879                                 const gl::RenderbufferState &renderbufferState)
880 {
881     GroupScope wg(json, "State");
882     json->addScalar("Width", renderbufferState.getWidth());
883     json->addScalar("Height", renderbufferState.getHeight());
884     SerializeFormat(json, renderbufferState.getFormat());
885     json->addScalar("Samples", renderbufferState.getSamples());
886     json->addCString("InitState", InitStateToString(renderbufferState.getInitState()));
887 }
888 
SerializeRenderbuffer(const gl::Context * context,JsonSerializer * json,ScratchBuffer * scratchBuffer,gl::Renderbuffer * renderbuffer)889 Result SerializeRenderbuffer(const gl::Context *context,
890                              JsonSerializer *json,
891                              ScratchBuffer *scratchBuffer,
892                              gl::Renderbuffer *renderbuffer)
893 {
894     GroupScope wg(json, "Renderbuffer", renderbuffer->id().value);
895     SerializeRenderbufferState(json, renderbuffer->getState());
896     json->addString("Label", renderbuffer->getLabel());
897     MemoryBuffer *pixelsPtr = nullptr;
898     ANGLE_CHECK_GL_ALLOC(
899         const_cast<gl::Context *>(context),
900         scratchBuffer->getInitialized(renderbuffer->getMemorySize(), &pixelsPtr, 0));
901 
902     if (renderbuffer->initState(gl::ImageIndex()) == gl::InitState::Initialized)
903     {
904         gl::PixelPackState packState;
905         packState.alignment = 1;
906         ANGLE_TRY(renderbuffer->getImplementation()->getRenderbufferImage(
907             context, packState, nullptr, renderbuffer->getImplementationColorReadFormat(context),
908             renderbuffer->getImplementationColorReadType(context), pixelsPtr->data()));
909         json->addBlob("pixel", pixelsPtr->data(), pixelsPtr->size());
910     }
911     else
912     {
913         json->addCString("pixel", "Not initialized");
914     }
915     return Result::Continue;
916 }
917 
SerializeWorkGroupSize(JsonSerializer * json,const sh::WorkGroupSize & workGroupSize)918 void SerializeWorkGroupSize(JsonSerializer *json, const sh::WorkGroupSize &workGroupSize)
919 {
920     GroupScope wg(json, "workGroupSize");
921     json->addScalar("x", workGroupSize[0]);
922     json->addScalar("y", workGroupSize[1]);
923     json->addScalar("z", workGroupSize[2]);
924 }
925 
SerializeShaderVariable(JsonSerializer * json,const sh::ShaderVariable & shaderVariable)926 void SerializeShaderVariable(JsonSerializer *json, const sh::ShaderVariable &shaderVariable)
927 {
928     GroupScope wg(json, "ShaderVariable");
929     json->addScalar("Type", shaderVariable.type);
930     json->addScalar("Precision", shaderVariable.precision);
931     json->addString("Name", shaderVariable.name);
932     json->addString("MappedName", shaderVariable.mappedName);
933     json->addVector("ArraySizes", shaderVariable.arraySizes);
934     json->addScalar("StaticUse", shaderVariable.staticUse);
935     json->addScalar("Active", shaderVariable.active);
936     for (const sh::ShaderVariable &field : shaderVariable.fields)
937     {
938         SerializeShaderVariable(json, field);
939     }
940     json->addString("StructOrBlockName", shaderVariable.structOrBlockName);
941     json->addString("MappedStructOrBlockName", shaderVariable.mappedStructOrBlockName);
942     json->addScalar("RowMajorLayout", shaderVariable.isRowMajorLayout);
943     json->addScalar("Location", shaderVariable.location);
944     json->addScalar("Binding", shaderVariable.binding);
945     json->addScalar("ImageUnitFormat", shaderVariable.imageUnitFormat);
946     json->addScalar("Offset", shaderVariable.offset);
947     json->addScalar("Readonly", shaderVariable.readonly);
948     json->addScalar("Writeonly", shaderVariable.writeonly);
949     json->addScalar("Index", shaderVariable.index);
950     json->addScalar("YUV", shaderVariable.yuv);
951     json->addCString("Interpolation", InterpolationTypeToString(shaderVariable.interpolation));
952     json->addScalar("Invariant", shaderVariable.isInvariant);
953     json->addScalar("TexelFetchStaticUse", shaderVariable.texelFetchStaticUse);
954 }
955 
SerializeShaderVariablesVector(JsonSerializer * json,const std::vector<sh::ShaderVariable> & shaderVariables)956 void SerializeShaderVariablesVector(JsonSerializer *json,
957                                     const std::vector<sh::ShaderVariable> &shaderVariables)
958 {
959     for (const sh::ShaderVariable &shaderVariable : shaderVariables)
960     {
961         SerializeShaderVariable(json, shaderVariable);
962     }
963 }
964 
SerializeInterfaceBlocksVector(JsonSerializer * json,const std::vector<sh::InterfaceBlock> & interfaceBlocks)965 void SerializeInterfaceBlocksVector(JsonSerializer *json,
966                                     const std::vector<sh::InterfaceBlock> &interfaceBlocks)
967 {
968     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
969     {
970         GroupScope group(json, "Interface Block");
971         json->addString("Name", interfaceBlock.name);
972         json->addString("MappedName", interfaceBlock.mappedName);
973         json->addString("InstanceName", interfaceBlock.instanceName);
974         json->addScalar("ArraySize", interfaceBlock.arraySize);
975         json->addCString("Layout", BlockLayoutTypeToString(interfaceBlock.layout));
976         json->addScalar("Binding", interfaceBlock.binding);
977         json->addScalar("StaticUse", interfaceBlock.staticUse);
978         json->addScalar("Active", interfaceBlock.active);
979         json->addCString("BlockType", BlockTypeToString(interfaceBlock.blockType));
980         SerializeShaderVariablesVector(json, interfaceBlock.fields);
981     }
982 }
983 
SerializeShaderState(JsonSerializer * json,const gl::ShaderState & shaderState)984 void SerializeShaderState(JsonSerializer *json, const gl::ShaderState &shaderState)
985 {
986     GroupScope group(json, "ShaderState");
987     json->addString("Label", shaderState.getLabel());
988     json->addCString("Type", gl::ShaderTypeToString(shaderState.getShaderType()));
989     json->addScalar("Version", shaderState.getShaderVersion());
990     json->addString("TranslatedSource", shaderState.getTranslatedSource());
991     json->addVectorAsHash("CompiledBinary", shaderState.getCompiledBinary());
992     json->addString("Source", shaderState.getSource());
993     SerializeWorkGroupSize(json, shaderState.getLocalSize());
994     SerializeShaderVariablesVector(json, shaderState.getInputVaryings());
995     SerializeShaderVariablesVector(json, shaderState.getOutputVaryings());
996     SerializeShaderVariablesVector(json, shaderState.getUniforms());
997     SerializeInterfaceBlocksVector(json, shaderState.getUniformBlocks());
998     SerializeInterfaceBlocksVector(json, shaderState.getShaderStorageBlocks());
999     SerializeShaderVariablesVector(json, shaderState.getAllAttributes());
1000     SerializeShaderVariablesVector(json, shaderState.getActiveAttributes());
1001     SerializeShaderVariablesVector(json, shaderState.getActiveOutputVariables());
1002     json->addScalar("EarlyFragmentTestsOptimization",
1003                     shaderState.getEarlyFragmentTestsOptimization());
1004     json->addScalar("NumViews", shaderState.getNumViews());
1005     json->addScalar("SpecConstUsageBits", shaderState.getSpecConstUsageBits().bits());
1006     if (shaderState.getGeometryShaderInputPrimitiveType().valid())
1007     {
1008         json->addCString(
1009             "GeometryShaderInputPrimitiveType",
1010             PrimitiveModeToString(shaderState.getGeometryShaderInputPrimitiveType().value()));
1011     }
1012     if (shaderState.getGeometryShaderOutputPrimitiveType().valid())
1013     {
1014         json->addCString(
1015             "GeometryShaderOutputPrimitiveType",
1016             PrimitiveModeToString(shaderState.getGeometryShaderOutputPrimitiveType().value()));
1017     }
1018     if (shaderState.getGeometryShaderInvocations().valid())
1019     {
1020         json->addScalar("GeometryShaderInvocations",
1021                         shaderState.getGeometryShaderInvocations().value());
1022     }
1023     json->addCString("CompileStatus", CompileStatusToString(shaderState.getCompileStatus()));
1024 }
1025 
SerializeShader(JsonSerializer * json,GLuint id,gl::Shader * shader)1026 void SerializeShader(JsonSerializer *json, GLuint id, gl::Shader *shader)
1027 {
1028     GroupScope group(json, "Shader", id);
1029     SerializeShaderState(json, shader->getState());
1030     json->addScalar("Handle", shader->getHandle().value);
1031     json->addScalar("RefCount", shader->getRefCount());
1032     json->addScalar("FlaggedForDeletion", shader->isFlaggedForDeletion());
1033     // Do not serialize mType because it is already serialized in SerializeShaderState.
1034     json->addString("InfoLogString", shader->getInfoLogString());
1035     // Do not serialize compiler resources string because it can vary between test modes.
1036     json->addScalar("CurrentMaxComputeWorkGroupInvocations",
1037                     shader->getCurrentMaxComputeWorkGroupInvocations());
1038     json->addScalar("MaxComputeSharedMemory", shader->getMaxComputeSharedMemory());
1039 }
1040 
SerializeVariableLocationsVector(JsonSerializer * json,const std::string & group_name,const std::vector<gl::VariableLocation> & variableLocations)1041 void SerializeVariableLocationsVector(JsonSerializer *json,
1042                                       const std::string &group_name,
1043                                       const std::vector<gl::VariableLocation> &variableLocations)
1044 {
1045     GroupScope group(json, group_name);
1046     for (const gl::VariableLocation &variableLocation : variableLocations)
1047     {
1048         GroupScope vargroup(json, "Variable");
1049         json->addScalar("ArrayIndex", variableLocation.arrayIndex);
1050         json->addScalar("Index", variableLocation.index);
1051         json->addScalar("Ignored", variableLocation.ignored);
1052     }
1053 }
1054 
SerializeBlockMemberInfo(JsonSerializer * json,const sh::BlockMemberInfo & blockMemberInfo)1055 void SerializeBlockMemberInfo(JsonSerializer *json, const sh::BlockMemberInfo &blockMemberInfo)
1056 {
1057     GroupScope group(json, "BlockMemberInfo");
1058     json->addScalar("Offset", blockMemberInfo.offset);
1059     json->addScalar("Stride", blockMemberInfo.arrayStride);
1060     json->addScalar("MatrixStride", blockMemberInfo.matrixStride);
1061     json->addScalar("IsRowMajorMatrix", blockMemberInfo.isRowMajorMatrix);
1062     json->addScalar("TopLevelArrayStride", blockMemberInfo.topLevelArrayStride);
1063 }
1064 
SerializeActiveVariable(JsonSerializer * json,const gl::ActiveVariable & activeVariable)1065 void SerializeActiveVariable(JsonSerializer *json, const gl::ActiveVariable &activeVariable)
1066 {
1067     json->addScalar("ActiveShaders", activeVariable.activeShaders().to_ulong());
1068 }
1069 
SerializeBufferVariablesVector(JsonSerializer * json,const std::vector<gl::BufferVariable> & bufferVariables)1070 void SerializeBufferVariablesVector(JsonSerializer *json,
1071                                     const std::vector<gl::BufferVariable> &bufferVariables)
1072 {
1073     for (const gl::BufferVariable &bufferVariable : bufferVariables)
1074     {
1075         GroupScope group(json, "BufferVariable");
1076         json->addScalar("BufferIndex", bufferVariable.bufferIndex);
1077         SerializeBlockMemberInfo(json, bufferVariable.blockInfo);
1078         json->addScalar("TopLevelArraySize", bufferVariable.topLevelArraySize);
1079         SerializeActiveVariable(json, bufferVariable);
1080         SerializeShaderVariable(json, bufferVariable);
1081     }
1082 }
1083 
SerializeProgramAliasedBindings(JsonSerializer * json,const gl::ProgramAliasedBindings & programAliasedBindings)1084 void SerializeProgramAliasedBindings(JsonSerializer *json,
1085                                      const gl::ProgramAliasedBindings &programAliasedBindings)
1086 {
1087     for (const auto &programAliasedBinding : programAliasedBindings)
1088     {
1089         GroupScope group(json, programAliasedBinding.first);
1090         json->addScalar("Location", programAliasedBinding.second.location);
1091         json->addScalar("Aliased", programAliasedBinding.second.aliased);
1092     }
1093 }
1094 
SerializeProgramState(JsonSerializer * json,const gl::ProgramState & programState)1095 void SerializeProgramState(JsonSerializer *json, const gl::ProgramState &programState)
1096 {
1097     json->addString("Label", programState.getLabel());
1098     SerializeWorkGroupSize(json, programState.getComputeShaderLocalSize());
1099 
1100     auto attachedShaders = programState.getAttachedShaders();
1101     std::vector<GLint> shaderHandles(attachedShaders.size());
1102     std::transform(attachedShaders.begin(), attachedShaders.end(), shaderHandles.begin(),
1103                    [](gl::Shader *shader) { return shader ? shader->getHandle().value : 0; });
1104     json->addVector("Handle", shaderHandles);
1105     json->addScalar("LocationsUsedForXfbExtension", programState.getLocationsUsedForXfbExtension());
1106 
1107     json->addVectorOfStrings("TransformFeedbackVaryingNames",
1108                              programState.getTransformFeedbackVaryingNames());
1109     json->addScalar("ActiveUniformBlockBindingsMask",
1110                     programState.getActiveUniformBlockBindingsMask().to_ulong());
1111     SerializeVariableLocationsVector(json, "UniformLocations", programState.getUniformLocations());
1112     SerializeBufferVariablesVector(json, programState.getBufferVariables());
1113     SerializeRange(json, programState.getAtomicCounterUniformRange());
1114     SerializeVariableLocationsVector(json, "SecondaryOutputLocations",
1115                                      programState.getSecondaryOutputLocations());
1116     json->addScalar("ActiveOutputVariables", programState.getActiveOutputVariables().to_ulong());
1117     json->addVector("OutputVariableTypes", programState.getOutputVariableTypes());
1118     json->addScalar("DrawBufferTypeMask", programState.getDrawBufferTypeMask().to_ulong());
1119     json->addScalar("BinaryRetrieveableHint", programState.hasBinaryRetrieveableHint());
1120     json->addScalar("Separable", programState.isSeparable());
1121     json->addScalar("EarlyFragmentTestsOptimization",
1122                     programState.hasEarlyFragmentTestsOptimization());
1123     json->addScalar("NumViews", programState.getNumViews());
1124     json->addScalar("DrawIDLocation", programState.getDrawIDLocation());
1125     json->addScalar("BaseVertexLocation", programState.getBaseVertexLocation());
1126     json->addScalar("BaseInstanceLocation", programState.getBaseInstanceLocation());
1127     SerializeProgramAliasedBindings(json, programState.getUniformLocationBindings());
1128 }
1129 
SerializeProgramBindings(JsonSerializer * json,const gl::ProgramBindings & programBindings)1130 void SerializeProgramBindings(JsonSerializer *json, const gl::ProgramBindings &programBindings)
1131 {
1132     for (const auto &programBinding : programBindings)
1133     {
1134         json->addScalar(programBinding.first, programBinding.second);
1135     }
1136 }
1137 
SerializeProgram(JsonSerializer * json,GLuint id,gl::Program * program)1138 void SerializeProgram(JsonSerializer *json, GLuint id, gl::Program *program)
1139 {
1140     GroupScope group(json, "Program", id);
1141     SerializeProgramState(json, program->getState());
1142     json->addScalar("IsValidated", program->isValidated());
1143     SerializeProgramBindings(json, program->getAttributeBindings());
1144     SerializeProgramAliasedBindings(json, program->getFragmentOutputLocations());
1145     SerializeProgramAliasedBindings(json, program->getFragmentOutputIndexes());
1146     json->addScalar("IsLinked", program->isLinked());
1147     json->addScalar("IsFlaggedForDeletion", program->isFlaggedForDeletion());
1148     json->addScalar("RefCount", program->getRefCount());
1149     json->addScalar("ID", program->id().value);
1150 }
1151 
SerializeImageDesc(JsonSerializer * json,const gl::ImageDesc & imageDesc)1152 void SerializeImageDesc(JsonSerializer *json, const gl::ImageDesc &imageDesc)
1153 {
1154     GroupScope group(json, "ImageDesc");
1155     SerializeExtents(json, imageDesc.size);
1156     SerializeFormat(json, imageDesc.format);
1157     json->addScalar("Samples", imageDesc.samples);
1158     json->addScalar("FixesSampleLocations", imageDesc.fixedSampleLocations);
1159     json->addCString("InitState", InitStateToString(imageDesc.initState));
1160 }
1161 
SerializeTextureState(JsonSerializer * json,const gl::TextureState & textureState)1162 void SerializeTextureState(JsonSerializer *json, const gl::TextureState &textureState)
1163 {
1164     json->addCString("Type", TextureTypeToString(textureState.getType()));
1165     SerializeSwizzleState(json, textureState.getSwizzleState());
1166     {
1167         GroupScope samplerStateGroup(json, "SamplerState");
1168         SerializeSamplerState(json, textureState.getSamplerState());
1169     }
1170     json->addCString("SRGB", SrgbOverrideToString(textureState.getSRGBOverride()));
1171     json->addScalar("BaseLevel", textureState.getBaseLevel());
1172     json->addScalar("MaxLevel", textureState.getMaxLevel());
1173     json->addScalar("DepthStencilTextureMode", textureState.getDepthStencilTextureMode());
1174     json->addScalar("BeenBoundAsImage", textureState.hasBeenBoundAsImage());
1175     json->addScalar("ImmutableFormat", textureState.getImmutableFormat());
1176     json->addScalar("ImmutableLevels", textureState.getImmutableLevels());
1177     json->addScalar("Usage", textureState.getUsage());
1178     const std::vector<gl::ImageDesc> &imageDescs = textureState.getImageDescs();
1179     for (const gl::ImageDesc &imageDesc : imageDescs)
1180     {
1181         SerializeImageDesc(json, imageDesc);
1182     }
1183     SerializeRectangle(json, "Crop", textureState.getCrop());
1184 
1185     json->addScalar("GenerateMipmapHint", textureState.getGenerateMipmapHint());
1186     json->addCString("InitState", InitStateToString(textureState.getInitState()));
1187 }
1188 
SerializeTextureData(JsonSerializer * json,const gl::Context * context,gl::Texture * texture,ScratchBuffer * scratchBuffer)1189 Result SerializeTextureData(JsonSerializer *json,
1190                             const gl::Context *context,
1191                             gl::Texture *texture,
1192                             ScratchBuffer *scratchBuffer)
1193 {
1194     gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
1195         texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
1196         gl::ImageIndex::kEntireLevel);
1197     while (imageIter.hasNext())
1198     {
1199         gl::ImageIndex index = imageIter.next();
1200 
1201         const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
1202 
1203         if (desc.size.empty())
1204             continue;
1205 
1206         const gl::InternalFormat &format = *desc.format.info;
1207 
1208         // Check for supported textures
1209         ASSERT(index.getType() == gl::TextureType::_2D || index.getType() == gl::TextureType::_3D ||
1210                index.getType() == gl::TextureType::_2DArray ||
1211                index.getType() == gl::TextureType::CubeMap);
1212 
1213         GLenum getFormat = format.format;
1214         GLenum getType   = format.type;
1215 
1216         const gl::Extents size(desc.size.width, desc.size.height, desc.size.depth);
1217         const gl::PixelUnpackState &unpack = context->getState().getUnpackState();
1218 
1219         GLuint endByte  = 0;
1220         bool unpackSize = format.computePackUnpackEndByte(getType, size, unpack, true, &endByte);
1221         ASSERT(unpackSize);
1222         MemoryBuffer *texelsPtr = nullptr;
1223         ANGLE_CHECK_GL_ALLOC(const_cast<gl::Context *>(context),
1224                              scratchBuffer->getInitialized(endByte, &texelsPtr, 0));
1225 
1226         gl::PixelPackState packState;
1227         packState.alignment = 1;
1228 
1229         if (texture->getState().getInitState() == gl::InitState::Initialized)
1230         {
1231             if (format.compressed)
1232             {
1233                 // TODO: Read back compressed data. http://anglebug.com/6177
1234                 json->addCString("Texels", "compressed texel data");
1235             }
1236             else
1237             {
1238                 ANGLE_TRY(texture->getTexImage(context, packState, nullptr, index.getTarget(),
1239                                                index.getLevelIndex(), getFormat, getType,
1240                                                texelsPtr->data()));
1241                 json->addBlob("Texels", texelsPtr->data(), texelsPtr->size());
1242             }
1243         }
1244         else
1245         {
1246             json->addCString("Texels", "not initialized");
1247         }
1248     }
1249     return Result::Continue;
1250 }
1251 
SerializeTexture(const gl::Context * context,JsonSerializer * json,ScratchBuffer * scratchBuffer,gl::Texture * texture)1252 Result SerializeTexture(const gl::Context *context,
1253                         JsonSerializer *json,
1254                         ScratchBuffer *scratchBuffer,
1255                         gl::Texture *texture)
1256 {
1257     GroupScope group(json, "Texture", texture->getId());
1258     SerializeTextureState(json, texture->getState());
1259     json->addString("Label", texture->getLabel());
1260     // FrameCapture can not serialize mBoundSurface and mBoundStream
1261     // because they are likely to change with each run
1262     ANGLE_TRY(SerializeTextureData(json, context, texture, scratchBuffer));
1263     return Result::Continue;
1264 }
1265 
SerializeFormat(JsonSerializer * json,const angle::Format * format)1266 void SerializeFormat(JsonSerializer *json, const angle::Format *format)
1267 {
1268     json->addScalar("InternalFormat", format->glInternalFormat);
1269 }
1270 
SerializeVertexAttributeVector(JsonSerializer * json,const std::vector<gl::VertexAttribute> & vertexAttributes)1271 void SerializeVertexAttributeVector(JsonSerializer *json,
1272                                     const std::vector<gl::VertexAttribute> &vertexAttributes)
1273 {
1274     for (const gl::VertexAttribute &vertexAttribute : vertexAttributes)
1275     {
1276         GroupScope group(json, "VertexAttribute@BindingIndex", vertexAttribute.bindingIndex);
1277         json->addScalar("Enabled", vertexAttribute.enabled);
1278         ASSERT(vertexAttribute.format);
1279         SerializeFormat(json, vertexAttribute.format);
1280         json->addScalar("RelativeOffset", vertexAttribute.relativeOffset);
1281         json->addScalar("VertexAttribArrayStride", vertexAttribute.vertexAttribArrayStride);
1282     }
1283 }
1284 
SerializeVertexBindingsVector(JsonSerializer * json,const std::vector<gl::VertexBinding> & vertexBindings)1285 void SerializeVertexBindingsVector(JsonSerializer *json,
1286                                    const std::vector<gl::VertexBinding> &vertexBindings)
1287 {
1288     for (const gl::VertexBinding &vertexBinding : vertexBindings)
1289     {
1290         GroupScope group(json, "VertexBinding");
1291         json->addScalar("Stride", vertexBinding.getStride());
1292         json->addScalar("Divisor", vertexBinding.getDivisor());
1293         json->addScalar("Offset", vertexBinding.getOffset());
1294         json->addScalar("BufferID", vertexBinding.getBuffer().id().value);
1295         json->addScalar("BoundAttributesMask", vertexBinding.getBoundAttributesMask().to_ulong());
1296     }
1297 }
1298 
SerializeVertexArrayState(JsonSerializer * json,const gl::VertexArrayState & vertexArrayState)1299 void SerializeVertexArrayState(JsonSerializer *json, const gl::VertexArrayState &vertexArrayState)
1300 {
1301     json->addString("Label", vertexArrayState.getLabel());
1302     SerializeVertexAttributeVector(json, vertexArrayState.getVertexAttributes());
1303     if (vertexArrayState.getElementArrayBuffer())
1304     {
1305         json->addScalar("ElementArrayBufferID",
1306                         vertexArrayState.getElementArrayBuffer()->id().value);
1307     }
1308     else
1309     {
1310         json->addScalar("ElementArrayBufferID", 0);
1311     }
1312     SerializeVertexBindingsVector(json, vertexArrayState.getVertexBindings());
1313     json->addScalar("EnabledAttributesMask",
1314                     vertexArrayState.getEnabledAttributesMask().to_ulong());
1315     json->addScalar("VertexAttributesTypeMask",
1316                     vertexArrayState.getVertexAttributesTypeMask().to_ulong());
1317     json->addScalar("ClientMemoryAttribsMask",
1318                     vertexArrayState.getClientMemoryAttribsMask().to_ulong());
1319     json->addScalar("NullPointerClientMemoryAttribsMask",
1320                     vertexArrayState.getNullPointerClientMemoryAttribsMask().to_ulong());
1321 }
1322 
SerializeVertexArray(JsonSerializer * json,gl::VertexArray * vertexArray)1323 void SerializeVertexArray(JsonSerializer *json, gl::VertexArray *vertexArray)
1324 {
1325     GroupScope group(json, "VertexArray", vertexArray->id().value);
1326     SerializeVertexArrayState(json, vertexArray->getState());
1327     json->addScalar("BufferAccessValidationEnabled",
1328                     vertexArray->isBufferAccessValidationEnabled());
1329 }
1330 
1331 }  // namespace
1332 
SerializeContextToString(const gl::Context * context,std::string * stringOut)1333 Result SerializeContextToString(const gl::Context *context, std::string *stringOut)
1334 {
1335     JsonSerializer json;
1336     json.startDocument("Context");
1337 
1338     SerializeContextState(&json, context->getState());
1339     ScratchBuffer scratchBuffer(1);
1340     {
1341         const gl::FramebufferManager &framebufferManager =
1342             context->getState().getFramebufferManagerForCapture();
1343         GroupScope framebufferGroup(&json, "FramebufferManager");
1344         for (const auto &framebuffer : framebufferManager)
1345         {
1346             gl::Framebuffer *framebufferPtr = framebuffer.second;
1347             ANGLE_TRY(SerializeFramebuffer(context, &json, &scratchBuffer, framebufferPtr));
1348         }
1349     }
1350     {
1351         const gl::BufferManager &bufferManager = context->getState().getBufferManagerForCapture();
1352         GroupScope framebufferGroup(&json, "BufferManager");
1353         for (const auto &buffer : bufferManager)
1354         {
1355             gl::Buffer *bufferPtr = buffer.second;
1356             ANGLE_TRY(SerializeBuffer(context, &json, &scratchBuffer, bufferPtr));
1357         }
1358     }
1359     {
1360         const gl::SamplerManager &samplerManager =
1361             context->getState().getSamplerManagerForCapture();
1362         GroupScope samplerGroup(&json, "SamplerManager");
1363         for (const auto &sampler : samplerManager)
1364         {
1365             gl::Sampler *samplerPtr = sampler.second;
1366             SerializeSampler(&json, samplerPtr);
1367         }
1368     }
1369     {
1370         const gl::RenderbufferManager &renderbufferManager =
1371             context->getState().getRenderbufferManagerForCapture();
1372         GroupScope renderbufferGroup(&json, "RenderbufferManager");
1373         for (const auto &renderbuffer : renderbufferManager)
1374         {
1375             gl::Renderbuffer *renderbufferPtr = renderbuffer.second;
1376             ANGLE_TRY(SerializeRenderbuffer(context, &json, &scratchBuffer, renderbufferPtr));
1377         }
1378     }
1379     const gl::ShaderProgramManager &shaderProgramManager =
1380         context->getState().getShaderProgramManagerForCapture();
1381     {
1382         const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaderManager =
1383             shaderProgramManager.getShadersForCapture();
1384         GroupScope shaderGroup(&json, "ShaderManager");
1385         for (const auto &shader : shaderManager)
1386         {
1387             GLuint id             = shader.first;
1388             gl::Shader *shaderPtr = shader.second;
1389             SerializeShader(&json, id, shaderPtr);
1390         }
1391     }
1392     {
1393         const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programManager =
1394             shaderProgramManager.getProgramsForCaptureAndPerf();
1395         GroupScope shaderGroup(&json, "ProgramManager");
1396         for (const auto &program : programManager)
1397         {
1398             GLuint id               = program.first;
1399             gl::Program *programPtr = program.second;
1400             SerializeProgram(&json, id, programPtr);
1401         }
1402     }
1403     {
1404         const gl::TextureManager &textureManager =
1405             context->getState().getTextureManagerForCapture();
1406         GroupScope shaderGroup(&json, "TextureManager");
1407         for (const auto &texture : textureManager)
1408         {
1409             gl::Texture *texturePtr = texture.second;
1410             ANGLE_TRY(SerializeTexture(context, &json, &scratchBuffer, texturePtr));
1411         }
1412     }
1413     {
1414         const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
1415         GroupScope shaderGroup(&json, "VertexArrayMap");
1416         for (const auto &vertexArray : vertexArrayMap)
1417         {
1418             gl::VertexArray *vertexArrayPtr = vertexArray.second;
1419             SerializeVertexArray(&json, vertexArrayPtr);
1420         }
1421     }
1422     json.endDocument();
1423 
1424     *stringOut = json.data();
1425 
1426     scratchBuffer.clear();
1427     return Result::Continue;
1428 }
1429 
1430 }  // namespace angle
1431