• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 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 // FrameCapture.cpp:
7 //   ANGLE Frame capture implementation.
8 //
9 
10 #include "libANGLE/FrameCapture.h"
11 
12 #include <cerrno>
13 #include <cstring>
14 #include <fstream>
15 #include <string>
16 
17 #include "sys/stat.h"
18 
19 #include "common/system_utils.h"
20 #include "libANGLE/Context.h"
21 #include "libANGLE/Framebuffer.h"
22 #include "libANGLE/Query.h"
23 #include "libANGLE/ResourceMap.h"
24 #include "libANGLE/Shader.h"
25 #include "libANGLE/VertexArray.h"
26 #include "libANGLE/capture_gles_2_0_autogen.h"
27 #include "libANGLE/capture_gles_3_0_autogen.h"
28 #include "libANGLE/gl_enum_utils.h"
29 #include "libANGLE/queryconversions.h"
30 #include "libANGLE/queryutils.h"
31 
32 #define USE_SYSTEM_ZLIB
33 #include "compression_utils_portable.h"
34 
35 #if !ANGLE_CAPTURE_ENABLED
36 #    error Frame capture must be enbled to include this file.
37 #endif  // !ANGLE_CAPTURE_ENABLED
38 
39 namespace angle
40 {
41 namespace
42 {
43 
44 constexpr char kEnabledVarName[]      = "ANGLE_CAPTURE_ENABLED";
45 constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
46 constexpr char kFrameStartVarName[]   = "ANGLE_CAPTURE_FRAME_START";
47 constexpr char kFrameEndVarName[]     = "ANGLE_CAPTURE_FRAME_END";
48 constexpr char kCaptureLabel[]        = "ANGLE_CAPTURE_LABEL";
49 constexpr char kCompression[]         = "ANGLE_CAPTURE_COMPRESSION";
50 
51 #if defined(ANGLE_PLATFORM_ANDROID)
52 
53 constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
54 constexpr char kAndroidOutDir[]         = "debug.angle.capture.out_dir";
55 constexpr char kAndroidFrameStart[]     = "debug.angle.capture.frame_start";
56 constexpr char kAndroidFrameEnd[]       = "debug.angle.capture.frame_end";
57 constexpr char kAndroidCaptureLabel[]   = "debug.angle.capture.label";
58 constexpr char kAndroidCompression[]    = "debug.angle.capture.compression";
59 
60 constexpr int kStreamSize = 64;
61 
62 constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
63 
64 // Call out to 'getprop' on a shell and return a string if the value was set
AndroidGetEnvFromProp(const char * key)65 std::string AndroidGetEnvFromProp(const char *key)
66 {
67     std::string command("getprop ");
68     command += key;
69 
70     // Run the command and open a I/O stream to read results
71     char stream[kStreamSize] = {};
72     FILE *pipe               = popen(command.c_str(), "r");
73     if (pipe != nullptr)
74     {
75         fgets(stream, kStreamSize, pipe);
76         pclose(pipe);
77     }
78 
79     // Right strip white space
80     std::string result(stream);
81     result.erase(result.find_last_not_of(" \n\r\t") + 1);
82     return result;
83 }
84 
PrimeAndroidEnvironmentVariables()85 void PrimeAndroidEnvironmentVariables()
86 {
87     std::string enabled = AndroidGetEnvFromProp(kAndroidCaptureEnabled);
88     if (!enabled.empty())
89     {
90         INFO() << "Frame capture read " << enabled << " from " << kAndroidCaptureEnabled;
91         setenv(kEnabledVarName, enabled.c_str(), 1);
92     }
93 
94     std::string outDir = AndroidGetEnvFromProp(kAndroidOutDir);
95     if (!outDir.empty())
96     {
97         INFO() << "Frame capture read " << outDir << " from " << kAndroidOutDir;
98         setenv(kOutDirectoryVarName, outDir.c_str(), 1);
99     }
100 
101     std::string frameStart = AndroidGetEnvFromProp(kAndroidFrameStart);
102     if (!frameStart.empty())
103     {
104         INFO() << "Frame capture read " << frameStart << " from " << kAndroidFrameStart;
105         setenv(kFrameStartVarName, frameStart.c_str(), 1);
106     }
107 
108     std::string frameEnd = AndroidGetEnvFromProp(kAndroidFrameEnd);
109     if (!frameEnd.empty())
110     {
111         INFO() << "Frame capture read " << frameEnd << " from " << kAndroidFrameEnd;
112         setenv(kFrameEndVarName, frameEnd.c_str(), 1);
113     }
114 
115     std::string captureLabel = AndroidGetEnvFromProp(kAndroidCaptureLabel);
116     if (!captureLabel.empty())
117     {
118         INFO() << "Frame capture read " << captureLabel << " from " << kAndroidCaptureLabel;
119         setenv(kCaptureLabel, captureLabel.c_str(), 1);
120     }
121 
122     std::string compression = AndroidGetEnvFromProp(kAndroidCompression);
123     if (!compression.empty())
124     {
125         INFO() << "Frame capture read " << compression << " from " << kAndroidCompression;
126         setenv(kCompression, compression.c_str(), 1);
127     }
128 }
129 #endif
130 
GetDefaultOutDirectory()131 std::string GetDefaultOutDirectory()
132 {
133 #if defined(ANGLE_PLATFORM_ANDROID)
134     std::string path = "/sdcard/Android/data/";
135 
136     // Linux interface to get application id of the running process
137     FILE *cmdline = fopen("/proc/self/cmdline", "r");
138     char applicationId[512];
139     if (cmdline)
140     {
141         fread(applicationId, 1, sizeof(applicationId), cmdline);
142         fclose(cmdline);
143 
144         // Some package may have application id as <app_name>:<cmd_name>
145         char *colonSep = strchr(applicationId, ':');
146         if (colonSep)
147         {
148             *colonSep = '\0';
149         }
150     }
151     else
152     {
153         ERR() << "not able to lookup application id";
154     }
155 
156     path += std::string(applicationId) + kAndroidOutputSubdir;
157 
158     // Check for existance of output path
159     struct stat dir_stat;
160     if (stat(path.c_str(), &dir_stat) == -1)
161     {
162         ERR() << "Output directory '" << path
163               << "' does not exist.  Create it over adb using mkdir.";
164     }
165 
166     return path;
167 #else
168     return std::string("./");
169 #endif  // defined(ANGLE_PLATFORM_ANDROID)
170 }
171 
172 struct FmtCapturePrefix
173 {
FmtCapturePrefixangle::__anoncf1522460111::FmtCapturePrefix174     FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
175         : contextId(contextIdIn), captureLabel(captureLabelIn)
176     {}
177     gl::ContextID contextId;
178     const std::string &captureLabel;
179 };
180 
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)181 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
182 {
183     if (fmt.captureLabel.empty())
184     {
185         os << "angle";
186     }
187     else
188     {
189         os << fmt.captureLabel;
190     }
191     os << "_capture_context" << static_cast<int>(fmt.contextId);
192     return os;
193 }
194 
195 struct FmtReplayFunction
196 {
FmtReplayFunctionangle::__anoncf1522460111::FmtReplayFunction197     FmtReplayFunction(gl::ContextID contextIdIn, uint32_t frameIndexIn)
198         : contextId(contextIdIn), frameIndex(frameIndexIn)
199     {}
200     gl::ContextID contextId;
201     uint32_t frameIndex;
202 };
203 
operator <<(std::ostream & os,const FmtReplayFunction & fmt)204 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
205 {
206     os << "ReplayContext" << static_cast<int>(fmt.contextId) << "Frame" << fmt.frameIndex << "()";
207     return os;
208 }
209 
GetCaptureFileName(gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)210 std::string GetCaptureFileName(gl::ContextID contextId,
211                                const std::string &captureLabel,
212                                uint32_t frameIndex,
213                                const char *suffix)
214 {
215     std::stringstream fnameStream;
216     fnameStream << FmtCapturePrefix(contextId, captureLabel) << "_frame" << std::setfill('0')
217                 << std::setw(3) << frameIndex << suffix;
218     return fnameStream.str();
219 }
220 
GetCaptureFilePath(const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)221 std::string GetCaptureFilePath(const std::string &outDir,
222                                gl::ContextID contextId,
223                                const std::string &captureLabel,
224                                uint32_t frameIndex,
225                                const char *suffix)
226 {
227     return outDir + GetCaptureFileName(contextId, captureLabel, frameIndex, suffix);
228 }
229 
WriteParamStaticVarName(const CallCapture & call,const ParamCapture & param,int counter,std::ostream & out)230 void WriteParamStaticVarName(const CallCapture &call,
231                              const ParamCapture &param,
232                              int counter,
233                              std::ostream &out)
234 {
235     out << call.name() << "_" << param.name << "_" << counter;
236 }
237 
WriteGLFloatValue(std::ostream & out,GLfloat value)238 void WriteGLFloatValue(std::ostream &out, GLfloat value)
239 {
240     // Check for non-representable values
241     ASSERT(std::numeric_limits<float>::has_infinity);
242     ASSERT(std::numeric_limits<float>::has_quiet_NaN);
243 
244     if (std::isinf(value))
245     {
246         float negativeInf = -std::numeric_limits<float>::infinity();
247         if (value == negativeInf)
248         {
249             out << "-";
250         }
251         out << "std::numeric_limits<float>::infinity()";
252     }
253     else if (std::isnan(value))
254     {
255         out << "std::numeric_limits<float>::quiet_NaN()";
256     }
257     else
258     {
259         out << value;
260     }
261 }
262 
263 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)264 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
265 {
266     const T *data = reinterpret_cast<const T *>(vec.data());
267     size_t count  = vec.size() / sizeof(T);
268 
269     if (data == nullptr)
270     {
271         return;
272     }
273 
274     out << static_cast<CastT>(data[0]);
275 
276     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
277     {
278         out << ", " << static_cast<CastT>(data[dataIndex]);
279     }
280 }
281 
282 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)283 void WriteInlineData<GLfloat>(const std::vector<uint8_t> &vec, std::ostream &out)
284 {
285     const float *data = reinterpret_cast<const GLfloat *>(vec.data());
286     size_t count      = vec.size() / sizeof(GLfloat);
287 
288     if (data == nullptr)
289     {
290         return;
291     }
292 
293     WriteGLFloatValue(out, data[0]);
294 
295     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
296     {
297         out << ", ";
298         WriteGLFloatValue(out, data[dataIndex]);
299     }
300 }
301 
302 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)303 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
304 {
305     const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
306     size_t count       = vec.size() / sizeof(GLchar);
307 
308     if (data == nullptr || data[0] == '\0')
309     {
310         return;
311     }
312 
313     out << "\"";
314 
315     for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
316     {
317         if (data[dataIndex] == '\0')
318             break;
319 
320         out << static_cast<GLchar>(data[dataIndex]);
321     }
322 
323     out << "\"";
324 }
325 
326 constexpr size_t kInlineDataThreshold = 128;
327 
WriteStringParamReplay(std::ostream & out,const ParamCapture & param)328 void WriteStringParamReplay(std::ostream &out, const ParamCapture &param)
329 {
330     const std::vector<uint8_t> &data = param.data[0];
331     // null terminate C style string
332     ASSERT(data.size() > 0 && data.back() == '\0');
333     std::string str(data.begin(), data.end() - 1);
334     out << "\"" << str << "\"";
335 }
336 
WriteStringPointerParamReplay(DataCounters * counters,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)337 void WriteStringPointerParamReplay(DataCounters *counters,
338                                    std::ostream &out,
339                                    std::ostream &header,
340                                    const CallCapture &call,
341                                    const ParamCapture &param)
342 {
343     int counter = counters->getAndIncrement(call.entryPoint, param.name);
344 
345     header << "const char *";
346     WriteParamStaticVarName(call, param, counter, header);
347     header << "[] = { \n";
348 
349     for (const std::vector<uint8_t> &data : param.data)
350     {
351         // null terminate C style string
352         ASSERT(data.size() > 0 && data.back() == '\0');
353         std::string str(data.begin(), data.end() - 1);
354         header << "    R\"(" << str << ")\",\n";
355     }
356 
357     header << " };\n";
358     WriteParamStaticVarName(call, param, counter, out);
359 }
360 
361 template <typename ParamT>
WriteResourceIDPointerParamReplay(DataCounters * counters,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)362 void WriteResourceIDPointerParamReplay(DataCounters *counters,
363                                        std::ostream &out,
364                                        std::ostream &header,
365                                        const CallCapture &call,
366                                        const ParamCapture &param)
367 {
368     int counter = counters->getAndIncrement(call.entryPoint, param.name);
369 
370     header << "const GLuint ";
371     WriteParamStaticVarName(call, param, counter, header);
372     header << "[] = { ";
373 
374     const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
375     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
376     const char *name = GetResourceIDTypeName(resourceIDType);
377 
378     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
379     ASSERT(param.data.size() == 1);
380     const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
381     for (GLsizei resIndex = 0; resIndex < n; ++resIndex)
382     {
383         ParamT id = returnedIDs[resIndex];
384         if (resIndex > 0)
385         {
386             header << ", ";
387         }
388         header << "g" << name << "Map[" << id.value << "]";
389     }
390 
391     header << " };\n    ";
392 
393     WriteParamStaticVarName(call, param, counter, out);
394 }
395 
WriteBinaryParamReplay(DataCounters * counters,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)396 void WriteBinaryParamReplay(DataCounters *counters,
397                             std::ostream &out,
398                             std::ostream &header,
399                             const CallCapture &call,
400                             const ParamCapture &param,
401                             std::vector<uint8_t> *binaryData)
402 {
403     int counter = counters->getAndIncrement(call.entryPoint, param.name);
404 
405     ASSERT(param.data.size() == 1);
406     const std::vector<uint8_t> &data = param.data[0];
407 
408     if (data.size() > kInlineDataThreshold)
409     {
410         size_t offset = binaryData->size();
411         binaryData->resize(offset + data.size());
412         memcpy(binaryData->data() + offset, data.data(), data.size());
413         if (param.type == ParamType::TvoidConstPointer || param.type == ParamType::TvoidPointer)
414         {
415             out << "&gBinaryData[" << offset << "]";
416         }
417         else
418         {
419             out << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(&gBinaryData["
420                 << offset << "])";
421         }
422     }
423     else
424     {
425         ParamType overrideType = param.type;
426         if (param.type == ParamType::TGLvoidConstPointer ||
427             param.type == ParamType::TvoidConstPointer)
428         {
429             overrideType = ParamType::TGLubyteConstPointer;
430         }
431 
432         std::string paramTypeString = ParamTypeToString(overrideType);
433         header << paramTypeString.substr(0, paramTypeString.length() - 1);
434         WriteParamStaticVarName(call, param, counter, header);
435 
436         header << "[] = { ";
437 
438         switch (overrideType)
439         {
440             case ParamType::TGLintConstPointer:
441                 WriteInlineData<GLint>(data, header);
442                 break;
443             case ParamType::TGLshortConstPointer:
444                 WriteInlineData<GLshort>(data, header);
445                 break;
446             case ParamType::TGLfloatConstPointer:
447                 WriteInlineData<GLfloat>(data, header);
448                 break;
449             case ParamType::TGLubyteConstPointer:
450                 WriteInlineData<GLubyte, int>(data, header);
451                 break;
452             case ParamType::TGLuintConstPointer:
453             case ParamType::TGLenumConstPointer:
454                 WriteInlineData<GLuint>(data, header);
455                 break;
456             case ParamType::TGLcharPointer:
457                 WriteInlineData<GLchar>(data, header);
458                 break;
459             default:
460                 INFO() << "Unhandled ParamType: " << angle::ParamTypeToString(overrideType)
461                        << " in " << call.name();
462                 UNIMPLEMENTED();
463                 break;
464         }
465 
466         header << " };\n";
467 
468         WriteParamStaticVarName(call, param, counter, out);
469     }
470 }
471 
SyncIndexValue(GLsync sync)472 uintptr_t SyncIndexValue(GLsync sync)
473 {
474     return reinterpret_cast<uintptr_t>(sync);
475 }
476 
WriteCppReplayForCall(const CallCapture & call,DataCounters * counters,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData)477 void WriteCppReplayForCall(const CallCapture &call,
478                            DataCounters *counters,
479                            std::ostream &out,
480                            std::ostream &header,
481                            std::vector<uint8_t> *binaryData)
482 {
483     std::ostringstream callOut;
484 
485     if (call.entryPoint == gl::EntryPoint::CreateShader ||
486         call.entryPoint == gl::EntryPoint::CreateProgram)
487     {
488         GLuint id = call.params.getReturnValue().value.GLuintVal;
489         callOut << "gShaderProgramMap[" << id << "] = ";
490     }
491 
492     if (call.entryPoint == gl::EntryPoint::FenceSync)
493     {
494         GLsync sync = call.params.getReturnValue().value.GLsyncVal;
495         callOut << "gSyncMap[" << SyncIndexValue(sync) << "] = ";
496     }
497 
498     if (call.entryPoint == gl::EntryPoint::MapBufferRange ||
499         call.entryPoint == gl::EntryPoint::MapBufferRangeEXT)
500     {
501         GLbitfield access =
502             call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
503 
504         if (access & GL_MAP_WRITE_BIT)
505         {
506             // Track the returned pointer so we update its data when unmapped
507             gl::BufferID bufferID = call.params.getMappedBufferID();
508             callOut << "gMappedBufferData[";
509             WriteParamValueReplay<ParamType::TBufferID>(callOut, call, bufferID);
510             callOut << "] = ";
511         }
512     }
513 
514     callOut << call.name() << "(";
515 
516     bool first = true;
517     for (const ParamCapture &param : call.params.getParamCaptures())
518     {
519         if (!first)
520         {
521             callOut << ", ";
522         }
523 
524         if (param.arrayClientPointerIndex != -1)
525         {
526             callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
527         }
528         else if (param.readBufferSizeBytes > 0)
529         {
530             callOut << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(gReadBuffer)";
531         }
532         else if (param.data.empty())
533         {
534             if (param.type == ParamType::TGLenum)
535             {
536                 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
537             }
538             else if (param.type == ParamType::TGLbitfield)
539             {
540                 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
541             }
542             else if (param.type == ParamType::TGLfloat)
543             {
544                 WriteGLFloatValue(callOut, param.value.GLfloatVal);
545             }
546             else if (param.type == ParamType::TGLsync)
547             {
548                 callOut << "gSyncMap[" << SyncIndexValue(param.value.GLsyncVal) << "]";
549             }
550             else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
551             {
552                 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
553                 {
554                     callOut << "GL_TIMEOUT_IGNORED";
555                 }
556                 else
557                 {
558                     WriteParamCaptureReplay(callOut, call, param);
559                 }
560             }
561             else
562             {
563                 WriteParamCaptureReplay(callOut, call, param);
564             }
565         }
566         else
567         {
568             switch (param.type)
569             {
570                 case ParamType::TGLcharConstPointer:
571                     WriteStringParamReplay(callOut, param);
572                     break;
573                 case ParamType::TGLcharConstPointerPointer:
574                     WriteStringPointerParamReplay(counters, callOut, header, call, param);
575                     break;
576                 case ParamType::TBufferIDConstPointer:
577                     WriteResourceIDPointerParamReplay<gl::BufferID>(counters, callOut, out, call,
578                                                                     param);
579                     break;
580                 case ParamType::TFenceNVIDConstPointer:
581                     WriteResourceIDPointerParamReplay<gl::FenceNVID>(counters, callOut, out, call,
582                                                                      param);
583                     break;
584                 case ParamType::TFramebufferIDConstPointer:
585                     WriteResourceIDPointerParamReplay<gl::FramebufferID>(counters, callOut, out,
586                                                                          call, param);
587                     break;
588                 case ParamType::TMemoryObjectIDConstPointer:
589                     WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(counters, callOut, out,
590                                                                           call, param);
591                     break;
592                 case ParamType::TProgramPipelineIDConstPointer:
593                     WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(counters, callOut, out,
594                                                                              call, param);
595                     break;
596                 case ParamType::TQueryIDConstPointer:
597                     WriteResourceIDPointerParamReplay<gl::QueryID>(counters, callOut, out, call,
598                                                                    param);
599                     break;
600                 case ParamType::TRenderbufferIDConstPointer:
601                     WriteResourceIDPointerParamReplay<gl::RenderbufferID>(counters, callOut, out,
602                                                                           call, param);
603                     break;
604                 case ParamType::TSamplerIDConstPointer:
605                     WriteResourceIDPointerParamReplay<gl::SamplerID>(counters, callOut, out, call,
606                                                                      param);
607                     break;
608                 case ParamType::TSemaphoreIDConstPointer:
609                     WriteResourceIDPointerParamReplay<gl::SemaphoreID>(counters, callOut, out, call,
610                                                                        param);
611                     break;
612                 case ParamType::TTextureIDConstPointer:
613                     WriteResourceIDPointerParamReplay<gl::TextureID>(counters, callOut, out, call,
614                                                                      param);
615                     break;
616                 case ParamType::TTransformFeedbackIDConstPointer:
617                     WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(counters, callOut,
618                                                                                out, call, param);
619                     break;
620                 case ParamType::TVertexArrayIDConstPointer:
621                     WriteResourceIDPointerParamReplay<gl::VertexArrayID>(counters, callOut, out,
622                                                                          call, param);
623                     break;
624                 default:
625                     WriteBinaryParamReplay(counters, callOut, header, call, param, binaryData);
626                     break;
627             }
628         }
629 
630         first = false;
631     }
632 
633     callOut << ")";
634 
635     out << callOut.str();
636 }
637 
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)638 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
639 {
640     size_t found = 0;
641     for (size_t size : clientArraySizes)
642     {
643         if (size > found)
644             found = size;
645     }
646 
647     return found;
648 }
649 
650 struct SaveFileHelper
651 {
SaveFileHelperangle::__anoncf1522460111::SaveFileHelper652     SaveFileHelper(const std::string &filePathIn, std::ios_base::openmode mode = std::ios::out)
653         : ofs(filePathIn, mode), filePath(filePathIn)
654     {
655         if (!ofs.is_open())
656         {
657             FATAL() << "Could not open " << filePathIn;
658         }
659     }
660 
~SaveFileHelperangle::__anoncf1522460111::SaveFileHelper661     ~SaveFileHelper() { printf("Saved '%s'.\n", filePath.c_str()); }
662 
663     template <typename T>
operator <<angle::__anoncf1522460111::SaveFileHelper664     SaveFileHelper &operator<<(const T &value)
665     {
666         ofs << value;
667         if (ofs.bad())
668         {
669             FATAL() << "Error writing to " << filePath;
670         }
671         return *this;
672     }
673 
674     std::ofstream ofs;
675     std::string filePath;
676 };
677 
GetBinaryDataFilePath(bool compression,gl::ContextID contextId,const std::string & captureLabel)678 std::string GetBinaryDataFilePath(bool compression,
679                                   gl::ContextID contextId,
680                                   const std::string &captureLabel)
681 {
682     std::stringstream fnameStream;
683     fnameStream << FmtCapturePrefix(contextId, captureLabel) << ".angledata";
684     if (compression)
685     {
686         fnameStream << ".gz";
687     }
688     return fnameStream.str();
689 }
690 
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)691 void SaveBinaryData(bool compression,
692                     const std::string &outDir,
693                     gl::ContextID contextId,
694                     const std::string &captureLabel,
695                     const std::vector<uint8_t> &binaryData)
696 {
697     std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
698     std::string dataFilepath       = outDir + binaryDataFileName;
699 
700     SaveFileHelper saveData(dataFilepath, std::ios::binary);
701 
702     if (compression)
703     {
704         // Save compressed data.
705         uLong uncompressedSize       = static_cast<uLong>(binaryData.size());
706         uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
707 
708         std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
709 
710         uLong compressedSize = expectedCompressedSize;
711         int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
712                                                         binaryData.data(), uncompressedSize,
713                                                         nullptr, nullptr);
714 
715         if (zResult != Z_OK)
716         {
717             FATAL() << "Error compressing binary data: " << zResult;
718         }
719 
720         saveData.ofs.write(reinterpret_cast<const char *>(compressedData.data()), compressedSize);
721     }
722     else
723     {
724         saveData.ofs.write(reinterpret_cast<const char *>(binaryData.data()), binaryData.size());
725     }
726 }
727 
WriteLoadBinaryDataCall(bool compression,std::ostream & out,gl::ContextID contextId,const std::string & captureLabel)728 void WriteLoadBinaryDataCall(bool compression,
729                              std::ostream &out,
730                              gl::ContextID contextId,
731                              const std::string &captureLabel)
732 {
733     std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
734     out << "    LoadBinaryData(\"" << binaryDataFileName << "\");\n";
735 }
736 
WriteCppReplay(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const std::vector<CallCapture> & frameCalls,const std::vector<CallCapture> & setupCalls,std::vector<uint8_t> * binaryData)737 void WriteCppReplay(bool compression,
738                     const std::string &outDir,
739                     gl::ContextID contextId,
740                     const std::string &captureLabel,
741                     uint32_t frameIndex,
742                     const std::vector<CallCapture> &frameCalls,
743                     const std::vector<CallCapture> &setupCalls,
744                     std::vector<uint8_t> *binaryData)
745 {
746     DataCounters counters;
747 
748     std::stringstream out;
749     std::stringstream header;
750 
751     header << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
752     header << "";
753     header << "\n";
754     header << "namespace\n";
755     header << "{\n";
756 
757     if (!captureLabel.empty())
758     {
759         out << "namespace " << captureLabel << "\n";
760         out << "{\n";
761     }
762 
763     if (frameIndex == 0 || !setupCalls.empty())
764     {
765         out << "void SetupContext" << Str(static_cast<int>(contextId)) << "Replay()\n";
766         out << "{\n";
767 
768         std::stringstream setupCallStream;
769 
770         WriteLoadBinaryDataCall(compression, setupCallStream, contextId, captureLabel);
771 
772         for (const CallCapture &call : setupCalls)
773         {
774             setupCallStream << "    ";
775             WriteCppReplayForCall(call, &counters, setupCallStream, header, binaryData);
776             setupCallStream << ";\n";
777         }
778 
779         out << setupCallStream.str();
780 
781         out << "}\n";
782         out << "\n";
783     }
784 
785     out << "void " << FmtReplayFunction(contextId, frameIndex) << "\n";
786     out << "{\n";
787 
788     std::stringstream callStream;
789 
790     for (const CallCapture &call : frameCalls)
791     {
792         callStream << "    ";
793         WriteCppReplayForCall(call, &counters, callStream, header, binaryData);
794         callStream << ";\n";
795     }
796 
797     out << callStream.str();
798     out << "}\n";
799 
800     if (!captureLabel.empty())
801     {
802         out << "} // namespace " << captureLabel << "\n";
803     }
804 
805     header << "}  // namespace\n";
806 
807     {
808         std::string outString    = out.str();
809         std::string headerString = header.str();
810 
811         std::string cppFilePath =
812             GetCaptureFilePath(outDir, contextId, captureLabel, frameIndex, ".cpp");
813 
814         SaveFileHelper saveCpp(cppFilePath);
815         saveCpp << headerString << "\n" << outString;
816     }
817 }
818 
WriteCppReplayIndexFiles(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameStart,uint32_t frameEnd,size_t readBufferSize,const gl::AttribArray<size_t> & clientArraySizes,const HasResourceTypeMap & hasResourceType)819 void WriteCppReplayIndexFiles(bool compression,
820                               const std::string &outDir,
821                               gl::ContextID contextId,
822                               const std::string &captureLabel,
823                               uint32_t frameStart,
824                               uint32_t frameEnd,
825                               size_t readBufferSize,
826                               const gl::AttribArray<size_t> &clientArraySizes,
827                               const HasResourceTypeMap &hasResourceType)
828 {
829     size_t maxClientArraySize = MaxClientArraySize(clientArraySizes);
830 
831     std::stringstream header;
832     std::stringstream source;
833 
834     header << "#pragma once\n";
835     header << "\n";
836     header << "#include \"util/gles_loader_autogen.h\"\n";
837     header << "\n";
838     header << "#include <cstdint>\n";
839     header << "#include <cstdio>\n";
840     header << "#include <cstring>\n";
841     header << "#include <limits>\n";
842     header << "#include <vector>\n";
843     header << "#include <unordered_map>\n";
844     header << "\n";
845 
846     if (!captureLabel.empty())
847     {
848         header << "namespace " << captureLabel << "\n";
849         header << "{\n";
850     }
851     header << "// Replay functions\n";
852     header << "\n";
853     header << "// Maps from <captured Program ID, captured location> to run-time location.\n";
854     header
855         << "using LocationsMap = std::unordered_map<GLuint, std::unordered_map<GLint, GLint>>;\n";
856     header << "extern LocationsMap gUniformLocations;\n";
857     header << "extern GLuint gCurrentProgram;\n";
858     header << "void UpdateUniformLocation(GLuint program, const char *name, GLint location);\n";
859     header << "void DeleteUniformLocations(GLuint program);\n";
860     header << "void UpdateCurrentProgram(GLuint program);\n";
861     header << "\n";
862     header << "// Maps from captured Resource ID to run-time Resource ID.\n";
863     header << "using ResourceMap = std::unordered_map<GLuint, GLuint>;\n";
864     header << "\n";
865     header << "\n";
866     header << "constexpr uint32_t kReplayFrameStart = " << frameStart << ";\n";
867     header << "constexpr uint32_t kReplayFrameEnd = " << frameEnd << ";\n";
868     header << "\n";
869     header << "void SetupContext" << static_cast<int>(contextId) << "Replay();\n";
870     header << "void ReplayContext" << static_cast<int>(contextId)
871            << "Frame(uint32_t frameIndex);\n";
872     header << "\n";
873     header << "using FramebufferChangeCallback = void(*)(void *userData, GLenum target, GLuint "
874               "framebuffer);\n";
875     header << "void SetFramebufferChangeCallback(void *userData, FramebufferChangeCallback "
876               "callback);\n";
877     header << "void OnFramebufferChange(GLenum target, GLuint framebuffer);\n";
878     header << "\n";
879     for (uint32_t frameIndex = frameStart; frameIndex < frameEnd; ++frameIndex)
880     {
881         header << "void " << FmtReplayFunction(contextId, frameIndex) << ";\n";
882     }
883     header << "\n";
884     header << "constexpr bool kIsBinaryDataCompressed = " << (compression ? "true" : "false")
885            << ";\n";
886     header << "\n";
887     header << "using DecompressCallback = uint8_t *(*)(const std::vector<uint8_t> &);\n";
888     header << "void SetBinaryDataDecompressCallback(DecompressCallback callback);\n";
889     header << "void SetBinaryDataDir(const char *dataDir);\n";
890     header << "void LoadBinaryData(const char *fileName);\n";
891     header << "\n";
892     header << "// Global state\n";
893     header << "\n";
894     header << "extern uint8_t *gBinaryData;\n";
895 
896     source << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
897     source << "\n";
898 
899     if (!captureLabel.empty())
900     {
901         source << "namespace " << captureLabel << "\n";
902         source << "{\n";
903     }
904 
905     source << "namespace\n";
906     source << "{\n";
907     source << "void UpdateResourceMap(ResourceMap *resourceMap, GLuint id, GLsizei "
908               "readBufferOffset)\n";
909     source << "{\n";
910     source << "    GLuint returnedID;\n";
911     std::string captureNamespace = !captureLabel.empty() ? captureLabel + "::" : "";
912     source << "    memcpy(&returnedID, &" << captureNamespace
913            << "gReadBuffer[readBufferOffset], sizeof(GLuint));\n";
914     source << "    (*resourceMap)[id] = returnedID;\n";
915     source << "}\n";
916     source << "\n";
917     source << "DecompressCallback gDecompressCallback;\n";
918     source << "const char *gBinaryDataDir = \".\";\n";
919     source << "FramebufferChangeCallback gFramebufferChangeCallback;\n";
920     source << "void *gFramebufferChangeCallbackUserData;\n";
921     source << "}  // namespace\n";
922     source << "\n";
923     source << "LocationsMap gUniformLocations;\n";
924     source << "GLuint gCurrentProgram = 0;\n";
925     source << "\n";
926     source << "void UpdateUniformLocation(GLuint program, const char *name, GLint location)\n";
927     source << "{\n";
928     source << "    gUniformLocations[program][location] = glGetUniformLocation(program, name);\n";
929     source << "}\n";
930     source << "void DeleteUniformLocations(GLuint program)\n";
931     source << "{\n";
932     source << "    gUniformLocations.erase(program);\n";
933     source << "}\n";
934     source << "void UpdateCurrentProgram(GLuint program)\n";
935     source << "{\n";
936     source << "    gCurrentProgram = program;\n";
937     source << "}\n";
938     source << "\n";
939 
940     source << "uint8_t *gBinaryData = nullptr;\n";
941 
942     if (readBufferSize > 0)
943     {
944         header << "extern uint8_t gReadBuffer[" << readBufferSize << "];\n";
945         source << "uint8_t gReadBuffer[" << readBufferSize << "];\n";
946     }
947     if (maxClientArraySize > 0)
948     {
949         header << "extern uint8_t gClientArrays[" << gl::MAX_VERTEX_ATTRIBS << "]["
950                << maxClientArraySize << "];\n";
951         source << "uint8_t gClientArrays[" << gl::MAX_VERTEX_ATTRIBS << "][" << maxClientArraySize
952                << "];\n";
953     }
954     for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
955     {
956         // TODO: Only emit resources needed by the frames (anglebug.com/4223)
957         const char *name = GetResourceIDTypeName(resourceType);
958         header << "extern ResourceMap g" << name << "Map;\n";
959         source << "ResourceMap g" << name << "Map;\n";
960     }
961 
962     header << "using SyncResourceMap = std::unordered_map<uintptr_t, GLsync>;\n";
963     header << "extern SyncResourceMap gSyncMap;\n";
964     source << "SyncResourceMap gSyncMap;\n";
965 
966     header << "\n";
967 
968     source << "\n";
969     source << "void SetFramebufferChangeCallback(void *userData, FramebufferChangeCallback "
970               "callback)\n";
971     source << "{\n";
972     source << "    gFramebufferChangeCallbackUserData = userData;\n";
973     source << "    gFramebufferChangeCallback = callback;\n";
974     source << "}\n";
975     source << "\n";
976     source << "void OnFramebufferChange(GLenum target, GLuint framebuffer)\n";
977     source << "{\n";
978     source << "    if (gFramebufferChangeCallback)\n";
979     source << "        gFramebufferChangeCallback(gFramebufferChangeCallbackUserData, target, "
980               "framebuffer);\n";
981     source << "}\n";
982 
983     source << "\n";
984     source << "void ReplayContext" << static_cast<int>(contextId) << "Frame(uint32_t frameIndex)\n";
985     source << "{\n";
986     source << "    switch (frameIndex)\n";
987     source << "    {\n";
988     for (uint32_t frameIndex = frameStart; frameIndex < frameEnd; ++frameIndex)
989     {
990         source << "        case " << frameIndex << ":\n";
991         source << "            ReplayContext" << static_cast<int>(contextId) << "Frame"
992                << frameIndex << "();\n";
993         source << "            break;\n";
994     }
995     source << "        default:\n";
996     source << "            break;\n";
997     source << "    }\n";
998     source << "}\n";
999     source << "\n";
1000     source << "void SetBinaryDataDecompressCallback(DecompressCallback callback)\n";
1001     source << "{\n";
1002     source << "    gDecompressCallback = callback;\n";
1003     source << "}\n";
1004     source << "\n";
1005     source << "void SetBinaryDataDir(const char *dataDir)\n";
1006     source << "{\n";
1007     source << "    gBinaryDataDir = dataDir;\n";
1008     source << "}\n";
1009     source << "\n";
1010     source << "void LoadBinaryData(const char *fileName)\n";
1011     source << "{\n";
1012     source << "    if (gBinaryData != nullptr)\n";
1013     source << "    {\n";
1014     source << "        delete [] gBinaryData;\n";
1015     source << "    }\n";
1016     source << "    char pathBuffer[1000] = {};\n";
1017     source << "    sprintf(pathBuffer, \"%s/%s\", gBinaryDataDir, fileName);\n";
1018     source << "    FILE *fp = fopen(pathBuffer, \"rb\");\n";
1019     source << "    if (fp == 0)\n";
1020     source << "    {\n";
1021     source << "        fprintf(stderr, \"Error loading binary data file: %s\\n\", fileName);\n";
1022     source << "        exit(1);\n";
1023     source << "    }\n";
1024     source << "    fseek(fp, 0, SEEK_END);\n";
1025     source << "    long size = ftell(fp);\n";
1026     source << "    fseek(fp, 0, SEEK_SET);\n";
1027     source << "    if (gDecompressCallback)\n";
1028     source << "    {\n";
1029     source << "        if (!strstr(fileName, \".gz\"))\n";
1030     source << "        {\n";
1031     source << "            fprintf(stderr, \"Filename does not end in .gz\");\n";
1032     source << "            exit(1);\n";
1033     source << "        }\n";
1034     source << "        std::vector<uint8_t> compressedData(size);\n";
1035     source << "        (void)fread(compressedData.data(), 1, size, fp);\n";
1036     source << "        gBinaryData = gDecompressCallback(compressedData);\n";
1037     source << "    }\n";
1038     source << "    else\n";
1039     source << "    {\n";
1040     source << "        if (!strstr(fileName, \".angledata\"))\n";
1041     source << "        {\n";
1042     source << "            fprintf(stderr, \"Filename does not end in .angledata\");\n";
1043     source << "            exit(1);\n";
1044     source << "        }\n";
1045     source << "        gBinaryData = new uint8_t[size];\n";
1046     source << "        (void)fread(gBinaryData, 1, size, fp);\n";
1047     source << "    }\n";
1048     source << "    fclose(fp);\n";
1049     source << "}\n";
1050 
1051     if (maxClientArraySize > 0)
1052     {
1053         header
1054             << "void UpdateClientArrayPointer(int arrayIndex, const void *data, uint64_t size);\n";
1055 
1056         source << "\n";
1057         source << "void UpdateClientArrayPointer(int arrayIndex, const void *data, uint64_t size)"
1058                << "\n";
1059         source << "{\n";
1060         source << "    memcpy(gClientArrays[arrayIndex], data, static_cast<size_t>(size));\n";
1061         source << "}\n";
1062     }
1063 
1064     // Data types and functions for tracking contents of mapped buffers
1065     header << "using BufferHandleMap = std::unordered_map<GLuint, void*>;\n";
1066     header << "extern BufferHandleMap gMappedBufferData;\n";
1067     header << "void UpdateClientBufferData(GLuint bufferID, const void *source, GLsizei size);\n";
1068     source << "BufferHandleMap gMappedBufferData;\n";
1069     source << "\n";
1070     source << "void UpdateClientBufferData(GLuint bufferID, const void *source, GLsizei size)";
1071     source << "\n";
1072     source << "{\n";
1073     source << "    memcpy(gMappedBufferData[gBufferMap[bufferID]], source, size);\n";
1074     source << "}\n";
1075 
1076     for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
1077     {
1078         // TODO: Only emit resources needed by the frames (anglebug.com/4223)
1079         const char *name = GetResourceIDTypeName(resourceType);
1080         header << "void Update" << name << "ID(GLuint id, GLsizei readBufferOffset);\n";
1081 
1082         source << "\n";
1083         source << "void Update" << name << "ID(GLuint id, GLsizei readBufferOffset)\n";
1084         source << "{\n";
1085         source << "    UpdateResourceMap(&g" << name << "Map, id, readBufferOffset);\n";
1086         source << "}\n";
1087     }
1088 
1089     if (!captureLabel.empty())
1090     {
1091         header << "} // namespace " << captureLabel << "\n";
1092         source << "} // namespace " << captureLabel << "\n";
1093     }
1094 
1095     {
1096         std::string headerContents = header.str();
1097 
1098         std::stringstream headerPathStream;
1099         headerPathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << ".h";
1100         std::string headerPath = headerPathStream.str();
1101 
1102         SaveFileHelper saveHeader(headerPath);
1103         saveHeader << headerContents;
1104     }
1105 
1106     {
1107         std::string sourceContents = source.str();
1108 
1109         std::stringstream sourcePathStream;
1110         sourcePathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << ".cpp";
1111         std::string sourcePath = sourcePathStream.str();
1112 
1113         SaveFileHelper saveSource(sourcePath);
1114         saveSource << sourceContents;
1115     }
1116 
1117     {
1118         std::stringstream indexPathStream;
1119         indexPathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << "_files.txt";
1120         std::string indexPath = indexPathStream.str();
1121 
1122         SaveFileHelper saveIndex(indexPath);
1123         for (uint32_t frameIndex = frameStart; frameIndex <= frameEnd; ++frameIndex)
1124         {
1125             saveIndex << GetCaptureFileName(contextId, captureLabel, frameIndex, ".cpp") << "\n";
1126         }
1127     }
1128 }
1129 
GetAttachedProgramSources(const gl::Program * program)1130 ProgramSources GetAttachedProgramSources(const gl::Program *program)
1131 {
1132     ProgramSources sources;
1133     for (gl::ShaderType shaderType : gl::AllShaderTypes())
1134     {
1135         const gl::Shader *shader = program->getAttachedShader(shaderType);
1136         if (shader)
1137         {
1138             sources[shaderType] = shader->getSourceString();
1139         }
1140     }
1141     return sources;
1142 }
1143 
1144 template <typename IDType>
CaptureUpdateResourceIDs(const CallCapture & call,const ParamCapture & param,std::vector<CallCapture> * callsOut)1145 void CaptureUpdateResourceIDs(const CallCapture &call,
1146                               const ParamCapture &param,
1147                               std::vector<CallCapture> *callsOut)
1148 {
1149     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1150     ASSERT(param.data.size() == 1);
1151     ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1152     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
1153     const char *resourceName = GetResourceIDTypeName(resourceIDType);
1154 
1155     std::stringstream updateFuncNameStr;
1156     updateFuncNameStr << "Update" << resourceName << "ID";
1157     std::string updateFuncName = updateFuncNameStr.str();
1158 
1159     const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1160 
1161     for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1162     {
1163         IDType id                = returnedIDs[idIndex];
1164         GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1165         ParamBuffer params;
1166         params.addValueParam("id", ParamType::TGLuint, id.value);
1167         params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1168         callsOut->emplace_back(updateFuncName, std::move(params));
1169     }
1170 }
1171 
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1172 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1173 {
1174     const std::vector<gl::LinkedUniform> &uniforms     = program->getState().getUniforms();
1175     const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1176 
1177     for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1178     {
1179         const gl::VariableLocation &locationVar = locations[location];
1180         const gl::LinkedUniform &uniform        = uniforms[locationVar.index];
1181 
1182         ParamBuffer params;
1183         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1184 
1185         std::string name = uniform.name;
1186 
1187         if (uniform.isArray())
1188         {
1189             if (locationVar.arrayIndex > 0)
1190             {
1191                 // Non-sequential array uniform locations are not currently handled.
1192                 // In practice array locations shouldn't ever be non-sequential.
1193                 ASSERT(uniform.location == -1 ||
1194                        location == uniform.location + static_cast<int>(locationVar.arrayIndex));
1195                 continue;
1196             }
1197 
1198             if (uniform.isArrayOfArrays())
1199             {
1200                 UNIMPLEMENTED();
1201             }
1202 
1203             name = gl::StripLastArrayIndex(name);
1204         }
1205 
1206         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1207         CaptureString(name.c_str(), &nameParam);
1208         params.addParam(std::move(nameParam));
1209 
1210         params.addValueParam("location", ParamType::TGLint, location);
1211         callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1212     }
1213 }
1214 
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1215 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1216 {
1217     ParamBuffer params;
1218     params.addValueParam("program", ParamType::TShaderProgramID, program);
1219     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1220 }
1221 
CaptureOnFramebufferChange(GLenum target,gl::FramebufferID framebufferID,std::vector<CallCapture> * callsOut)1222 void CaptureOnFramebufferChange(GLenum target,
1223                                 gl::FramebufferID framebufferID,
1224                                 std::vector<CallCapture> *callsOut)
1225 {
1226     ParamBuffer params;
1227     params.addValueParam("target", ParamType::TGLenum, target);
1228     params.addValueParam("framebuffer", ParamType::TFramebufferID, framebufferID);
1229     callsOut->emplace_back("OnFramebufferChange", std::move(params));
1230 }
1231 
MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> * callsOut)1232 void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
1233 {
1234     const CallCapture &call = callsOut->back();
1235 
1236     switch (call.entryPoint)
1237     {
1238         case gl::EntryPoint::GenBuffers:
1239         {
1240             const ParamCapture &buffers =
1241                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1242             CaptureUpdateResourceIDs<gl::BufferID>(call, buffers, callsOut);
1243             break;
1244         }
1245 
1246         case gl::EntryPoint::GenFencesNV:
1247         {
1248             const ParamCapture &fences =
1249                 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1250             CaptureUpdateResourceIDs<gl::FenceNVID>(call, fences, callsOut);
1251             break;
1252         }
1253 
1254         case gl::EntryPoint::GenFramebuffers:
1255         case gl::EntryPoint::GenFramebuffersOES:
1256         {
1257             const ParamCapture &framebuffers =
1258                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1259             CaptureUpdateResourceIDs<gl::FramebufferID>(call, framebuffers, callsOut);
1260             break;
1261         }
1262 
1263         case gl::EntryPoint::GenProgramPipelines:
1264         {
1265             const ParamCapture &pipelines =
1266                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1267             CaptureUpdateResourceIDs<gl::ProgramPipelineID>(call, pipelines, callsOut);
1268             break;
1269         }
1270 
1271         case gl::EntryPoint::GenQueries:
1272         case gl::EntryPoint::GenQueriesEXT:
1273         {
1274             const ParamCapture &queries =
1275                 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1276             CaptureUpdateResourceIDs<gl::QueryID>(call, queries, callsOut);
1277             break;
1278         }
1279 
1280         case gl::EntryPoint::GenRenderbuffers:
1281         case gl::EntryPoint::GenRenderbuffersOES:
1282         {
1283             const ParamCapture &renderbuffers =
1284                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1285             CaptureUpdateResourceIDs<gl::RenderbufferID>(call, renderbuffers, callsOut);
1286             break;
1287         }
1288 
1289         case gl::EntryPoint::GenSamplers:
1290         {
1291             const ParamCapture &samplers =
1292                 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1293             CaptureUpdateResourceIDs<gl::SamplerID>(call, samplers, callsOut);
1294             break;
1295         }
1296 
1297         case gl::EntryPoint::GenSemaphoresEXT:
1298         {
1299             const ParamCapture &semaphores =
1300                 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1301             CaptureUpdateResourceIDs<gl::SemaphoreID>(call, semaphores, callsOut);
1302             break;
1303         }
1304 
1305         case gl::EntryPoint::GenTextures:
1306         {
1307             const ParamCapture &textures =
1308                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1309             CaptureUpdateResourceIDs<gl::TextureID>(call, textures, callsOut);
1310             break;
1311         }
1312 
1313         case gl::EntryPoint::GenTransformFeedbacks:
1314         {
1315             const ParamCapture &xfbs =
1316                 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1317             CaptureUpdateResourceIDs<gl::TransformFeedbackID>(call, xfbs, callsOut);
1318             break;
1319         }
1320 
1321         case gl::EntryPoint::GenVertexArrays:
1322         case gl::EntryPoint::GenVertexArraysOES:
1323         {
1324             const ParamCapture &vertexArrays =
1325                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1326             CaptureUpdateResourceIDs<gl::VertexArrayID>(call, vertexArrays, callsOut);
1327             break;
1328         }
1329 
1330         default:
1331             break;
1332     }
1333 }
1334 
CaptureUpdateCurrentProgram(const CallCapture & call,std::vector<CallCapture> * callsOut)1335 void CaptureUpdateCurrentProgram(const CallCapture &call, std::vector<CallCapture> *callsOut)
1336 {
1337     const ParamCapture &param =
1338         call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
1339     gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1340 
1341     ParamBuffer paramBuffer;
1342     paramBuffer.addValueParam("program", ParamType::TShaderProgramID, programID);
1343 
1344     callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1345 }
1346 
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1347 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
1348 {
1349     if (currentValue.Type != gl::VertexAttribType::Float)
1350         return false;
1351 
1352     return currentValue.Values.FloatValues[0] == 0.0f &&
1353            currentValue.Values.FloatValues[1] == 0.0f &&
1354            currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1355 }
1356 
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1357 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1358 {
1359     const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1360     for (const auto &activeQueryIter : activeQueries)
1361     {
1362         const gl::Query *activeQuery = activeQueryIter.get();
1363         if (activeQuery && activeQuery->id() == queryID)
1364         {
1365             return true;
1366         }
1367     }
1368 
1369     return false;
1370 }
1371 
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1372 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1373 {
1374     setupCalls->emplace_back(std::move(call));
1375 }
1376 
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const gl::FramebufferAttachment & attachment)1377 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
1378                                   const gl::State &replayState,
1379                                   const gl::FramebufferAttachment &attachment)
1380 {
1381     GLuint resourceID = attachment.getResource()->getId();
1382 
1383     // TODO(jmadill): Layer attachments. http://anglebug.com/3662
1384     if (attachment.type() == GL_TEXTURE)
1385     {
1386         gl::ImageIndex index = attachment.getTextureImageIndex();
1387 
1388         Capture(setupCalls, CaptureFramebufferTexture2D(replayState, true, GL_FRAMEBUFFER,
1389                                                         attachment.getBinding(), index.getTarget(),
1390                                                         {resourceID}, index.getLevelIndex()));
1391     }
1392     else
1393     {
1394         ASSERT(attachment.type() == GL_RENDERBUFFER);
1395         Capture(setupCalls, CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
1396                                                            attachment.getBinding(), GL_RENDERBUFFER,
1397                                                            {resourceID}));
1398     }
1399 }
1400 
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,const gl::Program * program,std::vector<CallCapture> * callsOut)1401 void CaptureUpdateUniformValues(const gl::State &replayState,
1402                                 const gl::Context *context,
1403                                 const gl::Program *program,
1404                                 std::vector<CallCapture> *callsOut)
1405 {
1406     const std::vector<gl::LinkedUniform> &uniforms     = program->getState().getUniforms();
1407     const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1408 
1409     for (const gl::VariableLocation &location : locations)
1410     {
1411         const gl::LinkedUniform &uniform = uniforms[location.index];
1412 
1413         if (!program->isLinked())
1414         {
1415             // We can't populate uniforms if the program hasn't been linked
1416             continue;
1417         }
1418 
1419         if (uniform.isArray())
1420         {
1421             UNIMPLEMENTED();
1422         }
1423 
1424         // We need to bind the program and update its uniforms
1425         // TODO (http://anglebug.com/3662): Only bind if different from currently bound
1426         Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
1427         CaptureUpdateCurrentProgram(callsOut->back(), callsOut);
1428 
1429         const gl::UniformTypeInfo *typeInfo = uniform.typeInfo;
1430         gl::UniformLocation uniformLoc      = {static_cast<int>(location.index)};
1431 
1432         switch (typeInfo->componentType)
1433         {
1434             case GL_FLOAT:
1435             {
1436                 std::vector<GLfloat> components(typeInfo->componentCount);
1437                 program->getUniformfv(context, uniformLoc, components.data());
1438                 switch (typeInfo->type)
1439                 {
1440                     // Note: All matrix uniforms are populated without transpose
1441                     case GL_FLOAT_MAT4x3:
1442                         Capture(callsOut, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
1443                                                                     1, false, components.data()));
1444                         break;
1445                     case GL_FLOAT_MAT4x2:
1446                         Capture(callsOut, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
1447                                                                     1, false, components.data()));
1448                         break;
1449                     case GL_FLOAT_MAT4:
1450                         Capture(callsOut, CaptureUniformMatrix4fv(replayState, true, uniformLoc, 1,
1451                                                                   false, components.data()));
1452                         break;
1453                     case GL_FLOAT_MAT3x4:
1454                         Capture(callsOut, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
1455                                                                     1, false, components.data()));
1456                         break;
1457                     case GL_FLOAT_MAT3x2:
1458                         Capture(callsOut, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
1459                                                                     1, false, components.data()));
1460                         break;
1461                     case GL_FLOAT_MAT3:
1462                         Capture(callsOut, CaptureUniformMatrix3fv(replayState, true, uniformLoc, 1,
1463                                                                   false, components.data()));
1464                         break;
1465                     case GL_FLOAT_MAT2x4:
1466                         Capture(callsOut, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
1467                                                                     1, false, components.data()));
1468                         break;
1469                     case GL_FLOAT_MAT2x3:
1470                         Capture(callsOut, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
1471                                                                     1, false, components.data()));
1472                         break;
1473                     case GL_FLOAT_MAT2:
1474                         Capture(callsOut, CaptureUniformMatrix2fv(replayState, true, uniformLoc, 1,
1475                                                                   false, components.data()));
1476                         break;
1477                     case GL_FLOAT_VEC4:
1478                         Capture(callsOut, CaptureUniform4fv(replayState, true, uniformLoc, 1,
1479                                                             components.data()));
1480                         break;
1481                     case GL_FLOAT_VEC3:
1482                         Capture(callsOut, CaptureUniform3fv(replayState, true, uniformLoc, 1,
1483                                                             components.data()));
1484                         break;
1485                     case GL_FLOAT_VEC2:
1486                         Capture(callsOut, CaptureUniform2fv(replayState, true, uniformLoc, 1,
1487                                                             components.data()));
1488                         break;
1489                     case GL_FLOAT:
1490                         Capture(callsOut, CaptureUniform1fv(replayState, true, uniformLoc, 1,
1491                                                             components.data()));
1492                         break;
1493                     default:
1494                         UNIMPLEMENTED();
1495                         break;
1496                 }
1497                 break;
1498             }
1499             case GL_INT:
1500             {
1501                 std::vector<GLint> components(typeInfo->componentCount);
1502                 program->getUniformiv(context, uniformLoc, components.data());
1503                 switch (typeInfo->componentCount)
1504                 {
1505                     case 4:
1506                         Capture(callsOut, CaptureUniform4iv(replayState, true, uniformLoc, 1,
1507                                                             components.data()));
1508                         break;
1509                     case 3:
1510                         Capture(callsOut, CaptureUniform3iv(replayState, true, uniformLoc, 1,
1511                                                             components.data()));
1512                         break;
1513                     case 2:
1514                         Capture(callsOut, CaptureUniform2iv(replayState, true, uniformLoc, 1,
1515                                                             components.data()));
1516                         break;
1517                     case 1:
1518                         Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc, 1,
1519                                                             components.data()));
1520                         break;
1521                     default:
1522                         UNIMPLEMENTED();
1523                         break;
1524                 }
1525                 break;
1526             }
1527             case GL_UNSIGNED_INT:
1528             {
1529                 std::vector<GLuint> components(typeInfo->componentCount);
1530                 program->getUniformuiv(context, uniformLoc, components.data());
1531                 switch (typeInfo->componentCount)
1532                 {
1533                     case 4:
1534                         Capture(callsOut, CaptureUniform4uiv(replayState, true, uniformLoc, 1,
1535                                                              components.data()));
1536                         break;
1537                     case 3:
1538                         Capture(callsOut, CaptureUniform3uiv(replayState, true, uniformLoc, 1,
1539                                                              components.data()));
1540                         break;
1541                     case 2:
1542                         Capture(callsOut, CaptureUniform2uiv(replayState, true, uniformLoc, 1,
1543                                                              components.data()));
1544                         break;
1545                     case 1:
1546                         Capture(callsOut, CaptureUniform1uiv(replayState, true, uniformLoc, 1,
1547                                                              components.data()));
1548                         break;
1549                     default:
1550                         UNIMPLEMENTED();
1551                         break;
1552                 }
1553                 break;
1554             }
1555             default:
1556                 UNIMPLEMENTED();
1557                 break;
1558         }
1559     }
1560 }
1561 
CaptureVertexArrayData(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)1562 void CaptureVertexArrayData(std::vector<CallCapture> *setupCalls,
1563                             const gl::Context *context,
1564                             const gl::VertexArray *vertexArray,
1565                             gl::State *replayState)
1566 {
1567     const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
1568     const std::vector<gl::VertexBinding> &vertexBindings  = vertexArray->getVertexBindings();
1569 
1570     for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1571     {
1572         const gl::VertexAttribute defaultAttrib(attribIndex);
1573         const gl::VertexBinding defaultBinding;
1574 
1575         const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
1576         const gl::VertexBinding &binding  = vertexBindings[attrib.bindingIndex];
1577 
1578         if (attrib.enabled != defaultAttrib.enabled)
1579         {
1580             Capture(setupCalls, CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
1581         }
1582 
1583         if (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
1584             binding.getStride() != defaultBinding.getStride() ||
1585             binding.getBuffer().get() != nullptr)
1586         {
1587             gl::Buffer *buffer = binding.getBuffer().get();
1588 
1589             if (buffer != replayState->getArrayBuffer())
1590             {
1591                 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
1592                 Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array,
1593                                                       buffer->id()));
1594             }
1595 
1596             Capture(setupCalls, CaptureVertexAttribPointer(
1597                                     *replayState, true, attribIndex, attrib.format->channelCount,
1598                                     attrib.format->vertexAttribType, attrib.format->isNorm(),
1599                                     binding.getStride(), attrib.pointer));
1600         }
1601 
1602         if (binding.getDivisor() != 0)
1603         {
1604             Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
1605                                                            binding.getDivisor()));
1606         }
1607     }
1608 }
1609 
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)1610 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
1611                            gl::State *replayState,
1612                            const gl::Texture *texture)
1613 {
1614     // Use mip-level 0 for the base dimensions
1615     gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
1616     const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
1617 
1618     switch (texture->getType())
1619     {
1620         case gl::TextureType::_2D:
1621         case gl::TextureType::CubeMap:
1622         {
1623             Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
1624                                                     texture->getImmutableLevels(),
1625                                                     desc.format.info->internalFormat,
1626                                                     desc.size.width, desc.size.height));
1627             break;
1628         }
1629         case gl::TextureType::_3D:
1630         case gl::TextureType::_2DArray:
1631         {
1632             Capture(setupCalls, CaptureTexStorage3D(
1633                                     *replayState, true, texture->getType(),
1634                                     texture->getImmutableLevels(), desc.format.info->internalFormat,
1635                                     desc.size.width, desc.size.height, desc.size.depth));
1636             break;
1637         }
1638         default:
1639             UNIMPLEMENTED();
1640             break;
1641     }
1642 }
1643 
CaptureTextureContents(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture,const gl::ImageIndex & index,const gl::ImageDesc & desc,GLuint size,const void * data)1644 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
1645                             gl::State *replayState,
1646                             const gl::Texture *texture,
1647                             const gl::ImageIndex &index,
1648                             const gl::ImageDesc &desc,
1649                             GLuint size,
1650                             const void *data)
1651 {
1652     const gl::InternalFormat &format = *desc.format.info;
1653 
1654     bool is3D =
1655         (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray);
1656 
1657     if (format.compressed)
1658     {
1659         if (is3D)
1660         {
1661             if (texture->getImmutableFormat())
1662             {
1663                 Capture(setupCalls,
1664                         CaptureCompressedTexSubImage3D(
1665                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
1666                             desc.size.width, desc.size.height, desc.size.depth,
1667                             format.internalFormat, size, data));
1668             }
1669             else
1670             {
1671                 Capture(setupCalls,
1672                         CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
1673                                                     index.getLevelIndex(), format.internalFormat,
1674                                                     desc.size.width, desc.size.height,
1675                                                     desc.size.depth, 0, size, data));
1676             }
1677         }
1678         else
1679         {
1680             if (texture->getImmutableFormat())
1681             {
1682                 Capture(setupCalls,
1683                         CaptureCompressedTexSubImage2D(
1684                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
1685                             desc.size.width, desc.size.height, format.internalFormat, size, data));
1686             }
1687             else
1688             {
1689                 Capture(setupCalls, CaptureCompressedTexImage2D(
1690                                         *replayState, true, index.getTarget(),
1691                                         index.getLevelIndex(), format.internalFormat,
1692                                         desc.size.width, desc.size.height, 0, size, data));
1693             }
1694         }
1695     }
1696     else
1697     {
1698         if (is3D)
1699         {
1700             if (texture->getImmutableFormat())
1701             {
1702                 Capture(setupCalls,
1703                         CaptureTexSubImage3D(*replayState, true, index.getTarget(),
1704                                              index.getLevelIndex(), 0, 0, 0, desc.size.width,
1705                                              desc.size.height, desc.size.depth, format.format,
1706                                              format.type, data));
1707             }
1708             else
1709             {
1710                 Capture(
1711                     setupCalls,
1712                     CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
1713                                       format.internalFormat, desc.size.width, desc.size.height,
1714                                       desc.size.depth, 0, format.format, format.type, data));
1715             }
1716         }
1717         else
1718         {
1719             if (texture->getImmutableFormat())
1720             {
1721                 Capture(setupCalls,
1722                         CaptureTexSubImage2D(*replayState, true, index.getTarget(),
1723                                              index.getLevelIndex(), 0, 0, desc.size.width,
1724                                              desc.size.height, format.format, format.type, data));
1725             }
1726             else
1727             {
1728                 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
1729                                                       index.getLevelIndex(), format.internalFormat,
1730                                                       desc.size.width, desc.size.height, 0,
1731                                                       format.format, format.type, data));
1732             }
1733         }
1734     }
1735 }
1736 
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,const ShaderSourceMap & cachedShaderSources,const ProgramSourceMap & cachedProgramSources,const TextureLevelDataMap & cachedTextureLevelData)1737 void CaptureMidExecutionSetup(const gl::Context *context,
1738                               std::vector<CallCapture> *setupCalls,
1739                               const ShaderSourceMap &cachedShaderSources,
1740                               const ProgramSourceMap &cachedProgramSources,
1741                               const TextureLevelDataMap &cachedTextureLevelData)
1742 {
1743     const gl::State &apiState = context->getState();
1744     gl::State replayState(nullptr, nullptr, nullptr, EGL_OPENGL_ES_API, apiState.getClientVersion(),
1745                           false, true, true, true, false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
1746 
1747     // Small helper function to make the code more readable.
1748     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
1749 
1750     // Currently this code assumes we can use create-on-bind. It does not support 'Gen' usage.
1751     // TODO(jmadill): Use handle mapping for captured objects. http://anglebug.com/3662
1752 
1753     // Capture Buffer data.
1754     const gl::BufferManager &buffers       = apiState.getBufferManagerForCapture();
1755     const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
1756 
1757     for (const auto &bufferIter : buffers)
1758     {
1759         gl::BufferID id    = {bufferIter.first};
1760         gl::Buffer *buffer = bufferIter.second;
1761 
1762         if (id.value == 0)
1763         {
1764             continue;
1765         }
1766 
1767         // glBufferData. Would possibly be better implemented using a getData impl method.
1768         // Saving buffers that are mapped during a swap is not yet handled.
1769         if (buffer->getSize() == 0)
1770         {
1771             continue;
1772         }
1773         ASSERT(!buffer->isMapped());
1774         (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
1775                                GL_MAP_READ_BIT);
1776 
1777         // Generate binding.
1778         cap(CaptureGenBuffers(replayState, true, 1, &id));
1779         MaybeCaptureUpdateResourceIDs(setupCalls);
1780 
1781         // Always use the array buffer binding point to upload data to keep things simple.
1782         if (buffer != replayState.getArrayBuffer())
1783         {
1784             replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
1785             cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
1786         }
1787 
1788         cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
1789                               static_cast<GLsizeiptr>(buffer->getSize()), buffer->getMapPointer(),
1790                               buffer->getUsage()));
1791 
1792         GLboolean dontCare;
1793         (void)buffer->unmap(context, &dontCare);
1794     }
1795 
1796     // Vertex input states. Only handles GLES 2.0 states right now.
1797     // Must happen after buffer data initialization.
1798     // TODO(http://anglebug.com/3662): Complete state capture.
1799 
1800     // Capture default vertex attribs
1801     const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
1802         apiState.getVertexAttribCurrentValues();
1803 
1804     for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1805     {
1806         const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
1807         if (!IsDefaultCurrentValue(defaultValue))
1808         {
1809             Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
1810                                                        defaultValue.Values.FloatValues));
1811         }
1812     }
1813 
1814     // Capture vertex array objects
1815     const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
1816     gl::VertexArrayID boundVertexArrayID     = {0};
1817     for (const auto &vertexArrayIter : vertexArrayMap)
1818     {
1819         gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
1820         cap(CaptureGenVertexArrays(replayState, true, 1, &vertexArrayID));
1821         MaybeCaptureUpdateResourceIDs(setupCalls);
1822 
1823         if (vertexArrayIter.second)
1824         {
1825             const gl::VertexArray *vertexArray = vertexArrayIter.second;
1826 
1827             // Bind the vertexArray (unless default) and populate it
1828             if (vertexArrayID.value != 0)
1829             {
1830                 cap(CaptureBindVertexArray(replayState, true, vertexArrayID));
1831                 boundVertexArrayID = vertexArrayID;
1832             }
1833             CaptureVertexArrayData(setupCalls, context, vertexArray, &replayState);
1834         }
1835     }
1836 
1837     // Bind the current vertex array
1838     const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
1839     if (currentVertexArray->id() != boundVertexArrayID)
1840     {
1841         cap(CaptureBindVertexArray(replayState, true, currentVertexArray->id()));
1842     }
1843 
1844     // Capture Buffer bindings.
1845     for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
1846     {
1847         gl::BufferID bufferID = boundBuffers[binding].id();
1848 
1849         // Filter out redundant buffer binding commands. Note that the code in the previous section
1850         // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
1851         // we set earlier.
1852         bool isArray                  = binding == gl::BufferBinding::Array;
1853         const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
1854         if ((isArray && arrayBuffer && arrayBuffer->id() != bufferID) ||
1855             (!isArray && bufferID.value != 0))
1856         {
1857             cap(CaptureBindBuffer(replayState, true, binding, bufferID));
1858         }
1859     }
1860 
1861     // Set a unpack alignment of 1.
1862     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
1863     if (currentUnpackState.alignment != 1)
1864     {
1865         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
1866         currentUnpackState.alignment = 1;
1867     }
1868 
1869     // Capture Texture setup and data.
1870     const gl::TextureManager &textures         = apiState.getTextureManagerForCapture();
1871     const gl::TextureBindingMap &boundTextures = apiState.getBoundTexturesForCapture();
1872 
1873     gl::TextureTypeMap<gl::TextureID> currentTextureBindings;
1874 
1875     for (const auto &textureIter : textures)
1876     {
1877         gl::TextureID id           = {textureIter.first};
1878         const gl::Texture *texture = textureIter.second;
1879 
1880         if (id.value == 0)
1881         {
1882             continue;
1883         }
1884 
1885         // Gen the Texture.
1886         cap(CaptureGenTextures(replayState, true, 1, &id));
1887         MaybeCaptureUpdateResourceIDs(setupCalls);
1888         cap(CaptureBindTexture(replayState, true, texture->getType(), id));
1889 
1890         currentTextureBindings[texture->getType()] = id;
1891 
1892         // Capture sampler parameter states.
1893         // TODO(jmadill): More sampler / texture states. http://anglebug.com/3662
1894         gl::SamplerState defaultSamplerState =
1895             gl::SamplerState::CreateDefaultForTarget(texture->getType());
1896         const gl::SamplerState &textureSamplerState = texture->getSamplerState();
1897 
1898         auto capTexParam = [cap, &replayState, texture](GLenum pname, GLint param) {
1899             cap(CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
1900         };
1901 
1902         auto capTexParamf = [cap, &replayState, texture](GLenum pname, GLfloat param) {
1903             cap(CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
1904         };
1905 
1906         if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
1907         {
1908             capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
1909         }
1910 
1911         if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
1912         {
1913             capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
1914         }
1915 
1916         if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
1917         {
1918             capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
1919         }
1920 
1921         if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
1922         {
1923             capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
1924         }
1925 
1926         if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
1927         {
1928             capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
1929         }
1930 
1931         if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
1932         {
1933             capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
1934         }
1935 
1936         if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
1937         {
1938             capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
1939         }
1940 
1941         if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
1942         {
1943             capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
1944         }
1945 
1946         if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
1947         {
1948             capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
1949         }
1950 
1951         // Texture parameters
1952         if (texture->getSwizzleRed() != GL_RED)
1953         {
1954             capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
1955         }
1956 
1957         if (texture->getSwizzleGreen() != GL_GREEN)
1958         {
1959             capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
1960         }
1961 
1962         if (texture->getSwizzleBlue() != GL_BLUE)
1963         {
1964             capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
1965         }
1966 
1967         if (texture->getSwizzleAlpha() != GL_ALPHA)
1968         {
1969             capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
1970         }
1971 
1972         if (texture->getBaseLevel() != 0)
1973         {
1974             capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
1975         }
1976 
1977         if (texture->getMaxLevel() != 1000)
1978         {
1979             capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
1980         }
1981 
1982         // If the texture is immutable, initialize it with TexStorage
1983         if (texture->getImmutableFormat())
1984         {
1985             CaptureTextureStorage(setupCalls, &replayState, texture);
1986         }
1987 
1988         // Iterate texture levels and layers.
1989         gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
1990             texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
1991             gl::ImageIndex::kEntireLevel);
1992         while (imageIter.hasNext())
1993         {
1994             gl::ImageIndex index = imageIter.next();
1995 
1996             const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
1997 
1998             if (desc.size.empty())
1999                 continue;
2000 
2001             const gl::InternalFormat &format = *desc.format.info;
2002 
2003             // Check for supported textures
2004             ASSERT(index.getType() == gl::TextureType::_2D ||
2005                    index.getType() == gl::TextureType::_3D ||
2006                    index.getType() == gl::TextureType::_2DArray ||
2007                    index.getType() == gl::TextureType::CubeMap);
2008 
2009             if (format.compressed)
2010             {
2011                 // For compressed images, we've tracked a copy of the incoming data, so we can
2012                 // use that rather than try to read data back that may have been converted.
2013 
2014                 // Look up the data for the requested texture
2015                 const auto &foundTextureLevels = cachedTextureLevelData.find(texture->id());
2016                 ASSERT(foundTextureLevels != cachedTextureLevelData.end());
2017 
2018                 // For that texture, look up the data for the given level
2019                 GLint level                   = index.getLevelIndex();
2020                 const auto &foundTextureLevel = foundTextureLevels->second.find(level);
2021                 ASSERT(foundTextureLevel != foundTextureLevels->second.end());
2022                 const std::vector<uint8_t> &capturedTextureLevel = foundTextureLevel->second;
2023 
2024                 // Use the shadow copy of the data to populate the call
2025                 CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2026                                        static_cast<GLuint>(capturedTextureLevel.size()),
2027                                        capturedTextureLevel.data());
2028             }
2029             else
2030             {
2031                 // Use ANGLE_get_image to read back pixel data.
2032                 if (context->getExtensions().getImageANGLE)
2033                 {
2034                     GLenum getFormat = format.format;
2035                     GLenum getType   = format.type;
2036 
2037                     angle::MemoryBuffer data;
2038 
2039                     const gl::Extents size(desc.size.width, desc.size.height, desc.size.depth);
2040                     const gl::PixelUnpackState &unpack = apiState.getUnpackState();
2041 
2042                     GLuint endByte = 0;
2043                     bool unpackSize =
2044                         format.computePackUnpackEndByte(getType, size, unpack, true, &endByte);
2045                     ASSERT(unpackSize);
2046 
2047                     bool result = data.resize(endByte);
2048                     ASSERT(result);
2049 
2050                     gl::PixelPackState packState;
2051                     packState.alignment = 1;
2052 
2053                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
2054                                                index.getLevelIndex(), getFormat, getType,
2055                                                data.data());
2056 
2057                     CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2058                                            static_cast<GLuint>(data.size()), data.data());
2059                 }
2060                 else
2061                 {
2062                     CaptureTextureContents(setupCalls, &replayState, texture, index, desc, 0,
2063                                            nullptr);
2064                 }
2065             }
2066         }
2067     }
2068 
2069     // Set Texture bindings.
2070     size_t currentActiveTexture = 0;
2071     for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
2072     {
2073         const gl::TextureBindingVector &bindings = boundTextures[textureType];
2074         for (size_t bindingIndex = 0; bindingIndex < bindings.size(); ++bindingIndex)
2075         {
2076             gl::TextureID textureID = bindings[bindingIndex].id();
2077 
2078             if (textureID.value != 0)
2079             {
2080                 if (currentActiveTexture != bindingIndex)
2081                 {
2082                     cap(CaptureActiveTexture(replayState, true,
2083                                              GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
2084                     currentActiveTexture = bindingIndex;
2085                 }
2086 
2087                 if (currentTextureBindings[textureType] != textureID)
2088                 {
2089                     cap(CaptureBindTexture(replayState, true, textureType, textureID));
2090                     currentTextureBindings[textureType] = textureID;
2091                 }
2092             }
2093         }
2094     }
2095 
2096     // Set active Texture.
2097     size_t stateActiveTexture = apiState.getActiveSampler();
2098     if (currentActiveTexture != stateActiveTexture)
2099     {
2100         cap(CaptureActiveTexture(replayState, true,
2101                                  GL_TEXTURE0 + static_cast<GLenum>(stateActiveTexture)));
2102     }
2103 
2104     // Capture Renderbuffers.
2105     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
2106 
2107     gl::RenderbufferID currentRenderbuffer = {0};
2108     for (const auto &renderbufIter : renderbuffers)
2109     {
2110         gl::RenderbufferID id                = {renderbufIter.first};
2111         const gl::Renderbuffer *renderbuffer = renderbufIter.second;
2112 
2113         // Generate renderbuffer id.
2114         cap(CaptureGenRenderbuffers(replayState, true, 1, &id));
2115         MaybeCaptureUpdateResourceIDs(setupCalls);
2116         cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
2117 
2118         currentRenderbuffer = id;
2119 
2120         GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
2121 
2122         if (renderbuffer->getSamples() > 0)
2123         {
2124             // Note: We could also use extensions if available.
2125             cap(CaptureRenderbufferStorageMultisample(
2126                 replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat,
2127                 renderbuffer->getWidth(), renderbuffer->getHeight()));
2128         }
2129         else
2130         {
2131             cap(CaptureRenderbufferStorage(replayState, true, GL_RENDERBUFFER, internalformat,
2132                                            renderbuffer->getWidth(), renderbuffer->getHeight()));
2133         }
2134 
2135         // TODO(jmadill): Capture renderbuffer contents. http://anglebug.com/3662
2136     }
2137 
2138     // Set Renderbuffer binding.
2139     if (currentRenderbuffer != apiState.getRenderbufferId())
2140     {
2141         cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER,
2142                                     apiState.getRenderbufferId()));
2143     }
2144 
2145     // Capture Framebuffers.
2146     const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
2147 
2148     gl::FramebufferID currentDrawFramebuffer = {0};
2149     gl::FramebufferID currentReadFramebuffer = {0};
2150 
2151     for (const auto &framebufferIter : framebuffers)
2152     {
2153         gl::FramebufferID id               = {framebufferIter.first};
2154         const gl::Framebuffer *framebuffer = framebufferIter.second;
2155 
2156         // The default Framebuffer exists (by default).
2157         if (framebuffer->isDefault())
2158             continue;
2159 
2160         cap(CaptureGenFramebuffers(replayState, true, 1, &id));
2161         MaybeCaptureUpdateResourceIDs(setupCalls);
2162         cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
2163         currentDrawFramebuffer = currentReadFramebuffer = id;
2164 
2165         // Color Attachments.
2166         for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
2167         {
2168             if (!colorAttachment.isAttached())
2169             {
2170                 continue;
2171             }
2172 
2173             CaptureFramebufferAttachment(setupCalls, replayState, colorAttachment);
2174         }
2175 
2176         const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
2177         if (depthAttachment)
2178         {
2179             ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT);
2180             CaptureFramebufferAttachment(setupCalls, replayState, *depthAttachment);
2181         }
2182 
2183         const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
2184         if (stencilAttachment)
2185         {
2186             ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT);
2187             CaptureFramebufferAttachment(setupCalls, replayState, *stencilAttachment);
2188         }
2189 
2190         // TODO(jmadill): Draw buffer states. http://anglebug.com/3662
2191     }
2192 
2193     // Capture framebuffer bindings.
2194     gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
2195     gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
2196     if (stateDrawFramebuffer == stateReadFramebuffer)
2197     {
2198         if (currentDrawFramebuffer != stateDrawFramebuffer ||
2199             currentReadFramebuffer != stateReadFramebuffer)
2200         {
2201             cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, stateDrawFramebuffer));
2202             currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
2203         }
2204     }
2205     else
2206     {
2207         if (currentDrawFramebuffer != stateDrawFramebuffer)
2208         {
2209             cap(CaptureBindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
2210                                        currentDrawFramebuffer));
2211             currentDrawFramebuffer = stateDrawFramebuffer;
2212         }
2213 
2214         if (currentReadFramebuffer != stateReadFramebuffer)
2215         {
2216             cap(CaptureBindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
2217                                        replayState.getReadFramebuffer()->id()));
2218             currentReadFramebuffer = stateReadFramebuffer;
2219         }
2220     }
2221 
2222     // Capture Shaders and Programs.
2223     const gl::ShaderProgramManager &shadersAndPrograms =
2224         apiState.getShaderProgramManagerForCapture();
2225     const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
2226         shadersAndPrograms.getShadersForCapture();
2227     const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
2228         shadersAndPrograms.getProgramsForCapture();
2229 
2230     // Capture Program binary state. Use shader ID 1 as a temporary shader ID.
2231     gl::ShaderProgramID tempShaderID = {1};
2232     for (const auto &programIter : programs)
2233     {
2234         gl::ShaderProgramID id     = {programIter.first};
2235         const gl::Program *program = programIter.second;
2236 
2237         // Get last compiled shader source.
2238         const auto &foundSources = cachedProgramSources.find(id);
2239         ASSERT(foundSources != cachedProgramSources.end());
2240         const ProgramSources &linkedSources = foundSources->second;
2241 
2242         // Unlinked programs don't have an executable. Thus they don't need to be linked.
2243         if (!program->isLinked())
2244         {
2245             continue;
2246         }
2247 
2248         cap(CaptureCreateProgram(replayState, true, id.value));
2249 
2250         // Compile with last linked sources.
2251         for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
2252         {
2253             const std::string &sourceString = linkedSources[shaderType];
2254             const char *sourcePointer       = sourceString.c_str();
2255 
2256             // Compile and attach the temporary shader. Then free it immediately.
2257             cap(CaptureCreateShader(replayState, true, shaderType, tempShaderID.value));
2258             cap(CaptureShaderSource(replayState, true, tempShaderID, 1, &sourcePointer, nullptr));
2259             cap(CaptureCompileShader(replayState, true, tempShaderID));
2260             cap(CaptureAttachShader(replayState, true, id, tempShaderID));
2261             cap(CaptureDeleteShader(replayState, true, tempShaderID));
2262         }
2263 
2264         // Gather XFB varyings
2265         std::vector<std::string> xfbVaryings;
2266         for (const gl::TransformFeedbackVarying &xfbVarying :
2267              program->getState().getLinkedTransformFeedbackVaryings())
2268         {
2269             xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
2270         }
2271 
2272         if (!xfbVaryings.empty())
2273         {
2274             std::vector<const char *> varyingsStrings;
2275             for (const std::string &varyingString : xfbVaryings)
2276             {
2277                 varyingsStrings.push_back(varyingString.data());
2278             }
2279 
2280             GLenum xfbMode = program->getState().getTransformFeedbackBufferMode();
2281             cap(CaptureTransformFeedbackVaryings(replayState, true, id,
2282                                                  static_cast<GLint>(xfbVaryings.size()),
2283                                                  varyingsStrings.data(), xfbMode));
2284         }
2285 
2286         cap(CaptureLinkProgram(replayState, true, id));
2287         CaptureUpdateUniformLocations(program, setupCalls);
2288         CaptureUpdateUniformValues(replayState, context, program, setupCalls);
2289     }
2290 
2291     // Handle shaders.
2292     for (const auto &shaderIter : shaders)
2293     {
2294         gl::ShaderProgramID id = {shaderIter.first};
2295         gl::Shader *shader     = shaderIter.second;
2296         cap(CaptureCreateShader(replayState, true, shader->getType(), id.value));
2297 
2298         std::string shaderSource  = shader->getSourceString();
2299         const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
2300 
2301         // This does not handle some more tricky situations like attaching shaders to a non-linked
2302         // program. Or attaching uncompiled shaders. Or attaching and then deleting a shader.
2303         // TODO(jmadill): Handle trickier program uses. http://anglebug.com/3662
2304         if (shader->isCompiled())
2305         {
2306             const auto &foundSources = cachedShaderSources.find(id);
2307             ASSERT(foundSources != cachedShaderSources.end());
2308             const std::string &capturedSource = foundSources->second;
2309 
2310             if (capturedSource != shaderSource)
2311             {
2312                 ASSERT(!capturedSource.empty());
2313                 sourcePointer = capturedSource.c_str();
2314             }
2315 
2316             cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2317             cap(CaptureCompileShader(replayState, true, id));
2318         }
2319 
2320         if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str()))
2321         {
2322             cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2323         }
2324     }
2325 
2326     // For now we assume the installed program executable is the same as the current program.
2327     // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
2328     if (apiState.getProgram())
2329     {
2330         cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
2331         CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
2332     }
2333 
2334     // TODO(http://anglebug.com/3662): ES 3.x objects.
2335 
2336     // Create existing queries. Note that queries may be genned and not yet started. In that
2337     // case the queries will exist in the query map as nullptr entries.
2338     const gl::QueryMap &queryMap = context->getQueriesForCapture();
2339     for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
2340          queryIter != queryMap.endWithNull(); ++queryIter)
2341     {
2342         ASSERT(queryIter->first);
2343         gl::QueryID queryID = {queryIter->first};
2344 
2345         cap(CaptureGenQueries(replayState, true, 1, &queryID));
2346         MaybeCaptureUpdateResourceIDs(setupCalls);
2347 
2348         gl::Query *query = queryIter->second;
2349         if (query)
2350         {
2351             gl::QueryType queryType = query->getType();
2352 
2353             // Begin the query to generate the object
2354             cap(CaptureBeginQuery(replayState, true, queryType, queryID));
2355 
2356             // End the query if it was not active
2357             if (!IsQueryActive(apiState, queryID))
2358             {
2359                 cap(CaptureEndQuery(replayState, true, queryType));
2360             }
2361         }
2362     }
2363 
2364     // Transform Feedback
2365     const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
2366     for (const auto &xfbIter : xfbMap)
2367     {
2368         gl::TransformFeedbackID xfbID = {xfbIter.first};
2369         cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
2370         MaybeCaptureUpdateResourceIDs(setupCalls);
2371 
2372         gl::TransformFeedback *xfb = xfbIter.second;
2373         if (!xfb)
2374         {
2375             // The object was never created
2376             continue;
2377         }
2378 
2379         // Bind XFB to create the object
2380         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
2381 
2382         // Bind the buffers associated with this XFB object
2383         for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
2384         {
2385             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
2386 
2387             // Note: Buffers bound with BindBufferBase can be used with BindBuffer
2388             cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
2389                                        xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
2390         }
2391 
2392         if (xfb->isActive() || xfb->isPaused())
2393         {
2394             // We don't support active XFB in MEC yet
2395             UNIMPLEMENTED();
2396         }
2397     }
2398 
2399     // Bind the current XFB buffer after populating XFB objects
2400     gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
2401     cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, currentXFB->id()));
2402 
2403     // Capture Sampler Objects
2404     const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
2405     for (const auto &samplerIter : samplers)
2406     {
2407         gl::SamplerID samplerID = {samplerIter.first};
2408         cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
2409         MaybeCaptureUpdateResourceIDs(setupCalls);
2410 
2411         gl::Sampler *sampler = samplerIter.second;
2412         if (!sampler)
2413         {
2414             continue;
2415         }
2416 
2417         gl::SamplerState defaultSamplerState;
2418         if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
2419         {
2420             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
2421                                          sampler->getMinFilter()));
2422         }
2423         if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
2424         {
2425             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
2426                                          sampler->getMagFilter()));
2427         }
2428         if (sampler->getWrapS() != defaultSamplerState.getWrapS())
2429         {
2430             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
2431                                          sampler->getWrapS()));
2432         }
2433         if (sampler->getWrapR() != defaultSamplerState.getWrapR())
2434         {
2435             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
2436                                          sampler->getWrapR()));
2437         }
2438         if (sampler->getWrapT() != defaultSamplerState.getWrapT())
2439         {
2440             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
2441                                          sampler->getWrapT()));
2442         }
2443         if (sampler->getMinLod() != defaultSamplerState.getMinLod())
2444         {
2445             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
2446                                          sampler->getMinLod()));
2447         }
2448         if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
2449         {
2450             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
2451                                          sampler->getMaxLod()));
2452         }
2453         if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
2454         {
2455             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
2456                                          sampler->getCompareMode()));
2457         }
2458         if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
2459         {
2460             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
2461                                          sampler->getCompareFunc()));
2462         }
2463     }
2464 
2465     // Bind samplers
2466     gl::SamplerBindingVector samplerBindings = apiState.getSamplers();
2467     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
2468          ++bindingIndex)
2469     {
2470         gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
2471         if (samplerID.value != 0)
2472         {
2473             cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
2474         }
2475     }
2476 
2477     // Capture GL Context states.
2478     // TODO(http://anglebug.com/3662): Complete state capture.
2479     auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
2480         if (capValue)
2481         {
2482             cap(CaptureEnable(replayState, true, capEnum));
2483         }
2484         else
2485         {
2486             cap(CaptureDisable(replayState, true, capEnum));
2487         }
2488     };
2489 
2490     // Rasterizer state. Missing ES 3.x features.
2491     // TODO(http://anglebug.com/3662): Complete state capture.
2492     const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
2493     const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
2494     if (currentRasterState.cullFace != defaultRasterState.cullFace)
2495     {
2496         capCap(GL_CULL_FACE, currentRasterState.cullFace);
2497     }
2498 
2499     if (currentRasterState.cullMode != defaultRasterState.cullMode)
2500     {
2501         cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
2502     }
2503 
2504     if (currentRasterState.frontFace != defaultRasterState.frontFace)
2505     {
2506         cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
2507     }
2508 
2509     // Depth/stencil state.
2510     const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
2511     const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
2512     if (defaultDSState.depthFunc != currentDSState.depthFunc)
2513     {
2514         cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
2515     }
2516 
2517     if (defaultDSState.depthMask != currentDSState.depthMask)
2518     {
2519         cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
2520     }
2521 
2522     if (defaultDSState.depthTest != currentDSState.depthTest)
2523     {
2524         capCap(GL_DEPTH_TEST, currentDSState.depthTest);
2525     }
2526 
2527     if (defaultDSState.stencilTest != currentDSState.stencilTest)
2528     {
2529         capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
2530     }
2531 
2532     if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
2533         defaultDSState.stencilMask != currentDSState.stencilMask || apiState.getStencilRef() != 0)
2534     {
2535         cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
2536                                        apiState.getStencilRef(), currentDSState.stencilMask));
2537     }
2538 
2539     if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
2540         defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
2541         apiState.getStencilBackRef() != 0)
2542     {
2543         cap(CaptureStencilFuncSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFunc,
2544                                        apiState.getStencilBackRef(),
2545                                        currentDSState.stencilBackMask));
2546     }
2547 
2548     if (defaultDSState.stencilFail != currentDSState.stencilFail ||
2549         defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
2550         defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
2551     {
2552         cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
2553                                      currentDSState.stencilPassDepthFail,
2554                                      currentDSState.stencilPassDepthPass));
2555     }
2556 
2557     if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
2558         defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
2559         defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
2560     {
2561         cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
2562                                      currentDSState.stencilBackPassDepthFail,
2563                                      currentDSState.stencilBackPassDepthPass));
2564     }
2565 
2566     if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
2567     {
2568         cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
2569                                        currentDSState.stencilWritemask));
2570     }
2571 
2572     if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
2573     {
2574         cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
2575                                        currentDSState.stencilBackWritemask));
2576     }
2577 
2578     // Blend state.
2579     const gl::BlendState &defaultBlendState = replayState.getBlendState();
2580     const gl::BlendState &currentBlendState = apiState.getBlendState();
2581 
2582     if (currentBlendState.blend != defaultBlendState.blend)
2583     {
2584         capCap(GL_BLEND, currentBlendState.blend);
2585     }
2586 
2587     if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
2588         currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
2589         currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
2590         currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
2591     {
2592         cap(CaptureBlendFuncSeparate(
2593             replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
2594             currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
2595     }
2596 
2597     if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
2598         currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
2599     {
2600         cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
2601                                          currentBlendState.blendEquationAlpha));
2602     }
2603 
2604     if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
2605         currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
2606         currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
2607         currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
2608     {
2609         cap(CaptureColorMask(replayState, true,
2610                              gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
2611                              gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
2612                              gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
2613                              gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
2614     }
2615 
2616     const gl::ColorF &currentBlendColor = apiState.getBlendColor();
2617     if (currentBlendColor != gl::ColorF())
2618     {
2619         cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
2620                               currentBlendColor.blue, currentBlendColor.alpha));
2621     }
2622 
2623     // Pixel storage states.
2624     gl::PixelPackState &currentPackState = replayState.getPackState();
2625     if (currentPackState.alignment != apiState.getPackAlignment())
2626     {
2627         cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
2628         currentPackState.alignment = apiState.getPackAlignment();
2629     }
2630 
2631     if (currentPackState.rowLength != apiState.getPackRowLength())
2632     {
2633         cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
2634         currentPackState.rowLength = apiState.getPackRowLength();
2635     }
2636 
2637     if (currentPackState.skipRows != apiState.getPackSkipRows())
2638     {
2639         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
2640         currentPackState.skipRows = apiState.getPackSkipRows();
2641     }
2642 
2643     if (currentPackState.skipPixels != apiState.getPackSkipPixels())
2644     {
2645         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
2646                                apiState.getPackSkipPixels()));
2647         currentPackState.skipPixels = apiState.getPackSkipPixels();
2648     }
2649 
2650     // We set unpack alignment above, no need to change it here
2651     ASSERT(currentUnpackState.alignment == 1);
2652     if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
2653     {
2654         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
2655                                apiState.getUnpackRowLength()));
2656         currentUnpackState.rowLength = apiState.getUnpackRowLength();
2657     }
2658 
2659     if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
2660     {
2661         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
2662                                apiState.getUnpackSkipRows()));
2663         currentUnpackState.skipRows = apiState.getUnpackSkipRows();
2664     }
2665 
2666     if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
2667     {
2668         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
2669                                apiState.getUnpackSkipPixels()));
2670         currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
2671     }
2672 
2673     if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
2674     {
2675         cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
2676                                apiState.getUnpackImageHeight()));
2677         currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
2678     }
2679 
2680     if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
2681     {
2682         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
2683                                apiState.getUnpackSkipImages()));
2684         currentUnpackState.skipImages = apiState.getUnpackSkipImages();
2685     }
2686 
2687     // Clear state. Missing ES 3.x features.
2688     // TODO(http://anglebug.com/3662): Complete state capture.
2689     const gl::ColorF &currentClearColor = apiState.getColorClearValue();
2690     if (currentClearColor != gl::ColorF())
2691     {
2692         cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
2693                               currentClearColor.blue, currentClearColor.alpha));
2694     }
2695 
2696     if (apiState.getDepthClearValue() != 1.0f)
2697     {
2698         cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
2699     }
2700 
2701     if (apiState.getStencilClearValue() != 0)
2702     {
2703         cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
2704     }
2705 
2706     // Viewport / scissor / clipping planes.
2707     const gl::Rectangle &currentViewport = apiState.getViewport();
2708     if (currentViewport != gl::Rectangle())
2709     {
2710         cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
2711                             currentViewport.width, currentViewport.height));
2712     }
2713 
2714     if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
2715     {
2716         cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
2717     }
2718 
2719     if (apiState.isScissorTestEnabled())
2720     {
2721         capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
2722     }
2723 
2724     const gl::Rectangle &currentScissor = apiState.getScissor();
2725     if (currentScissor != gl::Rectangle())
2726     {
2727         cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
2728                            currentScissor.width, currentScissor.height));
2729     }
2730 
2731     if (apiState.isDitherEnabled())
2732     {
2733         capCap(GL_DITHER, apiState.isDitherEnabled());
2734     }
2735 
2736     const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
2737     for (const auto &syncIter : syncs)
2738     {
2739         // TODO: Create existing sync objects (http://anglebug.com/3662)
2740         (void)syncIter;
2741         UNIMPLEMENTED();
2742     }
2743 
2744     // Allow the replayState object to be destroyed conveniently.
2745     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
2746 }
2747 }  // namespace
2748 
ParamCapture()2749 ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup) {}
2750 
ParamCapture(const char * nameIn,ParamType typeIn)2751 ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn)
2752     : name(nameIn), type(typeIn), enumGroup(gl::GLenumGroup::DefaultGroup)
2753 {}
2754 
2755 ParamCapture::~ParamCapture() = default;
2756 
ParamCapture(ParamCapture && other)2757 ParamCapture::ParamCapture(ParamCapture &&other)
2758     : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup)
2759 {
2760     *this = std::move(other);
2761 }
2762 
operator =(ParamCapture && other)2763 ParamCapture &ParamCapture::operator=(ParamCapture &&other)
2764 {
2765     std::swap(name, other.name);
2766     std::swap(type, other.type);
2767     std::swap(value, other.value);
2768     std::swap(enumGroup, other.enumGroup);
2769     std::swap(data, other.data);
2770     std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex);
2771     std::swap(readBufferSizeBytes, other.readBufferSizeBytes);
2772     return *this;
2773 }
2774 
ParamBuffer()2775 ParamBuffer::ParamBuffer() {}
2776 
2777 ParamBuffer::~ParamBuffer() = default;
2778 
ParamBuffer(ParamBuffer && other)2779 ParamBuffer::ParamBuffer(ParamBuffer &&other)
2780 {
2781     *this = std::move(other);
2782 }
2783 
operator =(ParamBuffer && other)2784 ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other)
2785 {
2786     std::swap(mParamCaptures, other.mParamCaptures);
2787     std::swap(mClientArrayDataParam, other.mClientArrayDataParam);
2788     std::swap(mReadBufferSize, other.mReadBufferSize);
2789     std::swap(mReturnValueCapture, other.mReturnValueCapture);
2790     std::swap(mMappedBufferID, other.mMappedBufferID);
2791     return *this;
2792 }
2793 
getParam(const char * paramName,ParamType paramType,int index)2794 ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index)
2795 {
2796     ParamCapture &capture = mParamCaptures[index];
2797     ASSERT(capture.name == paramName);
2798     ASSERT(capture.type == paramType);
2799     return capture;
2800 }
2801 
getParam(const char * paramName,ParamType paramType,int index) const2802 const ParamCapture &ParamBuffer::getParam(const char *paramName,
2803                                           ParamType paramType,
2804                                           int index) const
2805 {
2806     return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index);
2807 }
2808 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index)2809 ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
2810                                             const char *paramName2,
2811                                             ParamType paramType,
2812                                             int index)
2813 {
2814     ParamCapture &capture = mParamCaptures[index];
2815     ASSERT(capture.name == paramName1 || capture.name == paramName2);
2816     ASSERT(capture.type == paramType);
2817     return capture;
2818 }
2819 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index) const2820 const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
2821                                                   const char *paramName2,
2822                                                   ParamType paramType,
2823                                                   int index) const
2824 {
2825     return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType,
2826                                                              index);
2827 }
2828 
addParam(ParamCapture && param)2829 void ParamBuffer::addParam(ParamCapture &&param)
2830 {
2831     if (param.arrayClientPointerIndex != -1)
2832     {
2833         ASSERT(mClientArrayDataParam == -1);
2834         mClientArrayDataParam = static_cast<int>(mParamCaptures.size());
2835     }
2836 
2837     mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize);
2838     mParamCaptures.emplace_back(std::move(param));
2839 }
2840 
addReturnValue(ParamCapture && returnValue)2841 void ParamBuffer::addReturnValue(ParamCapture &&returnValue)
2842 {
2843     mReturnValueCapture = std::move(returnValue);
2844 }
2845 
getClientArrayPointerParameter()2846 ParamCapture &ParamBuffer::getClientArrayPointerParameter()
2847 {
2848     ASSERT(hasClientArrayData());
2849     return mParamCaptures[mClientArrayDataParam];
2850 }
2851 
CallCapture(gl::EntryPoint entryPointIn,ParamBuffer && paramsIn)2852 CallCapture::CallCapture(gl::EntryPoint entryPointIn, ParamBuffer &&paramsIn)
2853     : entryPoint(entryPointIn), params(std::move(paramsIn))
2854 {}
2855 
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)2856 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn)
2857     : entryPoint(gl::EntryPoint::Invalid),
2858       customFunctionName(customFunctionNameIn),
2859       params(std::move(paramsIn))
2860 {}
2861 
2862 CallCapture::~CallCapture() = default;
2863 
CallCapture(CallCapture && other)2864 CallCapture::CallCapture(CallCapture &&other)
2865 {
2866     *this = std::move(other);
2867 }
2868 
operator =(CallCapture && other)2869 CallCapture &CallCapture::operator=(CallCapture &&other)
2870 {
2871     std::swap(entryPoint, other.entryPoint);
2872     std::swap(customFunctionName, other.customFunctionName);
2873     std::swap(params, other.params);
2874     return *this;
2875 }
2876 
name() const2877 const char *CallCapture::name() const
2878 {
2879     if (entryPoint == gl::EntryPoint::Invalid)
2880     {
2881         ASSERT(!customFunctionName.empty());
2882         return customFunctionName.c_str();
2883     }
2884 
2885     return gl::GetEntryPointName(entryPoint);
2886 }
2887 
ReplayContext(size_t readBufferSizebytes,const gl::AttribArray<size_t> & clientArraysSizebytes)2888 ReplayContext::ReplayContext(size_t readBufferSizebytes,
2889                              const gl::AttribArray<size_t> &clientArraysSizebytes)
2890 {
2891     mReadBuffer.resize(readBufferSizebytes);
2892 
2893     for (uint32_t i = 0; i < clientArraysSizebytes.size(); i++)
2894     {
2895         mClientArraysBuffer[i].resize(clientArraysSizebytes[i]);
2896     }
2897 }
~ReplayContext()2898 ReplayContext::~ReplayContext() {}
2899 
FrameCapture()2900 FrameCapture::FrameCapture()
2901     : mEnabled(true),
2902       mCompression(true),
2903       mClientVertexArrayMap{},
2904       mFrameIndex(0),
2905       mFrameStart(0),
2906       mFrameEnd(10),
2907       mClientArraySizes{},
2908       mReadBufferSize(0),
2909       mHasResourceType{}
2910 {
2911     reset();
2912 
2913 #if defined(ANGLE_PLATFORM_ANDROID)
2914     PrimeAndroidEnvironmentVariables();
2915 #endif
2916 
2917     std::string enabledFromEnv = angle::GetEnvironmentVar(kEnabledVarName);
2918     if (enabledFromEnv == "0")
2919     {
2920         mEnabled = false;
2921     }
2922 
2923     std::string pathFromEnv = angle::GetEnvironmentVar(kOutDirectoryVarName);
2924     if (pathFromEnv.empty())
2925     {
2926         mOutDirectory = GetDefaultOutDirectory();
2927     }
2928     else
2929     {
2930         mOutDirectory = pathFromEnv;
2931     }
2932 
2933     // Ensure the capture path ends with a slash.
2934     if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
2935     {
2936         mOutDirectory += '/';
2937     }
2938 
2939     std::string startFromEnv = angle::GetEnvironmentVar(kFrameStartVarName);
2940     if (!startFromEnv.empty())
2941     {
2942         mFrameStart = atoi(startFromEnv.c_str());
2943     }
2944 
2945     std::string endFromEnv = angle::GetEnvironmentVar(kFrameEndVarName);
2946     if (!endFromEnv.empty())
2947     {
2948         mFrameEnd = atoi(endFromEnv.c_str());
2949     }
2950 
2951     std::string labelFromEnv = angle::GetEnvironmentVar(kCaptureLabel);
2952     if (!labelFromEnv.empty())
2953     {
2954         // Optional label to provide unique file names and namespaces
2955         mCaptureLabel = labelFromEnv;
2956     }
2957 
2958     std::string compressionFromEnv = angle::GetEnvironmentVar(kCompression);
2959     if (compressionFromEnv == "0")
2960     {
2961         mCompression = false;
2962     }
2963 }
2964 
2965 FrameCapture::~FrameCapture() = default;
2966 
captureCompressedTextureData(const gl::Context * context,const CallCapture & call)2967 void FrameCapture::captureCompressedTextureData(const gl::Context *context, const CallCapture &call)
2968 {
2969     // For compressed textures, track a shadow copy of the data
2970     // for use during mid-execution capture, rather than reading it back
2971     // with ANGLE_get_image
2972 
2973     // Storing the compressed data is handled the same for all entry points,
2974     // they just have slightly different parameter locations
2975     int dataParamOffset    = -1;
2976     int xoffsetParamOffset = -1;
2977     int yoffsetParamOffset = -1;
2978     int zoffsetParamOffset = -1;
2979     int widthParamOffset   = -1;
2980     int heightParamOffset  = -1;
2981     int depthParamOffset   = -1;
2982     switch (call.entryPoint)
2983     {
2984         case gl::EntryPoint::CompressedTexSubImage3D:
2985             xoffsetParamOffset = 2;
2986             yoffsetParamOffset = 3;
2987             zoffsetParamOffset = 4;
2988             widthParamOffset   = 5;
2989             heightParamOffset  = 6;
2990             depthParamOffset   = 7;
2991             dataParamOffset    = 10;
2992             break;
2993         case gl::EntryPoint::CompressedTexImage3D:
2994             widthParamOffset  = 4;
2995             heightParamOffset = 5;
2996             depthParamOffset  = 6;
2997             dataParamOffset   = 9;
2998             break;
2999         case gl::EntryPoint::CompressedTexSubImage2D:
3000             xoffsetParamOffset = 2;
3001             yoffsetParamOffset = 3;
3002             widthParamOffset   = 4;
3003             heightParamOffset  = 5;
3004             dataParamOffset    = 8;
3005             break;
3006         case gl::EntryPoint::CompressedTexImage2D:
3007             widthParamOffset  = 3;
3008             heightParamOffset = 4;
3009             dataParamOffset   = 7;
3010             break;
3011         default:
3012             // There should be no other callers of this function
3013             ASSERT(0);
3014             break;
3015     }
3016 
3017     gl::Buffer *pixelUnpackBuffer =
3018         context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
3019 
3020     const uint8_t *data = static_cast<const uint8_t *>(
3021         call.params.getParam("data", ParamType::TvoidConstPointer, dataParamOffset)
3022             .value.voidConstPointerVal);
3023 
3024     GLsizei imageSize = call.params.getParam("imageSize", ParamType::TGLsizei, dataParamOffset - 1)
3025                             .value.GLsizeiVal;
3026 
3027     const uint8_t *pixelData = nullptr;
3028 
3029     if (pixelUnpackBuffer)
3030     {
3031         // If using pixel unpack buffer, map the buffer and track its data
3032         ASSERT(!pixelUnpackBuffer->isMapped());
3033         (void)pixelUnpackBuffer->mapRange(context, reinterpret_cast<GLintptr>(data), imageSize,
3034                                           GL_MAP_READ_BIT);
3035 
3036         pixelData = reinterpret_cast<const uint8_t *>(pixelUnpackBuffer->getMapPointer());
3037     }
3038     else
3039     {
3040         pixelData = data;
3041     }
3042 
3043     if (!pixelData)
3044     {
3045         // If no pointer was provided and we weren't able to map the buffer, there is no data to
3046         // capture
3047         return;
3048     }
3049 
3050     // Look up the texture type
3051     gl::TextureTarget targetPacked =
3052         call.params.getParam("targetPacked", ParamType::TTextureTarget, 0).value.TextureTargetVal;
3053     gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
3054 
3055     // Create a copy of the incoming data
3056     std::vector<uint8_t> compressedData;
3057     compressedData.assign(pixelData, pixelData + imageSize);
3058 
3059     // Look up the currently bound texture
3060     gl::Texture *texture = context->getState().getTargetTexture(textureType);
3061     ASSERT(texture);
3062 
3063     // Record the data, indexed by textureID and level
3064     GLint level             = call.params.getParam("level", ParamType::TGLint, 1).value.GLintVal;
3065     auto foundTextureLevels = mCachedTextureLevelData.find(texture->id());
3066     if (foundTextureLevels == mCachedTextureLevelData.end())
3067     {
3068         // Initialize the texture ID data.
3069         auto emplaceResult = mCachedTextureLevelData.emplace(texture->id(), TextureLevels());
3070         ASSERT(emplaceResult.second);
3071         foundTextureLevels = emplaceResult.first;
3072     }
3073 
3074     // Get the format of the texture for use with the compressed block size math.
3075     const gl::InternalFormat &format = *texture->getFormat(targetPacked, level).info;
3076 
3077     TextureLevels &foundLevels = foundTextureLevels->second;
3078     auto foundLevel            = foundLevels.find(level);
3079 
3080     // Divide dimensions according to block size.
3081     const gl::Extents &levelExtents = texture->getExtents(targetPacked, level);
3082 
3083     if (foundLevel == foundLevels.end())
3084     {
3085         // Initialize texture rectangle data. Default init to zero for stability.
3086         GLuint sizeInBytes;
3087         bool result = format.computeCompressedImageSize(levelExtents, &sizeInBytes);
3088         ASSERT(result);
3089 
3090         std::vector<uint8_t> newPixelData(sizeInBytes, 0);
3091         auto emplaceResult = foundLevels.emplace(level, std::move(newPixelData));
3092         ASSERT(emplaceResult.second);
3093         foundLevel = emplaceResult.first;
3094     }
3095 
3096     // Unpack the various pixel rectangle parameters.
3097     ASSERT(widthParamOffset != -1);
3098     ASSERT(heightParamOffset != -1);
3099     GLsizei pixelWidth =
3100         call.params.getParam("width", ParamType::TGLsizei, widthParamOffset).value.GLsizeiVal;
3101     GLsizei pixelHeight =
3102         call.params.getParam("height", ParamType::TGLsizei, heightParamOffset).value.GLsizeiVal;
3103     GLsizei pixelDepth = 1;
3104     if (depthParamOffset != -1)
3105     {
3106         pixelDepth =
3107             call.params.getParam("depth", ParamType::TGLsizei, depthParamOffset).value.GLsizeiVal;
3108     }
3109 
3110     GLint xoffset = 0;
3111     GLint yoffset = 0;
3112     GLint zoffset = 0;
3113 
3114     if (xoffsetParamOffset != -1)
3115     {
3116         xoffset =
3117             call.params.getParam("xoffset", ParamType::TGLint, xoffsetParamOffset).value.GLintVal;
3118     }
3119 
3120     if (yoffsetParamOffset != -1)
3121     {
3122         yoffset =
3123             call.params.getParam("yoffset", ParamType::TGLint, yoffsetParamOffset).value.GLintVal;
3124     }
3125 
3126     if (zoffsetParamOffset != -1)
3127     {
3128         zoffset =
3129             call.params.getParam("zoffset", ParamType::TGLint, zoffsetParamOffset).value.GLintVal;
3130     }
3131 
3132     // Since we're dealing in 4x4 blocks, scale down the width/height pixel offsets.
3133     ASSERT(format.compressedBlockWidth == 4);
3134     ASSERT(format.compressedBlockHeight == 4);
3135     ASSERT(format.compressedBlockDepth == 1);
3136     pixelWidth >>= 2;
3137     pixelHeight >>= 2;
3138     xoffset >>= 2;
3139     yoffset >>= 2;
3140 
3141     // Update pixel data.
3142     std::vector<uint8_t> &levelData = foundLevel->second;
3143 
3144     GLint pixelBytes = static_cast<GLint>(format.pixelBytes);
3145 
3146     GLint pixelRowPitch   = pixelWidth * pixelBytes;
3147     GLint pixelDepthPitch = pixelRowPitch * pixelHeight;
3148     GLint levelRowPitch   = (levelExtents.width >> 2) * pixelBytes;
3149     GLint levelDepthPitch = levelRowPitch * (levelExtents.height >> 2);
3150 
3151     for (GLint zindex = 0; zindex < pixelDepth; ++zindex)
3152     {
3153         GLint z = zindex + zoffset;
3154         for (GLint yindex = 0; yindex < pixelHeight; ++yindex)
3155         {
3156             GLint y           = yindex + yoffset;
3157             GLint pixelOffset = zindex * pixelDepthPitch + yindex * pixelRowPitch;
3158             GLint levelOffset = z * levelDepthPitch + y * levelRowPitch + xoffset * pixelBytes;
3159             memcpy(&levelData[levelOffset], &pixelData[pixelOffset], pixelRowPitch);
3160         }
3161     }
3162 
3163     if (pixelUnpackBuffer)
3164     {
3165         GLboolean success;
3166         (void)pixelUnpackBuffer->unmap(context, &success);
3167         ASSERT(success);
3168     }
3169 }
3170 
maybeCaptureClientData(const gl::Context * context,CallCapture & call)3171 void FrameCapture::maybeCaptureClientData(const gl::Context *context, CallCapture &call)
3172 {
3173     switch (call.entryPoint)
3174     {
3175         case gl::EntryPoint::VertexAttribPointer:
3176         {
3177             // Get array location
3178             GLuint index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
3179 
3180             if (call.params.hasClientArrayData())
3181             {
3182                 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
3183             }
3184             else
3185             {
3186                 mClientVertexArrayMap[index] = -1;
3187             }
3188             break;
3189         }
3190 
3191         case gl::EntryPoint::DeleteBuffers:
3192         {
3193             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
3194             const gl::BufferID *bufferIDs =
3195                 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
3196                     .value.BufferIDConstPointerVal;
3197             for (GLsizei i = 0; i < count; i++)
3198             {
3199                 // For each buffer being deleted, check our backup of data and remove it
3200                 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
3201                 if (bufferDataInfo != mBufferDataMap.end())
3202                 {
3203                     mBufferDataMap.erase(bufferDataInfo);
3204                 }
3205             }
3206             break;
3207         }
3208 
3209         case gl::EntryPoint::DrawArrays:
3210         {
3211             if (context->getStateCache().hasAnyActiveClientAttrib())
3212             {
3213                 // Get counts from paramBuffer.
3214                 GLint firstVertex =
3215                     call.params.getParam("first", ParamType::TGLint, 1).value.GLintVal;
3216                 GLsizei drawCount =
3217                     call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
3218                 captureClientArraySnapshot(context, firstVertex + drawCount, 1);
3219             }
3220             break;
3221         }
3222 
3223         case gl::EntryPoint::DrawElements:
3224         {
3225             if (context->getStateCache().hasAnyActiveClientAttrib())
3226             {
3227                 GLsizei count =
3228                     call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
3229                 gl::DrawElementsType drawElementsType =
3230                     call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
3231                         .value.DrawElementsTypeVal;
3232                 const void *indices =
3233                     call.params.getParam("indices", ParamType::TvoidConstPointer, 3)
3234                         .value.voidConstPointerVal;
3235 
3236                 gl::IndexRange indexRange;
3237 
3238                 bool restart = context->getState().isPrimitiveRestartEnabled();
3239 
3240                 gl::Buffer *elementArrayBuffer =
3241                     context->getState().getVertexArray()->getElementArrayBuffer();
3242                 if (elementArrayBuffer)
3243                 {
3244                     size_t offset = reinterpret_cast<size_t>(indices);
3245                     (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset,
3246                                                             count, restart, &indexRange);
3247                 }
3248                 else
3249                 {
3250                     indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
3251                 }
3252 
3253                 // index starts from 0
3254                 captureClientArraySnapshot(context, indexRange.end + 1, 1);
3255             }
3256             break;
3257         }
3258 
3259         case gl::EntryPoint::CompileShader:
3260         {
3261             // Refresh the cached shader sources.
3262             gl::ShaderProgramID shaderID =
3263                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
3264                     .value.ShaderProgramIDVal;
3265             const gl::Shader *shader       = context->getShader(shaderID);
3266             mCachedShaderSources[shaderID] = shader->getSourceString();
3267             break;
3268         }
3269 
3270         case gl::EntryPoint::LinkProgram:
3271         {
3272             // Refresh the cached program sources.
3273             gl::ShaderProgramID programID =
3274                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
3275                     .value.ShaderProgramIDVal;
3276             const gl::Program *program       = context->getProgramResolveLink(programID);
3277             mCachedProgramSources[programID] = GetAttachedProgramSources(program);
3278             break;
3279         }
3280 
3281         case gl::EntryPoint::CompressedTexImage1D:
3282         case gl::EntryPoint::CompressedTexSubImage1D:
3283         {
3284             UNIMPLEMENTED();
3285             break;
3286         }
3287 
3288         case gl::EntryPoint::CompressedTexImage2D:
3289         case gl::EntryPoint::CompressedTexImage3D:
3290         case gl::EntryPoint::CompressedTexSubImage2D:
3291         case gl::EntryPoint::CompressedTexSubImage3D:
3292         {
3293             captureCompressedTextureData(context, call);
3294             break;
3295         }
3296 
3297         case gl::EntryPoint::DeleteTextures:
3298         {
3299             // Free any TextureLevelDataMap entries being tracked for this texture
3300             // This is to cover the scenario where a texture has been created, its
3301             // levels cached, then texture deleted and recreated, receiving the same ID
3302 
3303             // Look up how many textures are being deleted
3304             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
3305 
3306             // Look up the pointer to list of textures
3307             const gl::TextureID *textureIDs =
3308                 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
3309                     .value.TextureIDConstPointerVal;
3310 
3311             // For each texture listed for deletion
3312             for (int32_t i = 0; i < n; ++i)
3313             {
3314                 // Look it up in the cache, and delete it if found
3315                 const auto &foundTextureLevels = mCachedTextureLevelData.find(textureIDs[i]);
3316                 if (foundTextureLevels != mCachedTextureLevelData.end())
3317                 {
3318                     // Delete all texture levels at once
3319                     mCachedTextureLevelData.erase(foundTextureLevels);
3320                 }
3321             }
3322             break;
3323         }
3324 
3325         case gl::EntryPoint::MapBuffer:
3326         {
3327             UNIMPLEMENTED();
3328             break;
3329         }
3330         case gl::EntryPoint::MapBufferOES:
3331         {
3332             UNIMPLEMENTED();
3333             break;
3334         }
3335         case gl::EntryPoint::UnmapNamedBuffer:
3336         {
3337             UNIMPLEMENTED();
3338             break;
3339         }
3340 
3341         case gl::EntryPoint::MapBufferRange:
3342         case gl::EntryPoint::MapBufferRangeEXT:
3343         {
3344             // Use the access bits to see if contents may be modified
3345             GLbitfield access =
3346                 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
3347 
3348             if (access & GL_MAP_WRITE_BIT)
3349             {
3350                 // If this buffer was mapped writable, we don't have any visibility into what
3351                 // happens to it. Therefore, remember the details about it, and we'll read it back
3352                 // on Unmap to repopulate it during replay.
3353 
3354                 gl::BufferBinding target =
3355                     call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
3356                         .value.BufferBindingVal;
3357                 GLintptr offset =
3358                     call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
3359                 GLsizeiptr length =
3360                     call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
3361 
3362                 gl::Buffer *buffer           = context->getState().getTargetBuffer(target);
3363                 mBufferDataMap[buffer->id()] = std::make_pair(offset, length);
3364 
3365                 // Track the bufferID that was just mapped
3366                 call.params.setMappedBufferID(buffer->id());
3367             }
3368             break;
3369         }
3370 
3371         case gl::EntryPoint::UnmapBuffer:
3372         case gl::EntryPoint::UnmapBufferOES:
3373         {
3374             // See if we need to capture the buffer contents
3375             captureMappedBufferSnapshot(context, call);
3376             break;
3377         }
3378 
3379         default:
3380             break;
3381     }
3382 }
3383 
captureCall(const gl::Context * context,CallCapture && call)3384 void FrameCapture::captureCall(const gl::Context *context, CallCapture &&call)
3385 {
3386     // Process client data snapshots.
3387     maybeCaptureClientData(context, call);
3388 
3389     mReadBufferSize = std::max(mReadBufferSize, call.params.getReadBufferSize());
3390     mFrameCalls.emplace_back(std::move(call));
3391 
3392     maybeCapturePostCallUpdates(context);
3393 }
3394 
maybeCapturePostCallUpdates(const gl::Context * context)3395 void FrameCapture::maybeCapturePostCallUpdates(const gl::Context *context)
3396 {
3397     // Process resource ID updates.
3398     MaybeCaptureUpdateResourceIDs(&mFrameCalls);
3399 
3400     const CallCapture &lastCall = mFrameCalls.back();
3401     switch (lastCall.entryPoint)
3402     {
3403         case gl::EntryPoint::LinkProgram:
3404         {
3405             const ParamCapture &param =
3406                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
3407             const gl::Program *program =
3408                 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
3409             CaptureUpdateUniformLocations(program, &mFrameCalls);
3410             break;
3411         }
3412         case gl::EntryPoint::UseProgram:
3413             CaptureUpdateCurrentProgram(lastCall, &mFrameCalls);
3414             break;
3415         case gl::EntryPoint::DeleteProgram:
3416         {
3417             const ParamCapture &param =
3418                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
3419             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
3420             break;
3421         }
3422         case gl::EntryPoint::BindFramebuffer:
3423         {
3424             const ParamCapture &target = lastCall.params.getParam("target", ParamType::TGLenum, 0);
3425             const ParamCapture &framebuffer =
3426                 lastCall.params.getParam("framebufferPacked", ParamType::TFramebufferID, 1);
3427             CaptureOnFramebufferChange(target.value.GLenumVal, framebuffer.value.FramebufferIDVal,
3428                                        &mFrameCalls);
3429             break;
3430         }
3431         default:
3432             break;
3433     }
3434 }
3435 
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)3436 void FrameCapture::captureClientArraySnapshot(const gl::Context *context,
3437                                               size_t vertexCount,
3438                                               size_t instanceCount)
3439 {
3440     const gl::VertexArray *vao = context->getState().getVertexArray();
3441 
3442     // Capture client array data.
3443     for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
3444     {
3445         const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
3446         const gl::VertexBinding &binding  = vao->getVertexBinding(attrib.bindingIndex);
3447 
3448         int callIndex = mClientVertexArrayMap[attribIndex];
3449 
3450         if (callIndex != -1)
3451         {
3452             size_t count = vertexCount;
3453 
3454             if (binding.getDivisor() > 0)
3455             {
3456                 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
3457                                                binding.getDivisor());
3458             }
3459 
3460             // The last capture element doesn't take up the full stride.
3461             size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
3462 
3463             CallCapture &call   = mFrameCalls[callIndex];
3464             ParamCapture &param = call.params.getClientArrayPointerParameter();
3465             ASSERT(param.type == ParamType::TvoidConstPointer);
3466 
3467             ParamBuffer updateParamBuffer;
3468             updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
3469                                                    static_cast<uint32_t>(attribIndex));
3470 
3471             ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
3472             CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
3473             updateParamBuffer.addParam(std::move(updateMemory));
3474 
3475             updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
3476 
3477             mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
3478 
3479             mClientArraySizes[attribIndex] =
3480                 std::max(mClientArraySizes[attribIndex], bytesToCapture);
3481         }
3482     }
3483 }
3484 
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)3485 void FrameCapture::captureMappedBufferSnapshot(const gl::Context *context, const CallCapture &call)
3486 {
3487     // If the buffer was mapped writable, we need to restore its data, since we have no visibility
3488     // into what the client did to the buffer while mapped
3489     // This sequence will result in replay calls like this:
3490     //   ...
3491     //   gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
3492     //                                                        GL_MAP_WRITE_BIT);
3493     //   ...
3494     //   UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
3495     //   glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
3496     //   ...
3497 
3498     // Re-map the buffer, using the info we tracked about the buffer
3499     gl::BufferBinding target =
3500         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
3501 
3502     gl::Buffer *buffer         = context->getState().getTargetBuffer(target);
3503     const auto &bufferDataInfo = mBufferDataMap.find(buffer->id());
3504     if (bufferDataInfo == mBufferDataMap.end())
3505     {
3506         // This buffer was not marked writable, so we did not back it up
3507         return;
3508     }
3509 
3510     GLintptr offset   = bufferDataInfo->second.first;
3511     GLsizeiptr length = bufferDataInfo->second.second;
3512 
3513     // Map the buffer so we can copy its contents out
3514     ASSERT(!buffer->isMapped());
3515     angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
3516     if (result != angle::Result::Continue)
3517     {
3518         ERR() << "Failed to mapRange of buffer" << std::endl;
3519     }
3520     const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
3521 
3522     // Create the parameters to our helper for use during replay
3523     ParamBuffer dataParamBuffer;
3524 
3525     // Pass in the target buffer ID
3526     dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
3527 
3528     // Capture the current buffer data with a binary param
3529     ParamCapture captureData("source", ParamType::TvoidConstPointer);
3530     CaptureMemory(data, length, &captureData);
3531     dataParamBuffer.addParam(std::move(captureData));
3532 
3533     // Also track its size for use with memcpy
3534     dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
3535 
3536     // Call the helper that populates the buffer with captured data
3537     mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
3538 
3539     // Unmap the buffer and move on
3540     GLboolean dontCare;
3541     (void)buffer->unmap(context, &dontCare);
3542 }
3543 
onEndFrame(const gl::Context * context)3544 void FrameCapture::onEndFrame(const gl::Context *context)
3545 {
3546     // Note that we currently capture before the start frame to collect shader and program sources.
3547     if (!mFrameCalls.empty() && mFrameIndex >= mFrameStart)
3548     {
3549         WriteCppReplay(mCompression, mOutDirectory, context->id(), mCaptureLabel, mFrameIndex,
3550                        mFrameCalls, mSetupCalls, &mBinaryData);
3551 
3552         // Save the index files after the last frame.
3553         if (mFrameIndex == mFrameEnd)
3554         {
3555             WriteCppReplayIndexFiles(mCompression, mOutDirectory, context->id(), mCaptureLabel,
3556                                      mFrameStart, mFrameEnd, mReadBufferSize, mClientArraySizes,
3557                                      mHasResourceType);
3558 
3559             if (!mBinaryData.empty())
3560             {
3561                 SaveBinaryData(mCompression, mOutDirectory, context->id(), mCaptureLabel,
3562                                mBinaryData);
3563                 mBinaryData.clear();
3564             }
3565         }
3566     }
3567 
3568     // Count resource IDs. This is also done on every frame. It could probably be done by checking
3569     // the GL state instead of the calls.
3570     for (const CallCapture &call : mFrameCalls)
3571     {
3572         for (const ParamCapture &param : call.params.getParamCaptures())
3573         {
3574             ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
3575             if (idType != ResourceIDType::InvalidEnum)
3576             {
3577                 mHasResourceType.set(idType);
3578             }
3579         }
3580     }
3581 
3582     reset();
3583     mFrameIndex++;
3584 
3585     if (enabled() && mFrameIndex == mFrameStart)
3586     {
3587         mSetupCalls.clear();
3588         CaptureMidExecutionSetup(context, &mSetupCalls, mCachedShaderSources, mCachedProgramSources,
3589                                  mCachedTextureLevelData);
3590     }
3591 }
3592 
3593 DataCounters::DataCounters() = default;
3594 
3595 DataCounters::~DataCounters() = default;
3596 
getAndIncrement(gl::EntryPoint entryPoint,const std::string & paramName)3597 int DataCounters::getAndIncrement(gl::EntryPoint entryPoint, const std::string &paramName)
3598 {
3599     Counter counterKey = {entryPoint, paramName};
3600     return mData[counterKey]++;
3601 }
3602 
isCapturing() const3603 bool FrameCapture::isCapturing() const
3604 {
3605     // Currently we will always do a capture up until the last frame. In the future we could improve
3606     // mid execution capture by only capturing between the start and end frames. The only necessary
3607     // reason we need to capture before the start is for attached program and shader sources.
3608     return mEnabled && mFrameIndex <= mFrameEnd;
3609 }
3610 
replay(gl::Context * context)3611 void FrameCapture::replay(gl::Context *context)
3612 {
3613     ReplayContext replayContext(mReadBufferSize, mClientArraySizes);
3614     for (const CallCapture &call : mFrameCalls)
3615     {
3616         INFO() << "frame index: " << mFrameIndex << " " << call.name();
3617 
3618         if (call.entryPoint == gl::EntryPoint::Invalid)
3619         {
3620             if (call.customFunctionName == "UpdateClientArrayPointer")
3621             {
3622                 GLint arrayIndex =
3623                     call.params.getParam("arrayIndex", ParamType::TGLint, 0).value.GLintVal;
3624                 ASSERT(arrayIndex < gl::MAX_VERTEX_ATTRIBS);
3625 
3626                 const ParamCapture &pointerParam =
3627                     call.params.getParam("pointer", ParamType::TvoidConstPointer, 1);
3628                 ASSERT(pointerParam.data.size() == 1);
3629                 const void *pointer = pointerParam.data[0].data();
3630 
3631                 size_t size = static_cast<size_t>(
3632                     call.params.getParam("size", ParamType::TGLuint64, 2).value.GLuint64Val);
3633 
3634                 std::vector<uint8_t> &curClientArrayBuffer =
3635                     replayContext.getClientArraysBuffer()[arrayIndex];
3636                 ASSERT(curClientArrayBuffer.size() >= size);
3637                 memcpy(curClientArrayBuffer.data(), pointer, size);
3638             }
3639             continue;
3640         }
3641 
3642         ReplayCall(context, &replayContext, call);
3643     }
3644 }
3645 
reset()3646 void FrameCapture::reset()
3647 {
3648     mFrameCalls.clear();
3649     mSetupCalls.clear();
3650     mClientVertexArrayMap.fill(-1);
3651 
3652     // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
3653     // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
3654     // necessary.
3655 }
3656 
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)3657 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
3658 {
3659     std::vector<uint8_t> data(size);
3660     memcpy(data.data(), source, size);
3661     paramCapture->data.emplace_back(std::move(data));
3662 }
3663 
CaptureString(const GLchar * str,ParamCapture * paramCapture)3664 void CaptureString(const GLchar *str, ParamCapture *paramCapture)
3665 {
3666     // include the '\0' suffix
3667     CaptureMemory(str, strlen(str) + 1, paramCapture);
3668 }
3669 
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)3670 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
3671 {
3672     // Write the incoming string up to limit, including null terminator
3673     size_t length = strlen(str) + 1;
3674 
3675     if (length > limit)
3676     {
3677         // If too many characters, resize the string to fit in the limit
3678         std::string newStr = str;
3679         newStr.resize(limit - 1);
3680         CaptureString(newStr.c_str(), paramCapture);
3681     }
3682     else
3683     {
3684         CaptureMemory(str, length, paramCapture);
3685     }
3686 }
3687 
GetLinkedProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)3688 gl::Program *GetLinkedProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
3689 {
3690     gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
3691     ASSERT(program->isLinked());
3692     return program;
3693 }
3694 
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)3695 void CaptureGetParameter(const gl::State &glState,
3696                          GLenum pname,
3697                          size_t typeSize,
3698                          ParamCapture *paramCapture)
3699 {
3700     GLenum nativeType;
3701     unsigned int numParams;
3702     if (!gl::GetQueryParameterInfo(glState, pname, &nativeType, &numParams))
3703     {
3704         numParams = 1;
3705     }
3706 
3707     paramCapture->readBufferSizeBytes = typeSize * numParams;
3708 }
3709 
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)3710 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
3711 {
3712     paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
3713     CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
3714 }
3715 
3716 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)3717 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
3718                                                   const CallCapture &call,
3719                                                   GLboolean value)
3720 {
3721     switch (value)
3722     {
3723         case GL_TRUE:
3724             os << "GL_TRUE";
3725             break;
3726         case GL_FALSE:
3727             os << "GL_FALSE";
3728             break;
3729         default:
3730             os << "GL_INVALID_ENUM";
3731     }
3732 }
3733 
3734 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)3735 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
3736                                                          const CallCapture &call,
3737                                                          const void *value)
3738 {
3739     if (value == 0)
3740     {
3741         os << "nullptr";
3742     }
3743     else
3744     {
3745         os << "reinterpret_cast<const void *>("
3746            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
3747     }
3748 }
3749 
3750 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)3751 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
3752                                                        const CallCapture &call,
3753                                                        GLDEBUGPROCKHR value)
3754 {}
3755 
3756 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)3757 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
3758                                                     const CallCapture &call,
3759                                                     GLDEBUGPROC value)
3760 {}
3761 
3762 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)3763 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
3764                                                  const CallCapture &call,
3765                                                  gl::BufferID value)
3766 {
3767     os << "gBufferMap[" << value.value << "]";
3768 }
3769 
3770 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)3771 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
3772                                                   const CallCapture &call,
3773                                                   gl::FenceNVID value)
3774 {
3775     os << "gFenceMap[" << value.value << "]";
3776 }
3777 
3778 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)3779 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
3780                                                       const CallCapture &call,
3781                                                       gl::FramebufferID value)
3782 {
3783     os << "gFramebufferMap[" << value.value << "]";
3784 }
3785 
3786 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)3787 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
3788                                                        const CallCapture &call,
3789                                                        gl::MemoryObjectID value)
3790 {
3791     os << "gMemoryObjectMap[" << value.value << "]";
3792 }
3793 
3794 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)3795 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
3796                                                           const CallCapture &call,
3797                                                           gl::ProgramPipelineID value)
3798 {
3799     os << "gProgramPipelineMap[" << value.value << "]";
3800 }
3801 
3802 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)3803 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
3804                                                 const CallCapture &call,
3805                                                 gl::QueryID value)
3806 {
3807     os << "gQueryMap[" << value.value << "]";
3808 }
3809 
3810 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)3811 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
3812                                                        const CallCapture &call,
3813                                                        gl::RenderbufferID value)
3814 {
3815     os << "gRenderbufferMap[" << value.value << "]";
3816 }
3817 
3818 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)3819 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
3820                                                   const CallCapture &call,
3821                                                   gl::SamplerID value)
3822 {
3823     os << "gSamplerMap[" << value.value << "]";
3824 }
3825 
3826 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)3827 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
3828                                                     const CallCapture &call,
3829                                                     gl::SemaphoreID value)
3830 {
3831     os << "gSempahoreMap[" << value.value << "]";
3832 }
3833 
3834 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)3835 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
3836                                                         const CallCapture &call,
3837                                                         gl::ShaderProgramID value)
3838 {
3839     os << "gShaderProgramMap[" << value.value << "]";
3840 }
3841 
3842 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsync value)3843 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
3844                                                const CallCapture &call,
3845                                                GLsync value)
3846 {
3847     os << "gSyncMap[" << SyncIndexValue(value) << "]";
3848 }
3849 
3850 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)3851 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
3852                                                   const CallCapture &call,
3853                                                   gl::TextureID value)
3854 {
3855     os << "gTextureMap[" << value.value << "]";
3856 }
3857 
3858 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)3859 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
3860                                                             const CallCapture &call,
3861                                                             gl::TransformFeedbackID value)
3862 {
3863     os << "gTransformFeedbackMap[" << value.value << "]";
3864 }
3865 
3866 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)3867 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
3868                                                       const CallCapture &call,
3869                                                       gl::VertexArrayID value)
3870 {
3871     os << "gVertexArrayMap[" << value.value << "]";
3872 }
3873 
FindShaderProgramIDInCall(const CallCapture & call,gl::ShaderProgramID * idOut)3874 bool FindShaderProgramIDInCall(const CallCapture &call, gl::ShaderProgramID *idOut)
3875 {
3876     for (const ParamCapture &param : call.params.getParamCaptures())
3877     {
3878         if (param.type == ParamType::TShaderProgramID && param.name == "programPacked")
3879         {
3880             *idOut = param.value.ShaderProgramIDVal;
3881             return true;
3882         }
3883     }
3884 
3885     return false;
3886 }
3887 
3888 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)3889 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
3890                                                         const CallCapture &call,
3891                                                         gl::UniformLocation value)
3892 {
3893     if (value.value == -1)
3894     {
3895         os << "-1";
3896         return;
3897     }
3898 
3899     os << "gUniformLocations[";
3900 
3901     // Find the program from the call parameters.
3902     gl::ShaderProgramID programID;
3903     if (FindShaderProgramIDInCall(call, &programID))
3904     {
3905         os << "gShaderProgramMap[" << programID.value << "]";
3906     }
3907     else
3908     {
3909         os << "gCurrentProgram";
3910     }
3911 
3912     os << "][" << value.value << "]";
3913 }
3914 }  // namespace angle
3915