• 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/capture/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/angle_version_info.h"
20 #include "common/mathutil.h"
21 #include "common/serializer/JsonSerializer.h"
22 #include "common/string_utils.h"
23 #include "common/system_utils.h"
24 #include "libANGLE/Config.h"
25 #include "libANGLE/Context.h"
26 #include "libANGLE/Display.h"
27 #include "libANGLE/Fence.h"
28 #include "libANGLE/Framebuffer.h"
29 #include "libANGLE/GLES1Renderer.h"
30 #include "libANGLE/Query.h"
31 #include "libANGLE/ResourceMap.h"
32 #include "libANGLE/Shader.h"
33 #include "libANGLE/Surface.h"
34 #include "libANGLE/VertexArray.h"
35 #include "libANGLE/capture/capture_gles_1_0_autogen.h"
36 #include "libANGLE/capture/capture_gles_2_0_autogen.h"
37 #include "libANGLE/capture/capture_gles_3_0_autogen.h"
38 #include "libANGLE/capture/capture_gles_3_1_autogen.h"
39 #include "libANGLE/capture/capture_gles_3_2_autogen.h"
40 #include "libANGLE/capture/capture_gles_ext_autogen.h"
41 #include "libANGLE/capture/frame_capture_utils.h"
42 #include "libANGLE/capture/gl_enum_utils.h"
43 #include "libANGLE/entry_points_utils.h"
44 #include "libANGLE/queryconversions.h"
45 #include "libANGLE/queryutils.h"
46 #include "third_party/ceval/ceval.h"
47 
48 #define USE_SYSTEM_ZLIB
49 #include "compression_utils_portable.h"
50 
51 #if !ANGLE_CAPTURE_ENABLED
52 #    error Frame capture must be enabled to include this file.
53 #endif  // !ANGLE_CAPTURE_ENABLED
54 
55 namespace angle
56 {
57 namespace
58 {
59 
60 constexpr char kEnabledVarName[]        = "ANGLE_CAPTURE_ENABLED";
61 constexpr char kOutDirectoryVarName[]   = "ANGLE_CAPTURE_OUT_DIR";
62 constexpr char kFrameStartVarName[]     = "ANGLE_CAPTURE_FRAME_START";
63 constexpr char kFrameEndVarName[]       = "ANGLE_CAPTURE_FRAME_END";
64 constexpr char kTriggerVarName[]        = "ANGLE_CAPTURE_TRIGGER";
65 constexpr char kCaptureLabelVarName[]   = "ANGLE_CAPTURE_LABEL";
66 constexpr char kCompressionVarName[]    = "ANGLE_CAPTURE_COMPRESSION";
67 constexpr char kSerializeStateVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
68 constexpr char kValidationVarName[]     = "ANGLE_CAPTURE_VALIDATION";
69 constexpr char kValidationExprVarName[] = "ANGLE_CAPTURE_VALIDATION_EXPR";
70 constexpr char kTrimEnabledVarName[]    = "ANGLE_CAPTURE_TRIM_ENABLED";
71 constexpr char kSourceSizeVarName[]     = "ANGLE_CAPTURE_SOURCE_SIZE";
72 
73 constexpr size_t kBinaryAlignment   = 16;
74 constexpr size_t kFunctionSizeLimit = 5000;
75 
76 // Limit based on MSVC Compiler Error C2026
77 constexpr size_t kStringLengthLimit = 16380;
78 
79 // Default limit to number of bytes in a capture source files.
80 constexpr size_t kDefaultSourceFileSizeThreshold = 400000;
81 
82 // Android debug properties that correspond to the above environment variables
83 constexpr char kAndroidEnabled[]        = "debug.angle.capture.enabled";
84 constexpr char kAndroidOutDir[]         = "debug.angle.capture.out_dir";
85 constexpr char kAndroidFrameStart[]     = "debug.angle.capture.frame_start";
86 constexpr char kAndroidFrameEnd[]       = "debug.angle.capture.frame_end";
87 constexpr char kAndroidTrigger[]        = "debug.angle.capture.trigger";
88 constexpr char kAndroidCaptureLabel[]   = "debug.angle.capture.label";
89 constexpr char kAndroidCompression[]    = "debug.angle.capture.compression";
90 constexpr char kAndroidValidation[]     = "debug.angle.capture.validation";
91 constexpr char kAndroidValidationExpr[] = "debug.angle.capture.validation_expr";
92 constexpr char kAndroidTrimEnabled[]    = "debug.angle.capture.trim_enabled";
93 constexpr char kAndroidSourceSize[]     = "debug.angle.capture.source_size";
94 
95 struct FramebufferCaptureFuncs
96 {
FramebufferCaptureFuncsangle::__anonf35832ea0111::FramebufferCaptureFuncs97     FramebufferCaptureFuncs(bool isGLES1)
98     {
99         if (isGLES1)
100         {
101             framebufferTexture2D    = &gl::CaptureFramebufferTexture2DOES;
102             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbufferOES;
103             bindFramebuffer         = &gl::CaptureBindFramebufferOES;
104             genFramebuffers         = &gl::CaptureGenFramebuffersOES;
105             bindRenderbuffer        = &gl::CaptureBindRenderbufferOES;
106             genRenderbuffers        = &gl::CaptureGenRenderbuffersOES;
107             renderbufferStorage     = &gl::CaptureRenderbufferStorageOES;
108         }
109         else
110         {
111             framebufferTexture2D    = &gl::CaptureFramebufferTexture2D;
112             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbuffer;
113             bindFramebuffer         = &gl::CaptureBindFramebuffer;
114             genFramebuffers         = &gl::CaptureGenFramebuffers;
115             bindRenderbuffer        = &gl::CaptureBindRenderbuffer;
116             genRenderbuffers        = &gl::CaptureGenRenderbuffers;
117             renderbufferStorage     = &gl::CaptureRenderbufferStorage;
118         }
119     }
120 
121     decltype(&gl::CaptureFramebufferTexture2D) framebufferTexture2D;
122     decltype(&gl::CaptureFramebufferRenderbuffer) framebufferRenderbuffer;
123     decltype(&gl::CaptureBindFramebuffer) bindFramebuffer;
124     decltype(&gl::CaptureGenFramebuffers) genFramebuffers;
125     decltype(&gl::CaptureBindRenderbuffer) bindRenderbuffer;
126     decltype(&gl::CaptureGenRenderbuffers) genRenderbuffers;
127     decltype(&gl::CaptureRenderbufferStorage) renderbufferStorage;
128 };
129 
GetDefaultOutDirectory()130 std::string GetDefaultOutDirectory()
131 {
132 #if defined(ANGLE_PLATFORM_ANDROID)
133     std::string path = "/sdcard/Android/data/";
134 
135     // Linux interface to get application id of the running process
136     FILE *cmdline = fopen("/proc/self/cmdline", "r");
137     char applicationId[512];
138     if (cmdline)
139     {
140         fread(applicationId, 1, sizeof(applicationId), cmdline);
141         fclose(cmdline);
142 
143         // Some package may have application id as <app_name>:<cmd_name>
144         char *colonSep = strchr(applicationId, ':');
145         if (colonSep)
146         {
147             *colonSep = '\0';
148         }
149     }
150     else
151     {
152         ERR() << "not able to lookup application id";
153     }
154 
155     constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
156     path += std::string(applicationId) + kAndroidOutputSubdir;
157 
158     // Check for existence of output path
159     struct stat dir_stat;
160     if (stat(path.c_str(), &dir_stat) == -1)
161     {
162         ERR() << "Output directory '" << path
163               << "' does not exist.  Create it over adb using mkdir.";
164     }
165 
166     return path;
167 #else
168     return std::string("./");
169 #endif  // defined(ANGLE_PLATFORM_ANDROID)
170 }
171 
GetCaptureTrigger()172 std::string GetCaptureTrigger()
173 {
174     // Use the GetAndSet variant to improve future lookup times
175     return GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
176 }
177 
operator <<(std::ostream & os,gl::ContextID contextId)178 std::ostream &operator<<(std::ostream &os, gl::ContextID contextId)
179 {
180     os << static_cast<int>(contextId.value);
181     return os;
182 }
183 
184 // Used to indicate that "shared" should be used to identify the files.
185 constexpr gl::ContextID kSharedContextId = {0};
186 // Used to indicate no context ID should be output.
187 constexpr gl::ContextID kNoContextId = {std::numeric_limits<uint32_t>::max()};
188 
189 struct FmtCapturePrefix
190 {
FmtCapturePrefixangle::__anonf35832ea0111::FmtCapturePrefix191     FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
192         : contextId(contextIdIn), captureLabel(captureLabelIn)
193     {}
194     gl::ContextID contextId;
195     const std::string &captureLabel;
196 };
197 
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)198 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
199 {
200     if (fmt.captureLabel.empty())
201     {
202         os << "angle_capture";
203     }
204     else
205     {
206         os << fmt.captureLabel;
207     }
208 
209     if (fmt.contextId == kSharedContextId)
210     {
211         os << "_shared";
212     }
213     else if (fmt.contextId != kNoContextId)
214     {
215         os << "_context" << fmt.contextId;
216     }
217 
218     return os;
219 }
220 
221 enum class ReplayFunc
222 {
223     Replay,
224     Setup,
225     Reset,
226 };
227 
228 constexpr uint32_t kNoPartId = std::numeric_limits<uint32_t>::max();
229 
230 struct FmtReplayFunction
231 {
FmtReplayFunctionangle::__anonf35832ea0111::FmtReplayFunction232     FmtReplayFunction(gl::ContextID contextIdIn,
233                       uint32_t frameIndexIn,
234                       uint32_t partIdIn = kNoPartId)
235         : contextId(contextIdIn), frameIndex(frameIndexIn), partId(partIdIn)
236     {}
237     gl::ContextID contextId;
238     uint32_t frameIndex;
239     uint32_t partId;
240 };
241 
operator <<(std::ostream & os,const FmtReplayFunction & fmt)242 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
243 {
244     os << "ReplayContext";
245 
246     if (fmt.contextId == kSharedContextId)
247     {
248         os << "Shared";
249     }
250     else
251     {
252         os << fmt.contextId;
253     }
254 
255     os << "Frame" << fmt.frameIndex;
256 
257     if (fmt.partId != kNoPartId)
258     {
259         os << "Part" << fmt.partId;
260     }
261     os << "()";
262     return os;
263 }
264 
265 struct FmtSetupFunction
266 {
FmtSetupFunctionangle::__anonf35832ea0111::FmtSetupFunction267     FmtSetupFunction(uint32_t partIdIn, gl::ContextID contextIdIn)
268         : partId(partIdIn), contextId(contextIdIn)
269     {}
270 
271     uint32_t partId;
272     gl::ContextID contextId;
273 };
274 
operator <<(std::ostream & os,const FmtSetupFunction & fmt)275 std::ostream &operator<<(std::ostream &os, const FmtSetupFunction &fmt)
276 {
277     os << "SetupReplayContext";
278 
279     if (fmt.contextId == kSharedContextId)
280     {
281         os << "Shared";
282     }
283     else
284     {
285         os << fmt.contextId;
286     }
287 
288     if (fmt.partId != kNoPartId)
289     {
290         os << "Part" << fmt.partId;
291     }
292     os << "()";
293     return os;
294 }
295 
296 struct FmtResetFunction
297 {
FmtResetFunctionangle::__anonf35832ea0111::FmtResetFunction298     FmtResetFunction() {}
299 };
300 
operator <<(std::ostream & os,const FmtResetFunction & fmt)301 std::ostream &operator<<(std::ostream &os, const FmtResetFunction &fmt)
302 {
303     os << "ResetReplay()";
304     return os;
305 }
306 
307 struct FmtFunction
308 {
FmtFunctionangle::__anonf35832ea0111::FmtFunction309     FmtFunction(ReplayFunc funcTypeIn,
310                 gl::ContextID contextIdIn,
311                 uint32_t frameIndexIn,
312                 uint32_t partIdIn)
313         : funcType(funcTypeIn), contextId(contextIdIn), frameIndex(frameIndexIn), partId(partIdIn)
314     {}
315 
316     ReplayFunc funcType;
317     gl::ContextID contextId;
318     uint32_t frameIndex;
319     uint32_t partId;
320 };
321 
operator <<(std::ostream & os,const FmtFunction & fmt)322 std::ostream &operator<<(std::ostream &os, const FmtFunction &fmt)
323 {
324     switch (fmt.funcType)
325     {
326         case ReplayFunc::Replay:
327             os << FmtReplayFunction(fmt.contextId, fmt.frameIndex, fmt.partId);
328             break;
329 
330         case ReplayFunc::Setup:
331             os << FmtSetupFunction(fmt.partId, fmt.contextId);
332             break;
333 
334         case ReplayFunc::Reset:
335             os << FmtResetFunction();
336             break;
337 
338         default:
339             UNREACHABLE();
340             break;
341     }
342 
343     return os;
344 }
345 
346 struct FmtGetSerializedContextStateFunction
347 {
FmtGetSerializedContextStateFunctionangle::__anonf35832ea0111::FmtGetSerializedContextStateFunction348     FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn, uint32_t frameIndexIn)
349         : contextId(contextIdIn), frameIndex(frameIndexIn)
350     {}
351     gl::ContextID contextId;
352     uint32_t frameIndex;
353 };
354 
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)355 std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
356 {
357     os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data()";
358     return os;
359 }
360 
WriteGLFloatValue(std::ostream & out,GLfloat value)361 void WriteGLFloatValue(std::ostream &out, GLfloat value)
362 {
363     // Check for non-representable values
364     ASSERT(std::numeric_limits<float>::has_infinity);
365     ASSERT(std::numeric_limits<float>::has_quiet_NaN);
366 
367     if (std::isinf(value))
368     {
369         float negativeInf = -std::numeric_limits<float>::infinity();
370         if (value == negativeInf)
371         {
372             out << "-";
373         }
374         out << "std::numeric_limits<float>::infinity()";
375     }
376     else if (std::isnan(value))
377     {
378         out << "std::numeric_limits<float>::quiet_NaN()";
379     }
380     else
381     {
382         out << std::setprecision(16);
383         out << value;
384     }
385 }
386 
387 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)388 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
389 {
390     const T *data = reinterpret_cast<const T *>(vec.data());
391     size_t count  = vec.size() / sizeof(T);
392 
393     if (data == nullptr)
394     {
395         return;
396     }
397 
398     out << static_cast<CastT>(data[0]);
399 
400     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
401     {
402         out << ", " << static_cast<CastT>(data[dataIndex]);
403     }
404 }
405 
406 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)407 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
408 {
409     const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
410     size_t count       = vec.size() / sizeof(GLchar);
411 
412     if (data == nullptr || data[0] == '\0')
413     {
414         return;
415     }
416 
417     out << "\"";
418 
419     for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
420     {
421         if (data[dataIndex] == '\0')
422             break;
423 
424         out << static_cast<GLchar>(data[dataIndex]);
425     }
426 
427     out << "\"";
428 }
429 
WriteStringParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)430 void WriteStringParamReplay(ReplayWriter &replayWriter,
431                             std::ostream &out,
432                             std::ostream &header,
433                             const CallCapture &call,
434                             const ParamCapture &param,
435                             std::vector<uint8_t> *binaryData)
436 {
437     const std::vector<uint8_t> &data = param.data[0];
438     // null terminate C style string
439     ASSERT(data.size() > 0 && data.back() == '\0');
440     std::string str(data.begin(), data.end() - 1);
441 
442     constexpr size_t kMaxInlineStringLength = 20000;
443     if (str.size() > kMaxInlineStringLength)
444     {
445         // Store in binary file if the string is too long.
446         // Round up to 16-byte boundary for cross ABI safety.
447         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
448         binaryData->resize(offset + str.size() + 1);
449         memcpy(binaryData->data() + offset, str.data(), str.size() + 1);
450         out << "reinterpret_cast<const char *>(&gBinaryData[" << offset << "])";
451     }
452     else if (str.find('\n') != std::string::npos)
453     {
454         std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
455         header << "const char " << varName << "[] = R\"(" << str << ")\";\n";
456         out << varName;
457     }
458     else
459     {
460         out << "\"" << str << "\"";
461     }
462 }
463 
WriteStringPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)464 void WriteStringPointerParamReplay(ReplayWriter &replayWriter,
465                                    std::ostream &out,
466                                    std::ostream &header,
467                                    const CallCapture &call,
468                                    const ParamCapture &param)
469 {
470     // Concatenate the strings to ensure we get an accurate counter
471     std::vector<std::string> strings;
472     for (const std::vector<uint8_t> &data : param.data)
473     {
474         // null terminate C style string
475         ASSERT(data.size() > 0 && data.back() == '\0');
476         strings.emplace_back(data.begin(), data.end() - 1);
477     }
478 
479     bool isNewEntry     = false;
480     std::string varName = replayWriter.getInlineStringSetVariableName(call.entryPoint, param.name,
481                                                                       strings, &isNewEntry);
482 
483     if (isNewEntry)
484     {
485         header << "const char *const " << varName << "[] = { \n";
486 
487         for (const std::string &str : strings)
488         {
489             // Break up long strings for MSVC
490             size_t copyLength = 0;
491             std::string separator;
492             for (size_t i = 0; i < str.length(); i += kStringLengthLimit)
493             {
494                 if ((str.length() - i) <= kStringLengthLimit)
495                 {
496                     copyLength = str.length() - i;
497                     separator  = ",";
498                 }
499                 else
500                 {
501                     copyLength = kStringLengthLimit;
502                     separator  = "";
503                 }
504 
505                 header << "    R\"(" << str.substr(i, copyLength) << ")\"" << separator << "\n";
506             }
507         }
508 
509         header << "};\n";
510     }
511 
512     out << varName;
513 }
514 
515 template <typename ParamT>
WriteResourceIDPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)516 void WriteResourceIDPointerParamReplay(ReplayWriter &replayWriter,
517                                        std::ostream &out,
518                                        std::ostream &header,
519                                        const CallCapture &call,
520                                        const ParamCapture &param)
521 {
522     std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
523 
524     header << "const GLuint " << varName << "[] = { ";
525 
526     const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
527     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
528     const char *name = GetResourceIDTypeName(resourceIDType);
529 
530     if (param.dataNElements > 0)
531     {
532         ASSERT(param.data.size() == 1);
533 
534         const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
535         for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
536         {
537             ParamT id = returnedIDs[resIndex];
538             if (resIndex > 0)
539             {
540                 header << ", ";
541             }
542             header << "g" << name << "Map[" << id.value << "]";
543         }
544     }
545     else
546     {
547         header << "0";
548     }
549     header << " };\n    ";
550 
551     out << varName;
552 }
553 
WriteBinaryParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)554 void WriteBinaryParamReplay(ReplayWriter &replayWriter,
555                             std::ostream &out,
556                             std::ostream &header,
557                             const CallCapture &call,
558                             const ParamCapture &param,
559                             std::vector<uint8_t> *binaryData)
560 {
561     std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
562 
563     ASSERT(param.data.size() == 1);
564     const std::vector<uint8_t> &data = param.data[0];
565 
566     ParamType overrideType = param.type;
567     if (param.type == ParamType::TGLvoidConstPointer || param.type == ParamType::TvoidConstPointer)
568     {
569         overrideType = ParamType::TGLubyteConstPointer;
570     }
571     if (overrideType == ParamType::TGLenumConstPointer || overrideType == ParamType::TGLcharPointer)
572     {
573         // Inline if data are of type string or enum
574         std::string paramTypeString = ParamTypeToString(param.type);
575         header << paramTypeString.substr(0, paramTypeString.length() - 1) << varName << "[] = { ";
576         if (overrideType == ParamType::TGLenumConstPointer)
577         {
578             WriteInlineData<GLuint>(data, header);
579         }
580         else
581         {
582             ASSERT(overrideType == ParamType::TGLcharPointer);
583             WriteInlineData<GLchar>(data, header);
584         }
585         header << " };\n";
586         out << varName;
587     }
588     else
589     {
590         // Store in binary file if data are not of type string or enum
591         // Round up to 16-byte boundary for cross ABI safety
592         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
593         binaryData->resize(offset + data.size());
594         memcpy(binaryData->data() + offset, data.data(), data.size());
595         out << "reinterpret_cast<" << ParamTypeToString(overrideType) << ">(&gBinaryData[" << offset
596             << "])";
597     }
598 }
599 
SyncIndexValue(GLsync sync)600 uintptr_t SyncIndexValue(GLsync sync)
601 {
602     return reinterpret_cast<uintptr_t>(sync);
603 }
604 
WriteCppReplayForCall(const CallCapture & call,ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData)605 void WriteCppReplayForCall(const CallCapture &call,
606                            ReplayWriter &replayWriter,
607                            std::ostream &out,
608                            std::ostream &header,
609                            std::vector<uint8_t> *binaryData)
610 {
611     std::ostringstream callOut;
612 
613     if (call.entryPoint == EntryPoint::GLCreateShader ||
614         call.entryPoint == EntryPoint::GLCreateProgram ||
615         call.entryPoint == EntryPoint::GLCreateShaderProgramv)
616     {
617         GLuint id = call.params.getReturnValue().value.GLuintVal;
618         callOut << "gShaderProgramMap[" << id << "] = ";
619     }
620 
621     if (call.entryPoint == EntryPoint::GLFenceSync)
622     {
623         GLsync sync = call.params.getReturnValue().value.GLsyncVal;
624         callOut << "gSyncMap[" << SyncIndexValue(sync) << "] = ";
625     }
626 
627     // Depending on how a buffer is mapped, we may need to track its location for readback
628     bool trackBufferPointer = false;
629 
630     if (call.entryPoint == EntryPoint::GLMapBufferRange ||
631         call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
632     {
633         GLbitfield access =
634             call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
635 
636         trackBufferPointer = access & GL_MAP_WRITE_BIT;
637     }
638 
639     if (call.entryPoint == EntryPoint::GLMapBuffer || call.entryPoint == EntryPoint::GLMapBufferOES)
640     {
641         GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
642 
643         trackBufferPointer =
644             access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
645     }
646 
647     if (trackBufferPointer)
648     {
649         // Track the returned pointer so we update its data when unmapped
650         gl::BufferID bufferID = call.params.getMappedBufferID();
651         callOut << "gMappedBufferData[";
652         WriteParamValueReplay<ParamType::TBufferID>(callOut, call, bufferID);
653         callOut << "] = ";
654     }
655 
656     callOut << call.name() << "(";
657 
658     bool first = true;
659     for (const ParamCapture &param : call.params.getParamCaptures())
660     {
661         if (!first)
662         {
663             callOut << ", ";
664         }
665 
666         if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
667         {
668             callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
669         }
670         else if (param.readBufferSizeBytes > 0)
671         {
672             callOut << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(gReadBuffer)";
673         }
674         else if (param.data.empty())
675         {
676             if (param.type == ParamType::TGLenum)
677             {
678                 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
679             }
680             else if (param.type == ParamType::TGLbitfield)
681             {
682                 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
683             }
684             else if (param.type == ParamType::TGLfloat)
685             {
686                 WriteGLFloatValue(callOut, param.value.GLfloatVal);
687             }
688             else if (param.type == ParamType::TGLsync)
689             {
690                 callOut << "gSyncMap[" << SyncIndexValue(param.value.GLsyncVal) << "]";
691             }
692             else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
693             {
694                 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
695                 {
696                     callOut << "GL_TIMEOUT_IGNORED";
697                 }
698                 else
699                 {
700                     WriteParamCaptureReplay(callOut, call, param);
701                 }
702             }
703             else
704             {
705                 WriteParamCaptureReplay(callOut, call, param);
706             }
707         }
708         else
709         {
710             switch (param.type)
711             {
712                 case ParamType::TGLcharConstPointer:
713                     WriteStringParamReplay(replayWriter, callOut, header, call, param, binaryData);
714                     break;
715                 case ParamType::TGLcharConstPointerPointer:
716                     WriteStringPointerParamReplay(replayWriter, callOut, header, call, param);
717                     break;
718                 case ParamType::TBufferIDConstPointer:
719                     WriteResourceIDPointerParamReplay<gl::BufferID>(replayWriter, callOut, out,
720                                                                     call, param);
721                     break;
722                 case ParamType::TFenceNVIDConstPointer:
723                     WriteResourceIDPointerParamReplay<gl::FenceNVID>(replayWriter, callOut, out,
724                                                                      call, param);
725                     break;
726                 case ParamType::TFramebufferIDConstPointer:
727                     WriteResourceIDPointerParamReplay<gl::FramebufferID>(replayWriter, callOut, out,
728                                                                          call, param);
729                     break;
730                 case ParamType::TMemoryObjectIDConstPointer:
731                     WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(replayWriter, callOut,
732                                                                           out, call, param);
733                     break;
734                 case ParamType::TProgramPipelineIDConstPointer:
735                     WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(replayWriter, callOut,
736                                                                              out, call, param);
737                     break;
738                 case ParamType::TQueryIDConstPointer:
739                     WriteResourceIDPointerParamReplay<gl::QueryID>(replayWriter, callOut, out, call,
740                                                                    param);
741                     break;
742                 case ParamType::TRenderbufferIDConstPointer:
743                     WriteResourceIDPointerParamReplay<gl::RenderbufferID>(replayWriter, callOut,
744                                                                           out, call, param);
745                     break;
746                 case ParamType::TSamplerIDConstPointer:
747                     WriteResourceIDPointerParamReplay<gl::SamplerID>(replayWriter, callOut, out,
748                                                                      call, param);
749                     break;
750                 case ParamType::TSemaphoreIDConstPointer:
751                     WriteResourceIDPointerParamReplay<gl::SemaphoreID>(replayWriter, callOut, out,
752                                                                        call, param);
753                     break;
754                 case ParamType::TTextureIDConstPointer:
755                     WriteResourceIDPointerParamReplay<gl::TextureID>(replayWriter, callOut, out,
756                                                                      call, param);
757                     break;
758                 case ParamType::TTransformFeedbackIDConstPointer:
759                     WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(
760                         replayWriter, callOut, out, call, param);
761                     break;
762                 case ParamType::TVertexArrayIDConstPointer:
763                     WriteResourceIDPointerParamReplay<gl::VertexArrayID>(replayWriter, callOut, out,
764                                                                          call, param);
765                     break;
766                 default:
767                     WriteBinaryParamReplay(replayWriter, callOut, header, call, param, binaryData);
768                     break;
769             }
770         }
771 
772         first = false;
773     }
774 
775     callOut << ")";
776 
777     out << callOut.str();
778 }
779 
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)780 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
781 {
782     size_t found = 0;
783     for (size_t size : clientArraySizes)
784     {
785         if (size > found)
786         {
787             found = size;
788         }
789     }
790 
791     return found;
792 }
793 
CaptureMakeCurrent(EGLDisplay display,EGLSurface draw,EGLSurface read,EGLContext context)794 CallCapture CaptureMakeCurrent(EGLDisplay display,
795                                EGLSurface draw,
796                                EGLSurface read,
797                                EGLContext context)
798 {
799     ParamBuffer paramBuffer;
800     paramBuffer.addValueParam("display", ParamType::TEGLDisplay, display);
801     paramBuffer.addValueParam("draw", ParamType::TEGLSurface, draw);
802     paramBuffer.addValueParam("read", ParamType::TEGLSurface, read);
803     paramBuffer.addValueParam("context", ParamType::TEGLContext, context);
804 
805     return CallCapture(angle::EntryPoint::EGLMakeCurrent, std::move(paramBuffer));
806 }
807 
GetBinaryDataFilePath(bool compression,const std::string & captureLabel)808 std::string GetBinaryDataFilePath(bool compression, const std::string &captureLabel)
809 {
810     std::stringstream fnameStream;
811     fnameStream << FmtCapturePrefix(kNoContextId, captureLabel) << ".angledata";
812     if (compression)
813     {
814         fnameStream << ".gz";
815     }
816     return fnameStream.str();
817 }
818 
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)819 void SaveBinaryData(bool compression,
820                     const std::string &outDir,
821                     gl::ContextID contextId,
822                     const std::string &captureLabel,
823                     const std::vector<uint8_t> &binaryData)
824 {
825     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
826     std::string dataFilepath       = outDir + binaryDataFileName;
827 
828     SaveFileHelper saveData(dataFilepath);
829 
830     if (compression)
831     {
832         // Save compressed data.
833         uLong uncompressedSize       = static_cast<uLong>(binaryData.size());
834         uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
835 
836         std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
837 
838         uLong compressedSize = expectedCompressedSize;
839         int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
840                                                         binaryData.data(), uncompressedSize,
841                                                         nullptr, nullptr);
842 
843         if (zResult != Z_OK)
844         {
845             FATAL() << "Error compressing binary data: " << zResult;
846         }
847 
848         saveData.write(compressedData.data(), compressedSize);
849     }
850     else
851     {
852         saveData.write(binaryData.data(), binaryData.size());
853     }
854 }
855 
WriteInitReplayCall(bool compression,std::ostream & out,gl::ContextID contextId,const std::string & captureLabel,size_t maxClientArraySize,size_t readBufferSize,const PackedEnumMap<ResourceIDType,uint32_t> & maxIDs)856 void WriteInitReplayCall(bool compression,
857                          std::ostream &out,
858                          gl::ContextID contextId,
859                          const std::string &captureLabel,
860                          size_t maxClientArraySize,
861                          size_t readBufferSize,
862                          const PackedEnumMap<ResourceIDType, uint32_t> &maxIDs)
863 {
864     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
865     {
866         const char *name = GetResourceIDTypeName(resourceID);
867         out << "    uint32_t kMax" << name << " = " << maxIDs[resourceID] << ";\n";
868     }
869 
870     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
871     out << "    InitializeReplay(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
872         << readBufferSize;
873 
874     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
875     {
876         out << ", kMax" << GetResourceIDTypeName(resourceID);
877     }
878 
879     out << ");\n";
880 }
881 
882 // TODO (http://anglebug.com/4599): Reset more state on frame loop
MaybeResetResources(ResourceIDType resourceIDType,ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)883 void MaybeResetResources(ResourceIDType resourceIDType,
884                          ReplayWriter &replayWriter,
885                          std::stringstream &out,
886                          std::stringstream &header,
887                          ResourceTracker *resourceTracker,
888                          std::vector<uint8_t> *binaryData)
889 {
890     // Local helper to get well structured blocks in Delete calls, i.e.
891     // const GLuint deleteTextures[] = {
892     //    gTextureMap[1], gTextureMap[2], gTextureMap[3], gTextureMap[4],
893     //    gTextureMap[5], gTextureMap[6], gTextureMap[7], gTextureMap[8]};
894     auto formatResourceIndex = [](std::stringstream &out, size_t i) {
895         if (i > 0)
896         {
897             out << ", ";
898         }
899         if ((i % 4) == 0)
900         {
901             out << "\n        ";
902         }
903     };
904 
905     switch (resourceIDType)
906     {
907         case ResourceIDType::Buffer:
908         {
909             TrackedResource &trackedBuffers =
910                 resourceTracker->getTrackedResource(ResourceIDType::Buffer);
911             ResourceSet &newBuffers           = trackedBuffers.getNewResources();
912             ResourceSet &buffersToRegen       = trackedBuffers.getResourcesToRegen();
913             ResourceCalls &bufferRegenCalls   = trackedBuffers.getResourceRegenCalls();
914             ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
915 
916             BufferCalls &bufferMapCalls   = resourceTracker->getBufferMapCalls();
917             BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
918 
919             // If we have any new buffers generated and not deleted during the run, or any buffers
920             // that we need to regen, delete them now
921             if (!newBuffers.empty() || !buffersToRegen.empty())
922             {
923                 size_t count = 0;
924 
925                 out << "    const GLuint deleteBuffers[] = {";
926 
927                 for (auto &oldBuffer : buffersToRegen)
928                 {
929                     formatResourceIndex(out, count);
930                     out << "gBufferMap[" << oldBuffer << "]";
931                     ++count;
932                 }
933 
934                 for (auto &newBuffer : newBuffers)
935                 {
936                     formatResourceIndex(out, count);
937                     out << "gBufferMap[" << newBuffer << "]";
938                     ++count;
939                 }
940 
941                 // Delete all the new and old buffers at once
942                 out << "};\n";
943                 out << "    glDeleteBuffers(" << count << ", deleteBuffers);\n";
944             }
945 
946             // If any of our starting buffers were deleted during the run, recreate them
947             for (GLuint id : buffersToRegen)
948             {
949                 // Emit their regen calls
950                 for (CallCapture &call : bufferRegenCalls[id])
951                 {
952                     out << "    ";
953                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
954                     out << ";\n";
955                 }
956             }
957 
958             // If any of our starting buffers were modified during the run, restore their contents
959             ResourceSet &buffersToRestore = trackedBuffers.getResourcesToRestore();
960             for (GLuint id : buffersToRestore)
961             {
962                 if (resourceTracker->getStartingBuffersMappedCurrent(id))
963                 {
964                     // Some drivers require the buffer to be unmapped before you can update data,
965                     // which violates the spec. See gl::Buffer::bufferDataImpl().
966                     for (CallCapture &call : bufferUnmapCalls[id])
967                     {
968                         out << "    ";
969                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
970                         out << ";\n";
971                     }
972                 }
973 
974                 // Emit their restore calls
975                 for (CallCapture &call : bufferRestoreCalls[id])
976                 {
977                     out << "    ";
978                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
979                     out << ";\n";
980 
981                     // Also note that this buffer has been implicitly unmapped by this call
982                     resourceTracker->setBufferUnmapped(id);
983                 }
984             }
985 
986             // Update the map/unmap of buffers to match the starting state
987             ResourceSet startingBuffers = trackedBuffers.getStartingResources();
988             for (GLuint id : startingBuffers)
989             {
990                 // If the buffer was mapped at the start, but is not mapped now, we need to map
991                 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
992                     !resourceTracker->getStartingBuffersMappedCurrent(id))
993                 {
994                     // Emit their map calls
995                     for (CallCapture &call : bufferMapCalls[id])
996                     {
997                         out << "    ";
998                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
999                         out << ";\n";
1000                     }
1001                 }
1002                 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
1003                 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
1004                     resourceTracker->getStartingBuffersMappedCurrent(id))
1005                 {
1006                     // Emit their unmap calls
1007                     for (CallCapture &call : bufferUnmapCalls[id])
1008                     {
1009                         out << "    ";
1010                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1011                         out << ";\n";
1012                     }
1013                 }
1014             }
1015 
1016             // Restore buffer bindings as seen during MEC
1017             std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
1018             for (CallCapture &call : bufferBindingCalls)
1019             {
1020                 out << "    ";
1021                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1022                 out << ";\n";
1023             }
1024 
1025             break;
1026         }
1027         case ResourceIDType::Framebuffer:
1028         {
1029             TrackedResource &trackedFramebuffers =
1030                 resourceTracker->getTrackedResource(ResourceIDType::Framebuffer);
1031             ResourceSet &newFramebuffers           = trackedFramebuffers.getNewResources();
1032             ResourceSet &framebuffersToRegen       = trackedFramebuffers.getResourcesToRegen();
1033             ResourceCalls &framebufferRegenCalls   = trackedFramebuffers.getResourceRegenCalls();
1034             ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
1035 
1036             // If we have any new framebuffers generated and not deleted during the run, or any
1037             // framebuffers that we need to regen, delete them now
1038             if (!newFramebuffers.empty() || !framebuffersToRegen.empty())
1039             {
1040                 size_t count = 0;
1041 
1042                 out << "    const GLuint deleteFramebuffers[] = {";
1043 
1044                 for (auto &oldFb : framebuffersToRegen)
1045                 {
1046                     formatResourceIndex(out, count);
1047                     out << "gFramebufferMap[" << oldFb << "]";
1048                     ++count;
1049                 }
1050 
1051                 for (auto &newFb : newFramebuffers)
1052                 {
1053                     formatResourceIndex(out, count);
1054                     out << "gFramebufferMap[" << newFb << "]";
1055                     ++count;
1056                 }
1057 
1058                 // Delete all the new and old framebuffers at once
1059                 out << "};\n";
1060                 out << "    glDeleteFramebuffers(" << count << ", deleteFramebuffers);\n";
1061             }
1062 
1063             for (GLuint id : framebuffersToRegen)
1064             {
1065                 // Emit their regen calls
1066                 for (CallCapture &call : framebufferRegenCalls[id])
1067                 {
1068                     out << "    ";
1069                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1070                     out << ";\n";
1071                 }
1072             }
1073 
1074             // If any of our starting framebuffers were modified during the run, restore their
1075             // contents
1076             ResourceSet &framebuffersToRestore = trackedFramebuffers.getResourcesToRestore();
1077             for (GLuint id : framebuffersToRestore)
1078             {
1079                 // Emit their restore calls
1080                 for (CallCapture &call : framebufferRestoreCalls[id])
1081                 {
1082                     out << "    ";
1083                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1084                     out << ";\n";
1085                 }
1086             }
1087             break;
1088         }
1089         case ResourceIDType::Renderbuffer:
1090         {
1091             ResourceSet &newRenderbuffers =
1092                 resourceTracker->getTrackedResource(ResourceIDType::Renderbuffer).getNewResources();
1093 
1094             // Delete any new renderbuffers generated and not deleted during the run
1095             if (!newRenderbuffers.empty())
1096             {
1097                 size_t count = 0;
1098 
1099                 out << "    const GLuint deleteRenderbuffers[] = {";
1100 
1101                 for (auto &newRb : newRenderbuffers)
1102                 {
1103                     formatResourceIndex(out, count);
1104                     out << "gRenderbufferMap[" << newRb << "]";
1105                     ++count;
1106                 }
1107 
1108                 out << "};\n";
1109                 out << "    glDeleteRenderbuffers(" << count << ", deleteRenderbuffers);\n";
1110             }
1111 
1112             // TODO (http://anglebug.com/4599): Handle renderbuffers that need regen
1113             // This would only happen if a starting renderbuffer was deleted during the run.
1114             ASSERT(resourceTracker->getTrackedResource(ResourceIDType::Renderbuffer)
1115                        .getResourcesToRegen()
1116                        .empty());
1117             break;
1118         }
1119         case ResourceIDType::ShaderProgram:
1120         {
1121             ResourceSet &newPrograms =
1122                 resourceTracker->getTrackedResource(ResourceIDType::ShaderProgram)
1123                     .getNewResources();
1124 
1125             // If we have any new programs created and not deleted during the run, delete them now
1126             for (const GLuint &newProgram : newPrograms)
1127             {
1128                 out << "    glDeleteProgram(gShaderProgramMap[" << newProgram << "]);\n";
1129             }
1130 
1131             // TODO (http://anglebug.com/5968): Handle programs that need regen
1132             // This would only happen if a starting program was deleted during the run
1133             ASSERT(resourceTracker->getTrackedResource(ResourceIDType::ShaderProgram)
1134                        .getResourcesToRegen()
1135                        .empty());
1136             break;
1137         }
1138         case ResourceIDType::Texture:
1139         {
1140             TrackedResource &trackedTextures =
1141                 resourceTracker->getTrackedResource(ResourceIDType::Texture);
1142             ResourceSet &newTextures           = trackedTextures.getNewResources();
1143             ResourceSet &texturesToRegen       = trackedTextures.getResourcesToRegen();
1144             ResourceCalls &textureRegenCalls   = trackedTextures.getResourceRegenCalls();
1145             ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
1146 
1147             // If we have any new textures generated and not deleted during the run, or any textures
1148             // modified during the run that we need to regen, delete them now
1149             if (!newTextures.empty() || !texturesToRegen.empty())
1150             {
1151                 size_t count = 0;
1152 
1153                 out << "    const GLuint deleteTextures[] = {";
1154 
1155                 for (auto &oldTex : texturesToRegen)
1156                 {
1157                     formatResourceIndex(out, count);
1158                     out << "gTextureMap[" << oldTex << "]";
1159                     ++count;
1160                 }
1161 
1162                 for (auto &newTex : newTextures)
1163                 {
1164                     formatResourceIndex(out, count);
1165                     out << "gTextureMap[" << newTex << "]";
1166                     ++count;
1167                 }
1168 
1169                 out << "};\n";
1170                 out << "    glDeleteTextures(" << count << ", deleteTextures);\n";
1171             }
1172 
1173             // If any of our starting textures were deleted, regen them
1174             for (GLuint id : texturesToRegen)
1175             {
1176                 // Emit their regen calls
1177                 for (CallCapture &call : textureRegenCalls[id])
1178                 {
1179                     out << "    ";
1180                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1181                     out << ";\n";
1182                 }
1183             }
1184 
1185             // If any of our starting textures were modified during the run, restore their contents
1186             ResourceSet &texturesToRestore = trackedTextures.getResourcesToRestore();
1187             for (GLuint id : texturesToRestore)
1188             {
1189                 // Emit their restore calls
1190                 for (CallCapture &call : textureRestoreCalls[id])
1191                 {
1192                     out << "    ";
1193                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1194                     out << ";\n";
1195                 }
1196             }
1197             break;
1198         }
1199         case ResourceIDType::VertexArray:
1200         {
1201             ResourceSet &newVertextArrays =
1202                 resourceTracker->getTrackedResource(ResourceIDType::VertexArray).getNewResources();
1203 
1204             // If we have any new vertex arrays generated and not deleted during the run, delete
1205             // them now
1206             if (!newVertextArrays.empty())
1207             {
1208                 size_t count = 0;
1209 
1210                 out << "    const GLuint deleteVertexArrays[] = {";
1211 
1212                 for (auto &newVA : newVertextArrays)
1213                 {
1214                     formatResourceIndex(out, count);
1215                     out << "gVertexArrayMap[" << newVA << "]";
1216                     ++count;
1217                 }
1218 
1219                 out << "};\n";
1220                 out << "    glDeleteVertexArrays(" << count << ", deleteVertexArrays);\n";
1221             }
1222 
1223             // TODO (http://anglebug.com/4599): Handle vertex arrays that need regen
1224             // This would only happen if a starting vertex array was deleted during the run.
1225             ASSERT(resourceTracker->getTrackedResource(ResourceIDType::VertexArray)
1226                        .getResourcesToRegen()
1227                        .empty());
1228             break;
1229         }
1230         default:
1231             // TODO (http://anglebug.com/4599): Reset more than just buffers
1232             break;
1233     }
1234 }
1235 
MaybeResetFenceSyncObjects(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)1236 void MaybeResetFenceSyncObjects(std::stringstream &out,
1237                                 ReplayWriter &replayWriter,
1238                                 std::stringstream &header,
1239                                 ResourceTracker *resourceTracker,
1240                                 std::vector<uint8_t> *binaryData)
1241 {
1242     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
1243 
1244     // If any of our starting fence sync objects were deleted during the run, recreate them
1245     FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
1246     for (const GLsync sync : fenceSyncsToRegen)
1247     {
1248         // Emit their regen calls
1249         for (CallCapture &call : fenceSyncRegenCalls[sync])
1250         {
1251             out << "    ";
1252             WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1253             out << ";\n";
1254         }
1255     }
1256 }
1257 
MaybeResetOpaqueTypeObjects(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)1258 void MaybeResetOpaqueTypeObjects(ReplayWriter &replayWriter,
1259                                  std::stringstream &out,
1260                                  std::stringstream &header,
1261                                  ResourceTracker *resourceTracker,
1262                                  std::vector<uint8_t> *binaryData)
1263 {
1264     MaybeResetFenceSyncObjects(out, replayWriter, header, resourceTracker, binaryData);
1265 }
1266 
FindShaderProgramIDsInCall(const CallCapture & call,std::vector<gl::ShaderProgramID> & idsOut)1267 bool FindShaderProgramIDsInCall(const CallCapture &call, std::vector<gl::ShaderProgramID> &idsOut)
1268 {
1269     for (const ParamCapture &param : call.params.getParamCaptures())
1270     {
1271         // Only checking for programs right now, but could be expanded to all ResourceTypes
1272         if (param.type == ParamType::TShaderProgramID)
1273         {
1274             idsOut.push_back(param.value.ShaderProgramIDVal);
1275         }
1276     }
1277 
1278     return !idsOut.empty();
1279 }
1280 
MarkResourceIDActive(ResourceIDType resourceType,GLuint id,std::vector<CallCapture> * setupCalls,const ResourceIDToSetupCallsMap * resourceIDToSetupCallsMap)1281 void MarkResourceIDActive(ResourceIDType resourceType,
1282                           GLuint id,
1283                           std::vector<CallCapture> *setupCalls,
1284                           const ResourceIDToSetupCallsMap *resourceIDToSetupCallsMap)
1285 {
1286     const std::map<GLuint, gl::Range<size_t>> &resourceSetupCalls =
1287         (*resourceIDToSetupCallsMap)[resourceType];
1288     const auto iter = resourceSetupCalls.find(id);
1289     if (iter == resourceSetupCalls.end())
1290     {
1291         return;
1292     }
1293 
1294     // Mark all of the calls that were used to initialize this resource as ACTIVE
1295     const gl::Range<size_t> &calls = iter->second;
1296     for (size_t index : calls)
1297     {
1298         (*setupCalls)[index].isActive = true;
1299     }
1300 }
1301 
1302 // Some replay functions can get quite large. If over a certain size, this method breaks up the
1303 // function into parts to avoid overflowing the stack and causing slow compilation.
WriteCppReplayFunctionWithParts(const gl::ContextID contextID,ReplayFunc replayFunc,ReplayWriter & replayWriter,uint32_t frameIndex,std::vector<uint8_t> * binaryData,const std::vector<CallCapture> & calls,std::stringstream & header,std::stringstream & out)1304 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1305                                      ReplayFunc replayFunc,
1306                                      ReplayWriter &replayWriter,
1307                                      uint32_t frameIndex,
1308                                      std::vector<uint8_t> *binaryData,
1309                                      const std::vector<CallCapture> &calls,
1310                                      std::stringstream &header,
1311                                      std::stringstream &out)
1312 {
1313     int callCount = 0;
1314     int partCount = 0;
1315 
1316     if (calls.size() > kFunctionSizeLimit)
1317     {
1318         out << "void " << FmtFunction(replayFunc, contextID, frameIndex, ++partCount) << "\n";
1319     }
1320     else
1321     {
1322         out << "void " << FmtFunction(replayFunc, contextID, frameIndex, kNoPartId) << "\n";
1323     }
1324 
1325     out << "{\n";
1326 
1327     for (const CallCapture &call : calls)
1328     {
1329         if (!call.isActive)
1330         {
1331             // Don't write setup calls for inactive resources
1332             continue;
1333         }
1334 
1335         out << "    ";
1336         WriteCppReplayForCall(call, replayWriter, out, header, binaryData);
1337         out << ";\n";
1338 
1339         if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1340         {
1341             out << "}\n";
1342             out << "\n";
1343             out << "void " << FmtFunction(replayFunc, contextID, frameIndex, ++partCount) << "\n";
1344             out << "{\n";
1345         }
1346     }
1347     out << "}\n";
1348 
1349     if (partCount > 0)
1350     {
1351         out << "\n";
1352         out << "void " << FmtFunction(replayFunc, contextID, frameIndex, kNoPartId) << "\n";
1353         out << "{\n";
1354 
1355         // Write out the main call which calls all the parts.
1356         for (int i = 1; i <= partCount; i++)
1357         {
1358             out << "    " << FmtFunction(replayFunc, contextID, frameIndex, i) << ";\n";
1359         }
1360 
1361         out << "}\n";
1362     }
1363 }
1364 
1365 // Auxiliary contexts are other contexts in the share group that aren't the context calling
1366 // eglSwapBuffers().
WriteAuxiliaryContextCppSetupReplay(ReplayWriter & replayWriter,bool compression,const std::string & outDir,const gl::Context * context,const std::string & captureLabel,uint32_t frameIndex,const std::vector<CallCapture> & setupCalls,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,const FrameCaptureShared & frameCaptureShared)1367 void WriteAuxiliaryContextCppSetupReplay(ReplayWriter &replayWriter,
1368                                          bool compression,
1369                                          const std::string &outDir,
1370                                          const gl::Context *context,
1371                                          const std::string &captureLabel,
1372                                          uint32_t frameIndex,
1373                                          const std::vector<CallCapture> &setupCalls,
1374                                          std::vector<uint8_t> *binaryData,
1375                                          bool serializeStateEnabled,
1376                                          const FrameCaptureShared &frameCaptureShared)
1377 {
1378     ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
1379 
1380     {
1381         std::stringstream filenameStream;
1382         filenameStream << outDir << FmtCapturePrefix(context->id(), captureLabel);
1383         std::string filenamePattern = filenameStream.str();
1384         replayWriter.setFilenamePattern(filenamePattern);
1385     }
1386 
1387     {
1388         std::stringstream include;
1389         include << "#include \""
1390                 << FmtCapturePrefix(frameCaptureShared.getWindowSurfaceContextID(), captureLabel)
1391                 << ".h\"\n";
1392         include << "#include \"angle_trace_gl.h\"\n";
1393 
1394         std::string frameIncludes = include.str();
1395         replayWriter.setSourcePrologue(frameIncludes);
1396         replayWriter.setHeaderPrologue(frameIncludes);
1397     }
1398 
1399     {
1400         std::stringstream protoStream;
1401         std::stringstream headerStream;
1402         std::stringstream bodyStream;
1403 
1404         protoStream << "void " << FmtSetupFunction(kNoPartId, context->id());
1405         std::string proto = protoStream.str();
1406 
1407         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, replayWriter, frameIndex,
1408                                         binaryData, setupCalls, headerStream, bodyStream);
1409 
1410         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1411     }
1412 
1413     replayWriter.saveFrame();
1414 }
1415 
WriteShareGroupCppSetupReplay(ReplayWriter & replayWriter,bool compression,const std::string & outDir,const std::string & captureLabel,uint32_t frameIndex,uint32_t frameCount,const std::vector<CallCapture> & setupCalls,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,gl::ContextID windowSurfaceContextID)1416 void WriteShareGroupCppSetupReplay(ReplayWriter &replayWriter,
1417                                    bool compression,
1418                                    const std::string &outDir,
1419                                    const std::string &captureLabel,
1420                                    uint32_t frameIndex,
1421                                    uint32_t frameCount,
1422                                    const std::vector<CallCapture> &setupCalls,
1423                                    ResourceTracker *resourceTracker,
1424                                    std::vector<uint8_t> *binaryData,
1425                                    bool serializeStateEnabled,
1426                                    gl::ContextID windowSurfaceContextID)
1427 {
1428     {
1429         std::stringstream include;
1430 
1431         include << "#include \"angle_trace_gl.h\"\n";
1432         include << "#include \"" << FmtCapturePrefix(windowSurfaceContextID, captureLabel)
1433                 << ".h\"\n";
1434 
1435         std::string includeString = include.str();
1436 
1437         replayWriter.setSourcePrologue(includeString);
1438     }
1439 
1440     {
1441         std::stringstream protoStream;
1442         std::stringstream headerStream;
1443         std::stringstream bodyStream;
1444 
1445         protoStream << "void " << FmtSetupFunction(kNoPartId, kSharedContextId);
1446         std::string proto = protoStream.str();
1447 
1448         WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, replayWriter,
1449                                         frameIndex, binaryData, setupCalls, headerStream,
1450                                         bodyStream);
1451 
1452         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1453     }
1454 
1455     {
1456         std::stringstream filenameStream;
1457         filenameStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel);
1458 
1459         std::string filenamePattern = filenameStream.str();
1460 
1461         replayWriter.setFilenamePattern(filenamePattern);
1462     }
1463 
1464     replayWriter.saveSetupFile();
1465 }
1466 
GetAttachedProgramSources(const gl::Program * program)1467 ProgramSources GetAttachedProgramSources(const gl::Program *program)
1468 {
1469     ProgramSources sources;
1470     for (gl::ShaderType shaderType : gl::AllShaderTypes())
1471     {
1472         const gl::Shader *shader = program->getAttachedShader(shaderType);
1473         if (shader)
1474         {
1475             sources[shaderType] = shader->getSourceString();
1476         }
1477     }
1478     return sources;
1479 }
1480 
1481 template <typename IDType>
CaptureUpdateResourceIDs(const CallCapture & call,const ParamCapture & param,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1482 void CaptureUpdateResourceIDs(const CallCapture &call,
1483                               const ParamCapture &param,
1484                               ResourceTracker *resourceTracker,
1485                               std::vector<CallCapture> *callsOut)
1486 {
1487     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1488     ASSERT(param.data.size() == 1);
1489     ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1490     ASSERT(resourceIDType != ResourceIDType::InvalidEnum &&
1491            resourceIDType != ResourceIDType::ShaderProgram);
1492     const char *resourceName = GetResourceIDTypeName(resourceIDType);
1493 
1494     std::stringstream updateFuncNameStr;
1495     updateFuncNameStr << "Update" << resourceName << "ID";
1496     std::string updateFuncName = updateFuncNameStr.str();
1497 
1498     const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1499 
1500     ResourceSet &startingSet =
1501         resourceTracker->getTrackedResource(resourceIDType).getStartingResources();
1502 
1503     for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1504     {
1505         IDType id                = returnedIDs[idIndex];
1506         GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1507         ParamBuffer params;
1508         params.addValueParam("id", ParamType::TGLuint, id.value);
1509         params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1510         callsOut->emplace_back(updateFuncName, std::move(params));
1511 
1512         // Add only if not in starting resources.
1513         if (startingSet.find(id.value) == startingSet.end())
1514         {
1515             resourceTracker->getTrackedResource(resourceIDType).getNewResources().insert(id.value);
1516         }
1517     }
1518 }
1519 
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1520 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1521 {
1522     const std::vector<gl::LinkedUniform> &uniforms     = program->getState().getUniforms();
1523     const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1524 
1525     for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1526     {
1527         const gl::VariableLocation &locationVar = locations[location];
1528 
1529         // This handles the case where the application calls glBindUniformLocationCHROMIUM
1530         // on an unused uniform. We must still store a -1 into gUniformLocations in case the
1531         // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
1532         // force glGetUniformLocation to return -1.
1533         std::string name;
1534         int count = 1;
1535         ParamBuffer params;
1536         params.addValueParam("program", ParamType::TGLuint, program->id().value);
1537 
1538         if (locationVar.index >= uniforms.size())
1539         {
1540             name = "";
1541         }
1542         else
1543         {
1544             const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1545 
1546             name = uniform.name;
1547 
1548             if (uniform.isArray())
1549             {
1550                 if (locationVar.arrayIndex > 0)
1551                 {
1552                     // Non-sequential array uniform locations are not currently handled.
1553                     // In practice array locations shouldn't ever be non-sequential.
1554                     ASSERT(uniform.location == -1 ||
1555                            location == uniform.location + static_cast<int>(locationVar.arrayIndex));
1556                     continue;
1557                 }
1558 
1559                 if (uniform.isArrayOfArrays())
1560                 {
1561                     UNIMPLEMENTED();
1562                 }
1563 
1564                 name  = gl::StripLastArrayIndex(name);
1565                 count = uniform.arraySizes[0];
1566             }
1567         }
1568 
1569         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1570         CaptureString(name.c_str(), &nameParam);
1571         params.addParam(std::move(nameParam));
1572         params.addValueParam("location", ParamType::TGLint, location);
1573         params.addValueParam("count", ParamType::TGLint, static_cast<GLint>(count));
1574         callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1575     }
1576 }
1577 
CaptureValidateSerializedState(const gl::Context * context,std::vector<CallCapture> * callsOut)1578 void CaptureValidateSerializedState(const gl::Context *context, std::vector<CallCapture> *callsOut)
1579 {
1580     INFO() << "Capturing validation checkpoint at position " << callsOut->size();
1581 
1582     context->finishImmutable();
1583 
1584     std::string serializedState;
1585     angle::Result result = angle::SerializeContextToString(context, &serializedState);
1586     if (result != angle::Result::Continue)
1587     {
1588         ERR() << "Internal error serializing context state.";
1589         return;
1590     }
1591     ParamCapture serializedStateParam("serializedState", ParamType::TGLcharConstPointer);
1592     CaptureString(serializedState.c_str(), &serializedStateParam);
1593 
1594     ParamBuffer params;
1595     params.addParam(std::move(serializedStateParam));
1596 
1597     callsOut->emplace_back("VALIDATE_CHECKPOINT", std::move(params));
1598 }
1599 
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)1600 void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
1601                                       std::vector<CallCapture> *callsOut)
1602 {
1603     const std::vector<gl::InterfaceBlock> &uniformBlocks = program->getState().getUniformBlocks();
1604 
1605     for (GLuint index = 0; index < uniformBlocks.size(); ++index)
1606     {
1607         ParamBuffer params;
1608 
1609         std::string name;
1610         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1611 
1612         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1613         CaptureString(uniformBlocks[index].name.c_str(), &nameParam);
1614         params.addParam(std::move(nameParam));
1615 
1616         params.addValueParam("index", ParamType::TGLuint, index);
1617         callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
1618     }
1619 }
1620 
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1621 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1622 {
1623     ParamBuffer params;
1624     params.addValueParam("program", ParamType::TShaderProgramID, program);
1625     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1626 }
1627 
MaybeCaptureUpdateResourceIDs(ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1628 void MaybeCaptureUpdateResourceIDs(ResourceTracker *resourceTracker,
1629                                    std::vector<CallCapture> *callsOut)
1630 {
1631     const CallCapture &call = callsOut->back();
1632 
1633     switch (call.entryPoint)
1634     {
1635         case EntryPoint::GLGenBuffers:
1636         {
1637             const ParamCapture &buffers =
1638                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1639             CaptureUpdateResourceIDs<gl::BufferID>(call, buffers, resourceTracker, callsOut);
1640             break;
1641         }
1642 
1643         case EntryPoint::GLGenFencesNV:
1644         {
1645             const ParamCapture &fences =
1646                 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1647             CaptureUpdateResourceIDs<gl::FenceNVID>(call, fences, resourceTracker, callsOut);
1648             break;
1649         }
1650 
1651         case EntryPoint::GLGenFramebuffers:
1652         case EntryPoint::GLGenFramebuffersOES:
1653         {
1654             const ParamCapture &framebuffers =
1655                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1656             CaptureUpdateResourceIDs<gl::FramebufferID>(call, framebuffers, resourceTracker,
1657                                                         callsOut);
1658             break;
1659         }
1660 
1661         case EntryPoint::GLGenProgramPipelines:
1662         {
1663             const ParamCapture &pipelines =
1664                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1665             CaptureUpdateResourceIDs<gl::ProgramPipelineID>(call, pipelines, resourceTracker,
1666                                                             callsOut);
1667             break;
1668         }
1669 
1670         case EntryPoint::GLGenQueries:
1671         case EntryPoint::GLGenQueriesEXT:
1672         {
1673             const ParamCapture &queries =
1674                 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1675             CaptureUpdateResourceIDs<gl::QueryID>(call, queries, resourceTracker, callsOut);
1676             break;
1677         }
1678 
1679         case EntryPoint::GLGenRenderbuffers:
1680         case EntryPoint::GLGenRenderbuffersOES:
1681         {
1682             const ParamCapture &renderbuffers =
1683                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1684             CaptureUpdateResourceIDs<gl::RenderbufferID>(call, renderbuffers, resourceTracker,
1685                                                          callsOut);
1686             break;
1687         }
1688 
1689         case EntryPoint::GLGenSamplers:
1690         {
1691             const ParamCapture &samplers =
1692                 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1693             CaptureUpdateResourceIDs<gl::SamplerID>(call, samplers, resourceTracker, callsOut);
1694             break;
1695         }
1696 
1697         case EntryPoint::GLGenSemaphoresEXT:
1698         {
1699             const ParamCapture &semaphores =
1700                 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1701             CaptureUpdateResourceIDs<gl::SemaphoreID>(call, semaphores, resourceTracker, callsOut);
1702             break;
1703         }
1704 
1705         case EntryPoint::GLGenTextures:
1706         {
1707             const ParamCapture &textures =
1708                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1709             CaptureUpdateResourceIDs<gl::TextureID>(call, textures, resourceTracker, callsOut);
1710             break;
1711         }
1712 
1713         case EntryPoint::GLGenTransformFeedbacks:
1714         {
1715             const ParamCapture &xfbs =
1716                 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1717             CaptureUpdateResourceIDs<gl::TransformFeedbackID>(call, xfbs, resourceTracker,
1718                                                               callsOut);
1719             break;
1720         }
1721 
1722         case EntryPoint::GLGenVertexArrays:
1723         case EntryPoint::GLGenVertexArraysOES:
1724         {
1725             const ParamCapture &vertexArrays =
1726                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1727             CaptureUpdateResourceIDs<gl::VertexArrayID>(call, vertexArrays, resourceTracker,
1728                                                         callsOut);
1729             break;
1730         }
1731 
1732         case EntryPoint::GLCreateMemoryObjectsEXT:
1733         {
1734             const ParamCapture &memoryObjects =
1735                 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
1736             CaptureUpdateResourceIDs<gl::MemoryObjectID>(call, memoryObjects, resourceTracker,
1737                                                          callsOut);
1738             break;
1739         }
1740 
1741         default:
1742             break;
1743     }
1744 }
1745 
CaptureUpdateCurrentProgram(const CallCapture & call,int programParamPos,std::vector<CallCapture> * callsOut)1746 void CaptureUpdateCurrentProgram(const CallCapture &call,
1747                                  int programParamPos,
1748                                  std::vector<CallCapture> *callsOut)
1749 {
1750     const ParamCapture &param =
1751         call.params.getParam("programPacked", ParamType::TShaderProgramID, programParamPos);
1752     gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1753 
1754     ParamBuffer paramBuffer;
1755     paramBuffer.addValueParam("program", ParamType::TGLuint, programID.value);
1756 
1757     callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1758 }
1759 
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1760 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
1761 {
1762     if (currentValue.Type != gl::VertexAttribType::Float)
1763         return false;
1764 
1765     return currentValue.Values.FloatValues[0] == 0.0f &&
1766            currentValue.Values.FloatValues[1] == 0.0f &&
1767            currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1768 }
1769 
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1770 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1771 {
1772     const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1773     for (const auto &activeQueryIter : activeQueries)
1774     {
1775         const gl::Query *activeQuery = activeQueryIter.get();
1776         if (activeQuery && activeQuery->id() == queryID)
1777         {
1778             return true;
1779         }
1780     }
1781 
1782     return false;
1783 }
1784 
IsTextureUpdate(CallCapture & call)1785 bool IsTextureUpdate(CallCapture &call)
1786 {
1787     switch (call.entryPoint)
1788     {
1789         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
1790         case EntryPoint::GLCompressedTexImage1D:
1791         case EntryPoint::GLCompressedTexImage2D:
1792         case EntryPoint::GLCompressedTexImage2DRobustANGLE:
1793         case EntryPoint::GLCompressedTexImage3D:
1794         case EntryPoint::GLCompressedTexImage3DOES:
1795         case EntryPoint::GLCompressedTexImage3DRobustANGLE:
1796         case EntryPoint::GLCompressedTexSubImage1D:
1797         case EntryPoint::GLCompressedTexSubImage2D:
1798         case EntryPoint::GLCompressedTexSubImage2DRobustANGLE:
1799         case EntryPoint::GLCompressedTexSubImage3D:
1800         case EntryPoint::GLCompressedTexSubImage3DOES:
1801         case EntryPoint::GLCompressedTexSubImage3DRobustANGLE:
1802         case EntryPoint::GLCompressedTextureSubImage1D:
1803         case EntryPoint::GLCompressedTextureSubImage2D:
1804         case EntryPoint::GLCompressedTextureSubImage3D:
1805         case EntryPoint::GLCopyTexImage1D:
1806         case EntryPoint::GLCopyTexImage2D:
1807         case EntryPoint::GLCopyTexSubImage1D:
1808         case EntryPoint::GLCopyTexSubImage2D:
1809         case EntryPoint::GLCopyTexSubImage3D:
1810         case EntryPoint::GLCopyTexSubImage3DOES:
1811         case EntryPoint::GLCopyTexture3DANGLE:
1812         case EntryPoint::GLCopyTextureCHROMIUM:
1813         case EntryPoint::GLCopyTextureSubImage1D:
1814         case EntryPoint::GLCopyTextureSubImage2D:
1815         case EntryPoint::GLCopyTextureSubImage3D:
1816         case EntryPoint::GLTexImage1D:
1817         case EntryPoint::GLTexImage2D:
1818         case EntryPoint::GLTexImage2DExternalANGLE:
1819         case EntryPoint::GLTexImage2DMultisample:
1820         case EntryPoint::GLTexImage2DRobustANGLE:
1821         case EntryPoint::GLTexImage3D:
1822         case EntryPoint::GLTexImage3DMultisample:
1823         case EntryPoint::GLTexImage3DOES:
1824         case EntryPoint::GLTexImage3DRobustANGLE:
1825         case EntryPoint::GLTexSubImage1D:
1826         case EntryPoint::GLTexSubImage2D:
1827         case EntryPoint::GLTexSubImage2DRobustANGLE:
1828         case EntryPoint::GLTexSubImage3D:
1829         case EntryPoint::GLTexSubImage3DOES:
1830         case EntryPoint::GLTexSubImage3DRobustANGLE:
1831         case EntryPoint::GLTextureSubImage1D:
1832         case EntryPoint::GLTextureSubImage2D:
1833         case EntryPoint::GLTextureSubImage3D:
1834         case EntryPoint::GLCopyImageSubData:
1835         case EntryPoint::GLCopyImageSubDataEXT:
1836         case EntryPoint::GLCopyImageSubDataOES:
1837             return true;
1838         default:
1839             return false;
1840     }
1841 }
1842 
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1843 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1844 {
1845     setupCalls->emplace_back(std::move(call));
1846 }
1847 
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const FramebufferCaptureFuncs & framebufferFuncs,const gl::FramebufferAttachment & attachment)1848 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
1849                                   const gl::State &replayState,
1850                                   const FramebufferCaptureFuncs &framebufferFuncs,
1851                                   const gl::FramebufferAttachment &attachment)
1852 {
1853     GLuint resourceID = attachment.getResource()->getId();
1854 
1855     if (attachment.type() == GL_TEXTURE)
1856     {
1857         gl::ImageIndex index = attachment.getTextureImageIndex();
1858 
1859         if (index.usesTex3D())
1860         {
1861             Capture(setupCalls, CaptureFramebufferTextureLayer(
1862                                     replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
1863                                     {resourceID}, index.getLevelIndex(), index.getLayerIndex()));
1864         }
1865         else
1866         {
1867             Capture(setupCalls, framebufferFuncs.framebufferTexture2D(
1868                                     replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
1869                                     index.getTarget(), {resourceID}, index.getLevelIndex()));
1870         }
1871     }
1872     else
1873     {
1874         ASSERT(attachment.type() == GL_RENDERBUFFER);
1875         Capture(setupCalls, framebufferFuncs.framebufferRenderbuffer(
1876                                 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
1877                                 GL_RENDERBUFFER, {resourceID}));
1878     }
1879 }
1880 
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,gl::Program * program,std::vector<CallCapture> * callsOut)1881 void CaptureUpdateUniformValues(const gl::State &replayState,
1882                                 const gl::Context *context,
1883                                 gl::Program *program,
1884                                 std::vector<CallCapture> *callsOut)
1885 {
1886     if (!program->isLinked())
1887     {
1888         // We can't populate uniforms if the program hasn't been linked
1889         return;
1890     }
1891 
1892     // We need to bind the program and update its uniforms
1893     if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
1894     {
1895         Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
1896         CaptureUpdateCurrentProgram(callsOut->back(), 0, callsOut);
1897     }
1898 
1899     const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
1900 
1901     for (const gl::LinkedUniform &uniform : uniforms)
1902     {
1903         std::string uniformName = uniform.name;
1904 
1905         int uniformCount = 1;
1906         if (uniform.isArray())
1907         {
1908             if (uniform.isArrayOfArrays())
1909             {
1910                 UNIMPLEMENTED();
1911                 continue;
1912             }
1913 
1914             uniformCount = uniform.arraySizes[0];
1915             uniformName  = gl::StripLastArrayIndex(uniformName);
1916         }
1917 
1918         gl::UniformLocation uniformLoc      = program->getUniformLocation(uniformName);
1919         const gl::UniformTypeInfo *typeInfo = uniform.typeInfo;
1920         int componentCount                  = typeInfo->componentCount;
1921         int uniformSize                     = uniformCount * componentCount;
1922 
1923         // For arrayed uniforms, we'll need to increment a read location
1924         gl::UniformLocation readLoc = uniformLoc;
1925 
1926         // If the uniform is unused, just continue
1927         if (readLoc.value == -1)
1928         {
1929             continue;
1930         }
1931 
1932         // Image uniforms are special and cannot be set this way
1933         if (typeInfo->isImageType)
1934         {
1935             continue;
1936         }
1937 
1938         // Samplers should be populated with GL_INT, regardless of return type
1939         if (typeInfo->isSampler)
1940         {
1941             std::vector<GLint> uniformBuffer(uniformSize);
1942             for (int index = 0; index < uniformCount; index++, readLoc.value++)
1943             {
1944                 program->getUniformiv(context, readLoc,
1945                                       uniformBuffer.data() + index * componentCount);
1946             }
1947 
1948             Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
1949                                                 uniformBuffer.data()));
1950 
1951             continue;
1952         }
1953 
1954         switch (typeInfo->componentType)
1955         {
1956             case GL_FLOAT:
1957             {
1958                 std::vector<GLfloat> uniformBuffer(uniformSize);
1959                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1960                 {
1961                     program->getUniformfv(context, readLoc,
1962                                           uniformBuffer.data() + index * componentCount);
1963                 }
1964                 switch (typeInfo->type)
1965                 {
1966                     // Note: All matrix uniforms are populated without transpose
1967                     case GL_FLOAT_MAT4x3:
1968                         Capture(callsOut, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
1969                                                                     uniformCount, false,
1970                                                                     uniformBuffer.data()));
1971                         break;
1972                     case GL_FLOAT_MAT4x2:
1973                         Capture(callsOut, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
1974                                                                     uniformCount, false,
1975                                                                     uniformBuffer.data()));
1976                         break;
1977                     case GL_FLOAT_MAT4:
1978                         Capture(callsOut,
1979                                 CaptureUniformMatrix4fv(replayState, true, uniformLoc, uniformCount,
1980                                                         false, uniformBuffer.data()));
1981                         break;
1982                     case GL_FLOAT_MAT3x4:
1983                         Capture(callsOut, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
1984                                                                     uniformCount, false,
1985                                                                     uniformBuffer.data()));
1986                         break;
1987                     case GL_FLOAT_MAT3x2:
1988                         Capture(callsOut, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
1989                                                                     uniformCount, false,
1990                                                                     uniformBuffer.data()));
1991                         break;
1992                     case GL_FLOAT_MAT3:
1993                         Capture(callsOut,
1994                                 CaptureUniformMatrix3fv(replayState, true, uniformLoc, uniformCount,
1995                                                         false, uniformBuffer.data()));
1996                         break;
1997                     case GL_FLOAT_MAT2x4:
1998                         Capture(callsOut, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
1999                                                                     uniformCount, false,
2000                                                                     uniformBuffer.data()));
2001                         break;
2002                     case GL_FLOAT_MAT2x3:
2003                         Capture(callsOut, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
2004                                                                     uniformCount, false,
2005                                                                     uniformBuffer.data()));
2006                         break;
2007                     case GL_FLOAT_MAT2:
2008                         Capture(callsOut,
2009                                 CaptureUniformMatrix2fv(replayState, true, uniformLoc, uniformCount,
2010                                                         false, uniformBuffer.data()));
2011                         break;
2012                     case GL_FLOAT_VEC4:
2013                         Capture(callsOut, CaptureUniform4fv(replayState, true, uniformLoc,
2014                                                             uniformCount, uniformBuffer.data()));
2015                         break;
2016                     case GL_FLOAT_VEC3:
2017                         Capture(callsOut, CaptureUniform3fv(replayState, true, uniformLoc,
2018                                                             uniformCount, uniformBuffer.data()));
2019                         break;
2020                     case GL_FLOAT_VEC2:
2021                         Capture(callsOut, CaptureUniform2fv(replayState, true, uniformLoc,
2022                                                             uniformCount, uniformBuffer.data()));
2023                         break;
2024                     case GL_FLOAT:
2025                         Capture(callsOut, CaptureUniform1fv(replayState, true, uniformLoc,
2026                                                             uniformCount, uniformBuffer.data()));
2027                         break;
2028                     default:
2029                         UNIMPLEMENTED();
2030                         break;
2031                 }
2032                 break;
2033             }
2034             case GL_INT:
2035             {
2036                 std::vector<GLint> uniformBuffer(uniformSize);
2037                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2038                 {
2039                     program->getUniformiv(context, readLoc,
2040                                           uniformBuffer.data() + index * componentCount);
2041                 }
2042                 switch (componentCount)
2043                 {
2044                     case 4:
2045                         Capture(callsOut, CaptureUniform4iv(replayState, true, uniformLoc,
2046                                                             uniformCount, uniformBuffer.data()));
2047                         break;
2048                     case 3:
2049                         Capture(callsOut, CaptureUniform3iv(replayState, true, uniformLoc,
2050                                                             uniformCount, uniformBuffer.data()));
2051                         break;
2052                     case 2:
2053                         Capture(callsOut, CaptureUniform2iv(replayState, true, uniformLoc,
2054                                                             uniformCount, uniformBuffer.data()));
2055                         break;
2056                     case 1:
2057                         Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc,
2058                                                             uniformCount, uniformBuffer.data()));
2059                         break;
2060                     default:
2061                         UNIMPLEMENTED();
2062                         break;
2063                 }
2064                 break;
2065             }
2066             case GL_BOOL:
2067             case GL_UNSIGNED_INT:
2068             {
2069                 std::vector<GLuint> uniformBuffer(uniformSize);
2070                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2071                 {
2072                     program->getUniformuiv(context, readLoc,
2073                                            uniformBuffer.data() + index * componentCount);
2074                 }
2075                 switch (componentCount)
2076                 {
2077                     case 4:
2078                         Capture(callsOut, CaptureUniform4uiv(replayState, true, uniformLoc,
2079                                                              uniformCount, uniformBuffer.data()));
2080                         break;
2081                     case 3:
2082                         Capture(callsOut, CaptureUniform3uiv(replayState, true, uniformLoc,
2083                                                              uniformCount, uniformBuffer.data()));
2084                         break;
2085                     case 2:
2086                         Capture(callsOut, CaptureUniform2uiv(replayState, true, uniformLoc,
2087                                                              uniformCount, uniformBuffer.data()));
2088                         break;
2089                     case 1:
2090                         Capture(callsOut, CaptureUniform1uiv(replayState, true, uniformLoc,
2091                                                              uniformCount, uniformBuffer.data()));
2092                         break;
2093                     default:
2094                         UNIMPLEMENTED();
2095                         break;
2096                 }
2097                 break;
2098             }
2099             default:
2100                 UNIMPLEMENTED();
2101                 break;
2102         }
2103     }
2104 }
2105 
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2106 void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
2107                              gl::State *replayState,
2108                              GLuint attribIndex,
2109                              const gl::VertexAttribute &attrib,
2110                              const gl::VertexBinding &binding)
2111 {
2112     switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
2113     {
2114         case gl::ClientVertexArrayType::Vertex:
2115             Capture(setupCalls,
2116                     CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
2117                                          attrib.format->vertexAttribType, binding.getStride(),
2118                                          attrib.pointer));
2119             break;
2120         case gl::ClientVertexArrayType::Normal:
2121             Capture(setupCalls,
2122                     CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
2123                                          binding.getStride(), attrib.pointer));
2124             break;
2125         case gl::ClientVertexArrayType::Color:
2126             Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
2127                                                     attrib.format->vertexAttribType,
2128                                                     binding.getStride(), attrib.pointer));
2129             break;
2130         case gl::ClientVertexArrayType::PointSize:
2131             Capture(setupCalls,
2132                     CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
2133                                                binding.getStride(), attrib.pointer));
2134             break;
2135         case gl::ClientVertexArrayType::TextureCoord:
2136             Capture(setupCalls,
2137                     CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
2138                                            attrib.format->vertexAttribType, binding.getStride(),
2139                                            attrib.pointer));
2140             break;
2141         default:
2142             UNREACHABLE();
2143     }
2144 }
2145 
VertexBindingMatchesAttribStride(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2146 bool VertexBindingMatchesAttribStride(const gl::VertexAttribute &attrib,
2147                                       const gl::VertexBinding &binding)
2148 {
2149     if (attrib.vertexAttribArrayStride == 0 &&
2150         binding.getStride() == ComputeVertexAttributeTypeSize(attrib))
2151     {
2152         return true;
2153     }
2154 
2155     return attrib.vertexAttribArrayStride == binding.getStride();
2156 }
2157 
CaptureVertexArrayState(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)2158 void CaptureVertexArrayState(std::vector<CallCapture> *setupCalls,
2159                              const gl::Context *context,
2160                              const gl::VertexArray *vertexArray,
2161                              gl::State *replayState)
2162 {
2163     const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
2164     const std::vector<gl::VertexBinding> &vertexBindings  = vertexArray->getVertexBindings();
2165 
2166     gl::AttributesMask vertexPointerBindings;
2167 
2168     ASSERT(vertexAttribs.size() <= vertexBindings.size());
2169     for (GLuint attribIndex = 0; attribIndex < vertexAttribs.size(); ++attribIndex)
2170     {
2171         const gl::VertexAttribute defaultAttrib(attribIndex);
2172         const gl::VertexBinding defaultBinding;
2173 
2174         const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
2175         const gl::VertexBinding &binding  = vertexBindings[attrib.bindingIndex];
2176 
2177         if (attrib.enabled != defaultAttrib.enabled)
2178         {
2179             if (context->isGLES1())
2180             {
2181                 Capture(setupCalls,
2182                         CaptureEnableClientState(*replayState, false,
2183                                                  gl::GLES1Renderer::VertexArrayType(attribIndex)));
2184             }
2185             else
2186             {
2187                 Capture(setupCalls,
2188                         CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
2189             }
2190         }
2191 
2192         // Don't capture CaptureVertexAttribPointer calls when a non-default VAO is bound, the array
2193         // buffer is null and a non-null attrib pointer is used.
2194         bool skipInvalidAttrib = vertexArray->id().value != 0 &&
2195                                  binding.getBuffer().get() == nullptr && attrib.pointer != nullptr;
2196 
2197         if (!skipInvalidAttrib &&
2198             (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
2199              binding.getStride() != defaultBinding.getStride() ||
2200              binding.getBuffer().get() != nullptr))
2201         {
2202             // Each attribute can pull from a separate buffer, so check the binding
2203             gl::Buffer *buffer = binding.getBuffer().get();
2204             if (buffer != replayState->getArrayBuffer())
2205             {
2206                 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
2207 
2208                 gl::BufferID bufferID = {0};
2209                 if (buffer)
2210                 {
2211                     bufferID = buffer->id();
2212                 }
2213                 Capture(setupCalls,
2214                         CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array, bufferID));
2215             }
2216 
2217             // Establish the relationship between currently bound buffer and the VAO
2218             if (context->isGLES1())
2219             {
2220                 // Track indexes that used ES1 calls
2221                 vertexPointerBindings.set(attribIndex);
2222 
2223                 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
2224             }
2225             else if (attrib.bindingIndex == attribIndex &&
2226                      VertexBindingMatchesAttribStride(attrib, binding) &&
2227                      (!buffer || binding.getOffset() == reinterpret_cast<GLintptr>(attrib.pointer)))
2228             {
2229                 // Check if we can use strictly ES2 semantics, and track indexes that do.
2230                 vertexPointerBindings.set(attribIndex);
2231 
2232                 if (attrib.format->isPureInt())
2233                 {
2234                     Capture(setupCalls, CaptureVertexAttribIPointer(*replayState, true, attribIndex,
2235                                                                     attrib.format->channelCount,
2236                                                                     attrib.format->vertexAttribType,
2237                                                                     attrib.vertexAttribArrayStride,
2238                                                                     attrib.pointer));
2239                 }
2240                 else
2241                 {
2242                     Capture(setupCalls,
2243                             CaptureVertexAttribPointer(
2244                                 *replayState, true, attribIndex, attrib.format->channelCount,
2245                                 attrib.format->vertexAttribType, attrib.format->isNorm(),
2246                                 attrib.vertexAttribArrayStride, attrib.pointer));
2247                 }
2248 
2249                 if (binding.getDivisor() != 0)
2250                 {
2251                     Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
2252                                                                    binding.getDivisor()));
2253                 }
2254             }
2255             else
2256             {
2257                 ASSERT(context->getClientVersion() >= gl::ES_3_1);
2258 
2259                 if (attrib.format->isPureInt())
2260                 {
2261                     Capture(setupCalls, CaptureVertexAttribIFormat(*replayState, true, attribIndex,
2262                                                                    attrib.format->channelCount,
2263                                                                    attrib.format->vertexAttribType,
2264                                                                    attrib.relativeOffset));
2265                 }
2266                 else
2267                 {
2268                     Capture(setupCalls, CaptureVertexAttribFormat(*replayState, true, attribIndex,
2269                                                                   attrib.format->channelCount,
2270                                                                   attrib.format->vertexAttribType,
2271                                                                   attrib.format->isNorm(),
2272                                                                   attrib.relativeOffset));
2273                 }
2274 
2275                 Capture(setupCalls, CaptureVertexAttribBinding(*replayState, true, attribIndex,
2276                                                                attrib.bindingIndex));
2277             }
2278         }
2279     }
2280 
2281     // The loop below expects attribs and bindings to have equal counts
2282     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
2283                   "Max vertex attribs and bindings count mismatch");
2284 
2285     // Loop through binding indices that weren't used by VertexAttribPointer
2286     for (size_t bindingIndex : vertexPointerBindings.flip())
2287     {
2288         const gl::VertexBinding &binding = vertexBindings[bindingIndex];
2289 
2290         if (binding.getBuffer().id().value != 0)
2291         {
2292             Capture(setupCalls,
2293                     CaptureBindVertexBuffer(*replayState, true, static_cast<GLuint>(bindingIndex),
2294                                             binding.getBuffer().id(), binding.getOffset(),
2295                                             binding.getStride()));
2296         }
2297 
2298         if (binding.getDivisor() != 0)
2299         {
2300             Capture(setupCalls, CaptureVertexBindingDivisor(*replayState, true,
2301                                                             static_cast<GLuint>(bindingIndex),
2302                                                             binding.getDivisor()));
2303         }
2304     }
2305 
2306     // The element array buffer is not per attribute, but per VAO
2307     gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
2308     if (elementArrayBuffer)
2309     {
2310         Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
2311                                               elementArrayBuffer->id()));
2312     }
2313 }
2314 
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)2315 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
2316                            gl::State *replayState,
2317                            const gl::Texture *texture)
2318 {
2319     // Use mip-level 0 for the base dimensions
2320     gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
2321     const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
2322 
2323     switch (texture->getType())
2324     {
2325         case gl::TextureType::_2D:
2326         case gl::TextureType::CubeMap:
2327         {
2328             Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
2329                                                     texture->getImmutableLevels(),
2330                                                     desc.format.info->internalFormat,
2331                                                     desc.size.width, desc.size.height));
2332             break;
2333         }
2334         case gl::TextureType::_3D:
2335         case gl::TextureType::_2DArray:
2336         case gl::TextureType::CubeMapArray:
2337         {
2338             Capture(setupCalls, CaptureTexStorage3D(
2339                                     *replayState, true, texture->getType(),
2340                                     texture->getImmutableLevels(), desc.format.info->internalFormat,
2341                                     desc.size.width, desc.size.height, desc.size.depth));
2342             break;
2343         }
2344         case gl::TextureType::Buffer:
2345         {
2346             // Do nothing. This will already be captured as a buffer.
2347             break;
2348         }
2349         default:
2350             UNIMPLEMENTED();
2351             break;
2352     }
2353 }
2354 
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)2355 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
2356                             gl::State *replayState,
2357                             const gl::Texture *texture,
2358                             const gl::ImageIndex &index,
2359                             const gl::ImageDesc &desc,
2360                             GLuint size,
2361                             const void *data)
2362 {
2363     const gl::InternalFormat &format = *desc.format.info;
2364 
2365     if (index.getType() == gl::TextureType::Buffer)
2366     {
2367         // Zero binding size indicates full buffer bound
2368         if (texture->getBuffer().getSize() == 0)
2369         {
2370             Capture(setupCalls,
2371                     CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
2372                                         texture->getBuffer().get()->id()));
2373         }
2374         else
2375         {
2376             Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
2377                                                          format.internalFormat,
2378                                                          texture->getBuffer().get()->id(),
2379                                                          texture->getBuffer().getOffset(),
2380                                                          texture->getBuffer().getSize()));
2381         }
2382 
2383         // For buffers, we're done
2384         return;
2385     }
2386 
2387     bool is3D =
2388         (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
2389          index.getType() == gl::TextureType::CubeMapArray);
2390 
2391     if (format.compressed)
2392     {
2393         if (is3D)
2394         {
2395             if (texture->getImmutableFormat())
2396             {
2397                 Capture(setupCalls,
2398                         CaptureCompressedTexSubImage3D(
2399                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
2400                             desc.size.width, desc.size.height, desc.size.depth,
2401                             format.internalFormat, size, data));
2402             }
2403             else
2404             {
2405                 Capture(setupCalls,
2406                         CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
2407                                                     index.getLevelIndex(), format.internalFormat,
2408                                                     desc.size.width, desc.size.height,
2409                                                     desc.size.depth, 0, size, data));
2410             }
2411         }
2412         else
2413         {
2414             if (texture->getImmutableFormat())
2415             {
2416                 Capture(setupCalls,
2417                         CaptureCompressedTexSubImage2D(
2418                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
2419                             desc.size.width, desc.size.height, format.internalFormat, size, data));
2420             }
2421             else
2422             {
2423                 Capture(setupCalls, CaptureCompressedTexImage2D(
2424                                         *replayState, true, index.getTarget(),
2425                                         index.getLevelIndex(), format.internalFormat,
2426                                         desc.size.width, desc.size.height, 0, size, data));
2427             }
2428         }
2429     }
2430     else
2431     {
2432         if (is3D)
2433         {
2434             if (texture->getImmutableFormat())
2435             {
2436                 Capture(setupCalls,
2437                         CaptureTexSubImage3D(*replayState, true, index.getTarget(),
2438                                              index.getLevelIndex(), 0, 0, 0, desc.size.width,
2439                                              desc.size.height, desc.size.depth, format.format,
2440                                              format.type, data));
2441             }
2442             else
2443             {
2444                 Capture(
2445                     setupCalls,
2446                     CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
2447                                       format.internalFormat, desc.size.width, desc.size.height,
2448                                       desc.size.depth, 0, format.format, format.type, data));
2449             }
2450         }
2451         else
2452         {
2453             if (texture->getImmutableFormat())
2454             {
2455                 Capture(setupCalls,
2456                         CaptureTexSubImage2D(*replayState, true, index.getTarget(),
2457                                              index.getLevelIndex(), 0, 0, desc.size.width,
2458                                              desc.size.height, format.format, format.type, data));
2459             }
2460             else
2461             {
2462                 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
2463                                                       index.getLevelIndex(), format.internalFormat,
2464                                                       desc.size.width, desc.size.height, 0,
2465                                                       format.format, format.type, data));
2466             }
2467         }
2468     }
2469 }
2470 
GenerateLinkedProgram(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,std::vector<CallCapture> * setupCalls,gl::Program * program,gl::ShaderProgramID id,gl::ShaderProgramID tempIDStart,const ProgramSources & linkedSources)2471 void GenerateLinkedProgram(const gl::Context *context,
2472                            const gl::State &replayState,
2473                            ResourceTracker *resourceTracker,
2474                            std::vector<CallCapture> *setupCalls,
2475                            gl::Program *program,
2476                            gl::ShaderProgramID id,
2477                            gl::ShaderProgramID tempIDStart,
2478                            const ProgramSources &linkedSources)
2479 {
2480     // A map to store the gShaderProgram map lookup index of the temp shaders we attached below. We
2481     // need this map to retrieve the lookup index to pass to CaptureDetachShader calls at the end of
2482     // GenerateLinkedProgram.
2483     PackedEnumMap<gl::ShaderType, gl::ShaderProgramID> tempShaderIDTracker;
2484 
2485     // Compile with last linked sources.
2486     for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
2487     {
2488         // Bump the max shader program id for each new tempIDStart we use to create, compile, and
2489         // attach the temp shader object.
2490         resourceTracker->onShaderProgramAccess(tempIDStart);
2491         // Store the tempIDStart in the tempShaderIDTracker to retrieve for CaptureDetachShader
2492         // calls later.
2493         tempShaderIDTracker[shaderType] = tempIDStart;
2494         const std::string &sourceString = linkedSources[shaderType];
2495         const char *sourcePointer       = sourceString.c_str();
2496 
2497         if (sourceString.empty())
2498         {
2499             // If we don't have source for this shader, that means it was populated by the app
2500             // using glProgramBinary.  We need to look it up from our cached copy.
2501             const ProgramSources &cachedLinkedSources =
2502                 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
2503 
2504             const std::string &cachedSourceString = cachedLinkedSources[shaderType];
2505             sourcePointer                         = cachedSourceString.c_str();
2506             ASSERT(!cachedSourceString.empty());
2507         }
2508 
2509         // Compile and attach the temporary shader. Then free it immediately.
2510         Capture(setupCalls, CaptureCreateShader(replayState, true, shaderType, tempIDStart.value));
2511         Capture(setupCalls,
2512                 CaptureShaderSource(replayState, true, tempIDStart, 1, &sourcePointer, nullptr));
2513         Capture(setupCalls, CaptureCompileShader(replayState, true, tempIDStart));
2514         Capture(setupCalls, CaptureAttachShader(replayState, true, id, tempIDStart));
2515         // Increment tempIDStart to get a new gShaderProgram map index for the next linked stage
2516         // shader object. We can't reuse the same tempIDStart as we need to retrieve the index of
2517         // each attached shader object later to pass to CaptureDetachShader calls.
2518         tempIDStart.value += 1;
2519     }
2520 
2521     // Gather XFB varyings
2522     std::vector<std::string> xfbVaryings;
2523     for (const gl::TransformFeedbackVarying &xfbVarying :
2524          program->getState().getLinkedTransformFeedbackVaryings())
2525     {
2526         xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
2527     }
2528 
2529     if (!xfbVaryings.empty())
2530     {
2531         std::vector<const char *> varyingsStrings;
2532         for (const std::string &varyingString : xfbVaryings)
2533         {
2534             varyingsStrings.push_back(varyingString.data());
2535         }
2536 
2537         GLenum xfbMode = program->getState().getTransformFeedbackBufferMode();
2538         Capture(setupCalls, CaptureTransformFeedbackVaryings(replayState, true, id,
2539                                                              static_cast<GLint>(xfbVaryings.size()),
2540                                                              varyingsStrings.data(), xfbMode));
2541     }
2542 
2543     // Force the attributes to be bound the same way as in the existing program.
2544     // This can affect attributes that are optimized out in some implementations.
2545     for (const sh::ShaderVariable &attrib : program->getState().getProgramInputs())
2546     {
2547         if (gl::IsBuiltInName(attrib.name))
2548         {
2549             // Don't try to bind built-in attributes
2550             continue;
2551         }
2552 
2553         // Separable programs may not have a VS, meaning it may not have attributes.
2554         if (program->getExecutable().hasLinkedShaderStage(gl::ShaderType::Vertex))
2555         {
2556             ASSERT(attrib.location != -1);
2557             Capture(setupCalls, CaptureBindAttribLocation(replayState, true, id,
2558                                                           static_cast<GLuint>(attrib.location),
2559                                                           attrib.name.c_str()));
2560         }
2561     }
2562 
2563     if (program->isSeparable())
2564     {
2565         // MEC manually recreates separable programs, rather than attempting to recreate a call
2566         // to glCreateShaderProgramv(), so insert a call to mark it separable.
2567         Capture(setupCalls,
2568                 CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
2569     }
2570 
2571     Capture(setupCalls, CaptureLinkProgram(replayState, true, id));
2572     CaptureUpdateUniformLocations(program, setupCalls);
2573     CaptureUpdateUniformValues(replayState, context, program, setupCalls);
2574     CaptureUpdateUniformBlockIndexes(program, setupCalls);
2575 
2576     // Capture uniform block bindings for each program
2577     for (unsigned int uniformBlockIndex = 0;
2578          uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
2579     {
2580         GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
2581         Capture(setupCalls, CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex},
2582                                                        blockBinding));
2583     }
2584 
2585     // Add DetachShader call if that's what the app does, so that the
2586     // ResourceManagerBase::mHandleAllocator can release the ShaderProgramID handle assigned to the
2587     // shader object when glDeleteShader is called. This ensures the ShaderProgramID handles used in
2588     // SetupReplayContextShared() are consistent with the ShaderProgramID handles used by the app.
2589     for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
2590     {
2591         gl::Shader *attachedShader = program->getAttachedShader(shaderType);
2592         if (attachedShader == nullptr)
2593         {
2594             Capture(setupCalls,
2595                     CaptureDetachShader(replayState, true, id, tempShaderIDTracker[shaderType]));
2596         }
2597         Capture(setupCalls,
2598                 CaptureDeleteShader(replayState, true, tempShaderIDTracker[shaderType]));
2599     }
2600 }
2601 
2602 // TODO(http://anglebug.com/4599): Improve reset/restore call generation
2603 // There are multiple ways to track reset calls for individual resources. For now, we are tracking
2604 // separate lists of instructions that mirror the calls created during mid-execution setup. Other
2605 // methods could involve passing the original CallCaptures to this function, or tracking the
2606 // indices of original setup calls.
CaptureBufferResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)2607 void CaptureBufferResetCalls(const gl::State &replayState,
2608                              ResourceTracker *resourceTracker,
2609                              gl::BufferID *id,
2610                              const gl::Buffer *buffer)
2611 {
2612     GLuint bufferID = (*id).value;
2613 
2614     // Track this as a starting resource that may need to be restored.
2615     TrackedResource &trackedBuffers = resourceTracker->getTrackedResource(ResourceIDType::Buffer);
2616 
2617     // Track calls to regenerate a given buffer
2618     ResourceCalls &bufferRegenCalls = trackedBuffers.getResourceRegenCalls();
2619     Capture(&bufferRegenCalls[bufferID], CaptureGenBuffers(replayState, true, 1, id));
2620     MaybeCaptureUpdateResourceIDs(resourceTracker, &bufferRegenCalls[bufferID]);
2621 
2622     // Call glBufferStorageEXT when regenerating immutable buffers,
2623     // as we can't call glBufferData on restore.
2624     if (buffer->isImmutable())
2625     {
2626         Capture(&bufferRegenCalls[bufferID],
2627                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2628         Capture(
2629             &bufferRegenCalls[bufferID],
2630             CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
2631                                     static_cast<GLsizeiptr>(buffer->getSize()),
2632                                     buffer->getMapPointer(), buffer->getStorageExtUsageFlags()));
2633     }
2634 
2635     // Track calls to restore a given buffer's contents
2636     ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
2637     Capture(&bufferRestoreCalls[bufferID],
2638             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2639 
2640     // Mutable buffers will be restored here using glBufferData.
2641     // Immutable buffers need to be restored below, after maping.
2642     if (!buffer->isImmutable())
2643     {
2644         Capture(&bufferRestoreCalls[bufferID],
2645                 CaptureBufferData(replayState, true, gl::BufferBinding::Array,
2646                                   static_cast<GLsizeiptr>(buffer->getSize()),
2647                                   buffer->getMapPointer(), buffer->getUsage()));
2648     }
2649 
2650     if (buffer->isMapped())
2651     {
2652         // Track calls to remap a buffer that started as mapped
2653         BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
2654 
2655         Capture(&bufferMapCalls[bufferID],
2656                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2657 
2658         void *dontCare = nullptr;
2659         Capture(&bufferMapCalls[bufferID],
2660                 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
2661                                       static_cast<GLsizeiptr>(buffer->getMapOffset()),
2662                                       static_cast<GLsizeiptr>(buffer->getMapLength()),
2663                                       buffer->getAccessFlags(), dontCare));
2664 
2665         // Track the bufferID that was just mapped
2666         bufferMapCalls[bufferID].back().params.setMappedBufferID(buffer->id());
2667 
2668         // Restore immutable mapped buffers. Needs to happen after mapping.
2669         if (buffer->isImmutable())
2670         {
2671             ParamBuffer dataParamBuffer;
2672             dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
2673             ParamCapture captureData("source", ParamType::TvoidConstPointer);
2674             CaptureMemory(buffer->getMapPointer(), static_cast<GLsizeiptr>(buffer->getSize()),
2675                           &captureData);
2676             dataParamBuffer.addParam(std::move(captureData));
2677             dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
2678                                                       static_cast<GLsizeiptr>(buffer->getSize()));
2679             bufferMapCalls[bufferID].emplace_back("UpdateClientBufferData",
2680                                                   std::move(dataParamBuffer));
2681         }
2682     }
2683 
2684     // Track calls unmap a buffer that started as unmapped
2685     BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
2686     Capture(&bufferUnmapCalls[bufferID],
2687             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2688     Capture(&bufferUnmapCalls[bufferID],
2689             CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
2690 }
2691 
CaptureFenceSyncResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,GLsync syncID,const gl::Sync * sync)2692 void CaptureFenceSyncResetCalls(const gl::State &replayState,
2693                                 ResourceTracker *resourceTracker,
2694                                 GLsync syncID,
2695                                 const gl::Sync *sync)
2696 {
2697     // Track calls to regenerate a given fence sync
2698     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
2699     Capture(&fenceSyncRegenCalls[syncID],
2700             CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
2701     MaybeCaptureUpdateResourceIDs(resourceTracker, &fenceSyncRegenCalls[syncID]);
2702 }
2703 
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)2704 void CaptureBufferBindingResetCalls(const gl::State &replayState,
2705                                     ResourceTracker *resourceTracker,
2706                                     gl::BufferBinding binding,
2707                                     gl::BufferID id)
2708 {
2709     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
2710     Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
2711 }
2712 
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)2713 void CaptureIndexedBuffers(const gl::State &glState,
2714                            const gl::BufferVector &indexedBuffers,
2715                            gl::BufferBinding binding,
2716                            std::vector<CallCapture> *setupCalls)
2717 {
2718     for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
2719     {
2720         const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
2721 
2722         if (buffer.get() == nullptr)
2723         {
2724             continue;
2725         }
2726 
2727         GLintptr offset       = buffer.getOffset();
2728         GLsizeiptr size       = buffer.getSize();
2729         gl::BufferID bufferID = buffer.get()->id();
2730 
2731         // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
2732         if ((offset == 0) && (size == 0))
2733         {
2734             Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
2735         }
2736         else
2737         {
2738             Capture(setupCalls,
2739                     CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
2740         }
2741     }
2742 }
2743 
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)2744 void CaptureDefaultVertexAttribs(const gl::State &replayState,
2745                                  const gl::State &apiState,
2746                                  std::vector<CallCapture> *setupCalls)
2747 {
2748     const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
2749         apiState.getVertexAttribCurrentValues();
2750 
2751     for (GLuint attribIndex = 0; attribIndex < currentValues.size(); ++attribIndex)
2752     {
2753         const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
2754         if (!IsDefaultCurrentValue(defaultValue))
2755         {
2756             Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
2757                                                        defaultValue.Values.FloatValues));
2758         }
2759     }
2760 }
2761 
2762 // Capture the setup of the state that's shared by all of the contexts in the share group:
2763 // OpenGL ES Version 3.2 (October 22, 2019)
2764 // Chapter 5 Shared Objects and Multiple Contexts
2765 //     Objects that can be shared between contexts include buffer objects, program
2766 //   and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
2767 //   objects (except for the texture objects named zero).
2768 //     Objects which contain references to other objects include framebuffer, program
2769 //   pipeline, transform feedback, and vertex array objects. Such objects are called
2770 //   container objects and are not shared.
CaptureShareGroupMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker,gl::State & replayState)2771 void CaptureShareGroupMidExecutionSetup(const gl::Context *context,
2772                                         std::vector<CallCapture> *setupCalls,
2773                                         ResourceTracker *resourceTracker,
2774                                         gl::State &replayState)
2775 {
2776 
2777     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
2778     const gl::State &apiState              = context->getState();
2779 
2780     // Small helper function to make the code more readable.
2781     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
2782 
2783     // Capture Buffer data.
2784     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
2785     for (const auto &bufferIter : buffers)
2786     {
2787         gl::BufferID id    = {bufferIter.first};
2788         gl::Buffer *buffer = bufferIter.second;
2789 
2790         if (id.value == 0)
2791         {
2792             continue;
2793         }
2794 
2795         // Generate binding.
2796         cap(CaptureGenBuffers(replayState, true, 1, &id));
2797 
2798         resourceTracker->getTrackedResource(ResourceIDType::Buffer)
2799             .getStartingResources()
2800             .insert(id.value);
2801 
2802         MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
2803 
2804         // glBufferData. Would possibly be better implemented using a getData impl method.
2805         // Saving buffers that are mapped during a swap is not yet handled.
2806         if (buffer->getSize() == 0)
2807         {
2808             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
2809             continue;
2810         }
2811 
2812         // Remember if the buffer was already mapped
2813         GLboolean bufferMapped = buffer->isMapped();
2814 
2815         // If needed, map the buffer so we can capture its contents
2816         if (!bufferMapped)
2817         {
2818             (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
2819                                    GL_MAP_READ_BIT);
2820         }
2821 
2822         // Always use the array buffer binding point to upload data to keep things simple.
2823         if (buffer != replayState.getArrayBuffer())
2824         {
2825             replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
2826             cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
2827         }
2828 
2829         if (buffer->isImmutable())
2830         {
2831             cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
2832                                         static_cast<GLsizeiptr>(buffer->getSize()),
2833                                         buffer->getMapPointer(),
2834                                         buffer->getStorageExtUsageFlags()));
2835         }
2836         else
2837         {
2838             cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
2839                                   static_cast<GLsizeiptr>(buffer->getSize()),
2840                                   buffer->getMapPointer(), buffer->getUsage()));
2841         }
2842 
2843         if (bufferMapped)
2844         {
2845             void *dontCare = nullptr;
2846             Capture(setupCalls,
2847                     CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
2848                                           static_cast<GLsizeiptr>(buffer->getMapOffset()),
2849                                           static_cast<GLsizeiptr>(buffer->getMapLength()),
2850                                           buffer->getAccessFlags(), dontCare));
2851 
2852             resourceTracker->setStartingBufferMapped(buffer->id().value, true);
2853 
2854             frameCaptureShared->trackBufferMapping(
2855                 &setupCalls->back(), buffer->id(), buffer,
2856                 static_cast<GLsizeiptr>(buffer->getMapOffset()),
2857                 static_cast<GLsizeiptr>(buffer->getMapLength()),
2858                 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0,
2859                 (buffer->getStorageExtUsageFlags() & GL_MAP_COHERENT_BIT_EXT) != 0);
2860         }
2861         else
2862         {
2863             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
2864         }
2865 
2866         // Generate the calls needed to restore this buffer to original state for frame looping
2867         CaptureBufferResetCalls(replayState, resourceTracker, &id, buffer);
2868 
2869         // Unmap the buffer if it wasn't already mapped
2870         if (!bufferMapped)
2871         {
2872             GLboolean dontCare;
2873             (void)buffer->unmap(context, &dontCare);
2874         }
2875     }
2876 
2877     // Clear the array buffer binding.
2878     if (replayState.getTargetBuffer(gl::BufferBinding::Array))
2879     {
2880         cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, {0}));
2881         replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
2882     }
2883 
2884     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
2885     // leading to a crash in memcpy() when capturing the texture contents.
2886     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
2887     if (currentUnpackState.alignment != 1)
2888     {
2889         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
2890         currentUnpackState.alignment = 1;
2891     }
2892 
2893     // Capture Texture setup and data.
2894     const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
2895 
2896     for (const auto &textureIter : textures)
2897     {
2898         gl::TextureID id     = {textureIter.first};
2899         gl::Texture *texture = textureIter.second;
2900 
2901         if (id.value == 0)
2902         {
2903             continue;
2904         }
2905 
2906         // Track this as a starting resource that may need to be restored.
2907         TrackedResource &trackedTextures =
2908             resourceTracker->getTrackedResource(ResourceIDType::Texture);
2909         ResourceSet &startingTextures = trackedTextures.getStartingResources();
2910         startingTextures.insert(id.value);
2911 
2912         // For the initial texture creation calls, track in the generate list
2913         ResourceCalls &textureRegenCalls = trackedTextures.getResourceRegenCalls();
2914         CallVector texGenCalls({setupCalls, &textureRegenCalls[id.value]});
2915 
2916         // Gen the Texture.
2917         for (std::vector<CallCapture> *calls : texGenCalls)
2918         {
2919             Capture(calls, CaptureGenTextures(replayState, true, 1, &id));
2920             MaybeCaptureUpdateResourceIDs(resourceTracker, calls);
2921         }
2922 
2923         // For the remaining texture setup calls, track in the restore list
2924         ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
2925         CallVector texSetupCalls({setupCalls, &textureRestoreCalls[id.value]});
2926 
2927         for (std::vector<CallCapture> *calls : texSetupCalls)
2928         {
2929             Capture(calls, CaptureBindTexture(replayState, true, texture->getType(), id));
2930         }
2931         replayState.setSamplerTexture(context, texture->getType(), texture);
2932 
2933         // Capture sampler parameter states.
2934         // TODO(jmadill): More sampler / texture states. http://anglebug.com/3662
2935         gl::SamplerState defaultSamplerState =
2936             gl::SamplerState::CreateDefaultForTarget(texture->getType());
2937         const gl::SamplerState &textureSamplerState = texture->getSamplerState();
2938 
2939         auto capTexParam = [&replayState, texture, &texSetupCalls](GLenum pname, GLint param) {
2940             for (std::vector<CallCapture> *calls : texSetupCalls)
2941             {
2942                 Capture(calls,
2943                         CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
2944             }
2945         };
2946 
2947         auto capTexParamf = [&replayState, texture, &texSetupCalls](GLenum pname, GLfloat param) {
2948             for (std::vector<CallCapture> *calls : texSetupCalls)
2949             {
2950                 Capture(calls,
2951                         CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
2952             }
2953         };
2954 
2955         if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
2956         {
2957             capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
2958         }
2959 
2960         if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
2961         {
2962             capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
2963         }
2964 
2965         if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
2966         {
2967             capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
2968         }
2969 
2970         if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
2971         {
2972             capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
2973         }
2974 
2975         if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
2976         {
2977             capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
2978         }
2979 
2980         if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
2981         {
2982             capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
2983         }
2984 
2985         if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
2986         {
2987             capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
2988         }
2989 
2990         if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
2991         {
2992             capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
2993         }
2994 
2995         if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
2996         {
2997             capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
2998         }
2999 
3000         // Texture parameters
3001         if (texture->getSwizzleRed() != GL_RED)
3002         {
3003             capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
3004         }
3005 
3006         if (texture->getSwizzleGreen() != GL_GREEN)
3007         {
3008             capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
3009         }
3010 
3011         if (texture->getSwizzleBlue() != GL_BLUE)
3012         {
3013             capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
3014         }
3015 
3016         if (texture->getSwizzleAlpha() != GL_ALPHA)
3017         {
3018             capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
3019         }
3020 
3021         if (texture->getBaseLevel() != 0)
3022         {
3023             capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
3024         }
3025 
3026         if (texture->getMaxLevel() != 1000)
3027         {
3028             capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
3029         }
3030 
3031         // If the texture is immutable, initialize it with TexStorage
3032         if (texture->getImmutableFormat())
3033         {
3034             // We can only call TexStorage *once* on an immutable texture, so it needs special
3035             // handling. To solve this, immutable textures will have a BindTexture and TexStorage as
3036             // part of their textureRegenCalls. The resulting regen sequence will be:
3037             //
3038             //    const GLuint glDeleteTextures_texturesPacked_0[] = { gTextureMap[52] };
3039             //    glDeleteTextures(1, glDeleteTextures_texturesPacked_0);
3040             //    glGenTextures(1, reinterpret_cast<GLuint *>(gReadBuffer));
3041             //    UpdateTextureID(52, 0);
3042             //    glBindTexture(GL_TEXTURE_2D, gTextureMap[52]);
3043             //    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, 256, 512);
3044 
3045             // Bind the texture first just for textureRegenCalls
3046             Capture(&textureRegenCalls[id.value],
3047                     CaptureBindTexture(replayState, true, texture->getType(), id));
3048 
3049             // Then add TexStorage to texGenCalls instead of texSetupCalls
3050             for (std::vector<CallCapture> *calls : texGenCalls)
3051             {
3052                 CaptureTextureStorage(calls, &replayState, texture);
3053             }
3054         }
3055 
3056         // Iterate texture levels and layers.
3057         gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
3058             texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
3059             gl::ImageIndex::kEntireLevel);
3060         while (imageIter.hasNext())
3061         {
3062             gl::ImageIndex index = imageIter.next();
3063 
3064             const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
3065 
3066             if (desc.size.empty())
3067             {
3068                 continue;
3069             }
3070 
3071             const gl::InternalFormat &format = *desc.format.info;
3072 
3073             bool supportedType = (index.getType() == gl::TextureType::_2D ||
3074                                   index.getType() == gl::TextureType::_3D ||
3075                                   index.getType() == gl::TextureType::_2DArray ||
3076                                   index.getType() == gl::TextureType::Buffer ||
3077                                   index.getType() == gl::TextureType::CubeMap ||
3078                                   index.getType() == gl::TextureType::CubeMapArray);
3079 
3080             // Check for supported textures
3081             if (!supportedType)
3082             {
3083                 ERR() << "Unsupported texture type: " << index.getType();
3084                 UNREACHABLE();
3085             }
3086 
3087             if (index.getType() == gl::TextureType::Buffer)
3088             {
3089                 // The buffer contents are already backed up, but we need to emit the TexBuffer
3090                 // binding calls
3091                 for (std::vector<CallCapture> *calls : texSetupCalls)
3092                 {
3093                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, 0);
3094                 }
3095                 continue;
3096             }
3097 
3098             if (context->getExtensions().getImageANGLE)
3099             {
3100                 // Use ANGLE_get_image to read back pixel data.
3101                 angle::MemoryBuffer data;
3102 
3103                 const gl::Extents extents(desc.size.width, desc.size.height, desc.size.depth);
3104 
3105                 gl::PixelPackState packState;
3106                 packState.alignment = 1;
3107 
3108                 if (format.compressed)
3109                 {
3110                     // Calculate the size needed to store the compressed level
3111                     GLuint sizeInBytes;
3112                     bool result = format.computeCompressedImageSize(extents, &sizeInBytes);
3113                     ASSERT(result);
3114 
3115                     result = data.resize(sizeInBytes);
3116                     ASSERT(result);
3117 
3118                     (void)texture->getCompressedTexImage(context, packState, nullptr,
3119                                                          index.getTarget(), index.getLevelIndex(),
3120                                                          data.data());
3121                 }
3122                 else
3123                 {
3124                     GLenum getFormat = format.format;
3125                     GLenum getType   = format.type;
3126 
3127                     const gl::PixelUnpackState &unpack = apiState.getUnpackState();
3128 
3129                     GLuint endByte = 0;
3130                     bool unpackSize =
3131                         format.computePackUnpackEndByte(getType, extents, unpack, true, &endByte);
3132                     ASSERT(unpackSize);
3133 
3134                     bool result = data.resize(endByte);
3135                     ASSERT(result);
3136 
3137                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
3138                                                index.getLevelIndex(), getFormat, getType,
3139                                                data.data());
3140                 }
3141 
3142                 for (std::vector<CallCapture> *calls : texSetupCalls)
3143                 {
3144                     CaptureTextureContents(calls, &replayState, texture, index, desc,
3145                                            static_cast<GLuint>(data.size()), data.data());
3146                 }
3147             }
3148             else
3149             {
3150                 for (std::vector<CallCapture> *calls : texSetupCalls)
3151                 {
3152                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, nullptr);
3153                 }
3154             }
3155         }
3156     }
3157 
3158     // Capture Renderbuffers.
3159     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
3160     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
3161 
3162     for (const auto &renderbufIter : renderbuffers)
3163     {
3164         gl::RenderbufferID id                = {renderbufIter.first};
3165         const gl::Renderbuffer *renderbuffer = renderbufIter.second;
3166 
3167         // Generate renderbuffer id.
3168         cap(framebufferFuncs.genRenderbuffers(replayState, true, 1, &id));
3169 
3170         resourceTracker->getTrackedResource(ResourceIDType::Renderbuffer)
3171             .getStartingResources()
3172             .insert(id.value);
3173 
3174         MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
3175         cap(framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
3176 
3177         GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
3178 
3179         if (renderbuffer->getSamples() > 0)
3180         {
3181             // Note: We could also use extensions if available.
3182             cap(CaptureRenderbufferStorageMultisample(
3183                 replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat,
3184                 renderbuffer->getWidth(), renderbuffer->getHeight()));
3185         }
3186         else
3187         {
3188             cap(framebufferFuncs.renderbufferStorage(replayState, true, GL_RENDERBUFFER,
3189                                                      internalformat, renderbuffer->getWidth(),
3190                                                      renderbuffer->getHeight()));
3191         }
3192 
3193         // TODO(jmadill): Capture renderbuffer contents. http://anglebug.com/3662
3194     }
3195 
3196     // Capture Shaders and Programs.
3197     const gl::ShaderProgramManager &shadersAndPrograms =
3198         apiState.getShaderProgramManagerForCapture();
3199     const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
3200         shadersAndPrograms.getShadersForCapture();
3201     const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
3202         shadersAndPrograms.getProgramsForCaptureAndPerf();
3203 
3204     // Capture Program binary state.
3205     gl::ShaderProgramID tempShaderStartID = {resourceTracker->getMaxShaderPrograms()};
3206     for (const auto &programIter : programs)
3207     {
3208         gl::ShaderProgramID id = {programIter.first};
3209         gl::Program *program   = programIter.second;
3210 
3211         // Unlinked programs don't have an executable. Thus they don't need to be captured.
3212         // Programs are shared by contexts in the share group and only need to be captured once.
3213         if (!program->isLinked())
3214         {
3215             continue;
3216         }
3217 
3218         size_t programSetupStart = setupCalls->size();
3219 
3220         // Get last linked shader source.
3221         const ProgramSources &linkedSources =
3222             context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
3223 
3224         cap(CaptureCreateProgram(replayState, true, id.value));
3225 
3226         GenerateLinkedProgram(context, replayState, resourceTracker, setupCalls, program, id,
3227                               tempShaderStartID, linkedSources);
3228 
3229         // Update the program in replayState
3230         if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
3231         {
3232             // Note: We don't do this in GenerateLinkedProgram because it can't modify state
3233             (void)replayState.setProgram(context, program);
3234         }
3235 
3236         resourceTracker->getTrackedResource(ResourceIDType::ShaderProgram)
3237             .getStartingResources()
3238             .insert(id.value);
3239 
3240         size_t programSetupEnd = setupCalls->size();
3241 
3242         // Mark the range of calls used to setup this program
3243         frameCaptureShared->markResourceSetupCallsInactive(
3244             setupCalls, ResourceIDType::ShaderProgram, id.value,
3245             gl::Range<size_t>(programSetupStart, programSetupEnd));
3246     }
3247 
3248     // Handle shaders.
3249     for (const auto &shaderIter : shaders)
3250     {
3251         gl::ShaderProgramID id = {shaderIter.first};
3252         gl::Shader *shader     = shaderIter.second;
3253 
3254         // Skip shaders scheduled for deletion.
3255         // Shaders are shared by contexts in the share group and only need to be captured once.
3256         if (shader->hasBeenDeleted())
3257         {
3258             continue;
3259         }
3260 
3261         size_t shaderSetupStart = setupCalls->size();
3262 
3263         cap(CaptureCreateShader(replayState, true, shader->getType(), id.value));
3264 
3265         std::string shaderSource  = shader->getSourceString();
3266         const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
3267 
3268         // This does not handle some more tricky situations like attaching shaders to a non-linked
3269         // program. Or attaching uncompiled shaders. Or attaching and then deleting a shader.
3270         // TODO(jmadill): Handle trickier program uses. http://anglebug.com/3662
3271         if (shader->isCompiled())
3272         {
3273             const std::string &capturedSource =
3274                 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
3275             if (capturedSource != shaderSource)
3276             {
3277                 ASSERT(!capturedSource.empty());
3278                 sourcePointer = capturedSource.c_str();
3279             }
3280 
3281             cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
3282             cap(CaptureCompileShader(replayState, true, id));
3283         }
3284 
3285         if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str()))
3286         {
3287             cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
3288         }
3289 
3290         size_t shaderSetupEnd = setupCalls->size();
3291 
3292         // Mark the range of calls used to setup this shader
3293         frameCaptureShared->markResourceSetupCallsInactive(
3294             setupCalls, ResourceIDType::ShaderProgram, id.value,
3295             gl::Range<size_t>(shaderSetupStart, shaderSetupEnd));
3296     }
3297 
3298     // Capture Sampler Objects
3299     const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
3300     for (const auto &samplerIter : samplers)
3301     {
3302         gl::SamplerID samplerID = {samplerIter.first};
3303 
3304         // Don't gen the sampler if we've seen it before, since they are shared across the context
3305         // share group.
3306         cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
3307         MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
3308 
3309         gl::Sampler *sampler = samplerIter.second;
3310         if (!sampler)
3311         {
3312             continue;
3313         }
3314 
3315         gl::SamplerState defaultSamplerState;
3316         if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
3317         {
3318             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
3319                                          sampler->getMinFilter()));
3320         }
3321         if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
3322         {
3323             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
3324                                          sampler->getMagFilter()));
3325         }
3326         if (sampler->getWrapS() != defaultSamplerState.getWrapS())
3327         {
3328             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
3329                                          sampler->getWrapS()));
3330         }
3331         if (sampler->getWrapR() != defaultSamplerState.getWrapR())
3332         {
3333             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
3334                                          sampler->getWrapR()));
3335         }
3336         if (sampler->getWrapT() != defaultSamplerState.getWrapT())
3337         {
3338             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
3339                                          sampler->getWrapT()));
3340         }
3341         if (sampler->getMinLod() != defaultSamplerState.getMinLod())
3342         {
3343             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
3344                                          sampler->getMinLod()));
3345         }
3346         if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
3347         {
3348             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
3349                                          sampler->getMaxLod()));
3350         }
3351         if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
3352         {
3353             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
3354                                          sampler->getCompareMode()));
3355         }
3356         if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
3357         {
3358             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
3359                                          sampler->getCompareFunc()));
3360         }
3361     }
3362 
3363     // Capture Sync Objects
3364     const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
3365     for (const auto &syncIter : syncs)
3366     {
3367         GLsync syncID        = gl::bitCast<GLsync>(static_cast<size_t>(syncIter.first));
3368         const gl::Sync *sync = syncIter.second;
3369 
3370         if (!sync)
3371         {
3372             continue;
3373         }
3374         cap(CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
3375         CaptureFenceSyncResetCalls(replayState, resourceTracker, syncID, sync);
3376         resourceTracker->getStartingFenceSyncs().insert(syncID);
3377     }
3378 }
3379 
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls,ResourceTracker * resourceTracker,gl::State & replayState,bool validationEnabled)3380 void CaptureMidExecutionSetup(const gl::Context *context,
3381                               std::vector<CallCapture> *setupCalls,
3382                               std::vector<CallCapture> *shareGroupSetupCalls,
3383                               ResourceIDToSetupCallsMap *resourceIDToSetupCalls,
3384                               ResourceTracker *resourceTracker,
3385                               gl::State &replayState,
3386                               bool validationEnabled)
3387 {
3388     const gl::State &apiState = context->getState();
3389 
3390     // Small helper function to make the code more readable.
3391     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
3392 
3393     // Need to go from uint32 -> uint64 -> EGLContext (void*) to handle MSVC compiler
3394     // warning on 64b systems:
3395     //   error C4312: 'reinterpret_cast': conversion from 'uint32_t' to 'EGLContext' of
3396     //   greater size
3397     uint64_t contextID    = static_cast<uint64_t>(context->id().value);
3398     EGLContext eglContext = reinterpret_cast<EGLContext>(contextID);
3399     cap(CaptureMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext));
3400 
3401     // Vertex input states. Must happen after buffer data initialization. Do not capture on GLES1.
3402     if (!context->isGLES1())
3403     {
3404         CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
3405     }
3406 
3407     // Capture vertex array objects
3408     const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
3409     gl::VertexArrayID boundVertexArrayID     = {0};
3410     for (const auto &vertexArrayIter : vertexArrayMap)
3411     {
3412         gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
3413         if (vertexArrayID.value != 0)
3414         {
3415             cap(CaptureGenVertexArrays(replayState, true, 1, &vertexArrayID));
3416 
3417             resourceTracker->getTrackedResource(ResourceIDType::VertexArray)
3418                 .getStartingResources()
3419                 .insert(vertexArrayID.value);
3420 
3421             MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
3422         }
3423 
3424         if (vertexArrayIter.second)
3425         {
3426             const gl::VertexArray *vertexArray = vertexArrayIter.second;
3427 
3428             // Bind the vertexArray (unless default) and populate it
3429             if (vertexArrayID.value != 0)
3430             {
3431                 cap(CaptureBindVertexArray(replayState, true, vertexArrayID));
3432                 boundVertexArrayID = vertexArrayID;
3433             }
3434             CaptureVertexArrayState(setupCalls, context, vertexArray, &replayState);
3435         }
3436     }
3437 
3438     // Bind the current vertex array
3439     const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
3440     if (currentVertexArray->id() != boundVertexArrayID)
3441     {
3442         cap(CaptureBindVertexArray(replayState, true, currentVertexArray->id()));
3443     }
3444 
3445     // Capture indexed buffer bindings.
3446     const gl::BufferVector &uniformIndexedBuffers =
3447         apiState.getOffsetBindingPointerUniformBuffers();
3448     const gl::BufferVector &atomicCounterIndexedBuffers =
3449         apiState.getOffsetBindingPointerAtomicCounterBuffers();
3450     const gl::BufferVector &shaderStorageIndexedBuffers =
3451         apiState.getOffsetBindingPointerShaderStorageBuffers();
3452     CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
3453                           setupCalls);
3454     CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
3455                           gl::BufferBinding::AtomicCounter, setupCalls);
3456     CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
3457                           gl::BufferBinding::ShaderStorage, setupCalls);
3458 
3459     // Capture Buffer bindings.
3460     const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
3461     for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
3462     {
3463         gl::BufferID bufferID = boundBuffers[binding].id();
3464 
3465         // Filter out redundant buffer binding commands. Note that the code in the previous section
3466         // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
3467         // we set earlier.
3468         bool isArray                  = binding == gl::BufferBinding::Array;
3469         const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
3470         if ((isArray && arrayBuffer && arrayBuffer->id() != bufferID) ||
3471             (!isArray && bufferID.value != 0))
3472         {
3473             cap(CaptureBindBuffer(replayState, true, binding, bufferID));
3474             replayState.setBufferBinding(context, binding, boundBuffers[binding].get());
3475         }
3476 
3477         // Restore all buffer bindings for Reset
3478         if (bufferID.value != 0)
3479         {
3480             CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
3481         }
3482     }
3483 
3484     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
3485     // leading to a crash in memcpy() when capturing the texture contents.
3486     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
3487     if (currentUnpackState.alignment != 1)
3488     {
3489         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
3490         currentUnpackState.alignment = 1;
3491     }
3492 
3493     // Capture Texture setup and data.
3494     const gl::TextureBindingMap &apiBoundTextures = apiState.getBoundTexturesForCapture();
3495 
3496     // Set Texture bindings.
3497     for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
3498     {
3499         const gl::TextureBindingVector &apiBindings = apiBoundTextures[textureType];
3500         const gl::TextureBindingVector &replayBindings =
3501             replayState.getBoundTexturesForCapture()[textureType];
3502         ASSERT(apiBindings.size() == replayBindings.size());
3503         for (size_t bindingIndex = 0; bindingIndex < apiBindings.size(); ++bindingIndex)
3504         {
3505             gl::TextureID apiTextureID    = apiBindings[bindingIndex].id();
3506             gl::TextureID replayTextureID = replayBindings[bindingIndex].id();
3507 
3508             if (apiTextureID != replayTextureID)
3509             {
3510                 if (replayState.getActiveSampler() != bindingIndex)
3511                 {
3512                     cap(CaptureActiveTexture(replayState, true,
3513                                              GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
3514                     replayState.setActiveSampler(static_cast<unsigned int>(bindingIndex));
3515                 }
3516 
3517                 cap(CaptureBindTexture(replayState, true, textureType, apiTextureID));
3518                 replayState.setSamplerTexture(context, textureType,
3519                                               apiBindings[bindingIndex].get());
3520             }
3521         }
3522     }
3523 
3524     // Set active Texture.
3525     if (replayState.getActiveSampler() != apiState.getActiveSampler())
3526     {
3527         cap(CaptureActiveTexture(replayState, true,
3528                                  GL_TEXTURE0 + static_cast<GLenum>(apiState.getActiveSampler())));
3529         replayState.setActiveSampler(apiState.getActiveSampler());
3530     }
3531 
3532     // Set Renderbuffer binding.
3533     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
3534     gl::RenderbufferID currentRenderbuffer       = {0};
3535     for (const auto &renderbufIter : renderbuffers)
3536     {
3537         currentRenderbuffer = renderbufIter.second->id();
3538     }
3539 
3540     if (currentRenderbuffer != apiState.getRenderbufferId())
3541     {
3542         cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER,
3543                                     apiState.getRenderbufferId()));
3544     }
3545 
3546     // Capture Framebuffers.
3547     const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
3548     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
3549 
3550     gl::FramebufferID currentDrawFramebuffer = {0};
3551     gl::FramebufferID currentReadFramebuffer = {0};
3552 
3553     for (const auto &framebufferIter : framebuffers)
3554     {
3555         gl::FramebufferID id               = {framebufferIter.first};
3556         const gl::Framebuffer *framebuffer = framebufferIter.second;
3557 
3558         // The default Framebuffer exists (by default).
3559         if (framebuffer->isDefault())
3560         {
3561             continue;
3562         }
3563 
3564         // Track this as a starting resource that may need to be restored
3565         TrackedResource &trackedFramebuffers =
3566             resourceTracker->getTrackedResource(ResourceIDType::Framebuffer);
3567         ResourceSet &startingFramebuffers = trackedFramebuffers.getStartingResources();
3568         startingFramebuffers.insert(id.value);
3569 
3570         // Create two lists of calls for initial setup
3571         ResourceCalls &framebufferRegenCalls = trackedFramebuffers.getResourceRegenCalls();
3572         CallVector framebufferGenCalls({setupCalls, &framebufferRegenCalls[id.value]});
3573 
3574         // Gen the framebuffer
3575         for (std::vector<CallCapture> *calls : framebufferGenCalls)
3576         {
3577             Capture(calls, framebufferFuncs.genFramebuffers(replayState, true, 1, &id));
3578             MaybeCaptureUpdateResourceIDs(resourceTracker, calls);
3579         }
3580 
3581         // Create two lists of calls for remaining setup calls.  One for setup, and one for restore
3582         // during reset.
3583         ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
3584         CallVector framebufferSetupCalls({setupCalls, &framebufferRestoreCalls[id.value]});
3585 
3586         for (std::vector<CallCapture> *calls : framebufferSetupCalls)
3587         {
3588             Capture(calls, framebufferFuncs.bindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
3589         }
3590         currentDrawFramebuffer = currentReadFramebuffer = id;
3591 
3592         // Color Attachments.
3593         for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
3594         {
3595             if (!colorAttachment.isAttached())
3596             {
3597                 continue;
3598             }
3599 
3600             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
3601             {
3602                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, colorAttachment);
3603             }
3604         }
3605 
3606         const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
3607         if (depthAttachment)
3608         {
3609             ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
3610                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
3611             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
3612             {
3613                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
3614                                              *depthAttachment);
3615             }
3616         }
3617 
3618         const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
3619         if (stencilAttachment)
3620         {
3621             ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
3622                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
3623             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
3624             {
3625                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
3626                                              *stencilAttachment);
3627             }
3628         }
3629 
3630         gl::FramebufferState defaultFramebufferState(
3631             context->getCaps(), framebuffer->getState().id(),
3632             framebuffer->getState().getFramebufferSerial());
3633         const std::vector<GLenum> &defaultDrawBufferStates =
3634             defaultFramebufferState.getDrawBufferStates();
3635         const std::vector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
3636 
3637         if (drawBufferStates != defaultDrawBufferStates)
3638         {
3639             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
3640             {
3641                 Capture(calls, CaptureDrawBuffers(replayState, true,
3642                                                   static_cast<GLsizei>(drawBufferStates.size()),
3643                                                   drawBufferStates.data()));
3644             }
3645         }
3646     }
3647 
3648     // Capture framebuffer bindings.
3649     if (apiState.getDrawFramebuffer())
3650     {
3651         ASSERT(apiState.getReadFramebuffer());
3652         gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
3653         gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
3654         if (stateDrawFramebuffer == stateReadFramebuffer)
3655         {
3656             if (currentDrawFramebuffer != stateDrawFramebuffer ||
3657                 currentReadFramebuffer != stateReadFramebuffer)
3658             {
3659                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_FRAMEBUFFER,
3660                                                      stateDrawFramebuffer));
3661                 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
3662             }
3663         }
3664         else
3665         {
3666             if (currentDrawFramebuffer != stateDrawFramebuffer)
3667             {
3668                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
3669                                                      currentDrawFramebuffer));
3670                 currentDrawFramebuffer = stateDrawFramebuffer;
3671             }
3672 
3673             if (currentReadFramebuffer != stateReadFramebuffer)
3674             {
3675                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
3676                                                      replayState.getReadFramebuffer()->id()));
3677                 currentReadFramebuffer = stateReadFramebuffer;
3678             }
3679         }
3680     }
3681 
3682     // Capture Program Pipelines
3683     const gl::ProgramPipelineManager *programPipelineManager =
3684         apiState.getProgramPipelineManagerForCapture();
3685 
3686     for (const auto &ppoIterator : *programPipelineManager)
3687     {
3688         gl::ProgramPipeline *pipeline = ppoIterator.second;
3689         gl::ProgramPipelineID id      = {ppoIterator.first};
3690         cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
3691         MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
3692 
3693         // PPOs can contain graphics and compute programs, so loop through all shader types rather
3694         // than just the linked ones since getLinkedShaderStages() will return either only graphics
3695         // or compute stages.
3696         for (gl::ShaderType shaderType : gl::AllShaderTypes())
3697         {
3698             gl::Program *program = pipeline->getShaderProgram(shaderType);
3699             if (!program)
3700             {
3701                 continue;
3702             }
3703             ASSERT(program->isLinked());
3704             GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
3705             cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
3706                                         program->id()));
3707 
3708             // Set this program as active so it will be generated in Setup
3709             // Note: We aren't filtering ProgramPipelines, so this could be setting programs
3710             // active that aren't actually used.
3711             MarkResourceIDActive(ResourceIDType::ShaderProgram, program->id().value,
3712                                  shareGroupSetupCalls, resourceIDToSetupCalls);
3713         }
3714 
3715         gl::Program *program = pipeline->getActiveShaderProgram();
3716         if (program)
3717         {
3718             cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
3719         }
3720     }
3721 
3722     // For now we assume the installed program executable is the same as the current program.
3723     // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
3724     if (!context->isGLES1())
3725     {
3726         // If we have a program bound in the API, or if there is no program bound to the API at
3727         // time of capture and we bound a program for uniform updates during MEC, we must add
3728         // a set program call to replay the correct states.
3729         if (apiState.getProgram())
3730         {
3731             cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
3732             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
3733             (void)replayState.setProgram(context, apiState.getProgram());
3734 
3735             // Set this program as active so it will be generated in Setup
3736             MarkResourceIDActive(ResourceIDType::ShaderProgram, apiState.getProgram()->id().value,
3737                                  shareGroupSetupCalls, resourceIDToSetupCalls);
3738         }
3739         else if (replayState.getProgram())
3740         {
3741             cap(CaptureUseProgram(replayState, true, {0}));
3742             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
3743             (void)replayState.setProgram(context, nullptr);
3744         }
3745 
3746         // Same for program pipelines as for programs, see comment above.
3747         if (apiState.getProgramPipeline())
3748         {
3749             cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
3750         }
3751         else if (replayState.getProgramPipeline())
3752         {
3753             cap(CaptureBindProgramPipeline(replayState, true, {0}));
3754         }
3755     }
3756 
3757     // Create existing queries. Note that queries may be genned and not yet started. In that
3758     // case the queries will exist in the query map as nullptr entries.
3759     const gl::QueryMap &queryMap = context->getQueriesForCapture();
3760     for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
3761          queryIter != queryMap.endWithNull(); ++queryIter)
3762     {
3763         ASSERT(queryIter->first);
3764         gl::QueryID queryID = {queryIter->first};
3765 
3766         cap(CaptureGenQueries(replayState, true, 1, &queryID));
3767         MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
3768 
3769         gl::Query *query = queryIter->second;
3770         if (query)
3771         {
3772             gl::QueryType queryType = query->getType();
3773 
3774             // Begin the query to generate the object
3775             cap(CaptureBeginQuery(replayState, true, queryType, queryID));
3776 
3777             // End the query if it was not active
3778             if (!IsQueryActive(apiState, queryID))
3779             {
3780                 cap(CaptureEndQuery(replayState, true, queryType));
3781             }
3782         }
3783     }
3784 
3785     // Transform Feedback
3786     const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
3787     for (const auto &xfbIter : xfbMap)
3788     {
3789         gl::TransformFeedbackID xfbID = {xfbIter.first};
3790 
3791         // Do not capture the default XFB object.
3792         if (xfbID.value == 0)
3793         {
3794             continue;
3795         }
3796 
3797         cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
3798         MaybeCaptureUpdateResourceIDs(resourceTracker, setupCalls);
3799 
3800         gl::TransformFeedback *xfb = xfbIter.second;
3801         if (!xfb)
3802         {
3803             // The object was never created
3804             continue;
3805         }
3806 
3807         // Bind XFB to create the object
3808         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
3809 
3810         // Bind the buffers associated with this XFB object
3811         for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
3812         {
3813             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
3814 
3815             // Note: Buffers bound with BindBufferBase can be used with BindBuffer
3816             cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
3817                                        xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
3818         }
3819 
3820         if (xfb->isActive() || xfb->isPaused())
3821         {
3822             // We don't support active XFB in MEC yet
3823             UNIMPLEMENTED();
3824         }
3825     }
3826 
3827     // Bind the current XFB buffer after populating XFB objects
3828     gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
3829     if (currentXFB)
3830     {
3831         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
3832                                          currentXFB->id()));
3833     }
3834 
3835     // Bind samplers
3836     const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
3837     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
3838          ++bindingIndex)
3839     {
3840         gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
3841         if (samplerID.value != 0)
3842         {
3843             cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
3844         }
3845     }
3846 
3847     // Capture Image Texture bindings
3848     const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
3849     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
3850          ++bindingIndex)
3851     {
3852         const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
3853 
3854         if (imageUnit.texture == 0)
3855         {
3856             continue;
3857         }
3858 
3859         cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
3860                                     imageUnit.level, imageUnit.layered, imageUnit.layer,
3861                                     imageUnit.access, imageUnit.format));
3862     }
3863 
3864     // Capture GL Context states.
3865     auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
3866         if (capValue)
3867         {
3868             cap(CaptureEnable(replayState, true, capEnum));
3869         }
3870         else
3871         {
3872             cap(CaptureDisable(replayState, true, capEnum));
3873         }
3874     };
3875 
3876     // Capture GLES1 context states.
3877     if (context->isGLES1())
3878     {
3879         const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
3880         const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
3881         if (currentTextureState != defaultTextureState)
3882         {
3883             capCap(GL_TEXTURE_2D, currentTextureState);
3884         }
3885 
3886         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Projection));
3887         for (angle::Mat4 projectionMatrix :
3888              apiState.gles1().getMatrixStack(gl::MatrixType::Projection))
3889         {
3890             cap(CapturePushMatrix(replayState, true));
3891             cap(CaptureLoadMatrixf(replayState, true, projectionMatrix.elements().data()));
3892         }
3893 
3894         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Modelview));
3895         for (angle::Mat4 modelViewMatrix :
3896              apiState.gles1().getMatrixStack(gl::MatrixType::Modelview))
3897         {
3898             cap(CapturePushMatrix(replayState, true));
3899             cap(CaptureLoadMatrixf(replayState, true, modelViewMatrix.elements().data()));
3900         }
3901 
3902         gl::MatrixType currentMatrixMode = apiState.gles1().getMatrixMode();
3903         if (currentMatrixMode != gl::MatrixType::Modelview)
3904         {
3905             cap(CaptureMatrixMode(replayState, true, currentMatrixMode));
3906         }
3907     }
3908 
3909     // Rasterizer state. Missing ES 3.x features.
3910     const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
3911     const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
3912     if (currentRasterState.cullFace != defaultRasterState.cullFace)
3913     {
3914         capCap(GL_CULL_FACE, currentRasterState.cullFace);
3915     }
3916 
3917     if (currentRasterState.cullMode != defaultRasterState.cullMode)
3918     {
3919         cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
3920     }
3921 
3922     if (currentRasterState.frontFace != defaultRasterState.frontFace)
3923     {
3924         cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
3925     }
3926 
3927     if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
3928     {
3929         capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
3930     }
3931 
3932     if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
3933         currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits)
3934     {
3935         cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
3936                                  currentRasterState.polygonOffsetUnits));
3937     }
3938 
3939     // pointDrawMode/multiSample are only used in the D3D back-end right now.
3940 
3941     if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
3942     {
3943         capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
3944     }
3945 
3946     if (currentRasterState.dither != defaultRasterState.dither)
3947     {
3948         capCap(GL_DITHER, currentRasterState.dither);
3949     }
3950 
3951     // Depth/stencil state.
3952     const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
3953     const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
3954     if (defaultDSState.depthFunc != currentDSState.depthFunc)
3955     {
3956         cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
3957     }
3958 
3959     if (defaultDSState.depthMask != currentDSState.depthMask)
3960     {
3961         cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
3962     }
3963 
3964     if (defaultDSState.depthTest != currentDSState.depthTest)
3965     {
3966         capCap(GL_DEPTH_TEST, currentDSState.depthTest);
3967     }
3968 
3969     if (defaultDSState.stencilTest != currentDSState.stencilTest)
3970     {
3971         capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
3972     }
3973 
3974     if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
3975         currentDSState.stencilMask == currentDSState.stencilBackMask)
3976     {
3977         // Front and back are equal
3978         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
3979             defaultDSState.stencilMask != currentDSState.stencilMask ||
3980             apiState.getStencilRef() != 0)
3981         {
3982             cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
3983                                    apiState.getStencilRef(), currentDSState.stencilMask));
3984         }
3985     }
3986     else
3987     {
3988         // Front and back are separate
3989         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
3990             defaultDSState.stencilMask != currentDSState.stencilMask ||
3991             apiState.getStencilRef() != 0)
3992         {
3993             cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
3994                                            apiState.getStencilRef(), currentDSState.stencilMask));
3995         }
3996 
3997         if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
3998             defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
3999             apiState.getStencilBackRef() != 0)
4000         {
4001             cap(CaptureStencilFuncSeparate(
4002                 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
4003                 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
4004         }
4005     }
4006 
4007     if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
4008         currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
4009         currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
4010     {
4011         // Front and back are equal
4012         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
4013             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
4014             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
4015         {
4016             cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
4017                                  currentDSState.stencilPassDepthFail,
4018                                  currentDSState.stencilPassDepthPass));
4019         }
4020     }
4021     else
4022     {
4023         // Front and back are separate
4024         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
4025             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
4026             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
4027         {
4028             cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
4029                                          currentDSState.stencilPassDepthFail,
4030                                          currentDSState.stencilPassDepthPass));
4031         }
4032 
4033         if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
4034             defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
4035             defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
4036         {
4037             cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
4038                                          currentDSState.stencilBackPassDepthFail,
4039                                          currentDSState.stencilBackPassDepthPass));
4040         }
4041     }
4042 
4043     if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
4044     {
4045         // Front and back are equal
4046         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
4047         {
4048             cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
4049         }
4050     }
4051     else
4052     {
4053         // Front and back are separate
4054         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
4055         {
4056             cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
4057                                            currentDSState.stencilWritemask));
4058         }
4059 
4060         if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
4061         {
4062             cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
4063                                            currentDSState.stencilBackWritemask));
4064         }
4065     }
4066 
4067     // Blend state.
4068     const gl::BlendState &defaultBlendState = replayState.getBlendState();
4069     const gl::BlendState &currentBlendState = apiState.getBlendState();
4070 
4071     if (currentBlendState.blend != defaultBlendState.blend)
4072     {
4073         capCap(GL_BLEND, currentBlendState.blend);
4074     }
4075 
4076     if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
4077         currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
4078         currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
4079         currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
4080     {
4081         if (currentBlendState.sourceBlendRGB == currentBlendState.sourceBlendAlpha &&
4082             currentBlendState.destBlendRGB == currentBlendState.destBlendAlpha)
4083         {
4084             // Color and alpha are equal
4085             cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
4086                                  currentBlendState.destBlendRGB));
4087         }
4088         else
4089         {
4090             // Color and alpha are separate
4091             cap(CaptureBlendFuncSeparate(
4092                 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
4093                 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
4094         }
4095     }
4096 
4097     if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
4098         currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
4099     {
4100         cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
4101                                          currentBlendState.blendEquationAlpha));
4102     }
4103 
4104     if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
4105         currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
4106         currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
4107         currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
4108     {
4109         cap(CaptureColorMask(replayState, true,
4110                              gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
4111                              gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
4112                              gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
4113                              gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
4114     }
4115 
4116     const gl::ColorF &currentBlendColor = apiState.getBlendColor();
4117     if (currentBlendColor != gl::ColorF())
4118     {
4119         cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
4120                               currentBlendColor.blue, currentBlendColor.alpha));
4121     }
4122 
4123     // Pixel storage states.
4124     gl::PixelPackState &currentPackState = replayState.getPackState();
4125     if (currentPackState.alignment != apiState.getPackAlignment())
4126     {
4127         cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
4128         currentPackState.alignment = apiState.getPackAlignment();
4129     }
4130 
4131     if (currentPackState.rowLength != apiState.getPackRowLength())
4132     {
4133         cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
4134         currentPackState.rowLength = apiState.getPackRowLength();
4135     }
4136 
4137     if (currentPackState.skipRows != apiState.getPackSkipRows())
4138     {
4139         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
4140         currentPackState.skipRows = apiState.getPackSkipRows();
4141     }
4142 
4143     if (currentPackState.skipPixels != apiState.getPackSkipPixels())
4144     {
4145         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
4146                                apiState.getPackSkipPixels()));
4147         currentPackState.skipPixels = apiState.getPackSkipPixels();
4148     }
4149 
4150     // We set unpack alignment above, no need to change it here
4151     ASSERT(currentUnpackState.alignment == 1);
4152     if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
4153     {
4154         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
4155                                apiState.getUnpackRowLength()));
4156         currentUnpackState.rowLength = apiState.getUnpackRowLength();
4157     }
4158 
4159     if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
4160     {
4161         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
4162                                apiState.getUnpackSkipRows()));
4163         currentUnpackState.skipRows = apiState.getUnpackSkipRows();
4164     }
4165 
4166     if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
4167     {
4168         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
4169                                apiState.getUnpackSkipPixels()));
4170         currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
4171     }
4172 
4173     if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
4174     {
4175         cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
4176                                apiState.getUnpackImageHeight()));
4177         currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
4178     }
4179 
4180     if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
4181     {
4182         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
4183                                apiState.getUnpackSkipImages()));
4184         currentUnpackState.skipImages = apiState.getUnpackSkipImages();
4185     }
4186 
4187     // Clear state. Missing ES 3.x features.
4188     // TODO(http://anglebug.com/3662): Complete state capture.
4189     const gl::ColorF &currentClearColor = apiState.getColorClearValue();
4190     if (currentClearColor != gl::ColorF())
4191     {
4192         cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
4193                               currentClearColor.blue, currentClearColor.alpha));
4194     }
4195 
4196     if (apiState.getDepthClearValue() != 1.0f)
4197     {
4198         cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
4199     }
4200 
4201     if (apiState.getStencilClearValue() != 0)
4202     {
4203         cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
4204     }
4205 
4206     // Viewport / scissor / clipping planes.
4207     const gl::Rectangle &currentViewport = apiState.getViewport();
4208     if (currentViewport != gl::Rectangle())
4209     {
4210         cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
4211                             currentViewport.width, currentViewport.height));
4212     }
4213 
4214     if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
4215     {
4216         cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
4217     }
4218 
4219     if (apiState.isScissorTestEnabled())
4220     {
4221         capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
4222     }
4223 
4224     const gl::Rectangle &currentScissor = apiState.getScissor();
4225     if (currentScissor != gl::Rectangle())
4226     {
4227         cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
4228                            currentScissor.width, currentScissor.height));
4229     }
4230 
4231     // Allow the replayState object to be destroyed conveniently.
4232     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
4233 
4234     // Clean up the replay state.
4235     replayState.reset(context);
4236 
4237     if (validationEnabled)
4238     {
4239         CaptureValidateSerializedState(context, setupCalls);
4240     }
4241 }
4242 
SkipCall(EntryPoint entryPoint)4243 bool SkipCall(EntryPoint entryPoint)
4244 {
4245     switch (entryPoint)
4246     {
4247         case EntryPoint::GLDebugMessageCallback:
4248         case EntryPoint::GLDebugMessageCallbackKHR:
4249         case EntryPoint::GLDebugMessageControl:
4250         case EntryPoint::GLDebugMessageControlKHR:
4251         case EntryPoint::GLDebugMessageInsert:
4252         case EntryPoint::GLDebugMessageInsertKHR:
4253         case EntryPoint::GLGetDebugMessageLog:
4254         case EntryPoint::GLGetDebugMessageLogKHR:
4255         case EntryPoint::GLGetObjectLabelEXT:
4256         case EntryPoint::GLGetObjectLabelKHR:
4257         case EntryPoint::GLGetObjectPtrLabelKHR:
4258         case EntryPoint::GLGetPointervKHR:
4259         case EntryPoint::GLInsertEventMarkerEXT:
4260         case EntryPoint::GLLabelObjectEXT:
4261         case EntryPoint::GLObjectLabelKHR:
4262         case EntryPoint::GLObjectPtrLabelKHR:
4263         case EntryPoint::GLPopDebugGroupKHR:
4264         case EntryPoint::GLPopGroupMarkerEXT:
4265         case EntryPoint::GLPushDebugGroupKHR:
4266         case EntryPoint::GLPushGroupMarkerEXT:
4267             // Purposefully skip entry points from:
4268             // - KHR_debug
4269             // - EXT_debug_label
4270             // - EXT_debug_marker
4271             // There is no need to capture these for replaying a trace in our harness
4272             return true;
4273 
4274         case EntryPoint::GLGetActiveUniform:
4275         case EntryPoint::GLGetActiveUniformsiv:
4276             // Skip these calls because:
4277             // - We don't use the return values.
4278             // - Active uniform counts can vary between platforms due to cross stage optimizations
4279             //   and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
4280             return true;
4281 
4282         default:
4283             break;
4284     }
4285 
4286     return false;
4287 }
4288 
4289 template <typename ParamValueType>
4290 struct ParamValueTrait
4291 {
4292     static_assert(sizeof(ParamValueType) == 0, "invalid ParamValueType");
4293 };
4294 
4295 template <>
4296 struct ParamValueTrait<gl::FramebufferID>
4297 {
4298     static constexpr const char *name = "framebufferPacked";
4299     static const ParamType typeID     = ParamType::TFramebufferID;
4300 };
4301 
GetBaseName(const std::string & nameWithPath)4302 std::string GetBaseName(const std::string &nameWithPath)
4303 {
4304     std::vector<std::string> result = angle::SplitString(
4305         nameWithPath, "/\\", WhitespaceHandling::TRIM_WHITESPACE, SplitResult::SPLIT_WANT_NONEMPTY);
4306     ASSERT(!result.empty());
4307     return result.back();
4308 }
4309 
4310 template <>
4311 struct ParamValueTrait<gl::BufferID>
4312 {
4313     static constexpr const char *name = "bufferPacked";
4314     static const ParamType typeID     = ParamType::TBufferID;
4315 };
4316 
4317 template <>
4318 struct ParamValueTrait<gl::RenderbufferID>
4319 {
4320     static constexpr const char *name = "renderbufferPacked";
4321     static const ParamType typeID     = ParamType::TRenderbufferID;
4322 };
4323 
4324 template <>
4325 struct ParamValueTrait<gl::TextureID>
4326 {
4327     static constexpr const char *name = "texturePacked";
4328     static const ParamType typeID     = ParamType::TTextureID;
4329 };
4330 
4331 }  // namespace
4332 
ParamCapture()4333 ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup) {}
4334 
ParamCapture(const char * nameIn,ParamType typeIn)4335 ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn)
4336     : name(nameIn), type(typeIn), enumGroup(gl::GLenumGroup::DefaultGroup)
4337 {}
4338 
4339 ParamCapture::~ParamCapture() = default;
4340 
ParamCapture(ParamCapture && other)4341 ParamCapture::ParamCapture(ParamCapture &&other)
4342     : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup)
4343 {
4344     *this = std::move(other);
4345 }
4346 
operator =(ParamCapture && other)4347 ParamCapture &ParamCapture::operator=(ParamCapture &&other)
4348 {
4349     std::swap(name, other.name);
4350     std::swap(type, other.type);
4351     std::swap(value, other.value);
4352     std::swap(enumGroup, other.enumGroup);
4353     std::swap(data, other.data);
4354     std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex);
4355     std::swap(readBufferSizeBytes, other.readBufferSizeBytes);
4356     std::swap(dataNElements, other.dataNElements);
4357     return *this;
4358 }
4359 
ParamBuffer()4360 ParamBuffer::ParamBuffer() {}
4361 
4362 ParamBuffer::~ParamBuffer() = default;
4363 
ParamBuffer(ParamBuffer && other)4364 ParamBuffer::ParamBuffer(ParamBuffer &&other)
4365 {
4366     *this = std::move(other);
4367 }
4368 
operator =(ParamBuffer && other)4369 ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other)
4370 {
4371     std::swap(mParamCaptures, other.mParamCaptures);
4372     std::swap(mClientArrayDataParam, other.mClientArrayDataParam);
4373     std::swap(mReadBufferSize, other.mReadBufferSize);
4374     std::swap(mReturnValueCapture, other.mReturnValueCapture);
4375     std::swap(mMappedBufferID, other.mMappedBufferID);
4376     return *this;
4377 }
4378 
getParam(const char * paramName,ParamType paramType,int index)4379 ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index)
4380 {
4381     ParamCapture &capture = mParamCaptures[index];
4382     ASSERT(capture.name == paramName);
4383     ASSERT(capture.type == paramType);
4384     return capture;
4385 }
4386 
getParam(const char * paramName,ParamType paramType,int index) const4387 const ParamCapture &ParamBuffer::getParam(const char *paramName,
4388                                           ParamType paramType,
4389                                           int index) const
4390 {
4391     return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index);
4392 }
4393 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index)4394 ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
4395                                             const char *paramName2,
4396                                             ParamType paramType,
4397                                             int index)
4398 {
4399     ParamCapture &capture = mParamCaptures[index];
4400     ASSERT(capture.name == paramName1 || capture.name == paramName2);
4401     ASSERT(capture.type == paramType);
4402     return capture;
4403 }
4404 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index) const4405 const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
4406                                                   const char *paramName2,
4407                                                   ParamType paramType,
4408                                                   int index) const
4409 {
4410     return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType,
4411                                                              index);
4412 }
4413 
addParam(ParamCapture && param)4414 void ParamBuffer::addParam(ParamCapture &&param)
4415 {
4416     if (param.arrayClientPointerIndex != -1)
4417     {
4418         ASSERT(mClientArrayDataParam == -1);
4419         mClientArrayDataParam = static_cast<int>(mParamCaptures.size());
4420     }
4421 
4422     mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize);
4423     mParamCaptures.emplace_back(std::move(param));
4424 }
4425 
addReturnValue(ParamCapture && returnValue)4426 void ParamBuffer::addReturnValue(ParamCapture &&returnValue)
4427 {
4428     mReturnValueCapture = std::move(returnValue);
4429 }
4430 
getClientArrayPointerParameter()4431 ParamCapture &ParamBuffer::getClientArrayPointerParameter()
4432 {
4433     ASSERT(hasClientArrayData());
4434     return mParamCaptures[mClientArrayDataParam];
4435 }
4436 
CallCapture(EntryPoint entryPointIn,ParamBuffer && paramsIn)4437 CallCapture::CallCapture(EntryPoint entryPointIn, ParamBuffer &&paramsIn)
4438     : entryPoint(entryPointIn), params(std::move(paramsIn))
4439 {}
4440 
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)4441 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn)
4442     : entryPoint(EntryPoint::GLInvalid),
4443       customFunctionName(customFunctionNameIn),
4444       params(std::move(paramsIn))
4445 {}
4446 
4447 CallCapture::~CallCapture() = default;
4448 
CallCapture(CallCapture && other)4449 CallCapture::CallCapture(CallCapture &&other)
4450 {
4451     *this = std::move(other);
4452 }
4453 
operator =(CallCapture && other)4454 CallCapture &CallCapture::operator=(CallCapture &&other)
4455 {
4456     std::swap(entryPoint, other.entryPoint);
4457     std::swap(customFunctionName, other.customFunctionName);
4458     std::swap(params, other.params);
4459     std::swap(isActive, other.isActive);
4460     return *this;
4461 }
4462 
name() const4463 const char *CallCapture::name() const
4464 {
4465     if (entryPoint == EntryPoint::GLInvalid)
4466     {
4467         ASSERT(!customFunctionName.empty());
4468         return customFunctionName.c_str();
4469     }
4470 
4471     return angle::GetEntryPointName(entryPoint);
4472 }
4473 
ReplayContext(size_t readBufferSizebytes,const gl::AttribArray<size_t> & clientArraysSizebytes)4474 ReplayContext::ReplayContext(size_t readBufferSizebytes,
4475                              const gl::AttribArray<size_t> &clientArraysSizebytes)
4476 {
4477     mReadBuffer.resize(readBufferSizebytes);
4478 
4479     for (uint32_t i = 0; i < clientArraysSizebytes.size(); i++)
4480     {
4481         mClientArraysBuffer[i].resize(clientArraysSizebytes[i]);
4482     }
4483 }
~ReplayContext()4484 ReplayContext::~ReplayContext() {}
4485 
4486 FrameCapture::FrameCapture()  = default;
4487 FrameCapture::~FrameCapture() = default;
4488 
reset()4489 void FrameCapture::reset()
4490 {
4491     mSetupCalls.clear();
4492 }
4493 
FrameCaptureShared()4494 FrameCaptureShared::FrameCaptureShared()
4495     : mLastContextId{0},
4496       mEnabled(true),
4497       mSerializeStateEnabled(false),
4498       mCompression(true),
4499       mClientVertexArrayMap{},
4500       mFrameIndex(1),
4501       mCaptureStartFrame(1),
4502       mCaptureEndFrame(0),
4503       mClientArraySizes{},
4504       mReadBufferSize(0),
4505       mHasResourceType{},
4506       mResourceIDToSetupCalls{},
4507       mMaxAccessedResourceIDs{},
4508       mCaptureTrigger(0),
4509       mCaptureActive(false),
4510       mMidExecutionCaptureActive(false),
4511       mWindowSurfaceContextID({0})
4512 {
4513     reset();
4514 
4515     std::string enabledFromEnv =
4516         GetEnvironmentVarOrUnCachedAndroidProperty(kEnabledVarName, kAndroidEnabled);
4517     if (enabledFromEnv == "0")
4518     {
4519         mEnabled = false;
4520     }
4521 
4522     std::string pathFromEnv =
4523         GetEnvironmentVarOrUnCachedAndroidProperty(kOutDirectoryVarName, kAndroidOutDir);
4524     if (pathFromEnv.empty())
4525     {
4526         mOutDirectory = GetDefaultOutDirectory();
4527     }
4528     else
4529     {
4530         mOutDirectory = pathFromEnv;
4531     }
4532 
4533     // Ensure the capture path ends with a slash.
4534     if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
4535     {
4536         mOutDirectory += '/';
4537     }
4538 
4539     std::string startFromEnv =
4540         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameStartVarName, kAndroidFrameStart);
4541     if (!startFromEnv.empty())
4542     {
4543         mCaptureStartFrame = atoi(startFromEnv.c_str());
4544     }
4545     if (mCaptureStartFrame < 1)
4546     {
4547         WARN() << "Cannot use a capture start frame less than 1.";
4548         mCaptureStartFrame = 1;
4549     }
4550 
4551     std::string endFromEnv =
4552         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameEndVarName, kAndroidFrameEnd);
4553     if (!endFromEnv.empty())
4554     {
4555         mCaptureEndFrame = atoi(endFromEnv.c_str());
4556     }
4557 
4558     std::string captureTriggerFromEnv =
4559         GetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
4560     if (!captureTriggerFromEnv.empty())
4561     {
4562         mCaptureTrigger = atoi(captureTriggerFromEnv.c_str());
4563 
4564         // If the trigger has been populated, ignore the other frame range variables by setting them
4565         // to unreasonable values. This isn't perfect, but it is effective.
4566         mCaptureStartFrame = mCaptureEndFrame = std::numeric_limits<uint32_t>::max();
4567         INFO() << "Capture trigger detected, disabling capture start/end frame.";
4568     }
4569 
4570     std::string labelFromEnv =
4571         GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureLabelVarName, kAndroidCaptureLabel);
4572     if (!labelFromEnv.empty())
4573     {
4574         // Optional label to provide unique file names and namespaces
4575         mCaptureLabel = labelFromEnv;
4576     }
4577 
4578     std::string compressionFromEnv =
4579         GetEnvironmentVarOrUnCachedAndroidProperty(kCompressionVarName, kAndroidCompression);
4580     if (compressionFromEnv == "0")
4581     {
4582         mCompression = false;
4583     }
4584     std::string serializeStateFromEnv = angle::GetEnvironmentVar(kSerializeStateVarName);
4585     if (serializeStateFromEnv == "1")
4586     {
4587         mSerializeStateEnabled = true;
4588     }
4589 
4590     std::string validateSerialiedStateFromEnv =
4591         GetEnvironmentVarOrUnCachedAndroidProperty(kValidationVarName, kAndroidValidation);
4592     if (validateSerialiedStateFromEnv == "1")
4593     {
4594         mValidateSerializedState = true;
4595     }
4596 
4597     mValidationExpression =
4598         GetEnvironmentVarOrUnCachedAndroidProperty(kValidationExprVarName, kAndroidValidationExpr);
4599 
4600     if (!mValidationExpression.empty())
4601     {
4602         INFO() << "Validation expression is " << kValidationExprVarName;
4603     }
4604 
4605     std::string trimEnabledFromEnv =
4606         GetEnvironmentVarOrUnCachedAndroidProperty(kTrimEnabledVarName, kAndroidTrimEnabled);
4607     if (trimEnabledFromEnv == "0")
4608     {
4609         mTrimEnabled = false;
4610     }
4611 
4612     std::string sourceSizeFromEnv =
4613         GetEnvironmentVarOrUnCachedAndroidProperty(kSourceSizeVarName, kAndroidSourceSize);
4614     if (!sourceSizeFromEnv.empty())
4615     {
4616         int sourceSize = atoi(sourceSizeFromEnv.c_str());
4617         if (sourceSize < 0)
4618         {
4619             WARN() << "Invalid capture source size: " << sourceSize;
4620         }
4621         else
4622         {
4623             mReplayWriter.setSourceFileSizeThreshold(sourceSize);
4624         }
4625     }
4626 
4627     if (mFrameIndex == mCaptureStartFrame)
4628     {
4629         // Capture is starting from the first frame, so set the capture active to ensure all GLES
4630         // commands issued are handled correctly by maybeCapturePreCallUpdates() and
4631         // maybeCapturePostCallUpdates().
4632         setCaptureActive();
4633     }
4634 
4635     if (mCaptureEndFrame < mCaptureStartFrame)
4636     {
4637         mEnabled = false;
4638     }
4639 
4640     mReplayWriter.setCaptureLabel(mCaptureLabel);
4641 }
4642 
4643 FrameCaptureShared::~FrameCaptureShared() = default;
4644 
PageRange(size_t start,size_t end)4645 PageRange::PageRange(size_t start, size_t end) : start(start), end(end) {}
4646 PageRange::~PageRange() = default;
4647 
AddressRange()4648 AddressRange::AddressRange() {}
AddressRange(uintptr_t start,size_t size)4649 AddressRange::AddressRange(uintptr_t start, size_t size) : start(start), size(size) {}
4650 AddressRange::~AddressRange() = default;
4651 
end()4652 uintptr_t AddressRange::end()
4653 {
4654     return start + size;
4655 }
4656 
CoherentBuffer(uintptr_t start,size_t size,size_t pageSize)4657 CoherentBuffer::CoherentBuffer(uintptr_t start, size_t size, size_t pageSize) : mPageSize(pageSize)
4658 {
4659     mRange.start            = start;
4660     mRange.size             = size;
4661     mProtectionRange.start  = rx::roundDownPow2(start, pageSize);
4662     uintptr_t protectionEnd = rx::roundUpPow2(start + size, pageSize);
4663 
4664     mProtectionRange.size = protectionEnd - mProtectionRange.start;
4665     mPageCount            = mProtectionRange.size / pageSize;
4666 
4667     mProtectionStartPage = mProtectionRange.start / mPageSize;
4668     mProtectionEndPage   = mProtectionStartPage + mPageCount;
4669 
4670     mDirtyPages = std::vector<bool>(mPageCount);
4671     mDirtyPages.assign(mPageCount, true);
4672 }
4673 
getDirtyPageRanges()4674 std::vector<PageRange> CoherentBuffer::getDirtyPageRanges()
4675 {
4676     std::vector<PageRange> dirtyPageRanges;
4677 
4678     bool inDirty = false;
4679     for (size_t i = 0; i < mPageCount; i++)
4680     {
4681         if (!inDirty && mDirtyPages[i])
4682         {
4683             // Found start of a dirty range
4684             inDirty = true;
4685             // Set end page as last page initially
4686             dirtyPageRanges.push_back(PageRange(i, mPageCount));
4687         }
4688         else if (inDirty && !mDirtyPages[i])
4689         {
4690             // Found end of a dirty range
4691             inDirty                    = false;
4692             dirtyPageRanges.back().end = i;
4693         }
4694     }
4695 
4696     return dirtyPageRanges;
4697 }
4698 
getRange()4699 AddressRange CoherentBuffer::getRange()
4700 {
4701     return mRange;
4702 }
4703 
getDirtyAddressRange(const PageRange & dirtyPageRange)4704 AddressRange CoherentBuffer::getDirtyAddressRange(const PageRange &dirtyPageRange)
4705 {
4706     AddressRange range;
4707 
4708     if (dirtyPageRange.start == 0)
4709     {
4710         // First page, use non page aligned buffer start.
4711         range.start = mRange.start;
4712     }
4713     else
4714     {
4715         range.start = mProtectionRange.start + dirtyPageRange.start * mPageSize;
4716     }
4717 
4718     if (dirtyPageRange.end == mPageCount)
4719     {
4720         // Last page, use non page aligned buffer end.
4721         range.size = mRange.end() - range.start;
4722     }
4723     else
4724     {
4725         range.size = (dirtyPageRange.end - dirtyPageRange.start) * mPageSize;
4726         // This occurs when a buffer occupies 2 pages, but is smaller than a page.
4727         if (mRange.end() < range.end())
4728         {
4729             range.size = mRange.end() - range.start;
4730         }
4731     }
4732 
4733     // Dirty range must be in buffer
4734     ASSERT(range.start >= mRange.start && mRange.end() >= range.end());
4735 
4736     return range;
4737 }
4738 
~CoherentBuffer()4739 CoherentBuffer::~CoherentBuffer() {}
4740 
isDirty()4741 bool CoherentBuffer::isDirty()
4742 {
4743     return std::find(mDirtyPages.begin(), mDirtyPages.end(), true) != mDirtyPages.end();
4744 }
4745 
contains(size_t page,size_t * relativePage)4746 bool CoherentBuffer::contains(size_t page, size_t *relativePage)
4747 {
4748     bool isInProtectionRange = page >= mProtectionStartPage && page < mProtectionEndPage;
4749     if (!isInProtectionRange)
4750     {
4751         return false;
4752     }
4753 
4754     *relativePage = page - mProtectionStartPage;
4755 
4756     ASSERT(page >= mProtectionStartPage);
4757 
4758     return true;
4759 }
4760 
protectPageRange(const PageRange & pageRange)4761 void CoherentBuffer::protectPageRange(const PageRange &pageRange)
4762 {
4763     for (size_t i = pageRange.start; i < pageRange.end; i++)
4764     {
4765         setDirty(i, false);
4766     }
4767 }
4768 
setDirty(size_t relativePage,bool dirty)4769 void CoherentBuffer::setDirty(size_t relativePage, bool dirty)
4770 {
4771     if (mDirtyPages[relativePage] == dirty)
4772     {
4773         // The page is already set.
4774         // This can happen when tracked buffers overlap in a page.
4775         return;
4776     }
4777 
4778     uintptr_t pageStart = mProtectionRange.start + relativePage * mPageSize;
4779 
4780     // Last page end must be the same as protection end
4781     if (relativePage + 1 == mPageCount)
4782     {
4783         ASSERT(mProtectionRange.end() == pageStart + mPageSize);
4784     }
4785 
4786     bool ret;
4787     if (dirty)
4788     {
4789         ret = UnprotectMemory(pageStart, mPageSize);
4790     }
4791     else
4792     {
4793         ret = ProtectMemory(pageStart, mPageSize);
4794     }
4795 
4796     if (!ret)
4797     {
4798         ERR() << "Could not set protection for buffer page " << relativePage << " at "
4799               << reinterpret_cast<void *>(pageStart) << " with size " << mPageSize;
4800     }
4801     mDirtyPages[relativePage] = dirty;
4802 }
4803 
removeProtection(PageSharingType sharingType)4804 void CoherentBuffer::removeProtection(PageSharingType sharingType)
4805 {
4806     uintptr_t start = mProtectionRange.start;
4807     size_t size     = mProtectionRange.size;
4808 
4809     switch (sharingType)
4810     {
4811         case PageSharingType::FirstShared:
4812         case PageSharingType::FirstAndLastShared:
4813             start += mPageSize;
4814             break;
4815         default:
4816             break;
4817     }
4818 
4819     switch (sharingType)
4820     {
4821         case PageSharingType::FirstShared:
4822         case PageSharingType::LastShared:
4823             size -= mPageSize;
4824             break;
4825         case PageSharingType::FirstAndLastShared:
4826             size -= (2 * mPageSize);
4827             break;
4828         default:
4829             break;
4830     }
4831 
4832     if (size == 0)
4833     {
4834         return;
4835     }
4836 
4837     if (!UnprotectMemory(start, size))
4838     {
4839         ERR() << "Could not remove protection for buffer at " << start << " with size " << size;
4840     }
4841 }
4842 
CoherentBufferTracker()4843 CoherentBufferTracker::CoherentBufferTracker()
4844 {
4845     mPageSize = GetPageSize();
4846 
4847     PageFaultCallback callback = [this](uintptr_t address) { return handleWrite(address); };
4848 
4849     mPageFaultHandler = std::unique_ptr<PageFaultHandler>(CreatePageFaultHandler(callback));
4850 }
4851 
~CoherentBufferTracker()4852 CoherentBufferTracker::~CoherentBufferTracker()
4853 {
4854     disable();
4855 }
4856 
handleWrite(uintptr_t address)4857 PageFaultHandlerRangeType CoherentBufferTracker::handleWrite(uintptr_t address)
4858 {
4859     std::lock_guard<std::mutex> lock(mMutex);
4860     auto pagesInBuffers = getBufferPagesForAddress(address);
4861 
4862     if (pagesInBuffers.empty())
4863     {
4864         ERR() << "Didn't find a tracked buffer containing " << reinterpret_cast<void *>(address);
4865     }
4866 
4867     for (const auto &page : pagesInBuffers)
4868     {
4869         std::shared_ptr<CoherentBuffer> buffer = page.first;
4870         size_t relativePage                    = page.second;
4871         buffer->setDirty(relativePage, true);
4872     }
4873 
4874     return pagesInBuffers.empty() ? PageFaultHandlerRangeType::OutOfRange
4875                                   : PageFaultHandlerRangeType::InRange;
4876 }
4877 
getBufferPagesForAddress(uintptr_t address)4878 HashMap<std::shared_ptr<CoherentBuffer>, size_t> CoherentBufferTracker::getBufferPagesForAddress(
4879     uintptr_t address)
4880 {
4881     HashMap<std::shared_ptr<CoherentBuffer>, size_t> foundPages;
4882     size_t page = address / mPageSize;
4883     for (const auto &pair : mBuffers)
4884     {
4885         std::shared_ptr<CoherentBuffer> buffer = pair.second;
4886         size_t relativePage;
4887         if (buffer->contains(page, &relativePage))
4888         {
4889             foundPages.insert(std::make_pair(buffer, relativePage));
4890         }
4891     }
4892 
4893     return foundPages;
4894 }
4895 
isDirty(gl::BufferID id)4896 bool CoherentBufferTracker::isDirty(gl::BufferID id)
4897 {
4898     return mBuffers[id.value]->isDirty();
4899 }
4900 
enable()4901 void CoherentBufferTracker::enable()
4902 {
4903     if (mEnabled)
4904     {
4905         return;
4906     }
4907 
4908     bool ret = mPageFaultHandler->enable();
4909     if (ret)
4910     {
4911         mEnabled = true;
4912     }
4913     else
4914     {
4915         ERR() << "Could not enable page fault handler.";
4916     }
4917 }
4918 
haveBuffer(gl::BufferID id)4919 bool CoherentBufferTracker::haveBuffer(gl::BufferID id)
4920 {
4921     return mBuffers.find(id.value) != mBuffers.end();
4922 }
4923 
onEndFrame()4924 void CoherentBufferTracker::onEndFrame()
4925 {
4926     std::lock_guard<std::mutex> lock(mMutex);
4927 
4928     if (!mEnabled)
4929     {
4930         return;
4931     }
4932 
4933     // Remove protection from all buffers
4934     for (const auto &pair : mBuffers)
4935     {
4936         std::shared_ptr<CoherentBuffer> buffer = pair.second;
4937         buffer->removeProtection(PageSharingType::NoneShared);
4938     }
4939 
4940     disable();
4941 }
4942 
disable()4943 void CoherentBufferTracker::disable()
4944 {
4945     if (!mEnabled)
4946     {
4947         return;
4948     }
4949 
4950     if (mPageFaultHandler->disable())
4951     {
4952         mEnabled = false;
4953     }
4954     else
4955     {
4956         ERR() << "Could not disable page fault handler.";
4957     }
4958 }
4959 
addBuffer(gl::BufferID id,uintptr_t start,size_t size)4960 void CoherentBufferTracker::addBuffer(gl::BufferID id, uintptr_t start, size_t size)
4961 {
4962     std::lock_guard<std::mutex> lock(mMutex);
4963 
4964     if (haveBuffer(id))
4965     {
4966         return;
4967     }
4968 
4969     auto buffer = std::make_shared<CoherentBuffer>(start, size, mPageSize);
4970 
4971     mBuffers.insert(std::make_pair(id.value, std::move(buffer)));
4972 }
4973 
doesBufferSharePage(gl::BufferID id)4974 PageSharingType CoherentBufferTracker::doesBufferSharePage(gl::BufferID id)
4975 {
4976     bool firstPageShared = false;
4977     bool lastPageShared  = false;
4978 
4979     std::shared_ptr<CoherentBuffer> buffer = mBuffers[id.value];
4980 
4981     AddressRange range = buffer->getRange();
4982 
4983     size_t firstPage = range.start / mPageSize;
4984     size_t lastPage  = range.end() / mPageSize;
4985 
4986     for (const auto &pair : mBuffers)
4987     {
4988         gl::BufferID otherId = {pair.first};
4989         if (otherId != id)
4990         {
4991             std::shared_ptr<CoherentBuffer> otherBuffer = pair.second;
4992             size_t relativePage;
4993             if (otherBuffer->contains(firstPage, &relativePage))
4994             {
4995                 firstPageShared = true;
4996             }
4997             else if (otherBuffer->contains(lastPage, &relativePage))
4998             {
4999                 lastPageShared = true;
5000             }
5001         }
5002     }
5003 
5004     if (firstPageShared && !lastPageShared)
5005     {
5006         return PageSharingType::FirstShared;
5007     }
5008     else if (!firstPageShared && lastPageShared)
5009     {
5010         return PageSharingType::LastShared;
5011     }
5012     else if (firstPageShared && lastPageShared)
5013     {
5014         return PageSharingType::FirstAndLastShared;
5015     }
5016     else
5017     {
5018         return PageSharingType::NoneShared;
5019     }
5020 }
5021 
removeBuffer(gl::BufferID id)5022 void CoherentBufferTracker::removeBuffer(gl::BufferID id)
5023 {
5024     std::lock_guard<std::mutex> lock(mMutex);
5025 
5026     if (!haveBuffer(id))
5027     {
5028         return;
5029     }
5030 
5031     // If the buffer shares pages with other tracked buffers,
5032     // don't unprotect the overlapping pages.
5033     PageSharingType sharingType = doesBufferSharePage(id);
5034     mBuffers[id.value]->removeProtection(sharingType);
5035     mBuffers.erase(id.value);
5036 }
5037 
trackBufferMapping(CallCapture * call,gl::BufferID id,gl::Buffer * buffer,GLintptr offset,GLsizeiptr length,bool writable,bool coherent)5038 void FrameCaptureShared::trackBufferMapping(CallCapture *call,
5039                                             gl::BufferID id,
5040                                             gl::Buffer *buffer,
5041                                             GLintptr offset,
5042                                             GLsizeiptr length,
5043                                             bool writable,
5044                                             bool coherent)
5045 {
5046     // Track that the buffer was mapped
5047     mResourceTracker.setBufferMapped(id.value);
5048 
5049     if (writable)
5050     {
5051         // If this buffer was mapped writable, we don't have any visibility into what
5052         // happens to it. Therefore, remember the details about it, and we'll read it back
5053         // on Unmap to repopulate it during replay.
5054         mBufferDataMap[id] = std::make_pair(offset, length);
5055 
5056         // Track that this buffer was potentially modified
5057         mResourceTracker.getTrackedResource(ResourceIDType::Buffer).setModifiedResource(id.value);
5058 
5059         // Track the bufferID that was just mapped for use when writing return value
5060         call->params.setMappedBufferID(id);
5061 
5062         // Track coherent buffer
5063         // Check if capture is active to not initialize the coherent buffer tracker on the
5064         // first coherent glMapBufferRange call.
5065         if (coherent && (isCaptureActive() || mMidExecutionCaptureActive))
5066         {
5067             mCoherentBufferTracker.enable();
5068             uintptr_t data = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
5069             mCoherentBufferTracker.addBuffer(id, data, length);
5070         }
5071     }
5072 }
5073 
trackTextureUpdate(const gl::Context * context,const CallCapture & call)5074 void FrameCaptureShared::trackTextureUpdate(const gl::Context *context, const CallCapture &call)
5075 {
5076     int index             = 0;
5077     std::string paramName = "targetPacked";
5078     ParamType paramType   = ParamType::TTextureTarget;
5079 
5080     // Some calls provide the textureID directly
5081     // For the rest, look it up based on the currently bound texture
5082     switch (call.entryPoint)
5083     {
5084         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
5085             index     = 1;
5086             paramName = "destIdPacked";
5087             paramType = ParamType::TTextureID;
5088             break;
5089         case EntryPoint::GLCopyTextureCHROMIUM:
5090         case EntryPoint::GLCopySubTextureCHROMIUM:
5091         case EntryPoint::GLCopyTexture3DANGLE:
5092             index     = 3;
5093             paramName = "destIdPacked";
5094             paramType = ParamType::TTextureID;
5095             break;
5096         case EntryPoint::GLCopyImageSubData:
5097         case EntryPoint::GLCopyImageSubDataEXT:
5098         case EntryPoint::GLCopyImageSubDataOES:
5099             index     = 7;
5100             paramName = "dstTarget";
5101             paramType = ParamType::TGLenum;
5102             break;
5103         default:
5104             break;
5105     }
5106 
5107     GLuint id = 0;
5108     switch (paramType)
5109     {
5110         case ParamType::TTextureTarget:
5111         {
5112             gl::TextureTarget targetPacked =
5113                 call.params.getParam(paramName.c_str(), ParamType::TTextureTarget, index)
5114                     .value.TextureTargetVal;
5115             gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
5116             gl::Texture *texture        = context->getState().getTargetTexture(textureType);
5117             id                          = texture->id().value;
5118             break;
5119         }
5120         case ParamType::TTextureID:
5121         {
5122             gl::TextureID destIDPacked =
5123                 call.params.getParam(paramName.c_str(), ParamType::TTextureID, index)
5124                     .value.TextureIDVal;
5125             id = destIDPacked.value;
5126             break;
5127         }
5128         case ParamType::TGLenum:
5129         {
5130             GLenum target =
5131                 call.params.getParam(paramName.c_str(), ParamType::TGLenum, index).value.GLenumVal;
5132             gl::TextureTarget targetPacked = gl::PackParam<gl::TextureTarget>(target);
5133             gl::TextureType textureType    = gl::TextureTargetToType(targetPacked);
5134             gl::Texture *texture           = context->getState().getTargetTexture(textureType);
5135             id                             = texture->id().value;
5136             break;
5137         }
5138         default:
5139             ERR() << "Unhandled paramType= " << static_cast<int>(paramType);
5140             UNREACHABLE();
5141             break;
5142     }
5143 
5144     // Mark it as modified
5145     mResourceTracker.getTrackedResource(ResourceIDType::Texture).setModifiedResource(id);
5146 }
5147 
updateCopyImageSubData(CallCapture & call)5148 void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
5149 {
5150     // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
5151     // packed types that can remapped using gTextureMap and gRenderbufferMap
5152 
5153     GLint srcName    = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
5154     GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
5155     switch (srcTarget)
5156     {
5157         case GL_RENDERBUFFER:
5158         {
5159             // Convert the GLuint to RenderbufferID
5160             gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
5161             call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
5162                                              srcRenderbufferID, 0);
5163             break;
5164         }
5165         case GL_TEXTURE_2D:
5166         case GL_TEXTURE_2D_ARRAY:
5167         case GL_TEXTURE_3D:
5168         case GL_TEXTURE_CUBE_MAP:
5169         {
5170             // Convert the GLuint to TextureID
5171             gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
5172             call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
5173             break;
5174         }
5175         default:
5176             ERR() << "Unhandled srcTarget = " << srcTarget;
5177             UNREACHABLE();
5178             break;
5179     }
5180 
5181     // Change dstName to the appropriate type based on dstTarget
5182     GLint dstName    = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
5183     GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
5184     switch (dstTarget)
5185     {
5186         case GL_RENDERBUFFER:
5187         {
5188             // Convert the GLuint to RenderbufferID
5189             gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
5190             call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
5191                                              dstRenderbufferID, 6);
5192             break;
5193         }
5194         case GL_TEXTURE_2D:
5195         case GL_TEXTURE_2D_ARRAY:
5196         case GL_TEXTURE_3D:
5197         case GL_TEXTURE_CUBE_MAP:
5198         {
5199             // Convert the GLuint to TextureID
5200             gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
5201             call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
5202             break;
5203         }
5204         default:
5205             ERR() << "Unhandled dstTarget = " << dstTarget;
5206             UNREACHABLE();
5207             break;
5208     }
5209 }
5210 
overrideProgramBinary(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)5211 void FrameCaptureShared::overrideProgramBinary(const gl::Context *context,
5212                                                CallCapture &inCall,
5213                                                std::vector<CallCapture> &outCalls)
5214 {
5215     // Program binaries are inherently non-portable, even between two ANGLE builds.
5216     // If an application is using glProgramBinary in the middle of a trace, we need to replace
5217     // those calls with an equivalent sequence of portable calls.
5218     //
5219     // For example, here is a sequence an app could use for glProgramBinary:
5220     //
5221     //   gShaderProgramMap[42] = glCreateProgram();
5222     //   glProgramBinary(gShaderProgramMap[42], GL_PROGRAM_BINARY_ANGLE, gBinaryData[x], 1000);
5223     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
5224     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
5225     //
5226     // With this override, the glProgramBinary call will be replaced like so:
5227     //
5228     //   gShaderProgramMap[42] = glCreateProgram();
5229     //   === Begin override ===
5230     //   gShaderProgramMap[43] = glCreateShader(GL_VERTEX_SHADER);
5231     //   glShaderSource(gShaderProgramMap[43], 1, string_0, &gBinaryData[100]);
5232     //   glCompileShader(gShaderProgramMap[43]);
5233     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
5234     //   glDeleteShader(gShaderProgramMap[43]);
5235     //   gShaderProgramMap[43] = glCreateShader(GL_FRAGMENT_SHADER);
5236     //   glShaderSource(gShaderProgramMap[43], 1, string_1, &gBinaryData[200]);
5237     //   glCompileShader(gShaderProgramMap[43]);
5238     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
5239     //   glDeleteShader(gShaderProgramMap[43]);
5240     //   glBindAttribLocation(gShaderProgramMap[42], 0, "attrib1");
5241     //   glBindAttribLocation(gShaderProgramMap[42], 1, "attrib2");
5242     //   glLinkProgram(gShaderProgramMap[42]);
5243     //   UpdateUniformLocation(gShaderProgramMap[42], "foo", 0, 20);
5244     //   UpdateUniformLocation(gShaderProgramMap[42], "bar", 72, 1);
5245     //   glUseProgram(gShaderProgramMap[42]);
5246     //   UpdateCurrentProgram(gShaderProgramMap[42]);
5247     //   glUniform4fv(gUniformLocations[gCurrentProgram][0], 20, &gBinaryData[300]);
5248     //   glUniform1iv(gUniformLocations[gCurrentProgram][72], 1, &gBinaryData[400]);
5249     //   === End override ===
5250     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
5251     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
5252     //
5253     // To facilitate this override, we are serializing each shader stage source into the binary
5254     // itself.  See Program::serialize and Program::deserialize.  Once extracted from the binary,
5255     // they will be available via getProgramSources.
5256 
5257     gl::ShaderProgramID id = inCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
5258                                  .value.ShaderProgramIDVal;
5259 
5260     gl::Program *program = context->getProgramResolveLink(id);
5261     ASSERT(program);
5262 
5263     mResourceTracker.onShaderProgramAccess(id);
5264     gl::ShaderProgramID tempShaderStartID = {mResourceTracker.getMaxShaderPrograms()};
5265     GenerateLinkedProgram(context, context->getState(), &mResourceTracker, &outCalls, program, id,
5266                           tempShaderStartID, getProgramSources(id));
5267 }
5268 
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)5269 void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context,
5270                                                  CallCapture &inCall,
5271                                                  std::vector<CallCapture> &outCalls)
5272 {
5273     switch (inCall.entryPoint)
5274     {
5275         case EntryPoint::GLEGLImageTargetTexture2DOES:
5276         {
5277             // We don't support reading EGLImages. Instead, just pull from a tiny null texture.
5278             // TODO (anglebug.com/4964): Read back the image data and populate the texture.
5279             std::vector<uint8_t> pixelData = {0, 0, 0, 0};
5280             outCalls.emplace_back(
5281                 CaptureTexSubImage2D(context->getState(), true, gl::TextureTarget::_2D, 0, 0, 0, 1,
5282                                      1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data()));
5283             break;
5284         }
5285         case EntryPoint::GLEGLImageTargetRenderbufferStorageOES:
5286         {
5287             UNIMPLEMENTED();
5288             break;
5289         }
5290         case EntryPoint::GLCopyImageSubData:
5291         case EntryPoint::GLCopyImageSubDataEXT:
5292         case EntryPoint::GLCopyImageSubDataOES:
5293         {
5294             // We must look at the src and dst target types to determine which remap table to use
5295             updateCopyImageSubData(inCall);
5296             outCalls.emplace_back(std::move(inCall));
5297             break;
5298         }
5299         case EntryPoint::GLProgramBinary:
5300         case EntryPoint::GLProgramBinaryOES:
5301         {
5302             // Binary formats are not portable at all, so replace the calls with full linking
5303             // sequence
5304             overrideProgramBinary(context, inCall, outCalls);
5305             break;
5306         }
5307         default:
5308         {
5309             // Pass the single call through
5310             outCalls.emplace_back(std::move(inCall));
5311             break;
5312         }
5313     }
5314 }
5315 
maybeCaptureCoherentBuffers(const gl::Context * context)5316 void FrameCaptureShared::maybeCaptureCoherentBuffers(const gl::Context *context)
5317 {
5318     if (!isCaptureActive())
5319     {
5320         return;
5321     }
5322 
5323     std::lock_guard<std::mutex> lock(mCoherentBufferTracker.mMutex);
5324 
5325     for (const auto &pair : mCoherentBufferTracker.mBuffers)
5326     {
5327         gl::BufferID id = {pair.first};
5328         if (mCoherentBufferTracker.isDirty(id))
5329         {
5330             captureCoherentBufferSnapshot(context, id);
5331         }
5332     }
5333 }
5334 
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)5335 void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
5336                                                           CallCapture &call,
5337                                                           size_t instanceCount)
5338 {
5339     if (!context->getStateCache().hasAnyActiveClientAttrib())
5340     {
5341         return;
5342     }
5343 
5344     // Get counts from paramBuffer.
5345     GLint firstVertex =
5346         call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
5347     GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
5348     captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
5349 }
5350 
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)5351 void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
5352                                                             CallCapture &call,
5353                                                             size_t instanceCount)
5354 {
5355     if (!context->getStateCache().hasAnyActiveClientAttrib())
5356     {
5357         return;
5358     }
5359 
5360     // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
5361     // anything anyway, so skip capturing
5362     GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
5363     if (count == 0)
5364     {
5365         return;
5366     }
5367 
5368     gl::DrawElementsType drawElementsType =
5369         call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
5370             .value.DrawElementsTypeVal;
5371     const void *indices =
5372         call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
5373 
5374     gl::IndexRange indexRange;
5375 
5376     bool restart = context->getState().isPrimitiveRestartEnabled();
5377 
5378     gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
5379     if (elementArrayBuffer)
5380     {
5381         size_t offset = reinterpret_cast<size_t>(indices);
5382         (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
5383                                                 &indexRange);
5384     }
5385     else
5386     {
5387         ASSERT(indices);
5388         indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
5389     }
5390 
5391     // index starts from 0
5392     captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
5393 }
5394 
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)5395 void FrameCaptureShared::maybeCapturePreCallUpdates(
5396     const gl::Context *context,
5397     CallCapture &call,
5398     std::vector<CallCapture> *shareGroupSetupCalls,
5399     ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
5400 {
5401     switch (call.entryPoint)
5402     {
5403         case EntryPoint::GLVertexAttribPointer:
5404         case EntryPoint::GLVertexPointer:
5405         case EntryPoint::GLColorPointer:
5406         case EntryPoint::GLTexCoordPointer:
5407         case EntryPoint::GLNormalPointer:
5408         case EntryPoint::GLPointSizePointerOES:
5409         {
5410             // Get array location
5411             GLuint index = 0;
5412             if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
5413             {
5414                 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
5415             }
5416             else
5417             {
5418                 gl::ClientVertexArrayType type;
5419                 switch (call.entryPoint)
5420                 {
5421                     case EntryPoint::GLVertexPointer:
5422                         type = gl::ClientVertexArrayType::Vertex;
5423                         break;
5424                     case EntryPoint::GLColorPointer:
5425                         type = gl::ClientVertexArrayType::Color;
5426                         break;
5427                     case EntryPoint::GLTexCoordPointer:
5428                         type = gl::ClientVertexArrayType::TextureCoord;
5429                         break;
5430                     case EntryPoint::GLNormalPointer:
5431                         type = gl::ClientVertexArrayType::Normal;
5432                         break;
5433                     case EntryPoint::GLPointSizePointerOES:
5434                         type = gl::ClientVertexArrayType::PointSize;
5435                         break;
5436                     default:
5437                         UNREACHABLE();
5438                         type = gl::ClientVertexArrayType::InvalidEnum;
5439                 }
5440                 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
5441             }
5442 
5443             if (call.params.hasClientArrayData())
5444             {
5445                 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
5446             }
5447             else
5448             {
5449                 mClientVertexArrayMap[index] = -1;
5450             }
5451             break;
5452         }
5453 
5454         case EntryPoint::GLGenFramebuffers:
5455         case EntryPoint::GLGenFramebuffersOES:
5456         {
5457             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5458             const gl::FramebufferID *framebufferIDs =
5459                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1)
5460                     .value.FramebufferIDPointerVal;
5461             for (GLsizei i = 0; i < count; i++)
5462             {
5463                 handleGennedResource(framebufferIDs[i]);
5464             }
5465             break;
5466         }
5467 
5468         case EntryPoint::GLBindFramebuffer:
5469         case EntryPoint::GLBindFramebufferOES:
5470             maybeGenResourceOnBind<gl::FramebufferID>(call);
5471             break;
5472 
5473         case EntryPoint::GLGenRenderbuffers:
5474         case EntryPoint::GLGenRenderbuffersOES:
5475         {
5476             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5477             const gl::RenderbufferID *renderbufferIDs =
5478                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1)
5479                     .value.RenderbufferIDPointerVal;
5480             for (GLsizei i = 0; i < count; i++)
5481             {
5482                 handleGennedResource(renderbufferIDs[i]);
5483             }
5484             break;
5485         }
5486 
5487         case EntryPoint::GLBindRenderbuffer:
5488         case EntryPoint::GLBindRenderbufferOES:
5489             maybeGenResourceOnBind<gl::RenderbufferID>(call);
5490             break;
5491 
5492         case EntryPoint::GLGenTextures:
5493         {
5494             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5495             const gl::TextureID *textureIDs =
5496                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1)
5497                     .value.TextureIDPointerVal;
5498             for (GLsizei i = 0; i < count; i++)
5499             {
5500                 // If we're capturing, track what new textures have been genned
5501                 handleGennedResource(textureIDs[i]);
5502             }
5503             break;
5504         }
5505 
5506         case EntryPoint::GLBindTexture:
5507             maybeGenResourceOnBind<gl::TextureID>(call);
5508             break;
5509 
5510         case EntryPoint::GLDeleteBuffers:
5511         {
5512             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5513             const gl::BufferID *bufferIDs =
5514                 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
5515                     .value.BufferIDConstPointerVal;
5516             for (GLsizei i = 0; i < count; i++)
5517             {
5518                 // For each buffer being deleted, check our backup of data and remove it
5519                 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
5520                 if (bufferDataInfo != mBufferDataMap.end())
5521                 {
5522                     mBufferDataMap.erase(bufferDataInfo);
5523                 }
5524                 // If we're capturing, track what buffers have been deleted
5525                 handleDeletedResource(bufferIDs[i]);
5526             }
5527             break;
5528         }
5529 
5530         case EntryPoint::GLGenBuffers:
5531         {
5532             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5533             const gl::BufferID *bufferIDs =
5534                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
5535                     .value.BufferIDPointerVal;
5536             for (GLsizei i = 0; i < count; i++)
5537             {
5538                 handleGennedResource(bufferIDs[i]);
5539             }
5540             break;
5541         }
5542 
5543         case EntryPoint::GLBindBuffer:
5544             maybeGenResourceOnBind<gl::BufferID>(call);
5545             break;
5546 
5547         case EntryPoint::GLDeleteProgramPipelines:
5548         case EntryPoint::GLDeleteProgramPipelinesEXT:
5549         {
5550             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5551             const gl::ProgramPipelineID *pipelineIDs =
5552                 call.params
5553                     .getParam("pipelinesPacked", ParamType::TProgramPipelineIDConstPointer, 1)
5554                     .value.ProgramPipelineIDPointerVal;
5555             for (GLsizei i = 0; i < count; i++)
5556             {
5557                 handleDeletedResource(pipelineIDs[i]);
5558             }
5559             break;
5560         }
5561 
5562         case EntryPoint::GLGenProgramPipelines:
5563         case EntryPoint::GLGenProgramPipelinesEXT:
5564         {
5565             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5566             const gl::ProgramPipelineID *pipelineIDs =
5567                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1)
5568                     .value.ProgramPipelineIDPointerVal;
5569             for (GLsizei i = 0; i < count; i++)
5570             {
5571                 handleGennedResource(pipelineIDs[i]);
5572             }
5573             break;
5574         }
5575 
5576         case EntryPoint::GLDeleteSync:
5577         {
5578             GLsync sync = call.params.getParam("sync", ParamType::TGLsync, 0).value.GLsyncVal;
5579             FrameCaptureShared *frameCaptureShared =
5580                 context->getShareGroup()->getFrameCaptureShared();
5581             // If we're capturing, track which fence sync has been deleted
5582             if (frameCaptureShared->isCaptureActive())
5583             {
5584                 mResourceTracker.setDeletedFenceSync(sync);
5585             }
5586             break;
5587         }
5588 
5589         case EntryPoint::GLDrawArrays:
5590         {
5591             maybeCaptureDrawArraysClientData(context, call, 1);
5592             maybeCaptureCoherentBuffers(context);
5593             break;
5594         }
5595 
5596         case EntryPoint::GLDrawArraysInstanced:
5597         case EntryPoint::GLDrawArraysInstancedANGLE:
5598         case EntryPoint::GLDrawArraysInstancedEXT:
5599         {
5600             GLsizei instancecount =
5601                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
5602                     .value.GLsizeiVal;
5603 
5604             maybeCaptureDrawArraysClientData(context, call, instancecount);
5605             maybeCaptureCoherentBuffers(context);
5606             break;
5607         }
5608 
5609         case EntryPoint::GLDrawElements:
5610         {
5611             maybeCaptureDrawElementsClientData(context, call, 1);
5612             maybeCaptureCoherentBuffers(context);
5613             break;
5614         }
5615 
5616         case EntryPoint::GLDrawElementsInstanced:
5617         case EntryPoint::GLDrawElementsInstancedANGLE:
5618         case EntryPoint::GLDrawElementsInstancedEXT:
5619         {
5620             GLsizei instancecount =
5621                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
5622                     .value.GLsizeiVal;
5623 
5624             maybeCaptureDrawElementsClientData(context, call, instancecount);
5625             maybeCaptureCoherentBuffers(context);
5626             break;
5627         }
5628 
5629         case EntryPoint::GLCreateShaderProgramv:
5630         {
5631             // Refresh the cached shader sources.
5632             // The command CreateShaderProgramv() creates a stand-alone program from an array of
5633             // null-terminated source code strings for a single shader type, so we need update the
5634             // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
5635             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
5636             const ParamCapture &paramCapture =
5637                 call.params.getParam("typePacked", ParamType::TShaderType, 0);
5638             const ParamCapture &lineCount = call.params.getParam("count", ParamType::TGLsizei, 1);
5639             const ParamCapture &strings =
5640                 call.params.getParam("strings", ParamType::TGLcharConstPointerPointer, 2);
5641 
5642             std::ostringstream sourceString;
5643             for (int i = 0; i < lineCount.value.GLsizeiVal; ++i)
5644             {
5645                 sourceString << strings.value.GLcharConstPointerPointerVal[i];
5646             }
5647 
5648             gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
5649             ProgramSources source;
5650             source[shaderType] = sourceString.str();
5651             setProgramSources(programID, source);
5652             handleGennedResource(programID);
5653             break;
5654         }
5655 
5656         case EntryPoint::GLCreateProgram:
5657         {
5658             // If we're capturing, track which programs have been created
5659             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
5660             handleGennedResource(programID);
5661             break;
5662         }
5663 
5664         case EntryPoint::GLDeleteProgram:
5665         {
5666             // If we're capturing, track which programs have been deleted
5667             const ParamCapture &param =
5668                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
5669             handleDeletedResource(param.value.ShaderProgramIDVal);
5670             break;
5671         }
5672 
5673         case EntryPoint::GLCompileShader:
5674         {
5675             // Refresh the cached shader sources.
5676             gl::ShaderProgramID shaderID =
5677                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
5678                     .value.ShaderProgramIDVal;
5679             const gl::Shader *shader = context->getShader(shaderID);
5680             // Shaders compiled for ProgramBinary will not have a shader created
5681             if (shader)
5682             {
5683                 setShaderSource(shaderID, shader->getSourceString());
5684             }
5685             break;
5686         }
5687 
5688         case EntryPoint::GLLinkProgram:
5689         {
5690             // Refresh the cached program sources.
5691             gl::ShaderProgramID programID =
5692                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
5693                     .value.ShaderProgramIDVal;
5694             const gl::Program *program = context->getProgramResolveLink(programID);
5695             // Programs linked in support of ProgramBinary will not have attached shaders
5696             if (program->getState().hasAttachedShader())
5697             {
5698                 setProgramSources(programID, GetAttachedProgramSources(program));
5699             }
5700             break;
5701         }
5702 
5703         case EntryPoint::GLCompressedTexImage1D:
5704         case EntryPoint::GLCompressedTexSubImage1D:
5705         {
5706             UNIMPLEMENTED();
5707             break;
5708         }
5709 
5710         case EntryPoint::GLDeleteTextures:
5711         {
5712             // Free any TextureLevelDataMap entries being tracked for this texture
5713             // This is to cover the scenario where a texture has been created, its
5714             // levels cached, then texture deleted and recreated, receiving the same ID
5715 
5716             // Look up how many textures are being deleted
5717             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5718 
5719             // Look up the pointer to list of textures
5720             const gl::TextureID *textureIDs =
5721                 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
5722                     .value.TextureIDConstPointerVal;
5723 
5724             // For each texture listed for deletion
5725             for (int32_t i = 0; i < n; ++i)
5726             {
5727                 // If we're capturing, track what textures have been deleted
5728                 handleDeletedResource(textureIDs[i]);
5729             }
5730             break;
5731         }
5732 
5733         case EntryPoint::GLMapBuffer:
5734         case EntryPoint::GLMapBufferOES:
5735         {
5736             gl::BufferBinding target =
5737                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
5738                     .value.BufferBindingVal;
5739 
5740             GLbitfield access =
5741                 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
5742 
5743             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
5744 
5745             GLintptr offset   = 0;
5746             GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
5747 
5748             bool writable =
5749                 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
5750 
5751             FrameCaptureShared *frameCaptureShared =
5752                 context->getShareGroup()->getFrameCaptureShared();
5753             frameCaptureShared->trackBufferMapping(&call, buffer->id(), buffer, offset, length,
5754                                                    writable, false);
5755             break;
5756         }
5757 
5758         case EntryPoint::GLUnmapNamedBuffer:
5759         {
5760             UNIMPLEMENTED();
5761             break;
5762         }
5763 
5764         case EntryPoint::GLMapBufferRange:
5765         case EntryPoint::GLMapBufferRangeEXT:
5766         {
5767             GLintptr offset =
5768                 call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
5769             GLsizeiptr length =
5770                 call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
5771             GLbitfield access =
5772                 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
5773 
5774             gl::BufferBinding target =
5775                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
5776                     .value.BufferBindingVal;
5777             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
5778 
5779             FrameCaptureShared *frameCaptureShared =
5780                 context->getShareGroup()->getFrameCaptureShared();
5781             frameCaptureShared->trackBufferMapping(&call, buffer->id(), buffer, offset, length,
5782                                                    access & GL_MAP_WRITE_BIT,
5783                                                    access & GL_MAP_COHERENT_BIT_EXT);
5784             break;
5785         }
5786 
5787         case EntryPoint::GLUnmapBuffer:
5788         case EntryPoint::GLUnmapBufferOES:
5789         {
5790             // See if we need to capture the buffer contents
5791             captureMappedBufferSnapshot(context, call);
5792 
5793             // Track that the buffer was unmapped, for use during state reset
5794             gl::BufferBinding target =
5795                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
5796                     .value.BufferBindingVal;
5797             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
5798             mResourceTracker.setBufferUnmapped(buffer->id().value);
5799 
5800             // Remove from CoherentBufferTracker
5801             mCoherentBufferTracker.removeBuffer(buffer->id());
5802             break;
5803         }
5804 
5805         case EntryPoint::GLBufferData:
5806         case EntryPoint::GLBufferSubData:
5807         {
5808             gl::BufferBinding target =
5809                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
5810                     .value.BufferBindingVal;
5811 
5812             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
5813 
5814             // Track that this buffer's contents have been modified
5815             mResourceTracker.getTrackedResource(ResourceIDType::Buffer)
5816                 .setModifiedResource(buffer->id().value);
5817 
5818             // BufferData is equivalent to UnmapBuffer, for what we're tracking.
5819             // From the ES 3.1 spec in BufferData section:
5820             //     If any portion of the buffer object is mapped in the current context or any
5821             //     context current to another thread, it is as though UnmapBuffer (see section
5822             //     6.3.1) is executed in each such context prior to deleting the existing data
5823             //     store.
5824             // Track that the buffer was unmapped, for use during state reset
5825             mResourceTracker.setBufferUnmapped(buffer->id().value);
5826 
5827             break;
5828         }
5829         case EntryPoint::GLCopyBufferSubData:
5830         {
5831             maybeCaptureCoherentBuffers(context);
5832             break;
5833         }
5834         case EntryPoint::GLDeleteFramebuffers:
5835         case EntryPoint::GLDeleteFramebuffersOES:
5836         {
5837             // Look up how many framebuffers are being deleted
5838             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
5839 
5840             // Look up the pointer to list of framebuffers
5841             const gl::FramebufferID *framebufferIDs =
5842                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDConstPointer, 1)
5843                     .value.FramebufferIDConstPointerVal;
5844 
5845             // For each framebuffer listed for deletion
5846             for (int32_t i = 0; i < n; ++i)
5847             {
5848                 // If we're capturing, track what framebuffers have been deleted
5849                 handleDeletedResource(framebufferIDs[i]);
5850             }
5851             break;
5852         }
5853         default:
5854             break;
5855     }
5856 
5857     if (IsTextureUpdate(call))
5858     {
5859         // If this call modified texture contents, track it for possible reset
5860         trackTextureUpdate(context, call);
5861     }
5862 
5863     updateReadBufferSize(call.params.getReadBufferSize());
5864 
5865     std::vector<gl::ShaderProgramID> shaderProgramIDs;
5866     if (FindShaderProgramIDsInCall(call, shaderProgramIDs))
5867     {
5868         for (gl::ShaderProgramID shaderProgramID : shaderProgramIDs)
5869         {
5870             mResourceTracker.onShaderProgramAccess(shaderProgramID);
5871 
5872             if (isCaptureActive())
5873             {
5874                 // Track that this call referenced a ShaderProgram, setting it active for Setup
5875                 MarkResourceIDActive(ResourceIDType::ShaderProgram, shaderProgramID.value,
5876                                      shareGroupSetupCalls, resourceIDToSetupCalls);
5877             }
5878         }
5879     }
5880 
5881     updateResourceCountsFromCallCapture(call);
5882 }
5883 
5884 template <typename ParamValueType>
maybeGenResourceOnBind(CallCapture & call)5885 void FrameCaptureShared::maybeGenResourceOnBind(CallCapture &call)
5886 {
5887     const char *paramName     = ParamValueTrait<ParamValueType>::name;
5888     const ParamType paramType = ParamValueTrait<ParamValueType>::typeID;
5889 
5890     const ParamCapture &param = call.params.getParam(paramName, paramType, 1);
5891     const ParamValueType id   = AccessParamValue<ParamValueType>(paramType, param.value);
5892 
5893     // Don't inject the default resource or resources that are already generated
5894     if (id.value != 0 && !resourceIsGenerated(id))
5895     {
5896         handleGennedResource(id);
5897 
5898         ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
5899         const char *resourceName      = GetResourceIDTypeName(resourceIDType);
5900 
5901         std::stringstream updateFuncNameStr;
5902         updateFuncNameStr << "Set" << resourceName << "ID";
5903         std::string updateFuncName = updateFuncNameStr.str();
5904 
5905         ParamBuffer params;
5906         params.addValueParam("id", ParamType::TGLuint, id.value);
5907         mFrameCalls.emplace_back(updateFuncName, std::move(params));
5908     }
5909 }
5910 
updateResourceCountsFromParamCapture(const ParamCapture & param,ResourceIDType idType)5911 void FrameCaptureShared::updateResourceCountsFromParamCapture(const ParamCapture &param,
5912                                                               ResourceIDType idType)
5913 {
5914     if (idType != ResourceIDType::InvalidEnum)
5915     {
5916         mHasResourceType.set(idType);
5917 
5918         // Capture resource IDs for non-pointer types.
5919         if (strcmp(ParamTypeToString(param.type), "GLuint") == 0)
5920         {
5921             mMaxAccessedResourceIDs[idType] =
5922                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
5923         }
5924         // Capture resource IDs for pointer types.
5925         if (strstr(ParamTypeToString(param.type), "GLuint *") != nullptr)
5926         {
5927             if (param.data.size() == 1u)
5928             {
5929                 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(param.data[0].data());
5930                 size_t numHandles     = param.data[0].size() / sizeof(GLuint);
5931                 for (size_t handleIndex = 0; handleIndex < numHandles; ++handleIndex)
5932                 {
5933                     mMaxAccessedResourceIDs[idType] =
5934                         std::max(mMaxAccessedResourceIDs[idType], dataPtr[handleIndex]);
5935                 }
5936             }
5937         }
5938     }
5939 }
5940 
updateResourceCountsFromCallCapture(const CallCapture & call)5941 void FrameCaptureShared::updateResourceCountsFromCallCapture(const CallCapture &call)
5942 {
5943     for (const ParamCapture &param : call.params.getParamCaptures())
5944     {
5945         ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
5946         updateResourceCountsFromParamCapture(param, idType);
5947     }
5948 
5949     // Update resource IDs in the return value. Return values types are not stored as resource IDs,
5950     // but instead are stored as GLuints. Therefore we need to explicitly label the resource ID type
5951     // when we call update. Currently only shader and program creation are explicitly tracked.
5952     switch (call.entryPoint)
5953     {
5954         case EntryPoint::GLCreateShader:
5955         case EntryPoint::GLCreateProgram:
5956             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
5957                                                  ResourceIDType::ShaderProgram);
5958             break;
5959 
5960         default:
5961             break;
5962     }
5963 }
5964 
captureCall(const gl::Context * context,CallCapture && inCall,bool isCallValid)5965 void FrameCaptureShared::captureCall(const gl::Context *context,
5966                                      CallCapture &&inCall,
5967                                      bool isCallValid)
5968 {
5969     if (SkipCall(inCall.entryPoint))
5970     {
5971         return;
5972     }
5973 
5974     if (isCallValid)
5975     {
5976         // If the context ID has changed, then we need to inject an eglMakeCurrent() call. Only do
5977         // this if there is more than 1 context in the share group to avoid unnecessary
5978         // eglMakeCurrent() calls.
5979         size_t contextCount = context->getShareGroup()->getShareGroupContextCount();
5980         if (contextCount > 1 && mLastContextId != context->id())
5981         {
5982             // Inject the eglMakeCurrent() call.
5983             // The EGLDisplay and EGLSurface values can't be known here, since we may not even be
5984             // running the trace with ANGLE.
5985             // The EGLContext value is actually the context ID, so we can look it up in
5986             // 'gContextMap'.
5987             // Need to go from uint32 -> uint64 -> EGLContext (void*) to handle MSVC compiler
5988             // warning on 64b systems:
5989             //   error C4312: 'reinterpret_cast': conversion from 'uint32_t' to 'EGLContext' of
5990             //   greater size
5991             uint64_t contextID    = static_cast<uint64_t>(context->id().value);
5992             EGLContext eglContext = reinterpret_cast<EGLContext>(contextID);
5993             CallCapture makeCurrentCall =
5994                 CaptureMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext);
5995             mFrameCalls.emplace_back(std::move(makeCurrentCall));
5996             mLastContextId = context->id();
5997         }
5998 
5999         std::vector<CallCapture> outCalls;
6000         maybeOverrideEntryPoint(context, inCall, outCalls);
6001 
6002         // Need to loop on any new calls we added during override
6003         for (CallCapture &call : outCalls)
6004         {
6005             // During capture, consider all frame calls active
6006             if (isCaptureActive())
6007             {
6008                 call.isActive = true;
6009             }
6010 
6011             maybeCapturePreCallUpdates(context, call, &mShareGroupSetupCalls,
6012                                        &mResourceIDToSetupCalls);
6013             mFrameCalls.emplace_back(std::move(call));
6014             maybeCapturePostCallUpdates(context);
6015         }
6016 
6017         // Evaluate the validation expression to determine if we insert a validation checkpoint.
6018         // This lets the user pick a subset of calls to check instead of checking every call.
6019         if (mValidateSerializedState && !mValidationExpression.empty())
6020         {
6021             // Example substitution for frame #2, call #110:
6022             // Before: (call == 2) && (frame >= 100) && (frame <= 120) && ((frame % 10) == 0)
6023             // After:  (2 == 2) && (110 >= 100) && (110 <= 120) && ((110 % 10) == 0)
6024             // Evaluates to 1.0.
6025             std::string expression = mValidationExpression;
6026 
6027             angle::ReplaceAllSubstrings(&expression, "frame", std::to_string(mFrameIndex));
6028             angle::ReplaceAllSubstrings(&expression, "call", std::to_string(mFrameCalls.size()));
6029 
6030             double result = ceval_result(expression);
6031             if (result > 0)
6032             {
6033                 CaptureValidateSerializedState(context, &mFrameCalls);
6034             }
6035         }
6036     }
6037     else
6038     {
6039         INFO() << "FrameCapture: Not capturing invalid call to "
6040                << GetEntryPointName(inCall.entryPoint);
6041     }
6042 }
6043 
maybeCapturePostCallUpdates(const gl::Context * context)6044 void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
6045 {
6046     // Process resource ID updates.
6047     if (isCaptureActive())
6048     {
6049         MaybeCaptureUpdateResourceIDs(&mResourceTracker, &mFrameCalls);
6050     }
6051 
6052     CallCapture &lastCall = mFrameCalls.back();
6053     switch (lastCall.entryPoint)
6054     {
6055         case EntryPoint::GLCreateShaderProgramv:
6056         {
6057             gl::ShaderProgramID programId;
6058             programId.value            = lastCall.params.getReturnValue().value.GLuintVal;
6059             const gl::Program *program = context->getProgramResolveLink(programId);
6060             CaptureUpdateUniformLocations(program, &mFrameCalls);
6061             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
6062             break;
6063         }
6064         case EntryPoint::GLLinkProgram:
6065         {
6066             const ParamCapture &param =
6067                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
6068             const gl::Program *program =
6069                 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
6070             CaptureUpdateUniformLocations(program, &mFrameCalls);
6071             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
6072             break;
6073         }
6074         case EntryPoint::GLUseProgram:
6075             CaptureUpdateCurrentProgram(lastCall, 0, &mFrameCalls);
6076             break;
6077         case EntryPoint::GLActiveShaderProgram:
6078             CaptureUpdateCurrentProgram(lastCall, 1, &mFrameCalls);
6079             break;
6080         case EntryPoint::GLDeleteProgram:
6081         {
6082             const ParamCapture &param =
6083                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
6084             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
6085             break;
6086         }
6087         case EntryPoint::GLShaderSource:
6088         {
6089             lastCall.params.setValueParamAtIndex("count", ParamType::TGLsizei, 1, 1);
6090 
6091             ParamCapture &paramLength =
6092                 lastCall.params.getParam("length", ParamType::TGLintConstPointer, 3);
6093             paramLength.data.resize(1);
6094             // Set the length parameter to {-1} to signal that the actual string length
6095             // is to be used. Since we store the parameter blob as an array of four uint8_t
6096             // values, we have to pass the binary equivalent of -1.
6097             paramLength.data[0] = {0xff, 0xff, 0xff, 0xff};
6098             break;
6099         }
6100         default:
6101             break;
6102     }
6103 }
6104 
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)6105 void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
6106                                                     size_t vertexCount,
6107                                                     size_t instanceCount)
6108 {
6109     const gl::VertexArray *vao = context->getState().getVertexArray();
6110 
6111     // Capture client array data.
6112     for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
6113     {
6114         const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
6115         const gl::VertexBinding &binding  = vao->getVertexBinding(attrib.bindingIndex);
6116 
6117         int callIndex = mClientVertexArrayMap[attribIndex];
6118 
6119         if (callIndex != -1)
6120         {
6121             size_t count = vertexCount;
6122 
6123             if (binding.getDivisor() > 0)
6124             {
6125                 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
6126                                                binding.getDivisor());
6127             }
6128 
6129             // The last capture element doesn't take up the full stride.
6130             size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
6131 
6132             CallCapture &call   = mFrameCalls[callIndex];
6133             ParamCapture &param = call.params.getClientArrayPointerParameter();
6134             ASSERT(param.type == ParamType::TvoidConstPointer);
6135 
6136             ParamBuffer updateParamBuffer;
6137             updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
6138                                                    static_cast<uint32_t>(attribIndex));
6139 
6140             ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
6141             CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
6142             updateParamBuffer.addParam(std::move(updateMemory));
6143 
6144             updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
6145 
6146             mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
6147 
6148             mClientArraySizes[attribIndex] =
6149                 std::max(mClientArraySizes[attribIndex], bytesToCapture);
6150         }
6151     }
6152 }
6153 
captureCoherentBufferSnapshot(const gl::Context * context,gl::BufferID id)6154 void FrameCaptureShared::captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID id)
6155 {
6156     if (!hasBufferData(id))
6157     {
6158         // This buffer was not marked writable
6159         return;
6160     }
6161 
6162     const gl::State &apiState        = context->getState();
6163     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
6164     gl::Buffer *buffer               = buffers.getBuffer(id);
6165     if (!buffer)
6166     {
6167         // Could not find buffer binding
6168         return;
6169     }
6170 
6171     ASSERT(buffer->isMapped());
6172 
6173     std::shared_ptr<angle::CoherentBuffer> coherentBuffer =
6174         mCoherentBufferTracker.mBuffers[id.value];
6175 
6176     std::vector<PageRange> dirtyPageRanges = coherentBuffer->getDirtyPageRanges();
6177 
6178     AddressRange wholeRange = coherentBuffer->getRange();
6179 
6180     for (PageRange &pageRange : dirtyPageRanges)
6181     {
6182         // Write protect the memory already, so the app is blocked on writing during our capture
6183         coherentBuffer->protectPageRange(pageRange);
6184 
6185         // Create the parameters to our helper for use during replay
6186         ParamBuffer dataParamBuffer;
6187 
6188         // Pass in the target buffer ID
6189         dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
6190 
6191         // Capture the current buffer data with a binary param
6192         ParamCapture captureData("source", ParamType::TvoidConstPointer);
6193 
6194         AddressRange dirtyRange = coherentBuffer->getDirtyAddressRange(pageRange);
6195         CaptureMemory(reinterpret_cast<void *>(dirtyRange.start), dirtyRange.size, &captureData);
6196         dataParamBuffer.addParam(std::move(captureData));
6197 
6198         // Also track its size for use with memcpy
6199         dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
6200                                                   static_cast<GLsizeiptr>(dirtyRange.size));
6201 
6202         if (wholeRange.start != dirtyRange.start)
6203         {
6204             // Capture with offset
6205             GLsizeiptr offset = dirtyRange.start - wholeRange.start;
6206 
6207             ASSERT(offset > 0);
6208 
6209             // The dirty page range is not at the start of the buffer, track the offset.
6210             dataParamBuffer.addValueParam<GLsizeiptr>("offset", ParamType::TGLsizeiptr, offset);
6211 
6212             // Call the helper that populates the buffer with captured data
6213             mFrameCalls.emplace_back("UpdateClientBufferDataWithOffset",
6214                                      std::move(dataParamBuffer));
6215         }
6216         else
6217         {
6218             // Call the helper that populates the buffer with captured data
6219             mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
6220         }
6221     }
6222 }
6223 
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)6224 void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
6225                                                      const CallCapture &call)
6226 {
6227     // If the buffer was mapped writable, we need to restore its data, since we have no
6228     // visibility into what the client did to the buffer while mapped.
6229     // This sequence will result in replay calls like this:
6230     //   ...
6231     //   gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
6232     //                                                        GL_MAP_WRITE_BIT);
6233     //   ...
6234     //   UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
6235     //   glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
6236     //   ...
6237 
6238     // Re-map the buffer, using the info we tracked about the buffer
6239     gl::BufferBinding target =
6240         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
6241 
6242     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
6243     gl::Buffer *buffer                     = context->getState().getTargetBuffer(target);
6244     if (!frameCaptureShared->hasBufferData(buffer->id()))
6245     {
6246         // This buffer was not marked writable, so we did not back it up
6247         return;
6248     }
6249 
6250     std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
6251         frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
6252     GLintptr offset   = bufferDataOffsetAndLength.first;
6253     GLsizeiptr length = bufferDataOffsetAndLength.second;
6254 
6255     // Map the buffer so we can copy its contents out
6256     ASSERT(!buffer->isMapped());
6257     angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
6258     if (result != angle::Result::Continue)
6259     {
6260         ERR() << "Failed to mapRange of buffer" << std::endl;
6261     }
6262     const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
6263 
6264     // Create the parameters to our helper for use during replay
6265     ParamBuffer dataParamBuffer;
6266 
6267     // Pass in the target buffer ID
6268     dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
6269 
6270     // Capture the current buffer data with a binary param
6271     ParamCapture captureData("source", ParamType::TvoidConstPointer);
6272     CaptureMemory(data, length, &captureData);
6273     dataParamBuffer.addParam(std::move(captureData));
6274 
6275     // Also track its size for use with memcpy
6276     dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
6277 
6278     // Call the helper that populates the buffer with captured data
6279     mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
6280 
6281     // Unmap the buffer and move on
6282     GLboolean dontCare;
6283     (void)buffer->unmap(context, &dontCare);
6284 }
6285 
checkForCaptureTrigger()6286 void FrameCaptureShared::checkForCaptureTrigger()
6287 {
6288     // If the capture trigger has not been set, move on
6289     if (mCaptureTrigger == 0)
6290     {
6291         return;
6292     }
6293 
6294     // Otherwise, poll the value for a change
6295     std::string captureTriggerStr = GetCaptureTrigger();
6296     if (captureTriggerStr.empty())
6297     {
6298         return;
6299     }
6300 
6301     // If the value has changed, use the original value as the frame count
6302     // TODO (anglebug.com/4949): Improve capture at unknown frame time. It is good to
6303     // avoid polling if the feature is not enabled, but not entirely intuitive to set
6304     // a value to zero when you want to trigger it.
6305     uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
6306     if (captureTrigger != mCaptureTrigger)
6307     {
6308         // Start mid-execution capture for the current frame
6309         mCaptureStartFrame = mFrameIndex + 1;
6310 
6311         // Use the original trigger value as the frame count
6312         mCaptureEndFrame = mCaptureStartFrame + mCaptureTrigger - 1;
6313 
6314         INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
6315                << " frames";
6316 
6317         // Stop polling
6318         mCaptureTrigger = 0;
6319     }
6320 }
6321 
scanSetupCalls(const gl::Context * context,std::vector<CallCapture> & setupCalls)6322 void FrameCaptureShared::scanSetupCalls(const gl::Context *context,
6323                                         std::vector<CallCapture> &setupCalls)
6324 {
6325     // Scan all the instructions in the list for tracking
6326     for (CallCapture &call : setupCalls)
6327     {
6328         updateReadBufferSize(call.params.getReadBufferSize());
6329         updateResourceCountsFromCallCapture(call);
6330     }
6331 }
6332 
runMidExecutionCapture(const gl::Context * mainContext)6333 void FrameCaptureShared::runMidExecutionCapture(const gl::Context *mainContext)
6334 {
6335     mMidExecutionCaptureActive = true;
6336 
6337     // Make sure all pending work for every Context in the share group has completed so all data
6338     // (buffers, textures, etc.) has been updated and no resources are in use.
6339     egl::ShareGroup *shareGroup = mainContext->getShareGroup();
6340     shareGroup->finishAllContexts();
6341 
6342     const gl::State &contextState = mainContext->getState();
6343     gl::State mainContextReplayState(nullptr, nullptr, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
6344                                      contextState.getClientVersion(), false, true, true, true,
6345                                      false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG,
6346                                      contextState.hasProtectedContent());
6347     mainContextReplayState.initializeForCapture(mainContext);
6348 
6349     CaptureShareGroupMidExecutionSetup(mainContext, &mShareGroupSetupCalls, &mResourceTracker,
6350                                        mainContextReplayState);
6351 
6352     scanSetupCalls(mainContext, mShareGroupSetupCalls);
6353 
6354     for (const gl::Context *shareContext : shareGroup->getContexts())
6355     {
6356         FrameCapture *frameCapture = shareContext->getFrameCapture();
6357         ASSERT(frameCapture->getSetupCalls().empty());
6358 
6359         if (shareContext->id() == mainContext->id())
6360         {
6361             CaptureMidExecutionSetup(shareContext, &frameCapture->getSetupCalls(),
6362                                      &mShareGroupSetupCalls, &mResourceIDToSetupCalls,
6363                                      &mResourceTracker, mainContextReplayState,
6364                                      mValidateSerializedState);
6365             scanSetupCalls(mainContext, frameCapture->getSetupCalls());
6366         }
6367         else
6368         {
6369             gl::State auxContextReplayState(
6370                 nullptr, nullptr, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
6371                 shareContext->getState().getClientVersion(), false, true, true, true, false,
6372                 EGL_CONTEXT_PRIORITY_MEDIUM_IMG, shareContext->getState().hasProtectedContent());
6373             auxContextReplayState.initializeForCapture(shareContext);
6374 
6375             CaptureMidExecutionSetup(shareContext, &frameCapture->getSetupCalls(),
6376                                      &mShareGroupSetupCalls, &mResourceIDToSetupCalls,
6377                                      &mResourceTracker, auxContextReplayState,
6378                                      mValidateSerializedState);
6379 
6380             scanSetupCalls(mainContext, frameCapture->getSetupCalls());
6381 
6382             WriteAuxiliaryContextCppSetupReplay(
6383                 mReplayWriter, mCompression, mOutDirectory, shareContext, mCaptureLabel, 1,
6384                 frameCapture->getSetupCalls(), &mBinaryData, mSerializeStateEnabled, *this);
6385         }
6386     }
6387 
6388     mMidExecutionCaptureActive = false;
6389 }
6390 
onEndFrame(const gl::Context * context)6391 void FrameCaptureShared::onEndFrame(const gl::Context *context)
6392 {
6393     if (!enabled() || mFrameIndex > mCaptureEndFrame)
6394     {
6395         setCaptureInactive();
6396         mCoherentBufferTracker.onEndFrame();
6397         return;
6398     }
6399 
6400     FrameCapture *frameCapture = context->getFrameCapture();
6401 
6402     // Count resource IDs. This is also done on every frame. It could probably be done by
6403     // checking the GL state instead of the calls.
6404     for (const CallCapture &call : mFrameCalls)
6405     {
6406         for (const ParamCapture &param : call.params.getParamCaptures())
6407         {
6408             ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
6409             if (idType != ResourceIDType::InvalidEnum)
6410             {
6411                 mHasResourceType.set(idType);
6412             }
6413         }
6414     }
6415 
6416     // Assume that the context performing the swap is the "main" context.
6417     ASSERT(mWindowSurfaceContextID.value == 0 || mWindowSurfaceContextID == context->id());
6418     mWindowSurfaceContextID = context->id();
6419 
6420     // On Android, we can trigger a capture during the run
6421     checkForCaptureTrigger();
6422 
6423     // Check for MEC. Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
6424     if (mFrameIndex < mCaptureStartFrame)
6425     {
6426         if (mFrameIndex == mCaptureStartFrame - 1)
6427         {
6428             runMidExecutionCapture(context);
6429 
6430             // Set the capture active to ensure all GLES commands issued by the next frame are
6431             // handled correctly by maybeCapturePreCallUpdates() and maybeCapturePostCallUpdates().
6432             setCaptureActive();
6433         }
6434         mFrameIndex++;
6435         reset();
6436         return;
6437     }
6438 
6439     ASSERT(isCaptureActive());
6440 
6441     if (!mFrameCalls.empty())
6442     {
6443         mActiveFrameIndices.push_back(getReplayFrameIndex());
6444     }
6445 
6446     // Make sure all pending work for every Context in the share group has completed so all data
6447     // (buffers, textures, etc.) has been updated and no resources are in use.
6448     egl::ShareGroup *shareGroup = context->getShareGroup();
6449     shareGroup->finishAllContexts();
6450 
6451     // Only validate the first frame for now to save on retracing time.
6452     if (mValidateSerializedState && mFrameIndex == mCaptureStartFrame)
6453     {
6454         CaptureValidateSerializedState(context, &mFrameCalls);
6455     }
6456 
6457     writeMainContextCppReplay(context, frameCapture->getSetupCalls());
6458 
6459     if (mFrameIndex == mCaptureEndFrame)
6460     {
6461         // Write shared MEC after frame sequence so we can eliminate unused assets like programs
6462         WriteShareGroupCppSetupReplay(mReplayWriter, mCompression, mOutDirectory, mCaptureLabel, 1,
6463                                       1, mShareGroupSetupCalls, &mResourceTracker, &mBinaryData,
6464                                       mSerializeStateEnabled, mWindowSurfaceContextID);
6465 
6466         // Save the index files after the last frame.
6467         writeCppReplayIndexFiles(context, false);
6468         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
6469         mBinaryData.clear();
6470         mWroteIndexFile = true;
6471     }
6472 
6473     reset();
6474     mFrameIndex++;
6475 }
6476 
onDestroyContext(const gl::Context * context)6477 void FrameCaptureShared::onDestroyContext(const gl::Context *context)
6478 {
6479     if (!mEnabled)
6480     {
6481         return;
6482     }
6483     if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
6484     {
6485         // If context is destroyed before end frame is reached and at least
6486         // 1 frame has been recorded, then write the index files.
6487         // It doesn't make sense to write the index files when no frame has been recorded
6488         mFrameIndex -= 1;
6489         mCaptureEndFrame = mFrameIndex;
6490         writeCppReplayIndexFiles(context, true);
6491         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
6492         mBinaryData.clear();
6493         mWroteIndexFile = true;
6494     }
6495 }
6496 
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)6497 void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
6498 {
6499     if (!drawSurface)
6500     {
6501         return;
6502     }
6503 
6504     // Track the width, height and color space of the draw surface as provided to makeCurrent
6505     SurfaceParams &params = mDrawSurfaceParams[context->id()];
6506     params.extents        = gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
6507     params.colorSpace     = egl::FromEGLenum<egl::ColorSpace>(drawSurface->getGLColorspace());
6508 }
6509 
6510 DataCounters::DataCounters() = default;
6511 
6512 DataCounters::~DataCounters() = default;
6513 
getAndIncrement(EntryPoint entryPoint,const std::string & paramName)6514 int DataCounters::getAndIncrement(EntryPoint entryPoint, const std::string &paramName)
6515 {
6516     Counter counterKey = {entryPoint, paramName};
6517     return mData[counterKey]++;
6518 }
6519 
6520 DataTracker::DataTracker() = default;
6521 
6522 DataTracker::~DataTracker() = default;
6523 
6524 StringCounters::StringCounters() = default;
6525 
6526 StringCounters::~StringCounters() = default;
6527 
getStringCounter(const std::vector<std::string> & strings)6528 int StringCounters::getStringCounter(const std::vector<std::string> &strings)
6529 {
6530     const auto &id = mStringCounterMap.find(strings);
6531     if (id == mStringCounterMap.end())
6532     {
6533         return kStringsNotFound;
6534     }
6535     else
6536     {
6537         return mStringCounterMap[strings];
6538     }
6539 }
6540 
setStringCounter(const std::vector<std::string> & strings,int & counter)6541 void StringCounters::setStringCounter(const std::vector<std::string> &strings, int &counter)
6542 {
6543     ASSERT(counter >= 0);
6544     mStringCounterMap[strings] = counter;
6545 }
6546 
6547 TrackedResource::TrackedResource() = default;
6548 
6549 TrackedResource::~TrackedResource() = default;
6550 
6551 ResourceTracker::ResourceTracker() = default;
6552 
6553 ResourceTracker::~ResourceTracker() = default;
6554 
setDeletedFenceSync(GLsync sync)6555 void ResourceTracker::setDeletedFenceSync(GLsync sync)
6556 {
6557     ASSERT(sync != nullptr);
6558     if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
6559     {
6560         // This is a fence sync created after MEC was initialized. Ignore it.
6561         return;
6562     }
6563 
6564     // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
6565     mFenceSyncsToRegen.insert(sync);
6566 }
6567 
setGennedResource(GLuint id)6568 void TrackedResource::setGennedResource(GLuint id)
6569 {
6570     if (mStartingResources.find(id) == mStartingResources.end())
6571     {
6572         // This is a resource created after MEC was initialized, track it
6573         mNewResources.insert(id);
6574         return;
6575     }
6576 }
6577 
resourceIsGenerated(GLuint id)6578 bool TrackedResource::resourceIsGenerated(GLuint id)
6579 {
6580     return mStartingResources.find(id) != mStartingResources.end() ||
6581            mNewResources.find(id) != mNewResources.end();
6582 }
6583 
setDeletedResource(GLuint id)6584 void TrackedResource::setDeletedResource(GLuint id)
6585 {
6586     if (id == 0)
6587     {
6588         // Ignore ID 0
6589         return;
6590     }
6591 
6592     if (mNewResources.find(id) != mNewResources.end())
6593     {
6594         // This is a resource created after MEC was initialized, just clear it, since there will be
6595         // no actions required for it to return to starting state.
6596         mNewResources.erase(id);
6597         return;
6598     }
6599 
6600     if (mStartingResources.find(id) != mStartingResources.end())
6601     {
6602         // In this case, the app is deleting a resource we started with, we need to regen on loop
6603         mResourcesToRegen.insert(id);
6604 
6605         // Also restore its contents
6606         mResourcesToRestore.insert(id);
6607     }
6608 
6609     // If none of the above is true, the app is deleting a resource that was never genned.
6610 }
6611 
setModifiedResource(GLuint id)6612 void TrackedResource::setModifiedResource(GLuint id)
6613 {
6614     // If this was a starting resource, we need to track it for restore
6615     if (mStartingResources.find(id) != mStartingResources.end())
6616     {
6617         mResourcesToRestore.insert(id);
6618     }
6619 }
6620 
setBufferMapped(GLuint id)6621 void ResourceTracker::setBufferMapped(GLuint id)
6622 {
6623     // If this was a starting buffer, we may need to restore it to original state during Reset.
6624     // Skip buffers that were deleted after the starting point.
6625     const TrackedResource &trackedBuffers = getTrackedResource(ResourceIDType::Buffer);
6626     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
6627     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
6628     if (startingBuffers.find(id) != startingBuffers.end() &&
6629         buffersToRegen.find(id) == buffersToRegen.end())
6630     {
6631         // Track that its current state is mapped (true)
6632         mStartingBuffersMappedCurrent[id] = true;
6633     }
6634 }
6635 
setBufferUnmapped(GLuint id)6636 void ResourceTracker::setBufferUnmapped(GLuint id)
6637 {
6638     // If this was a starting buffer, we may need to restore it to original state during Reset.
6639     // Skip buffers that were deleted after the starting point.
6640     const TrackedResource &trackedBuffers = getTrackedResource(ResourceIDType::Buffer);
6641     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
6642     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
6643     if (startingBuffers.find(id) != startingBuffers.end() &&
6644         buffersToRegen.find(id) == buffersToRegen.end())
6645     {
6646         // Track that its current state is unmapped (false)
6647         mStartingBuffersMappedCurrent[id] = false;
6648     }
6649 }
6650 
getStartingBuffersMappedCurrent(GLuint id) const6651 bool ResourceTracker::getStartingBuffersMappedCurrent(GLuint id) const
6652 {
6653     const auto &foundBool = mStartingBuffersMappedCurrent.find(id);
6654     ASSERT(foundBool != mStartingBuffersMappedCurrent.end());
6655     return foundBool->second;
6656 }
6657 
getStartingBuffersMappedInitial(GLuint id) const6658 bool ResourceTracker::getStartingBuffersMappedInitial(GLuint id) const
6659 {
6660     const auto &foundBool = mStartingBuffersMappedInitial.find(id);
6661     ASSERT(foundBool != mStartingBuffersMappedInitial.end());
6662     return foundBool->second;
6663 }
6664 
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)6665 void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
6666 {
6667     mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
6668 }
6669 
isCapturing() const6670 bool FrameCaptureShared::isCapturing() const
6671 {
6672     // Currently we will always do a capture up until the last frame. In the future we could improve
6673     // mid execution capture by only capturing between the start and end frames. The only necessary
6674     // reason we need to capture before the start is for attached program and shader sources.
6675     return mEnabled && mFrameIndex <= mCaptureEndFrame;
6676 }
6677 
getFrameCount() const6678 uint32_t FrameCaptureShared::getFrameCount() const
6679 {
6680     return mCaptureEndFrame - mCaptureStartFrame + 1;
6681 }
6682 
getReplayFrameIndex() const6683 uint32_t FrameCaptureShared::getReplayFrameIndex() const
6684 {
6685     return mFrameIndex - mCaptureStartFrame + 1;
6686 }
6687 
replay(gl::Context * context)6688 void FrameCaptureShared::replay(gl::Context *context)
6689 {
6690     ReplayContext replayContext(mReadBufferSize, mClientArraySizes);
6691     for (const CallCapture &call : mFrameCalls)
6692     {
6693         INFO() << "frame index: " << mFrameIndex << " " << call.name();
6694 
6695         if (call.entryPoint == EntryPoint::GLInvalid)
6696         {
6697             if (call.customFunctionName == "UpdateClientArrayPointer")
6698             {
6699                 GLint arrayIndex =
6700                     call.params.getParam("arrayIndex", ParamType::TGLint, 0).value.GLintVal;
6701                 ASSERT(arrayIndex < gl::MAX_VERTEX_ATTRIBS);
6702 
6703                 const ParamCapture &pointerParam =
6704                     call.params.getParam("pointer", ParamType::TvoidConstPointer, 1);
6705                 ASSERT(pointerParam.data.size() == 1);
6706                 const void *pointer = pointerParam.data[0].data();
6707 
6708                 size_t size = static_cast<size_t>(
6709                     call.params.getParam("size", ParamType::TGLuint64, 2).value.GLuint64Val);
6710 
6711                 std::vector<uint8_t> &curClientArrayBuffer =
6712                     replayContext.getClientArraysBuffer()[arrayIndex];
6713                 ASSERT(curClientArrayBuffer.size() >= size);
6714                 memcpy(curClientArrayBuffer.data(), pointer, size);
6715             }
6716             continue;
6717         }
6718 
6719         ReplayCall(context, &replayContext, call);
6720     }
6721 }
6722 
6723 // Serialize trace metadata into a JSON file. The JSON file will be named "trace_prefix.json".
6724 //
6725 // As of writing, it will have the format like so:
6726 // {
6727 //     "TraceMetadata":
6728 //     {
6729 //         "AreClientArraysEnabled" : 1, "CaptureRevision" : 16631, "ConfigAlphaBits" : 8,
6730 //             "ConfigBlueBits" : 8, "ConfigDepthBits" : 24, "ConfigGreenBits" : 8,
6731 // ... etc ...
writeJSON(const gl::Context * context)6732 void FrameCaptureShared::writeJSON(const gl::Context *context)
6733 {
6734     const gl::ContextID contextId           = context->id();
6735     const SurfaceParams &surfaceParams      = mDrawSurfaceParams.at(contextId);
6736     const gl::State &glState                = context->getState();
6737     const egl::Config *config               = context->getConfig();
6738     const egl::AttributeMap &displayAttribs = context->getDisplay()->getAttributeMap();
6739 
6740     unsigned int frameCount = getFrameCount();
6741 
6742     JsonSerializer json;
6743     json.startGroup("TraceMetadata");
6744     json.addScalar("CaptureRevision", GetANGLERevision());
6745     json.addScalar("ContextClientMajorVersion", context->getClientMajorVersion());
6746     json.addScalar("ContextClientMinorVersion", context->getClientMinorVersion());
6747     json.addHexValue("DisplayPlatformType", displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE));
6748     json.addHexValue("DisplayDeviceType",
6749                      displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE));
6750     json.addScalar("FrameStart", 1);
6751     json.addScalar("FrameEnd", frameCount);
6752     json.addScalar("DrawSurfaceWidth", surfaceParams.extents.width);
6753     json.addScalar("DrawSurfaceHeight", surfaceParams.extents.height);
6754     json.addHexValue("DrawSurfaceColorSpace", ToEGLenum(surfaceParams.colorSpace));
6755     if (config)
6756     {
6757         json.addScalar("ConfigRedBits", config->redSize);
6758         json.addScalar("ConfigGreenBits", config->greenSize);
6759         json.addScalar("ConfigBlueBits", config->blueSize);
6760         json.addScalar("ConfigAlphaBits", config->alphaSize);
6761         json.addScalar("ConfigDepthBits", config->depthSize);
6762         json.addScalar("ConfigStencilBits", config->stencilSize);
6763     }
6764     else
6765     {
6766         json.addScalar("ConfigRedBits", EGL_DONT_CARE);
6767         json.addScalar("ConfigGreenBits", EGL_DONT_CARE);
6768         json.addScalar("ConfigBlueBits", EGL_DONT_CARE);
6769         json.addScalar("ConfigAlphaBits", EGL_DONT_CARE);
6770         json.addScalar("ConfigDepthBits", EGL_DONT_CARE);
6771         json.addScalar("ConfigStencilBits", EGL_DONT_CARE);
6772     }
6773     json.addBool("IsBinaryDataCompressed", mCompression);
6774     json.addBool("AreClientArraysEnabled", glState.areClientArraysEnabled());
6775     json.addBool("IsBindGeneratesResourcesEnabled", glState.isBindGeneratesResourceEnabled());
6776     json.addBool("IsWebGLCompatibilityEnabled", glState.isWebGL());
6777     json.addBool("IsRobustResourceInitEnabled", glState.isRobustResourceInitEnabled());
6778     json.addBool("IsTrimmingEnabled", mTrimEnabled);
6779     json.endGroup();
6780 
6781     {
6782         const std::vector<std::string> &traceFiles = mReplayWriter.getAndResetWrittenFiles();
6783         json.addVectorOfStrings("TraceFiles", traceFiles);
6784     }
6785 
6786     json.addScalar("WindowSurfaceContextID", contextId.value);
6787 
6788     {
6789         std::stringstream jsonFileNameStream;
6790         jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel)
6791                            << ".json";
6792         std::string jsonFileName = jsonFileNameStream.str();
6793 
6794         SaveFileHelper saveData(jsonFileName);
6795         saveData.write(reinterpret_cast<const uint8_t *>(json.data()), json.length());
6796     }
6797 }
6798 
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)6799 void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
6800                                                   bool writeResetContextCall)
6801 {
6802     // Ensure the last frame is written. This will no-op if the frame is already written.
6803     mReplayWriter.saveFrame();
6804 
6805     const gl::ContextID contextId = context->id();
6806 
6807     {
6808         std::stringstream header;
6809 
6810         header << "#pragma once\n";
6811         header << "\n";
6812         header << "#include <EGL/egl.h>\n";
6813         header << "#include <cstdint>\n";
6814 
6815         std::string includes = header.str();
6816         mReplayWriter.setHeaderPrologue(includes);
6817     }
6818 
6819     {
6820         std::stringstream source;
6821 
6822         source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
6823         source << "#include \"trace_fixture.h\"\n";
6824         source << "#include \"angle_trace_gl.h\"\n";
6825 
6826         std::string sourcePrologue = source.str();
6827         mReplayWriter.setSourcePrologue(sourcePrologue);
6828     }
6829 
6830     {
6831         std::string proto = "void InitReplay()";
6832 
6833         std::stringstream source;
6834         source << proto << "\n";
6835         source << "{\n";
6836         WriteInitReplayCall(mCompression, source, kSharedContextId, mCaptureLabel,
6837                             MaxClientArraySize(mClientArraySizes), mReadBufferSize,
6838                             mMaxAccessedResourceIDs);
6839         source << "}\n";
6840 
6841         mReplayWriter.addPrivateFunction(proto, std::stringstream(), source);
6842     }
6843 
6844     {
6845         std::string proto = "void ReplayFrame(uint32_t frameIndex)";
6846 
6847         std::stringstream source;
6848 
6849         source << proto << "\n";
6850         source << "{\n";
6851         source << "    switch (frameIndex)\n";
6852         source << "    {\n";
6853         for (uint32_t frameIndex : mActiveFrameIndices)
6854         {
6855             source << "        case " << frameIndex << ":\n";
6856             source << "            " << FmtReplayFunction(contextId, frameIndex) << ";\n";
6857             source << "            break;\n";
6858         }
6859         source << "        default:\n";
6860         source << "            break;\n";
6861         source << "    }\n";
6862         source << "}\n";
6863 
6864         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
6865     }
6866 
6867     if (writeResetContextCall)
6868     {
6869         std::string proto = "void ResetReplay()";
6870 
6871         std::stringstream source;
6872 
6873         source << proto << "\n";
6874         source << "{\n";
6875         source << "    // Reset context is empty because context is destroyed before end "
6876                   "frame is reached\n";
6877         source << "}\n";
6878 
6879         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
6880     }
6881 
6882     if (mSerializeStateEnabled)
6883     {
6884         std::string proto = "const char *GetSerializedContextState(uint32_t frameIndex)";
6885 
6886         std::stringstream source;
6887 
6888         source << proto << "\n";
6889         source << "{\n";
6890         source << "    switch (frameIndex)\n";
6891         source << "    {\n";
6892         for (uint32_t frameIndex = 1; frameIndex <= getFrameCount(); ++frameIndex)
6893         {
6894             source << "        case " << frameIndex << ":\n";
6895             source << "            return "
6896                    << FmtGetSerializedContextStateFunction(contextId, frameIndex) << ";\n";
6897         }
6898         source << "        default:\n";
6899         source << "            return nullptr;\n";
6900         source << "    }\n";
6901         source << "}\n";
6902 
6903         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
6904     }
6905 
6906     {
6907         std::stringstream fnameStream;
6908         fnameStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel);
6909         std::string fnamePattern = fnameStream.str();
6910 
6911         mReplayWriter.setFilenamePattern(fnamePattern);
6912     }
6913 
6914     mReplayWriter.saveIndexFilesAndHeader();
6915 
6916     writeJSON(context);
6917 }
6918 
writeMainContextCppReplay(const gl::Context * context,const std::vector<CallCapture> & setupCalls)6919 void FrameCaptureShared::writeMainContextCppReplay(const gl::Context *context,
6920                                                    const std::vector<CallCapture> &setupCalls)
6921 {
6922     ASSERT(mWindowSurfaceContextID == context->id());
6923 
6924     {
6925         std::stringstream header;
6926 
6927         header << "#include \"" << FmtCapturePrefix(context->id(), mCaptureLabel) << ".h\"\n";
6928         header << "#include \"angle_trace_gl.h\"\n";
6929 
6930         std::string headerString = header.str();
6931         mReplayWriter.setSourcePrologue(headerString);
6932     }
6933 
6934     uint32_t frameCount = getFrameCount();
6935     uint32_t frameIndex = getReplayFrameIndex();
6936 
6937     if (frameIndex == 1)
6938     {
6939         {
6940             std::stringstream protoStream;
6941             std::stringstream headerStream;
6942             std::stringstream bodyStream;
6943 
6944             protoStream << "void " << FmtSetupFunction(kNoPartId, context->id());
6945             std::string proto = protoStream.str();
6946 
6947             WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, mReplayWriter,
6948                                             frameIndex, &mBinaryData, setupCalls, headerStream,
6949                                             bodyStream);
6950 
6951             mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
6952         }
6953 
6954         {
6955             std::string proto = "void SetupReplay()";
6956 
6957             std::stringstream out;
6958 
6959             out << proto << "\n";
6960             out << "{\n";
6961             out << "    EGLContext context = eglGetCurrentContext();\n";
6962             out << "    gContextMap[" << context->id().value << "] = context;\n";
6963             out << "\n";
6964 
6965             // Setup all of the shared objects.
6966             out << "    InitReplay();\n";
6967             if (usesMidExecutionCapture())
6968             {
6969                 out << "    " << FmtSetupFunction(kNoPartId, kSharedContextId) << ";\n";
6970             }
6971 
6972             // Setup the presentation (this) context first.
6973             out << "    " << FmtSetupFunction(kNoPartId, context->id()) << ";\n";
6974             out << "\n";
6975 
6976             // Setup each of the auxiliary contexts.
6977             egl::ShareGroup *shareGroup            = context->getShareGroup();
6978             const egl::ContextSet &shareContextSet = shareGroup->getContexts();
6979             for (gl::Context *shareContext : shareContextSet)
6980             {
6981                 // Skip the presentation context, since that context was created by the test
6982                 // framework.
6983                 if (shareContext->id() == context->id())
6984                 {
6985                     continue;
6986                 }
6987 
6988                 // TODO(http://www.anglebug.com/5878): Support capture/replay of eglCreateContext()
6989                 // so this block can be moved into SetupReplayContextXX() by injecting them into the
6990                 // beginning of the setup call stream.
6991                 out << "    EGLContext context" << shareContext->id()
6992                     << " = eglCreateContext(nullptr, nullptr, context, nullptr);\n";
6993                 out << "    gContextMap[" << shareContext->id().value << "] = context"
6994                     << shareContext->id() << ";\n";
6995                 // The SetupReplayContextXX() calls only exist if this is a mid-execution capture
6996                 // and we can only call them if they exist, so only output the calls if this is a
6997                 // MEC.
6998                 if (usesMidExecutionCapture())
6999                 {
7000                     out << "    " << FmtSetupFunction(kNoPartId, shareContext->id()) << ";\n";
7001                 }
7002             }
7003 
7004             // If there are other contexts that were initialized, we need to make the main context
7005             // current again.
7006             if (shareContextSet.size() > 1)
7007             {
7008                 out << "\n";
7009                 out << "    eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, "
7010                        "context);\n";
7011             }
7012 
7013             out << "}\n";
7014 
7015             mReplayWriter.addPublicFunction(proto, std::stringstream(), out);
7016         }
7017     }
7018 
7019     // Emit code to reset back to starting state
7020     if (frameIndex == frameCount)
7021     {
7022         std::stringstream protoStream;
7023         std::stringstream headerStream;
7024         std::stringstream bodyStream;
7025 
7026         protoStream << "void " << FmtResetFunction();
7027         std::string proto = protoStream.str();
7028 
7029         bodyStream << proto << "\n";
7030         bodyStream << "{\n";
7031 
7032         // TODO(http://anglebug.com/5878): Look at moving this into the shared context file since
7033         // it's resetting shared objects.
7034         for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
7035         {
7036             // Framebuffers must be done last so updated textures can be bound to them
7037             if (resourceType == ResourceIDType::Framebuffer)
7038             {
7039                 continue;
7040             }
7041 
7042             MaybeResetResources(resourceType, mReplayWriter, bodyStream, headerStream,
7043                                 &mResourceTracker, &mBinaryData);
7044         }
7045 
7046         MaybeResetResources(ResourceIDType::Framebuffer, mReplayWriter, bodyStream, headerStream,
7047                             &mResourceTracker, &mBinaryData);
7048 
7049         // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
7050         MaybeResetOpaqueTypeObjects(mReplayWriter, bodyStream, headerStream, &mResourceTracker,
7051                                     &mBinaryData);
7052 
7053         bodyStream << "}\n";
7054 
7055         mReplayWriter.addPublicFunction(proto, headerStream, bodyStream);
7056     }
7057 
7058     if (!mFrameCalls.empty())
7059     {
7060         std::stringstream protoStream;
7061         protoStream << "void " << FmtReplayFunction(context->id(), frameIndex);
7062         std::string proto = protoStream.str();
7063 
7064         std::stringstream headerStream;
7065         std::stringstream bodyStream;
7066 
7067         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, mReplayWriter,
7068                                         frameIndex, &mBinaryData, mFrameCalls, headerStream,
7069                                         bodyStream);
7070 
7071         mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
7072     }
7073 
7074     if (mSerializeStateEnabled)
7075     {
7076         std::string serializedContextString;
7077         if (SerializeContextToString(const_cast<gl::Context *>(context),
7078                                      &serializedContextString) == Result::Continue)
7079         {
7080             std::stringstream protoStream;
7081             protoStream << "const char *"
7082                         << FmtGetSerializedContextStateFunction(context->id(), frameIndex);
7083             std::string proto = protoStream.str();
7084 
7085             std::stringstream bodyStream;
7086             bodyStream << proto << "\n";
7087             bodyStream << "{\n";
7088             bodyStream << "    return R\"(" << serializedContextString << ")\";\n";
7089             bodyStream << "}\n";
7090 
7091             mReplayWriter.addPrivateFunction(proto, std::stringstream(), bodyStream);
7092         }
7093     }
7094 
7095     {
7096         std::stringstream fnamePatternStream;
7097         fnamePatternStream << mOutDirectory << FmtCapturePrefix(context->id(), mCaptureLabel);
7098         std::string fnamePattern = fnamePatternStream.str();
7099 
7100         mReplayWriter.setFilenamePattern(fnamePattern);
7101     }
7102 
7103     if (mFrameIndex == mCaptureEndFrame)
7104     {
7105         mReplayWriter.saveFrame();
7106     }
7107     else
7108     {
7109         mReplayWriter.saveFrameIfFull();
7110     }
7111 }
7112 
reset()7113 void FrameCaptureShared::reset()
7114 {
7115     mFrameCalls.clear();
7116     mClientVertexArrayMap.fill(-1);
7117 
7118     // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
7119     // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
7120     // necessary.
7121 }
7122 
getShaderSource(gl::ShaderProgramID id) const7123 const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
7124 {
7125     const auto &foundSources = mCachedShaderSource.find(id);
7126     ASSERT(foundSources != mCachedShaderSource.end());
7127     return foundSources->second;
7128 }
7129 
setShaderSource(gl::ShaderProgramID id,std::string source)7130 void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
7131 {
7132     mCachedShaderSource[id] = source;
7133 }
7134 
getProgramSources(gl::ShaderProgramID id) const7135 const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
7136 {
7137     const auto &foundSources = mCachedProgramSources.find(id);
7138     ASSERT(foundSources != mCachedProgramSources.end());
7139     return foundSources->second;
7140 }
7141 
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)7142 void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
7143 {
7144     mCachedProgramSources[id] = sources;
7145 }
7146 
markResourceSetupCallsInactive(std::vector<CallCapture> * setupCalls,ResourceIDType type,GLuint id,gl::Range<size_t> range)7147 void FrameCaptureShared::markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
7148                                                         ResourceIDType type,
7149                                                         GLuint id,
7150                                                         gl::Range<size_t> range)
7151 {
7152     if (!mTrimEnabled)
7153     {
7154         return;
7155     }
7156 
7157     ASSERT(mResourceIDToSetupCalls[type].find(id) == mResourceIDToSetupCalls[type].end());
7158 
7159     // Mark all of the calls that were used to initialize this resource as INACTIVE
7160     for (size_t index : range)
7161     {
7162         (*setupCalls)[index].isActive = false;
7163     }
7164 
7165     mResourceIDToSetupCalls[type][id] = range;
7166 }
7167 
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)7168 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
7169 {
7170     std::vector<uint8_t> data(size);
7171     memcpy(data.data(), source, size);
7172     paramCapture->data.emplace_back(std::move(data));
7173 }
7174 
CaptureString(const GLchar * str,ParamCapture * paramCapture)7175 void CaptureString(const GLchar *str, ParamCapture *paramCapture)
7176 {
7177     // include the '\0' suffix
7178     CaptureMemory(str, strlen(str) + 1, paramCapture);
7179 }
7180 
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)7181 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
7182 {
7183     // Write the incoming string up to limit, including null terminator
7184     size_t length = strlen(str) + 1;
7185 
7186     if (length > limit)
7187     {
7188         // If too many characters, resize the string to fit in the limit
7189         std::string newStr = str;
7190         newStr.resize(limit - 1);
7191         CaptureString(newStr.c_str(), paramCapture);
7192     }
7193     else
7194     {
7195         CaptureMemory(str, length, paramCapture);
7196     }
7197 }
7198 
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)7199 void CaptureVertexPointerGLES1(const gl::State &glState,
7200                                gl::ClientVertexArrayType type,
7201                                const void *pointer,
7202                                ParamCapture *paramCapture)
7203 {
7204     paramCapture->value.voidConstPointerVal = pointer;
7205     if (!glState.getTargetBuffer(gl::BufferBinding::Array))
7206     {
7207         paramCapture->arrayClientPointerIndex =
7208             gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
7209     }
7210 }
7211 
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)7212 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
7213 {
7214     gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
7215     return program;
7216 }
7217 
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)7218 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
7219                                               gl::ShaderProgramID handle,
7220                                               gl::UniformBlockIndex uniformBlockIndex,
7221                                               GLenum pname,
7222                                               ParamCapture *paramCapture)
7223 {
7224     int numParams = 1;
7225 
7226     // From the OpenGL ES 3.0 spec:
7227     // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
7228     // active uniform indices for the uniform block identified by uniformBlockIndex is
7229     // returned. The number of elements that will be written to params is the value of
7230     // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
7231     if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
7232     {
7233         gl::Program *program = GetProgramForCapture(glState, handle);
7234         if (program)
7235         {
7236             gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
7237                                           GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
7238         }
7239     }
7240 
7241     paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
7242 }
7243 
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)7244 void CaptureGetParameter(const gl::State &glState,
7245                          GLenum pname,
7246                          size_t typeSize,
7247                          ParamCapture *paramCapture)
7248 {
7249     // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
7250     // This value needs to be updated if any new extensions are introduced that would allow for
7251     // more compressed texture formats. The current value is taken from:
7252     // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
7253     constexpr unsigned int kMaxReportedCapabilities = 69;
7254     paramCapture->readBufferSizeBytes               = typeSize * kMaxReportedCapabilities;
7255 }
7256 
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)7257 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
7258 {
7259     paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
7260     CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
7261 }
7262 
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)7263 void CaptureShaderStrings(GLsizei count,
7264                           const GLchar *const *strings,
7265                           const GLint *length,
7266                           ParamCapture *paramCapture)
7267 {
7268     // Concat the array elements of the string into one data vector,
7269     // append the terminating zero and use this as the captured shader
7270     // string. The string count and the length array are adjusted
7271     // accordingly in the capture post-processing
7272 
7273     std::vector<uint8_t> data;
7274     size_t offset = 0;
7275     for (GLsizei index = 0; index < count; ++index)
7276     {
7277         size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
7278         data.resize(offset + len);
7279         std::copy(strings[index], strings[index] + len, data.begin() + offset);
7280         offset += len;
7281     }
7282     data.push_back(0);
7283     paramCapture->data.emplace_back(std::move(data));
7284 }
7285 
7286 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)7287 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
7288                                                   const CallCapture &call,
7289                                                   GLboolean value)
7290 {
7291     switch (value)
7292     {
7293         case GL_TRUE:
7294             os << "GL_TRUE";
7295             break;
7296         case GL_FALSE:
7297             os << "GL_FALSE";
7298             break;
7299         default:
7300             os << "0x" << std::hex << std::uppercase << GLint(value);
7301     }
7302 }
7303 
7304 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean * value)7305 void WriteParamValueReplay<ParamType::TGLbooleanPointer>(std::ostream &os,
7306                                                          const CallCapture &call,
7307                                                          GLboolean *value)
7308 {
7309     if (value == 0)
7310     {
7311         os << "nullptr";
7312     }
7313     else
7314     {
7315         os << "reinterpret_cast<GLboolean *>("
7316            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
7317     }
7318 }
7319 
7320 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)7321 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
7322                                                          const CallCapture &call,
7323                                                          const void *value)
7324 {
7325     if (value == 0)
7326     {
7327         os << "nullptr";
7328     }
7329     else
7330     {
7331         os << "reinterpret_cast<const void *>("
7332            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
7333     }
7334 }
7335 
7336 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,void * value)7337 void WriteParamValueReplay<ParamType::TvoidPointer>(std::ostream &os,
7338                                                     const CallCapture &call,
7339                                                     void *value)
7340 {
7341     if (value == 0)
7342     {
7343         os << "nullptr";
7344     }
7345     else
7346     {
7347         os << "reinterpret_cast<void *>(" << static_cast<int>(reinterpret_cast<uintptr_t>(value))
7348            << ")";
7349     }
7350 }
7351 
7352 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLfloat * value)7353 void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
7354                                                             const CallCapture &call,
7355                                                             const GLfloat *value)
7356 {
7357     if (value == 0)
7358     {
7359         os << "nullptr";
7360     }
7361     else
7362     {
7363         os << "reinterpret_cast<const GLfloat *>("
7364            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
7365     }
7366 }
7367 
7368 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLint * value)7369 void WriteParamValueReplay<ParamType::TGLintConstPointer>(std::ostream &os,
7370                                                           const CallCapture &call,
7371                                                           const GLint *value)
7372 {
7373     if (value == 0)
7374     {
7375         os << "nullptr";
7376     }
7377     else
7378     {
7379         os << "reinterpret_cast<const GLint *>("
7380            << static_cast<int>(reinterpret_cast<intptr_t>(value)) << ")";
7381     }
7382 }
7383 
7384 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsizei * value)7385 void WriteParamValueReplay<ParamType::TGLsizeiPointer>(std::ostream &os,
7386                                                        const CallCapture &call,
7387                                                        GLsizei *value)
7388 {
7389     if (value == 0)
7390     {
7391         os << "nullptr";
7392     }
7393     else
7394     {
7395         os << "reinterpret_cast<GLsizei *>(" << static_cast<int>(reinterpret_cast<intptr_t>(value))
7396            << ")";
7397     }
7398 }
7399 
7400 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLuint * value)7401 void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
7402                                                            const CallCapture &call,
7403                                                            const GLuint *value)
7404 {
7405     if (value == 0)
7406     {
7407         os << "nullptr";
7408     }
7409     else
7410     {
7411         os << "reinterpret_cast<const GLuint *>("
7412            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
7413     }
7414 }
7415 
7416 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)7417 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
7418                                                        const CallCapture &call,
7419                                                        GLDEBUGPROCKHR value)
7420 {}
7421 
7422 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)7423 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
7424                                                     const CallCapture &call,
7425                                                     GLDEBUGPROC value)
7426 {}
7427 
7428 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)7429 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
7430                                                  const CallCapture &call,
7431                                                  gl::BufferID value)
7432 {
7433     os << "gBufferMap[" << value.value << "]";
7434 }
7435 
7436 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)7437 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
7438                                                   const CallCapture &call,
7439                                                   gl::FenceNVID value)
7440 {
7441     os << "gFenceNVMap[" << value.value << "]";
7442 }
7443 
7444 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)7445 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
7446                                                       const CallCapture &call,
7447                                                       gl::FramebufferID value)
7448 {
7449     os << "gFramebufferMap[" << value.value << "]";
7450 }
7451 
7452 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)7453 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
7454                                                        const CallCapture &call,
7455                                                        gl::MemoryObjectID value)
7456 {
7457     os << "gMemoryObjectMap[" << value.value << "]";
7458 }
7459 
7460 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)7461 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
7462                                                           const CallCapture &call,
7463                                                           gl::ProgramPipelineID value)
7464 {
7465     os << "gProgramPipelineMap[" << value.value << "]";
7466 }
7467 
7468 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)7469 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
7470                                                 const CallCapture &call,
7471                                                 gl::QueryID value)
7472 {
7473     os << "gQueryMap[" << value.value << "]";
7474 }
7475 
7476 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)7477 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
7478                                                        const CallCapture &call,
7479                                                        gl::RenderbufferID value)
7480 {
7481     os << "gRenderbufferMap[" << value.value << "]";
7482 }
7483 
7484 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)7485 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
7486                                                   const CallCapture &call,
7487                                                   gl::SamplerID value)
7488 {
7489     os << "gSamplerMap[" << value.value << "]";
7490 }
7491 
7492 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)7493 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
7494                                                     const CallCapture &call,
7495                                                     gl::SemaphoreID value)
7496 {
7497     os << "gSemaphoreMap[" << value.value << "]";
7498 }
7499 
7500 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)7501 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
7502                                                         const CallCapture &call,
7503                                                         gl::ShaderProgramID value)
7504 {
7505     os << "gShaderProgramMap[" << value.value << "]";
7506 }
7507 
7508 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsync value)7509 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
7510                                                const CallCapture &call,
7511                                                GLsync value)
7512 {
7513     os << "gSyncMap[" << SyncIndexValue(value) << "]";
7514 }
7515 
7516 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)7517 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
7518                                                   const CallCapture &call,
7519                                                   gl::TextureID value)
7520 {
7521     os << "gTextureMap[" << value.value << "]";
7522 }
7523 
7524 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)7525 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
7526                                                             const CallCapture &call,
7527                                                             gl::TransformFeedbackID value)
7528 {
7529     os << "gTransformFeedbackMap[" << value.value << "]";
7530 }
7531 
7532 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)7533 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
7534                                                       const CallCapture &call,
7535                                                       gl::VertexArrayID value)
7536 {
7537     os << "gVertexArrayMap[" << value.value << "]";
7538 }
7539 
7540 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)7541 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
7542                                                         const CallCapture &call,
7543                                                         gl::UniformLocation value)
7544 {
7545     if (value.value == -1)
7546     {
7547         os << "-1";
7548         return;
7549     }
7550 
7551     os << "gUniformLocations[";
7552 
7553     // Find the program from the call parameters.
7554     std::vector<gl::ShaderProgramID> programIDs;
7555     if (FindShaderProgramIDsInCall(call, programIDs))
7556     {
7557         ASSERT(programIDs.size() == 1);
7558         os << "gShaderProgramMap[" << programIDs[0].value << "]";
7559     }
7560     else
7561     {
7562         os << "gCurrentProgram";
7563     }
7564 
7565     os << "][" << value.value << "]";
7566 }
7567 
7568 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformBlockIndex value)7569 void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
7570                                                           const CallCapture &call,
7571                                                           gl::UniformBlockIndex value)
7572 {
7573     // Find the program from the call parameters.
7574     std::vector<gl::ShaderProgramID> programIDs;
7575     bool foundProgram = FindShaderProgramIDsInCall(call, programIDs);
7576     ASSERT(foundProgram && programIDs.size() == 1);
7577 
7578     os << "gUniformBlockIndexes[gShaderProgramMap[" << programIDs[0].value << "]][" << value.value
7579        << "]";
7580 }
7581 
7582 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLeglImageOES value)7583 void WriteParamValueReplay<ParamType::TGLeglImageOES>(std::ostream &os,
7584                                                       const CallCapture &call,
7585                                                       GLeglImageOES value)
7586 {
7587     uint64_t pointerValue = reinterpret_cast<uint64_t>(value);
7588     os << "reinterpret_cast<EGLImageKHR>(" << pointerValue << "ul)";
7589 }
7590 
7591 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLubyte value)7592 void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
7593                                                 const CallCapture &call,
7594                                                 GLubyte value)
7595 {
7596     const int v = value;
7597     os << v;
7598 }
7599 
7600 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLContext value)7601 void WriteParamValueReplay<ParamType::TEGLContext>(std::ostream &os,
7602                                                    const CallCapture &call,
7603                                                    EGLContext value)
7604 {
7605     os << "gContextMap[" << reinterpret_cast<size_t>(value) << "]";
7606 }
7607 
7608 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLDisplay value)7609 void WriteParamValueReplay<ParamType::TEGLDisplay>(std::ostream &os,
7610                                                    const CallCapture &call,
7611                                                    EGLDisplay value)
7612 {
7613     if (value == EGL_NO_DISPLAY)
7614     {
7615         os << "EGL_NO_DISPLAY";
7616         return;
7617     }
7618 
7619     // We don't support capturing real EGL calls.
7620     UNREACHABLE();
7621 }
7622 
7623 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLSurface value)7624 void WriteParamValueReplay<ParamType::TEGLSurface>(std::ostream &os,
7625                                                    const CallCapture &call,
7626                                                    EGLSurface value)
7627 {
7628     if (value == EGL_NO_SURFACE)
7629     {
7630         os << "EGL_NO_SURFACE";
7631         return;
7632     }
7633 
7634     // We don't support capturing real EGL calls.
7635     UNREACHABLE();
7636 }
7637 
7638 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLDEBUGPROCKHR value)7639 void WriteParamValueReplay<ParamType::TEGLDEBUGPROCKHR>(std::ostream &os,
7640                                                         const CallCapture &call,
7641                                                         EGLDEBUGPROCKHR value)
7642 {
7643     // The value isn't actually useful, but this fixes MSVC compile errors:
7644     // error: implicit conversion between pointer-to-function and pointer-to-object is a Microsoft
7645     // extension [-Werror,-Wmicrosoft-cast]
7646     os << reinterpret_cast<void *>(value);
7647 }
7648 
7649 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLGetBlobFuncANDROID value)7650 void WriteParamValueReplay<ParamType::TEGLGetBlobFuncANDROID>(std::ostream &os,
7651                                                               const CallCapture &call,
7652                                                               EGLGetBlobFuncANDROID value)
7653 {
7654     // The value isn't actually useful, but this fixes MSVC compile errors:
7655     // error: implicit conversion between pointer-to-function and pointer-to-object is a Microsoft
7656     // extension [-Werror,-Wmicrosoft-cast]
7657     os << reinterpret_cast<void *>(value);
7658 }
7659 
7660 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,EGLSetBlobFuncANDROID value)7661 void WriteParamValueReplay<ParamType::TEGLSetBlobFuncANDROID>(std::ostream &os,
7662                                                               const CallCapture &call,
7663                                                               EGLSetBlobFuncANDROID value)
7664 {
7665     // The value isn't actually useful, but this fixes MSVC compile errors:
7666     // error: implicit conversion between pointer-to-function and pointer-to-object is a Microsoft
7667     // extension [-Werror,-Wmicrosoft-cast]
7668     os << reinterpret_cast<void *>(value);
7669 }
7670 
7671 // ReplayWriter implementation.
ReplayWriter()7672 ReplayWriter::ReplayWriter()
7673     : mSourceFileSizeThreshold(kDefaultSourceFileSizeThreshold), mFrameIndex(1)
7674 {}
7675 
~ReplayWriter()7676 ReplayWriter::~ReplayWriter()
7677 {
7678     ASSERT(mPrivateFunctionPrototypes.empty());
7679     ASSERT(mPublicFunctionPrototypes.empty());
7680     ASSERT(mPrivateFunctions.empty());
7681     ASSERT(mPublicFunctions.empty());
7682     ASSERT(mGlobalVariableDeclarations.empty());
7683     ASSERT(mReplayHeaders.empty());
7684 }
7685 
setSourceFileSizeThreshold(size_t sourceFileSizeThreshold)7686 void ReplayWriter::setSourceFileSizeThreshold(size_t sourceFileSizeThreshold)
7687 {
7688     mSourceFileSizeThreshold = sourceFileSizeThreshold;
7689 }
7690 
setFilenamePattern(const std::string & pattern)7691 void ReplayWriter::setFilenamePattern(const std::string &pattern)
7692 {
7693     if (mFilenamePattern != pattern)
7694     {
7695         mFilenamePattern = pattern;
7696 
7697         // Reset the frame counter if the filename pattern changes.
7698         mFrameIndex = 1;
7699     }
7700 }
7701 
setCaptureLabel(const std::string & label)7702 void ReplayWriter::setCaptureLabel(const std::string &label)
7703 {
7704     mCaptureLabel = label;
7705 }
7706 
setSourcePrologue(const std::string & prologue)7707 void ReplayWriter::setSourcePrologue(const std::string &prologue)
7708 {
7709     mSourcePrologue = prologue;
7710 }
7711 
setHeaderPrologue(const std::string & prologue)7712 void ReplayWriter::setHeaderPrologue(const std::string &prologue)
7713 {
7714     mHeaderPrologue = prologue;
7715 }
7716 
addPublicFunction(const std::string & functionProto,const std::stringstream & headerStream,const std::stringstream & bodyStream)7717 void ReplayWriter::addPublicFunction(const std::string &functionProto,
7718                                      const std::stringstream &headerStream,
7719                                      const std::stringstream &bodyStream)
7720 {
7721     mPublicFunctionPrototypes.push_back(functionProto);
7722 
7723     std::string header = headerStream.str();
7724     std::string body   = bodyStream.str();
7725 
7726     if (!header.empty())
7727     {
7728         mReplayHeaders.emplace_back(header);
7729     }
7730 
7731     if (!body.empty())
7732     {
7733         mPublicFunctions.emplace_back(body);
7734     }
7735 }
7736 
addPrivateFunction(const std::string & functionProto,const std::stringstream & headerStream,const std::stringstream & bodyStream)7737 void ReplayWriter::addPrivateFunction(const std::string &functionProto,
7738                                       const std::stringstream &headerStream,
7739                                       const std::stringstream &bodyStream)
7740 {
7741     mPrivateFunctionPrototypes.push_back(functionProto);
7742 
7743     std::string header = headerStream.str();
7744     std::string body   = bodyStream.str();
7745 
7746     if (!header.empty())
7747     {
7748         mReplayHeaders.emplace_back(header);
7749     }
7750 
7751     if (!body.empty())
7752     {
7753         mPrivateFunctions.emplace_back(body);
7754     }
7755 }
7756 
getInlineVariableName(EntryPoint entryPoint,const std::string & paramName)7757 std::string ReplayWriter::getInlineVariableName(EntryPoint entryPoint, const std::string &paramName)
7758 {
7759     int counter = mDataTracker.getCounters().getAndIncrement(entryPoint, paramName);
7760     return GetVarName(entryPoint, paramName, counter);
7761 }
7762 
getInlineStringSetVariableName(EntryPoint entryPoint,const std::string & paramName,const std::vector<std::string> & strings,bool * isNewEntryOut)7763 std::string ReplayWriter::getInlineStringSetVariableName(EntryPoint entryPoint,
7764                                                          const std::string &paramName,
7765                                                          const std::vector<std::string> &strings,
7766                                                          bool *isNewEntryOut)
7767 {
7768     int counter    = mDataTracker.getStringCounters().getStringCounter(strings);
7769     *isNewEntryOut = (counter == kStringsNotFound);
7770     if (*isNewEntryOut)
7771     {
7772         // This is a unique set of strings, so set up their declaration and update the counter
7773         counter = mDataTracker.getCounters().getAndIncrement(entryPoint, paramName);
7774         mDataTracker.getStringCounters().setStringCounter(strings, counter);
7775 
7776         std::string varName = GetVarName(entryPoint, paramName, counter);
7777 
7778         std::stringstream declStream;
7779         declStream << "const char *const " << varName << "[]";
7780         std::string decl = declStream.str();
7781 
7782         mGlobalVariableDeclarations.push_back(decl);
7783 
7784         return varName;
7785     }
7786     else
7787     {
7788         return GetVarName(entryPoint, paramName, counter);
7789     }
7790 }
7791 
getStoredReplaySourceSize() const7792 size_t ReplayWriter::getStoredReplaySourceSize() const
7793 {
7794     size_t sum = 0;
7795     for (const std::string &header : mReplayHeaders)
7796     {
7797         sum += header.size();
7798     }
7799     for (const std::string &publicFunc : mPublicFunctions)
7800     {
7801         sum += publicFunc.size();
7802     }
7803     for (const std::string &privateFunc : mPrivateFunctions)
7804     {
7805         sum += privateFunc.size();
7806     }
7807     return sum;
7808 }
7809 
7810 // static
GetVarName(EntryPoint entryPoint,const std::string & paramName,int counter)7811 std::string ReplayWriter::GetVarName(EntryPoint entryPoint,
7812                                      const std::string &paramName,
7813                                      int counter)
7814 {
7815     std::stringstream strstr;
7816     strstr << GetEntryPointName(entryPoint) << "_" << paramName << "_" << counter;
7817     return strstr.str();
7818 }
7819 
saveFrame()7820 void ReplayWriter::saveFrame()
7821 {
7822     if (mReplayHeaders.empty() && mPublicFunctions.empty() && mPrivateFunctions.empty())
7823     {
7824         return;
7825     }
7826 
7827     std::stringstream strstr;
7828     strstr << mFilenamePattern << "_" << std::setfill('0') << std::setw(3) << mFrameIndex++
7829            << ".cpp";
7830 
7831     std::string frameFilePath = strstr.str();
7832 
7833     writeReplaySource(frameFilePath);
7834 }
7835 
saveFrameIfFull()7836 void ReplayWriter::saveFrameIfFull()
7837 {
7838     if (getStoredReplaySourceSize() < mSourceFileSizeThreshold)
7839     {
7840         INFO() << "Merging captured frame: " << getStoredReplaySourceSize()
7841                << " less than threshold of " << mSourceFileSizeThreshold << " bytes";
7842         return;
7843     }
7844 
7845     saveFrame();
7846 }
7847 
saveHeader()7848 void ReplayWriter::saveHeader()
7849 {
7850     std::stringstream headerPathStream;
7851     headerPathStream << mFilenamePattern << ".h";
7852     std::string headerPath = headerPathStream.str();
7853 
7854     SaveFileHelper saveH(headerPath);
7855 
7856     saveH << mHeaderPrologue << "\n";
7857 
7858     saveH << "// Public functions are declared in trace_fixture.h.\n";
7859     saveH << "\n";
7860     saveH << "// Private Functions\n";
7861     saveH << "\n";
7862 
7863     for (const std::string &proto : mPrivateFunctionPrototypes)
7864     {
7865         saveH << proto << ";\n";
7866     }
7867 
7868     saveH << "\n";
7869     saveH << "// Global variables\n";
7870     saveH << "\n";
7871 
7872     for (const std::string &globalVar : mGlobalVariableDeclarations)
7873     {
7874         saveH << "extern " << globalVar << ";\n";
7875     }
7876 
7877     mPublicFunctionPrototypes.clear();
7878     mPrivateFunctionPrototypes.clear();
7879     mGlobalVariableDeclarations.clear();
7880 
7881     addWrittenFile(headerPath);
7882 }
7883 
saveIndexFilesAndHeader()7884 void ReplayWriter::saveIndexFilesAndHeader()
7885 {
7886     std::stringstream sourcePathStream;
7887     sourcePathStream << mFilenamePattern << ".cpp";
7888     std::string sourcePath = sourcePathStream.str();
7889 
7890     writeReplaySource(sourcePath);
7891     saveHeader();
7892 }
7893 
saveSetupFile()7894 void ReplayWriter::saveSetupFile()
7895 {
7896     std::stringstream strstr;
7897     strstr << mFilenamePattern << ".cpp";
7898 
7899     std::string frameFilePath = strstr.str();
7900 
7901     writeReplaySource(frameFilePath);
7902 }
7903 
writeReplaySource(const std::string & filename)7904 void ReplayWriter::writeReplaySource(const std::string &filename)
7905 {
7906     SaveFileHelper saveCpp(filename);
7907 
7908     saveCpp << mSourcePrologue << "\n";
7909 
7910     for (const std::string &header : mReplayHeaders)
7911     {
7912         saveCpp << header << "\n";
7913     }
7914 
7915     saveCpp << "// Private Functions\n";
7916     saveCpp << "\n";
7917 
7918     for (const std::string &func : mPrivateFunctions)
7919     {
7920         saveCpp << func << "\n";
7921     }
7922 
7923     saveCpp << "// Public Functions\n";
7924     saveCpp << "\n";
7925     saveCpp << "extern \"C\"\n";
7926     saveCpp << "{\n";
7927 
7928     for (const std::string &func : mPublicFunctions)
7929     {
7930         saveCpp << func << "\n";
7931     }
7932 
7933     saveCpp << "}  // extern \"C\"\n";
7934 
7935     mReplayHeaders.clear();
7936     mPrivateFunctions.clear();
7937     mPublicFunctions.clear();
7938 
7939     addWrittenFile(filename);
7940 }
7941 
addWrittenFile(const std::string & filename)7942 void ReplayWriter::addWrittenFile(const std::string &filename)
7943 {
7944     std::string writtenFile = GetBaseName(filename);
7945     ASSERT(std::find(mWrittenFiles.begin(), mWrittenFiles.end(), writtenFile) ==
7946            mWrittenFiles.end());
7947     mWrittenFiles.push_back(writtenFile);
7948 }
7949 
getAndResetWrittenFiles()7950 std::vector<std::string> ReplayWriter::getAndResetWrittenFiles()
7951 {
7952     std::vector<std::string> results = std::move(mWrittenFiles);
7953     std::sort(results.begin(), results.end());
7954     ASSERT(mWrittenFiles.empty());
7955     return results;
7956 }
7957 }  // namespace angle
7958