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