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