• 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/aligned_memory.h"
20 #include "common/angle_version_info.h"
21 #include "common/frame_capture_utils.h"
22 #include "common/gl_enum_utils.h"
23 #include "common/mathutil.h"
24 #include "common/serializer/JsonSerializer.h"
25 #include "common/string_utils.h"
26 #include "common/system_utils.h"
27 #include "gpu_info_util/SystemInfo.h"
28 #include "image_util/storeimage.h"
29 #include "libANGLE/Config.h"
30 #include "libANGLE/Context.h"
31 #include "libANGLE/Context.inl.h"
32 #include "libANGLE/Display.h"
33 #include "libANGLE/EGLSync.h"
34 #include "libANGLE/Fence.h"
35 #include "libANGLE/Framebuffer.h"
36 #include "libANGLE/GLES1Renderer.h"
37 #include "libANGLE/Query.h"
38 #include "libANGLE/ResourceMap.h"
39 #include "libANGLE/Shader.h"
40 #include "libANGLE/Surface.h"
41 #include "libANGLE/VertexArray.h"
42 #include "libANGLE/capture/capture_egl_autogen.h"
43 #include "libANGLE/capture/capture_gles_1_0_autogen.h"
44 #include "libANGLE/capture/capture_gles_2_0_autogen.h"
45 #include "libANGLE/capture/capture_gles_3_0_autogen.h"
46 #include "libANGLE/capture/capture_gles_3_1_autogen.h"
47 #include "libANGLE/capture/capture_gles_3_2_autogen.h"
48 #include "libANGLE/capture/capture_gles_ext_autogen.h"
49 #include "libANGLE/capture/serialize.h"
50 #include "libANGLE/entry_points_utils.h"
51 #include "libANGLE/queryconversions.h"
52 #include "libANGLE/queryutils.h"
53 #include "libANGLE/validationEGL.h"
54 #include "third_party/ceval/ceval.h"
55 
56 #define USE_SYSTEM_ZLIB
57 #include "compression_utils_portable.h"
58 
59 #if !ANGLE_CAPTURE_ENABLED
60 #    error Frame capture must be enabled to include this file.
61 #endif  // !ANGLE_CAPTURE_ENABLED
62 
63 namespace angle
64 {
65 namespace
66 {
67 
68 // TODO: Consolidate to C output and remove option. http://anglebug.com/7753
69 
70 constexpr char kEnabledVarName[]        = "ANGLE_CAPTURE_ENABLED";
71 constexpr char kOutDirectoryVarName[]   = "ANGLE_CAPTURE_OUT_DIR";
72 constexpr char kFrameStartVarName[]     = "ANGLE_CAPTURE_FRAME_START";
73 constexpr char kFrameEndVarName[]       = "ANGLE_CAPTURE_FRAME_END";
74 constexpr char kTriggerVarName[]        = "ANGLE_CAPTURE_TRIGGER";
75 constexpr char kCaptureLabelVarName[]   = "ANGLE_CAPTURE_LABEL";
76 constexpr char kCompressionVarName[]    = "ANGLE_CAPTURE_COMPRESSION";
77 constexpr char kSerializeStateVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
78 constexpr char kValidationVarName[]     = "ANGLE_CAPTURE_VALIDATION";
79 constexpr char kValidationExprVarName[] = "ANGLE_CAPTURE_VALIDATION_EXPR";
80 constexpr char kTrimEnabledVarName[]    = "ANGLE_CAPTURE_TRIM_ENABLED";
81 constexpr char kSourceExtVarName[]      = "ANGLE_CAPTURE_SOURCE_EXT";
82 constexpr char kSourceSizeVarName[]     = "ANGLE_CAPTURE_SOURCE_SIZE";
83 constexpr char kForceShadowVarName[]    = "ANGLE_CAPTURE_FORCE_SHADOW";
84 
85 constexpr size_t kBinaryAlignment   = 16;
86 constexpr size_t kFunctionSizeLimit = 5000;
87 
88 // Limit based on MSVC Compiler Error C2026
89 constexpr size_t kStringLengthLimit = 16380;
90 
91 // Default limit to number of bytes in a capture source files.
92 constexpr char kDefaultSourceFileExt[]           = "cpp";
93 constexpr size_t kDefaultSourceFileSizeThreshold = 400000;
94 
95 // Android debug properties that correspond to the above environment variables
96 constexpr char kAndroidEnabled[]        = "debug.angle.capture.enabled";
97 constexpr char kAndroidOutDir[]         = "debug.angle.capture.out_dir";
98 constexpr char kAndroidFrameStart[]     = "debug.angle.capture.frame_start";
99 constexpr char kAndroidFrameEnd[]       = "debug.angle.capture.frame_end";
100 constexpr char kAndroidTrigger[]        = "debug.angle.capture.trigger";
101 constexpr char kAndroidCaptureLabel[]   = "debug.angle.capture.label";
102 constexpr char kAndroidCompression[]    = "debug.angle.capture.compression";
103 constexpr char kAndroidValidation[]     = "debug.angle.capture.validation";
104 constexpr char kAndroidValidationExpr[] = "debug.angle.capture.validation_expr";
105 constexpr char kAndroidTrimEnabled[]    = "debug.angle.capture.trim_enabled";
106 constexpr char kAndroidSourceExt[]      = "debug.angle.capture.source_ext";
107 constexpr char kAndroidSourceSize[]     = "debug.angle.capture.source_size";
108 constexpr char kAndroidForceShadow[]    = "debug.angle.capture.force_shadow";
109 
110 struct FramebufferCaptureFuncs
111 {
FramebufferCaptureFuncsangle::__anon9f9064c30111::FramebufferCaptureFuncs112     FramebufferCaptureFuncs(bool isGLES1)
113     {
114         if (isGLES1)
115         {
116             // From GL_OES_framebuffer_object
117             framebufferTexture2D    = &gl::CaptureFramebufferTexture2DOES;
118             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbufferOES;
119             bindFramebuffer         = &gl::CaptureBindFramebufferOES;
120             genFramebuffers         = &gl::CaptureGenFramebuffersOES;
121             bindRenderbuffer        = &gl::CaptureBindRenderbufferOES;
122             genRenderbuffers        = &gl::CaptureGenRenderbuffersOES;
123             renderbufferStorage     = &gl::CaptureRenderbufferStorageOES;
124         }
125         else
126         {
127             framebufferTexture2D    = &gl::CaptureFramebufferTexture2D;
128             framebufferRenderbuffer = &gl::CaptureFramebufferRenderbuffer;
129             bindFramebuffer         = &gl::CaptureBindFramebuffer;
130             genFramebuffers         = &gl::CaptureGenFramebuffers;
131             bindRenderbuffer        = &gl::CaptureBindRenderbuffer;
132             genRenderbuffers        = &gl::CaptureGenRenderbuffers;
133             renderbufferStorage     = &gl::CaptureRenderbufferStorage;
134         }
135     }
136 
137     decltype(&gl::CaptureFramebufferTexture2D) framebufferTexture2D;
138     decltype(&gl::CaptureFramebufferRenderbuffer) framebufferRenderbuffer;
139     decltype(&gl::CaptureBindFramebuffer) bindFramebuffer;
140     decltype(&gl::CaptureGenFramebuffers) genFramebuffers;
141     decltype(&gl::CaptureBindRenderbuffer) bindRenderbuffer;
142     decltype(&gl::CaptureGenRenderbuffers) genRenderbuffers;
143     decltype(&gl::CaptureRenderbufferStorage) renderbufferStorage;
144 };
145 
146 struct VertexArrayCaptureFuncs
147 {
VertexArrayCaptureFuncsangle::__anon9f9064c30111::VertexArrayCaptureFuncs148     VertexArrayCaptureFuncs(bool isGLES1)
149     {
150         if (isGLES1)
151         {
152             // From GL_OES_vertex_array_object
153             bindVertexArray    = &gl::CaptureBindVertexArrayOES;
154             deleteVertexArrays = &gl::CaptureDeleteVertexArraysOES;
155             genVertexArrays    = &gl::CaptureGenVertexArraysOES;
156             isVertexArray      = &gl::CaptureIsVertexArrayOES;
157         }
158         else
159         {
160             bindVertexArray    = &gl::CaptureBindVertexArray;
161             deleteVertexArrays = &gl::CaptureDeleteVertexArrays;
162             genVertexArrays    = &gl::CaptureGenVertexArrays;
163             isVertexArray      = &gl::CaptureIsVertexArray;
164         }
165     }
166 
167     decltype(&gl::CaptureBindVertexArray) bindVertexArray;
168     decltype(&gl::CaptureDeleteVertexArrays) deleteVertexArrays;
169     decltype(&gl::CaptureGenVertexArrays) genVertexArrays;
170     decltype(&gl::CaptureIsVertexArray) isVertexArray;
171 };
172 
GetDefaultOutDirectory()173 std::string GetDefaultOutDirectory()
174 {
175 #if defined(ANGLE_PLATFORM_ANDROID)
176     std::string path = "/sdcard/Android/data/";
177 
178     // Linux interface to get application id of the running process
179     FILE *cmdline = fopen("/proc/self/cmdline", "r");
180     char applicationId[512];
181     if (cmdline)
182     {
183         fread(applicationId, 1, sizeof(applicationId), cmdline);
184         fclose(cmdline);
185 
186         // Some package may have application id as <app_name>:<cmd_name>
187         char *colonSep = strchr(applicationId, ':');
188         if (colonSep)
189         {
190             *colonSep = '\0';
191         }
192     }
193     else
194     {
195         ERR() << "not able to lookup application id";
196     }
197 
198     constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
199     path += std::string(applicationId) + kAndroidOutputSubdir;
200 
201     // Check for existence of output path
202     struct stat dir_stat;
203     if (stat(path.c_str(), &dir_stat) == -1)
204     {
205         ERR() << "Output directory '" << path
206               << "' does not exist.  Create it over adb using mkdir.";
207     }
208 
209     return path;
210 #else
211     return std::string("./");
212 #endif  // defined(ANGLE_PLATFORM_ANDROID)
213 }
214 
GetCaptureTrigger()215 std::string GetCaptureTrigger()
216 {
217     // Use the GetAndSet variant to improve future lookup times
218     return GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
219 }
220 
operator <<(std::ostream & os,gl::ContextID contextId)221 std::ostream &operator<<(std::ostream &os, gl::ContextID contextId)
222 {
223     os << static_cast<int>(contextId.value);
224     return os;
225 }
226 
227 // Used to indicate that "shared" should be used to identify the files.
228 constexpr gl::ContextID kSharedContextId = {0};
229 // Used to indicate no context ID should be output.
230 constexpr gl::ContextID kNoContextId = {std::numeric_limits<uint32_t>::max()};
231 
232 struct FmtCapturePrefix
233 {
FmtCapturePrefixangle::__anon9f9064c30111::FmtCapturePrefix234     FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
235         : contextId(contextIdIn), captureLabel(captureLabelIn)
236     {}
237     gl::ContextID contextId;
238     const std::string &captureLabel;
239 };
240 
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)241 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
242 {
243     if (fmt.captureLabel.empty())
244     {
245         os << "angle_capture";
246     }
247     else
248     {
249         os << fmt.captureLabel;
250     }
251 
252     if (fmt.contextId == kSharedContextId)
253     {
254         os << "_shared";
255     }
256 
257     return os;
258 }
259 
260 enum class ReplayFunc
261 {
262     Replay,
263     Setup,
264     Reset,
265 };
266 
267 constexpr uint32_t kNoPartId = std::numeric_limits<uint32_t>::max();
268 
269 // In C, when you declare or define a function that takes no parameters, you must explicitly say the
270 // function takes "void" parameters. When you're calling the function you omit this void. It's
271 // therefore necessary to know how we're using a function to know if we should emi the "void".
272 enum FuncUsage
273 {
274     Prototype,
275     Definition,
276     Call,
277 };
278 
operator <<(std::ostream & os,FuncUsage usage)279 std::ostream &operator<<(std::ostream &os, FuncUsage usage)
280 {
281     os << "(";
282     if (usage != FuncUsage::Call)
283     {
284         os << "void";
285     }
286     os << ")";
287     return os;
288 }
289 
290 struct FmtReplayFunction
291 {
FmtReplayFunctionangle::__anon9f9064c30111::FmtReplayFunction292     FmtReplayFunction(gl::ContextID contextIdIn,
293                       FuncUsage usageIn,
294                       uint32_t frameIndexIn,
295                       uint32_t partIdIn = kNoPartId)
296         : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn), partId(partIdIn)
297     {}
298     gl::ContextID contextId;
299     FuncUsage usage;
300     uint32_t frameIndex;
301     uint32_t partId;
302 };
303 
operator <<(std::ostream & os,const FmtReplayFunction & fmt)304 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
305 {
306     os << "Replay";
307 
308     if (fmt.contextId == kSharedContextId)
309     {
310         os << "Shared";
311     }
312 
313     os << "Frame" << fmt.frameIndex;
314 
315     if (fmt.partId != kNoPartId)
316     {
317         os << "Part" << fmt.partId;
318     }
319     os << fmt.usage;
320     return os;
321 }
322 
323 struct FmtSetupFunction
324 {
FmtSetupFunctionangle::__anon9f9064c30111::FmtSetupFunction325     FmtSetupFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
326         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
327     {}
328 
329     uint32_t partId;
330     gl::ContextID contextId;
331     FuncUsage usage;
332 };
333 
operator <<(std::ostream & os,const FmtSetupFunction & fmt)334 std::ostream &operator<<(std::ostream &os, const FmtSetupFunction &fmt)
335 {
336     os << "SetupReplayContext";
337 
338     if (fmt.contextId == kSharedContextId)
339     {
340         os << "Shared";
341     }
342     else
343     {
344         os << fmt.contextId;
345     }
346 
347     if (fmt.partId != kNoPartId)
348     {
349         os << "Part" << fmt.partId;
350     }
351     os << fmt.usage;
352     return os;
353 }
354 
355 struct FmtResetFunction
356 {
FmtResetFunctionangle::__anon9f9064c30111::FmtResetFunction357     FmtResetFunction(uint32_t partIdIn, gl::ContextID contextIdIn, FuncUsage usageIn)
358         : partId(partIdIn), contextId(contextIdIn), usage(usageIn)
359     {}
360 
361     uint32_t partId;
362     gl::ContextID contextId;
363     FuncUsage usage;
364 };
365 
operator <<(std::ostream & os,const FmtResetFunction & fmt)366 std::ostream &operator<<(std::ostream &os, const FmtResetFunction &fmt)
367 {
368     os << "ResetReplayContext";
369 
370     if (fmt.contextId == kSharedContextId)
371     {
372         os << "Shared";
373     }
374     else
375     {
376         os << fmt.contextId;
377     }
378 
379     if (fmt.partId != kNoPartId)
380     {
381         os << "Part" << fmt.partId;
382     }
383     os << fmt.usage;
384     return os;
385 }
386 
387 struct FmtFunction
388 {
FmtFunctionangle::__anon9f9064c30111::FmtFunction389     FmtFunction(ReplayFunc funcTypeIn,
390                 gl::ContextID contextIdIn,
391                 FuncUsage usageIn,
392                 uint32_t frameIndexIn,
393                 uint32_t partIdIn)
394         : funcType(funcTypeIn),
395           contextId(contextIdIn),
396           usage(usageIn),
397           frameIndex(frameIndexIn),
398           partId(partIdIn)
399     {}
400 
401     ReplayFunc funcType;
402     gl::ContextID contextId;
403     FuncUsage usage;
404     uint32_t frameIndex;
405     uint32_t partId;
406 };
407 
operator <<(std::ostream & os,const FmtFunction & fmt)408 std::ostream &operator<<(std::ostream &os, const FmtFunction &fmt)
409 {
410     switch (fmt.funcType)
411     {
412         case ReplayFunc::Replay:
413             os << FmtReplayFunction(fmt.contextId, fmt.usage, fmt.frameIndex, fmt.partId);
414             break;
415 
416         case ReplayFunc::Setup:
417             os << FmtSetupFunction(fmt.partId, fmt.contextId, fmt.usage);
418             break;
419 
420         case ReplayFunc::Reset:
421             os << FmtResetFunction(fmt.partId, fmt.contextId, fmt.usage);
422             break;
423 
424         default:
425             UNREACHABLE();
426             break;
427     }
428 
429     return os;
430 }
431 
432 struct FmtGetSerializedContextStateFunction
433 {
FmtGetSerializedContextStateFunctionangle::__anon9f9064c30111::FmtGetSerializedContextStateFunction434     FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn,
435                                          FuncUsage usageIn,
436                                          uint32_t frameIndexIn)
437         : contextId(contextIdIn), usage(usageIn), frameIndex(frameIndexIn)
438     {}
439     gl::ContextID contextId;
440     FuncUsage usage;
441     uint32_t frameIndex;
442 };
443 
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)444 std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
445 {
446     os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data"
447        << fmt.usage;
448     return os;
449 }
450 
WriteGLFloatValue(std::ostream & out,GLfloat value)451 void WriteGLFloatValue(std::ostream &out, GLfloat value)
452 {
453     // Check for non-representable values
454     ASSERT(std::numeric_limits<float>::has_infinity);
455     ASSERT(std::numeric_limits<float>::has_quiet_NaN);
456 
457     if (std::isinf(value))
458     {
459         float negativeInf = -std::numeric_limits<float>::infinity();
460         if (value == negativeInf)
461         {
462             out << "-";
463         }
464         out << "INFINITY";
465     }
466     else if (std::isnan(value))
467     {
468         out << "NAN";
469     }
470     else
471     {
472         out << std::setprecision(16);
473         out << value;
474     }
475 }
476 
477 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)478 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
479 {
480     const T *data = reinterpret_cast<const T *>(vec.data());
481     size_t count  = vec.size() / sizeof(T);
482 
483     if (data == nullptr)
484     {
485         return;
486     }
487 
488     out << static_cast<CastT>(data[0]);
489 
490     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
491     {
492         out << ", " << static_cast<CastT>(data[dataIndex]);
493     }
494 }
495 
496 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)497 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
498 {
499     const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
500     size_t count       = vec.size() / sizeof(GLchar);
501 
502     if (data == nullptr || data[0] == '\0')
503     {
504         return;
505     }
506 
507     out << "\"";
508 
509     for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
510     {
511         if (data[dataIndex] == '\0')
512             break;
513 
514         out << static_cast<GLchar>(data[dataIndex]);
515     }
516 
517     out << "\"";
518 }
519 
520 // For compatibility with C, which does not have multi-line string literals, we break strings up
521 // into multiple lines like:
522 //
523 //   const char *str[] = {
524 //   "multiple\n"
525 //   "line\n"
526 //   "strings may have \"quotes\"\n"
527 //   "and \\slashes\\\n",
528 //   };
529 //
530 // Note we need to emit extra escapes to ensure quotes and other special characters are preserved.
531 struct FmtMultiLineString
532 {
FmtMultiLineStringangle::__anon9f9064c30111::FmtMultiLineString533     FmtMultiLineString(const std::string &str) : strings()
534     {
535         std::string str2;
536 
537         // Strip any carriage returns before splitting, for consistency
538         if (str.find("\r") != std::string::npos)
539         {
540             // str is const, so have to make a copy of it first
541             str2 = str;
542             ReplaceAllSubstrings(&str2, "\r", "");
543         }
544 
545         strings =
546             angle::SplitString(str2.empty() ? str : str2, "\n", WhitespaceHandling::KEEP_WHITESPACE,
547                                SplitResult::SPLIT_WANT_ALL);
548     }
549 
550     std::vector<std::string> strings;
551 };
552 
EscapeString(const std::string & string)553 std::string EscapeString(const std::string &string)
554 {
555     std::stringstream strstr;
556 
557     for (char c : string)
558     {
559         if (c == '\"' || c == '\\')
560         {
561             strstr << "\\";
562         }
563         strstr << c;
564     }
565 
566     return strstr.str();
567 }
568 
operator <<(std::ostream & ostr,const FmtMultiLineString & fmt)569 std::ostream &operator<<(std::ostream &ostr, const FmtMultiLineString &fmt)
570 {
571     ASSERT(!fmt.strings.empty());
572     bool first = true;
573     for (const std::string &string : fmt.strings)
574     {
575         if (first)
576         {
577             first = false;
578         }
579         else
580         {
581             ostr << "\\n\"\n";
582         }
583 
584         ostr << "\"" << EscapeString(string);
585     }
586 
587     ostr << "\"";
588 
589     return ostr;
590 }
591 
WriteStringParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)592 void WriteStringParamReplay(ReplayWriter &replayWriter,
593                             std::ostream &out,
594                             std::ostream &header,
595                             const CallCapture &call,
596                             const ParamCapture &param,
597                             std::vector<uint8_t> *binaryData)
598 {
599     const std::vector<uint8_t> &data = param.data[0];
600     // null terminate C style string
601     ASSERT(data.size() > 0 && data.back() == '\0');
602     std::string str(data.begin(), data.end() - 1);
603 
604     constexpr size_t kMaxInlineStringLength = 20000;
605     if (str.size() > kMaxInlineStringLength)
606     {
607         // Store in binary file if the string is too long.
608         // Round up to 16-byte boundary for cross ABI safety.
609         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
610         binaryData->resize(offset + str.size() + 1);
611         memcpy(binaryData->data() + offset, str.data(), str.size() + 1);
612         out << "(const char *)&gBinaryData[" << offset << "]";
613     }
614     else if (str.find('\n') != std::string::npos)
615     {
616         std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
617         header << "const char " << varName << "[] = \n" << FmtMultiLineString(str) << ";";
618         out << varName;
619     }
620     else
621     {
622         out << "\"" << str << "\"";
623     }
624 }
625 
WriteStringPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)626 void WriteStringPointerParamReplay(ReplayWriter &replayWriter,
627                                    std::ostream &out,
628                                    std::ostream &header,
629                                    const CallCapture &call,
630                                    const ParamCapture &param)
631 {
632     // Concatenate the strings to ensure we get an accurate counter
633     std::vector<std::string> strings;
634     for (const std::vector<uint8_t> &data : param.data)
635     {
636         // null terminate C style string
637         ASSERT(data.size() > 0 && data.back() == '\0');
638         strings.emplace_back(data.begin(), data.end() - 1);
639     }
640 
641     bool isNewEntry     = false;
642     std::string varName = replayWriter.getInlineStringSetVariableName(call.entryPoint, param.name,
643                                                                       strings, &isNewEntry);
644 
645     if (isNewEntry)
646     {
647         header << "const char *const " << varName << "[] = { \n";
648 
649         for (const std::string &str : strings)
650         {
651             // Break up long strings for MSVC
652             size_t copyLength = 0;
653             std::string separator;
654             for (size_t i = 0; i < str.length(); i += kStringLengthLimit)
655             {
656                 if ((str.length() - i) <= kStringLengthLimit)
657                 {
658                     copyLength = str.length() - i;
659                     separator  = ",";
660                 }
661                 else
662                 {
663                     copyLength = kStringLengthLimit;
664                     separator  = "";
665                 }
666 
667                 header << FmtMultiLineString(str.substr(i, copyLength)) << separator << "\n";
668             }
669         }
670 
671         header << "};\n";
672     }
673 
674     out << varName;
675 }
676 
677 enum class Indent
678 {
679     Indent,
680     NoIdent,
681 };
682 
UpdateResourceIDBuffer(std::ostream & out,Indent indent,size_t bufferIndex,const char * mapName,GLuint resourceID)683 void UpdateResourceIDBuffer(std::ostream &out,
684                             Indent indent,
685                             size_t bufferIndex,
686                             const char *mapName,
687                             GLuint resourceID)
688 {
689     if (indent == Indent::Indent)
690     {
691         out << "    ";
692     }
693     out << "UpdateResourceIDBuffer(" << bufferIndex << ", g" << mapName << "Map[" << resourceID
694         << "]);\n";
695 }
696 
697 template <typename ParamT>
WriteResourceIDPointerParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,size_t * maxResourceIDBufferSize)698 void WriteResourceIDPointerParamReplay(ReplayWriter &replayWriter,
699                                        std::ostream &out,
700                                        std::ostream &header,
701                                        const CallCapture &call,
702                                        const ParamCapture &param,
703                                        size_t *maxResourceIDBufferSize)
704 {
705     const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
706     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
707     const char *name = GetResourceIDTypeName(resourceIDType);
708 
709     if (param.dataNElements > 0)
710     {
711         ASSERT(param.data.size() == 1);
712 
713         const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
714         for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
715         {
716             ParamT id = returnedIDs[resIndex];
717             UpdateResourceIDBuffer(header, Indent::NoIdent, resIndex, name, id.value);
718         }
719 
720         *maxResourceIDBufferSize = std::max<size_t>(*maxResourceIDBufferSize, param.dataNElements);
721     }
722 
723     out << "gResourceIDBuffer";
724 }
725 
WriteBinaryParamReplay(ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)726 void WriteBinaryParamReplay(ReplayWriter &replayWriter,
727                             std::ostream &out,
728                             std::ostream &header,
729                             const CallCapture &call,
730                             const ParamCapture &param,
731                             std::vector<uint8_t> *binaryData)
732 {
733     std::string varName = replayWriter.getInlineVariableName(call.entryPoint, param.name);
734 
735     ASSERT(param.data.size() == 1);
736     const std::vector<uint8_t> &data = param.data[0];
737 
738     // Only inline strings (shaders) to simplify the C code.
739     ParamType overrideType = param.type;
740     if (param.type == ParamType::TvoidConstPointer)
741     {
742         overrideType = ParamType::TGLubyteConstPointer;
743     }
744     if (overrideType == ParamType::TGLcharPointer)
745     {
746         // Inline if data is of type string
747         std::string paramTypeString = ParamTypeToString(param.type);
748         header << paramTypeString.substr(0, paramTypeString.length() - 1) << varName << "[] = { ";
749         WriteInlineData<GLchar>(data, header);
750         header << " };\n";
751         out << varName;
752     }
753     else
754     {
755         // Store in binary file if data are not of type string
756         // Round up to 16-byte boundary for cross ABI safety
757         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
758         binaryData->resize(offset + data.size());
759         memcpy(binaryData->data() + offset, data.data(), data.size());
760         out << "(" << ParamTypeToString(overrideType) << ")&gBinaryData[" << offset << "]";
761     }
762 }
763 
WriteCppReplayForCall(const CallCapture & call,ReplayWriter & replayWriter,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)764 void WriteCppReplayForCall(const CallCapture &call,
765                            ReplayWriter &replayWriter,
766                            std::ostream &out,
767                            std::ostream &header,
768                            std::vector<uint8_t> *binaryData,
769                            size_t *maxResourceIDBufferSize)
770 {
771     std::ostringstream callOut;
772 
773     callOut << call.name() << "(";
774 
775     bool first = true;
776     for (const ParamCapture &param : call.params.getParamCaptures())
777     {
778         if (!first)
779         {
780             callOut << ", ";
781         }
782 
783         if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
784         {
785             callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
786         }
787         else if (param.readBufferSizeBytes > 0)
788         {
789             callOut << "(" << ParamTypeToString(param.type) << ")gReadBuffer";
790         }
791         else if (param.data.empty())
792         {
793             if (param.type == ParamType::TGLenum)
794             {
795                 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
796             }
797             else if (param.type == ParamType::TGLbitfield)
798             {
799                 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
800             }
801             else if (param.type == ParamType::TGLfloat)
802             {
803                 WriteGLFloatValue(callOut, param.value.GLfloatVal);
804             }
805             else if (param.type == ParamType::TGLsync)
806             {
807                 callOut << "gSyncMap[" << FmtPointerIndex(param.value.GLsyncVal) << "]";
808             }
809             else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
810             {
811                 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
812                 {
813                     callOut << "GL_TIMEOUT_IGNORED";
814                 }
815                 else
816                 {
817                     WriteParamCaptureReplay(callOut, call, param);
818                 }
819             }
820             else
821             {
822                 WriteParamCaptureReplay(callOut, call, param);
823             }
824         }
825         else
826         {
827             switch (param.type)
828             {
829                 case ParamType::TGLcharConstPointer:
830                     WriteStringParamReplay(replayWriter, callOut, header, call, param, binaryData);
831                     break;
832                 case ParamType::TGLcharConstPointerPointer:
833                     WriteStringPointerParamReplay(replayWriter, callOut, header, call, param);
834                     break;
835                 case ParamType::TBufferIDConstPointer:
836                     WriteResourceIDPointerParamReplay<gl::BufferID>(
837                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
838                     break;
839                 case ParamType::TFenceNVIDConstPointer:
840                     WriteResourceIDPointerParamReplay<gl::FenceNVID>(
841                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
842                     break;
843                 case ParamType::TFramebufferIDConstPointer:
844                     WriteResourceIDPointerParamReplay<gl::FramebufferID>(
845                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
846                     break;
847                 case ParamType::TMemoryObjectIDConstPointer:
848                     WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(
849                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
850                     break;
851                 case ParamType::TProgramPipelineIDConstPointer:
852                     WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(
853                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
854                     break;
855                 case ParamType::TQueryIDConstPointer:
856                     WriteResourceIDPointerParamReplay<gl::QueryID>(replayWriter, callOut, out, call,
857                                                                    param, maxResourceIDBufferSize);
858                     break;
859                 case ParamType::TRenderbufferIDConstPointer:
860                     WriteResourceIDPointerParamReplay<gl::RenderbufferID>(
861                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
862                     break;
863                 case ParamType::TSamplerIDConstPointer:
864                     WriteResourceIDPointerParamReplay<gl::SamplerID>(
865                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
866                     break;
867                 case ParamType::TSemaphoreIDConstPointer:
868                     WriteResourceIDPointerParamReplay<gl::SemaphoreID>(
869                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
870                     break;
871                 case ParamType::TTextureIDConstPointer:
872                     WriteResourceIDPointerParamReplay<gl::TextureID>(
873                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
874                     break;
875                 case ParamType::TTransformFeedbackIDConstPointer:
876                     WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(
877                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
878                     break;
879                 case ParamType::TVertexArrayIDConstPointer:
880                     WriteResourceIDPointerParamReplay<gl::VertexArrayID>(
881                         replayWriter, callOut, out, call, param, maxResourceIDBufferSize);
882                     break;
883                 default:
884                     WriteBinaryParamReplay(replayWriter, callOut, header, call, param, binaryData);
885                     break;
886             }
887         }
888 
889         first = false;
890     }
891 
892     callOut << ")";
893 
894     out << callOut.str();
895 }
896 
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)897 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
898 {
899     size_t found = 0;
900     for (size_t size : clientArraySizes)
901     {
902         if (size > found)
903         {
904             found = size;
905         }
906     }
907 
908     return found;
909 }
910 
GetBinaryDataFilePath(bool compression,const std::string & captureLabel)911 std::string GetBinaryDataFilePath(bool compression, const std::string &captureLabel)
912 {
913     std::stringstream fnameStream;
914     fnameStream << FmtCapturePrefix(kNoContextId, captureLabel) << ".angledata";
915     if (compression)
916     {
917         fnameStream << ".gz";
918     }
919     return fnameStream.str();
920 }
921 
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)922 void SaveBinaryData(bool compression,
923                     const std::string &outDir,
924                     gl::ContextID contextId,
925                     const std::string &captureLabel,
926                     const std::vector<uint8_t> &binaryData)
927 {
928     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
929     std::string dataFilepath       = outDir + binaryDataFileName;
930 
931     SaveFileHelper saveData(dataFilepath);
932 
933     if (compression)
934     {
935         // Save compressed data.
936         uLong uncompressedSize       = static_cast<uLong>(binaryData.size());
937         uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
938 
939         std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
940 
941         uLong compressedSize = expectedCompressedSize;
942         int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
943                                                         binaryData.data(), uncompressedSize,
944                                                         nullptr, nullptr);
945 
946         if (zResult != Z_OK)
947         {
948             FATAL() << "Error compressing binary data: " << zResult;
949         }
950 
951         saveData.write(compressedData.data(), compressedSize);
952     }
953     else
954     {
955         saveData.write(binaryData.data(), binaryData.size());
956     }
957 }
958 
WriteInitReplayCall(bool compression,std::ostream & out,gl::ContextID contextID,const std::string & captureLabel,size_t maxClientArraySize,size_t readBufferSize,size_t resourceIDBufferSize,const PackedEnumMap<ResourceIDType,uint32_t> & maxIDs)959 void WriteInitReplayCall(bool compression,
960                          std::ostream &out,
961                          gl::ContextID contextID,
962                          const std::string &captureLabel,
963                          size_t maxClientArraySize,
964                          size_t readBufferSize,
965                          size_t resourceIDBufferSize,
966                          const PackedEnumMap<ResourceIDType, uint32_t> &maxIDs)
967 {
968     std::string binaryDataFileName = GetBinaryDataFilePath(compression, captureLabel);
969 
970     out << "    // binaryDataFileName = " << binaryDataFileName << "\n";
971     out << "    // maxClientArraySize = " << maxClientArraySize << "\n";
972     out << "    // maxClientArraySize = " << maxClientArraySize << "\n";
973     out << "    // readBufferSize = " << readBufferSize << "\n";
974     out << "    // resourceIDBufferSize = " << resourceIDBufferSize << "\n";
975     out << "    // contextID = " << contextID << "\n";
976 
977     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
978     {
979         const char *name = GetResourceIDTypeName(resourceID);
980         out << "    // max" << name << " = " << maxIDs[resourceID] << "\n";
981     }
982 
983     out << "    InitializeReplay4(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
984         << readBufferSize << ", " << resourceIDBufferSize << ", " << contextID;
985 
986     for (ResourceIDType resourceID : AllEnums<ResourceIDType>())
987     {
988         out << ", " << maxIDs[resourceID];
989     }
990 
991     out << ");\n";
992 }
993 
DeleteResourcesInReset(std::stringstream & out,const ResourceSet & newResources,const ResourceSet & resourcesToDelete,const char * resourceName,size_t * maxResourceIDBufferSize)994 void DeleteResourcesInReset(std::stringstream &out,
995                             const ResourceSet &newResources,
996                             const ResourceSet &resourcesToDelete,
997                             const char *resourceName,
998                             size_t *maxResourceIDBufferSize)
999 {
1000     if (!newResources.empty() || !resourcesToDelete.empty())
1001     {
1002         size_t count = 0;
1003 
1004         for (GLuint oldResource : resourcesToDelete)
1005         {
1006             UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceName, oldResource);
1007         }
1008 
1009         for (GLuint newResource : newResources)
1010         {
1011             UpdateResourceIDBuffer(out, Indent::Indent, count++, resourceName, newResource);
1012         }
1013 
1014         // Delete all the new and old buffers at once
1015         out << "    glDelete" << resourceName << "s(" << count << ", gResourceIDBuffer);\n";
1016 
1017         *maxResourceIDBufferSize = std::max(*maxResourceIDBufferSize, count);
1018     }
1019 }
1020 
1021 // TODO (http://anglebug.com/4599): Reset more state on frame loop
MaybeResetResources(gl::ContextID contextID,ResourceIDType resourceIDType,ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool & anyResourceReset,size_t * maxResourceIDBufferSize)1022 void MaybeResetResources(gl::ContextID contextID,
1023                          ResourceIDType resourceIDType,
1024                          ReplayWriter &replayWriter,
1025                          std::stringstream &out,
1026                          std::stringstream &header,
1027                          ResourceTracker *resourceTracker,
1028                          std::vector<uint8_t> *binaryData,
1029                          bool &anyResourceReset,
1030                          size_t *maxResourceIDBufferSize)
1031 {
1032     // Track the initial output position so we can detect if it has moved
1033     std::streampos initialOutPos = out.tellp();
1034 
1035     switch (resourceIDType)
1036     {
1037         case ResourceIDType::Buffer:
1038         {
1039             TrackedResource &trackedBuffers =
1040                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Buffer);
1041             ResourceSet &newBuffers           = trackedBuffers.getNewResources();
1042             ResourceSet &buffersToDelete      = trackedBuffers.getResourcesToDelete();
1043             ResourceSet &buffersToRegen       = trackedBuffers.getResourcesToRegen();
1044             ResourceCalls &bufferRegenCalls   = trackedBuffers.getResourceRegenCalls();
1045             ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
1046 
1047             BufferCalls &bufferMapCalls   = resourceTracker->getBufferMapCalls();
1048             BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
1049 
1050             DeleteResourcesInReset(out, newBuffers, buffersToDelete, "Buffer",
1051                                    maxResourceIDBufferSize);
1052 
1053             // If any of our starting buffers were deleted during the run, recreate them
1054             for (GLuint id : buffersToRegen)
1055             {
1056                 // Emit their regen calls
1057                 for (CallCapture &call : bufferRegenCalls[id])
1058                 {
1059                     out << "    ";
1060                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1061                                           maxResourceIDBufferSize);
1062                     out << ";\n";
1063                 }
1064             }
1065 
1066             // If any of our starting buffers were modified during the run, restore their contents
1067             ResourceSet &buffersToRestore = trackedBuffers.getResourcesToRestore();
1068             for (GLuint id : buffersToRestore)
1069             {
1070                 if (resourceTracker->getStartingBuffersMappedCurrent(id))
1071                 {
1072                     // Some drivers require the buffer to be unmapped before you can update data,
1073                     // which violates the spec. See gl::Buffer::bufferDataImpl().
1074                     for (CallCapture &call : bufferUnmapCalls[id])
1075                     {
1076                         out << "    ";
1077                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1078                                               maxResourceIDBufferSize);
1079                         out << ";\n";
1080                     }
1081                 }
1082 
1083                 // Emit their restore calls
1084                 for (CallCapture &call : bufferRestoreCalls[id])
1085                 {
1086                     out << "    ";
1087                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1088                                           maxResourceIDBufferSize);
1089                     out << ";\n";
1090 
1091                     // Also note that this buffer has been implicitly unmapped by this call
1092                     resourceTracker->setBufferUnmapped(contextID, id);
1093                 }
1094             }
1095 
1096             // Update the map/unmap of buffers to match the starting state
1097             ResourceSet startingBuffers = trackedBuffers.getStartingResources();
1098             for (GLuint id : startingBuffers)
1099             {
1100                 // If the buffer was mapped at the start, but is not mapped now, we need to map
1101                 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
1102                     !resourceTracker->getStartingBuffersMappedCurrent(id))
1103                 {
1104                     // Emit their map calls
1105                     for (CallCapture &call : bufferMapCalls[id])
1106                     {
1107                         out << "    ";
1108                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1109                                               maxResourceIDBufferSize);
1110                         out << ";\n";
1111                     }
1112                 }
1113                 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
1114                 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
1115                     resourceTracker->getStartingBuffersMappedCurrent(id))
1116                 {
1117                     // Emit their unmap calls
1118                     for (CallCapture &call : bufferUnmapCalls[id])
1119                     {
1120                         out << "    ";
1121                         WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1122                                               maxResourceIDBufferSize);
1123                         out << ";\n";
1124                     }
1125                 }
1126             }
1127 
1128             // Restore buffer bindings as seen during MEC
1129             std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
1130             for (CallCapture &call : bufferBindingCalls)
1131             {
1132                 out << "    ";
1133                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1134                                       maxResourceIDBufferSize);
1135                 out << ";\n";
1136             }
1137 
1138             break;
1139         }
1140         case ResourceIDType::Framebuffer:
1141         {
1142             TrackedResource &trackedFramebuffers =
1143                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Framebuffer);
1144             ResourceSet &newFramebuffers           = trackedFramebuffers.getNewResources();
1145             ResourceSet &framebuffersToDelete      = trackedFramebuffers.getResourcesToDelete();
1146             ResourceSet &framebuffersToRegen       = trackedFramebuffers.getResourcesToRegen();
1147             ResourceCalls &framebufferRegenCalls   = trackedFramebuffers.getResourceRegenCalls();
1148             ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
1149 
1150             DeleteResourcesInReset(out, newFramebuffers, framebuffersToDelete, "Framebuffer",
1151                                    maxResourceIDBufferSize);
1152 
1153             for (GLuint id : framebuffersToRegen)
1154             {
1155                 // Emit their regen calls
1156                 for (CallCapture &call : framebufferRegenCalls[id])
1157                 {
1158                     out << "    ";
1159                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1160                                           maxResourceIDBufferSize);
1161                     out << ";\n";
1162                 }
1163             }
1164 
1165             // If any of our starting framebuffers were modified during the run, restore their
1166             // contents
1167             ResourceSet &framebuffersToRestore = trackedFramebuffers.getResourcesToRestore();
1168             for (GLuint id : framebuffersToRestore)
1169             {
1170                 // Emit their restore calls
1171                 for (CallCapture &call : framebufferRestoreCalls[id])
1172                 {
1173                     out << "    ";
1174                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1175                                           maxResourceIDBufferSize);
1176                     out << ";\n";
1177                 }
1178             }
1179             break;
1180         }
1181         case ResourceIDType::Renderbuffer:
1182         {
1183             TrackedResource &trackedRenderbuffers =
1184                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Renderbuffer);
1185             ResourceSet &newRenderbuffers         = trackedRenderbuffers.getNewResources();
1186             ResourceSet &renderbuffersToDelete    = trackedRenderbuffers.getResourcesToDelete();
1187             ResourceSet &renderbuffersToRegen     = trackedRenderbuffers.getResourcesToRegen();
1188             ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
1189             ResourceCalls &renderbufferRestoreCalls =
1190                 trackedRenderbuffers.getResourceRestoreCalls();
1191 
1192             DeleteResourcesInReset(out, newRenderbuffers, renderbuffersToDelete, "Renderbuffer",
1193                                    maxResourceIDBufferSize);
1194 
1195             for (GLuint id : renderbuffersToRegen)
1196             {
1197                 // Emit their regen calls
1198                 for (CallCapture &call : renderbufferRegenCalls[id])
1199                 {
1200                     out << "    ";
1201                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1202                                           maxResourceIDBufferSize);
1203                     out << ";\n";
1204                 }
1205             }
1206 
1207             // If any of our starting renderbuffers were modified during the run, restore their
1208             // contents
1209             ResourceSet &renderbuffersToRestore = trackedRenderbuffers.getResourcesToRestore();
1210             for (GLuint id : renderbuffersToRestore)
1211             {
1212                 // Emit their restore calls
1213                 for (CallCapture &call : renderbufferRestoreCalls[id])
1214                 {
1215                     out << "    ";
1216                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1217                                           maxResourceIDBufferSize);
1218                     out << ";\n";
1219                 }
1220             }
1221             break;
1222         }
1223         case ResourceIDType::ShaderProgram:
1224         {
1225             TrackedResource &trackedShaderPrograms =
1226                 resourceTracker->getTrackedResource(contextID, ResourceIDType::ShaderProgram);
1227             ResourceSet &newShaderPrograms         = trackedShaderPrograms.getNewResources();
1228             ResourceSet &shaderProgramsToDelete    = trackedShaderPrograms.getResourcesToDelete();
1229             ResourceSet &shaderProgramsToRegen     = trackedShaderPrograms.getResourcesToRegen();
1230             ResourceSet &shaderProgramsToRestore   = trackedShaderPrograms.getResourcesToRestore();
1231             ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
1232             ResourceCalls &shaderProgramRestoreCalls =
1233                 trackedShaderPrograms.getResourceRestoreCalls();
1234 
1235             // If we have any new shaders or programs created and not deleted during the run, delete
1236             // them now
1237             for (const GLuint &newShaderProgram : newShaderPrograms)
1238             {
1239                 if (resourceTracker->getShaderProgramType({newShaderProgram}) ==
1240                     ShaderProgramType::ShaderType)
1241                 {
1242                     out << "    glDeleteShader(gShaderProgramMap[" << newShaderProgram << "]);\n";
1243                 }
1244                 else
1245                 {
1246                     ASSERT(resourceTracker->getShaderProgramType({newShaderProgram}) ==
1247                            ShaderProgramType::ProgramType);
1248                     out << "    glDeleteProgram(gShaderProgramMap[" << newShaderProgram << "]);\n";
1249                 }
1250             }
1251 
1252             // Do the same for shaders/programs to be deleted
1253             for (const GLuint &shaderProgramToDelete : shaderProgramsToDelete)
1254             {
1255                 if (resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
1256                     ShaderProgramType::ShaderType)
1257                 {
1258                     out << "    glDeleteShader(gShaderProgramMap[" << shaderProgramToDelete
1259                         << "]);\n";
1260                 }
1261                 else
1262                 {
1263                     ASSERT(resourceTracker->getShaderProgramType({shaderProgramToDelete}) ==
1264                            ShaderProgramType::ProgramType);
1265                     out << "    glDeleteProgram(gShaderProgramMap[" << shaderProgramToDelete
1266                         << "]);\n";
1267                 }
1268             }
1269 
1270             for (const GLuint id : shaderProgramsToRegen)
1271             {
1272                 // Emit their regen calls
1273                 for (CallCapture &call : shaderProgramRegenCalls[id])
1274                 {
1275                     out << "    ";
1276                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1277                                           maxResourceIDBufferSize);
1278                     out << ";\n";
1279                 }
1280             }
1281 
1282             for (const GLuint id : shaderProgramsToRestore)
1283             {
1284                 // Emit their restore calls
1285                 for (CallCapture &call : shaderProgramRestoreCalls[id])
1286                 {
1287                     out << "    ";
1288                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1289                                           maxResourceIDBufferSize);
1290                     out << ";\n";
1291                 }
1292             }
1293 
1294             break;
1295         }
1296         case ResourceIDType::Texture:
1297         {
1298             TrackedResource &trackedTextures =
1299                 resourceTracker->getTrackedResource(contextID, ResourceIDType::Texture);
1300             ResourceSet &newTextures           = trackedTextures.getNewResources();
1301             ResourceSet &texturesToDelete      = trackedTextures.getResourcesToDelete();
1302             ResourceSet &texturesToRegen       = trackedTextures.getResourcesToRegen();
1303             ResourceCalls &textureRegenCalls   = trackedTextures.getResourceRegenCalls();
1304             ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
1305 
1306             DeleteResourcesInReset(out, newTextures, texturesToDelete, "Texture",
1307                                    maxResourceIDBufferSize);
1308 
1309             // If any of our starting textures were deleted, regen them
1310             for (GLuint id : texturesToRegen)
1311             {
1312                 // Emit their regen calls
1313                 for (CallCapture &call : textureRegenCalls[id])
1314                 {
1315                     out << "    ";
1316                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1317                                           maxResourceIDBufferSize);
1318                     out << ";\n";
1319                 }
1320             }
1321 
1322             // If any of our starting textures were modified during the run, restore their contents
1323             ResourceSet &texturesToRestore = trackedTextures.getResourcesToRestore();
1324             for (GLuint id : texturesToRestore)
1325             {
1326                 // Emit their restore calls
1327                 for (CallCapture &call : textureRestoreCalls[id])
1328                 {
1329                     out << "    ";
1330                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1331                                           maxResourceIDBufferSize);
1332                     out << ";\n";
1333                 }
1334             }
1335             break;
1336         }
1337         case ResourceIDType::VertexArray:
1338         {
1339             TrackedResource &trackedVertexArrays =
1340                 resourceTracker->getTrackedResource(contextID, ResourceIDType::VertexArray);
1341             ResourceSet &newVertexArrays           = trackedVertexArrays.getNewResources();
1342             ResourceSet &vertexArraysToDelete      = trackedVertexArrays.getResourcesToDelete();
1343             ResourceSet &vertexArraysToRegen       = trackedVertexArrays.getResourcesToRegen();
1344             ResourceSet &vertexArraysToRestore     = trackedVertexArrays.getResourcesToRestore();
1345             ResourceCalls &vertexArrayRegenCalls   = trackedVertexArrays.getResourceRegenCalls();
1346             ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
1347 
1348             DeleteResourcesInReset(out, newVertexArrays, vertexArraysToDelete, "VertexArray",
1349                                    maxResourceIDBufferSize);
1350 
1351             // If any of our starting vertex arrays were deleted during the run, recreate them
1352             for (GLuint id : vertexArraysToRegen)
1353             {
1354                 // Emit their regen calls
1355                 for (CallCapture &call : vertexArrayRegenCalls[id])
1356                 {
1357                     out << "    ";
1358                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1359                                           maxResourceIDBufferSize);
1360                     out << ";\n";
1361                 }
1362             }
1363 
1364             // If any of our starting vertex arrays were modified during the run, restore their
1365             // contents
1366             for (GLuint id : vertexArraysToRestore)
1367             {
1368                 // Emit their restore calls
1369                 for (CallCapture &call : vertexArrayRestoreCalls[id])
1370                 {
1371                     out << "    ";
1372                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1373                                           maxResourceIDBufferSize);
1374                     out << ";\n";
1375                 }
1376             }
1377             break;
1378         }
1379         case ResourceIDType::egl_Sync:
1380         {
1381             TrackedResource &trackedEGLSyncs =
1382                 resourceTracker->getTrackedResource(contextID, ResourceIDType::egl_Sync);
1383             ResourceSet &newEGLSyncs         = trackedEGLSyncs.getNewResources();
1384             ResourceSet &eglSyncsToDelete    = trackedEGLSyncs.getResourcesToDelete();
1385             ResourceSet &eglSyncsToRegen     = trackedEGLSyncs.getResourcesToRegen();
1386             ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
1387 
1388             if (!newEGLSyncs.empty() || !eglSyncsToDelete.empty())
1389             {
1390                 for (GLuint oldResource : eglSyncsToDelete)
1391                 {
1392                     out << "    eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << oldResource
1393                         << "]);\n";
1394                 }
1395 
1396                 for (GLuint newResource : newEGLSyncs)
1397                 {
1398                     out << "    eglDestroySyncKHR(gEGLDisplay, gEGLSyncMap[" << newResource
1399                         << "]);\n";
1400                 }
1401             }
1402 
1403             // If any of our starting EGLsyncs were deleted during the run, recreate them
1404             for (GLuint id : eglSyncsToRegen)
1405             {
1406                 // Emit their regen calls
1407                 for (CallCapture &call : eglSyncRegenCalls[id])
1408                 {
1409                     out << "    ";
1410                     WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1411                                           maxResourceIDBufferSize);
1412                     out << ";\n";
1413                 }
1414             }
1415             break;
1416         }
1417         default:
1418             // TODO (http://anglebug.com/4599): Reset more resource types
1419             break;
1420     }
1421 
1422     // If the output position has moved, we Reset something
1423     anyResourceReset = (initialOutPos != out.tellp());
1424 }
1425 
MaybeResetFenceSyncObjects(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1426 void MaybeResetFenceSyncObjects(std::stringstream &out,
1427                                 ReplayWriter &replayWriter,
1428                                 std::stringstream &header,
1429                                 ResourceTracker *resourceTracker,
1430                                 std::vector<uint8_t> *binaryData,
1431                                 size_t *maxResourceIDBufferSize)
1432 {
1433     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
1434 
1435     // If any of our starting fence sync objects were deleted during the run, recreate them
1436     FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
1437     for (const gl::SyncID syncID : fenceSyncsToRegen)
1438     {
1439         // Emit their regen calls
1440         for (CallCapture &call : fenceSyncRegenCalls[syncID])
1441         {
1442             out << "    ";
1443             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1444                                   maxResourceIDBufferSize);
1445             out << ";\n";
1446         }
1447     }
1448 }
1449 
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1450 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1451 {
1452     setupCalls->emplace_back(std::move(call));
1453 }
1454 
CaptureUpdateCurrentProgram(const CallCapture & call,int programParamPos,std::vector<CallCapture> * callsOut)1455 void CaptureUpdateCurrentProgram(const CallCapture &call,
1456                                  int programParamPos,
1457                                  std::vector<CallCapture> *callsOut)
1458 {
1459     const ParamCapture &param =
1460         call.params.getParam("programPacked", ParamType::TShaderProgramID, programParamPos);
1461     gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1462 
1463     ParamBuffer paramBuffer;
1464     paramBuffer.addValueParam("program", ParamType::TGLuint, programID.value);
1465 
1466     callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1467 }
1468 
ProgramNeedsReset(const gl::ContextID contextID,ResourceTracker * resourceTracker,gl::ShaderProgramID programID)1469 bool ProgramNeedsReset(const gl::ContextID contextID,
1470                        ResourceTracker *resourceTracker,
1471                        gl::ShaderProgramID programID)
1472 {
1473     // Check whether the program is listed in programs to regen or restore
1474     TrackedResource &trackedShaderPrograms =
1475         resourceTracker->getTrackedResource(contextID, ResourceIDType::ShaderProgram);
1476 
1477     ResourceSet &shaderProgramsToRegen = trackedShaderPrograms.getResourcesToRegen();
1478     if (shaderProgramsToRegen.count(programID.value) != 0)
1479     {
1480         return true;
1481     }
1482 
1483     ResourceSet &shaderProgramsToRestore = trackedShaderPrograms.getResourcesToRestore();
1484     if (shaderProgramsToRestore.count(programID.value) != 0)
1485     {
1486         return true;
1487     }
1488 
1489     return false;
1490 }
1491 
MaybeResetDefaultUniforms(std::stringstream & out,ReplayWriter & replayWriter,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1492 void MaybeResetDefaultUniforms(std::stringstream &out,
1493                                ReplayWriter &replayWriter,
1494                                std::stringstream &header,
1495                                const gl::Context *context,
1496                                ResourceTracker *resourceTracker,
1497                                std::vector<uint8_t> *binaryData,
1498                                size_t *maxResourceIDBufferSize)
1499 {
1500     DefaultUniformLocationsPerProgramMap &defaultUniformsToReset =
1501         resourceTracker->getDefaultUniformsToReset();
1502 
1503     for (const auto &uniformIter : defaultUniformsToReset)
1504     {
1505         gl::ShaderProgramID programID               = uniformIter.first;
1506         const DefaultUniformLocationsSet &locations = uniformIter.second;
1507 
1508         if (ProgramNeedsReset(context->id(), resourceTracker, programID))
1509         {
1510             // Skip programs marked for reset as they will update their own uniforms
1511             return;
1512         }
1513 
1514         // Bind the program to update its uniforms
1515         std::vector<CallCapture> bindCalls;
1516         Capture(&bindCalls, CaptureUseProgram(context->getState(), true, programID));
1517         CaptureUpdateCurrentProgram((&bindCalls)->back(), 0, &bindCalls);
1518         for (CallCapture &call : bindCalls)
1519         {
1520             out << "    ";
1521             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1522                                   maxResourceIDBufferSize);
1523             out << ";\n";
1524         }
1525 
1526         DefaultUniformCallsPerLocationMap &defaultUniformResetCalls =
1527             resourceTracker->getDefaultUniformResetCalls(programID);
1528 
1529         // Uniform arrays might have been modified in the middle (i.e. location 5 out of 10)
1530         // We only have Reset calls for the entire array, so emit them once for the entire array
1531         std::set<gl::UniformLocation> alreadyReset;
1532 
1533         // Emit the reset calls per modified location
1534         for (const gl::UniformLocation &location : locations)
1535         {
1536             gl::UniformLocation baseLocation =
1537                 resourceTracker->getDefaultUniformBaseLocation(programID, location);
1538             if (alreadyReset.find(baseLocation) != alreadyReset.end())
1539             {
1540                 // We've already Reset this array
1541                 continue;
1542             }
1543             alreadyReset.insert(baseLocation);
1544 
1545             ASSERT(defaultUniformResetCalls.find(baseLocation) != defaultUniformResetCalls.end());
1546             std::vector<CallCapture> &callsPerLocation = defaultUniformResetCalls[baseLocation];
1547 
1548             for (CallCapture &call : callsPerLocation)
1549             {
1550                 out << "    ";
1551                 WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1552                                       maxResourceIDBufferSize);
1553                 out << ";\n";
1554             }
1555         }
1556     }
1557 }
1558 
MaybeResetOpaqueTypeObjects(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,const gl::Context * context,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,size_t * maxResourceIDBufferSize)1559 void MaybeResetOpaqueTypeObjects(ReplayWriter &replayWriter,
1560                                  std::stringstream &out,
1561                                  std::stringstream &header,
1562                                  const gl::Context *context,
1563                                  ResourceTracker *resourceTracker,
1564                                  std::vector<uint8_t> *binaryData,
1565                                  size_t *maxResourceIDBufferSize)
1566 {
1567     MaybeResetFenceSyncObjects(out, replayWriter, header, resourceTracker, binaryData,
1568                                maxResourceIDBufferSize);
1569 
1570     MaybeResetDefaultUniforms(out, replayWriter, header, context, resourceTracker, binaryData,
1571                               maxResourceIDBufferSize);
1572 }
1573 
MaybeResetContextState(ReplayWriter & replayWriter,std::stringstream & out,std::stringstream & header,ResourceTracker * resourceTracker,const gl::Context * context,std::vector<uint8_t> * binaryData,StateResetHelper & stateResetHelper,size_t * maxResourceIDBufferSize)1574 void MaybeResetContextState(ReplayWriter &replayWriter,
1575                             std::stringstream &out,
1576                             std::stringstream &header,
1577                             ResourceTracker *resourceTracker,
1578                             const gl::Context *context,
1579                             std::vector<uint8_t> *binaryData,
1580                             StateResetHelper &stateResetHelper,
1581                             size_t *maxResourceIDBufferSize)
1582 {
1583     // Check dirty states per entrypoint
1584     for (const EntryPoint &entryPoint : stateResetHelper.getDirtyEntryPoints())
1585     {
1586         const CallResetMap *resetCalls = &stateResetHelper.getResetCalls();
1587 
1588         // Create the default reset call for this entrypoint
1589         if (resetCalls->find(entryPoint) == resetCalls->end())
1590         {
1591             // If we don't have any reset calls for these entrypoints, that means we started capture
1592             // from the beginning, amd mid-execution capture was not invoked.
1593             stateResetHelper.setDefaultResetCalls(context, entryPoint);
1594         }
1595 
1596         // Emit the calls
1597         for (const auto &call : resetCalls->at(entryPoint))
1598         {
1599             out << "    ";
1600             WriteCppReplayForCall(call, replayWriter, out, header, binaryData,
1601                                   maxResourceIDBufferSize);
1602             out << ";\n";
1603         }
1604     }
1605 }
1606 
MarkResourceIDActive(ResourceIDType resourceType,GLuint id,std::vector<CallCapture> * setupCalls,const ResourceIDToSetupCallsMap * resourceIDToSetupCallsMap)1607 void MarkResourceIDActive(ResourceIDType resourceType,
1608                           GLuint id,
1609                           std::vector<CallCapture> *setupCalls,
1610                           const ResourceIDToSetupCallsMap *resourceIDToSetupCallsMap)
1611 {
1612     const std::map<GLuint, gl::Range<size_t>> &resourceSetupCalls =
1613         (*resourceIDToSetupCallsMap)[resourceType];
1614     const auto iter = resourceSetupCalls.find(id);
1615     if (iter == resourceSetupCalls.end())
1616     {
1617         return;
1618     }
1619 
1620     // Mark all of the calls that were used to initialize this resource as ACTIVE
1621     const gl::Range<size_t> &calls = iter->second;
1622     for (size_t index : calls)
1623     {
1624         (*setupCalls)[index].isActive = true;
1625     }
1626 }
1627 
1628 // Some replay functions can get quite large. If over a certain size, this method breaks up the
1629 // 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,size_t * maxResourceIDBufferSize)1630 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1631                                      ReplayFunc replayFunc,
1632                                      ReplayWriter &replayWriter,
1633                                      uint32_t frameIndex,
1634                                      std::vector<uint8_t> *binaryData,
1635                                      const std::vector<CallCapture> &calls,
1636                                      std::stringstream &header,
1637                                      std::stringstream &out,
1638                                      size_t *maxResourceIDBufferSize)
1639 {
1640     int callCount = 0;
1641     int partCount = 0;
1642 
1643     if (calls.size() > kFunctionSizeLimit)
1644     {
1645         out << "void "
1646             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, ++partCount)
1647             << "\n";
1648     }
1649     else
1650     {
1651         out << "void "
1652             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1653             << "\n";
1654     }
1655 
1656     out << "{\n";
1657 
1658     for (const CallCapture &call : calls)
1659     {
1660         if (!call.isActive)
1661         {
1662             // Don't write setup calls for inactive resources
1663             continue;
1664         }
1665 
1666         out << "    ";
1667         WriteCppReplayForCall(call, replayWriter, out, header, binaryData, maxResourceIDBufferSize);
1668         out << ";\n";
1669 
1670         if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1671         {
1672             out << "}\n";
1673             out << "\n";
1674             out << "void "
1675                 << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex,
1676                                ++partCount)
1677                 << "\n";
1678             out << "{\n";
1679         }
1680     }
1681     out << "}\n";
1682 
1683     if (partCount > 0)
1684     {
1685         out << "\n";
1686         out << "void "
1687             << FmtFunction(replayFunc, contextID, FuncUsage::Definition, frameIndex, kNoPartId)
1688             << "\n";
1689         out << "{\n";
1690 
1691         // Write out the main call which calls all the parts.
1692         for (int i = 1; i <= partCount; i++)
1693         {
1694             out << "    " << FmtFunction(replayFunc, contextID, FuncUsage::Call, frameIndex, i)
1695                 << ";\n";
1696         }
1697 
1698         out << "}\n";
1699     }
1700 }
1701 
1702 // Auxiliary contexts are other contexts in the share group that aren't the context calling
1703 // 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,size_t * maxResourceIDBufferSize)1704 void WriteAuxiliaryContextCppSetupReplay(ReplayWriter &replayWriter,
1705                                          bool compression,
1706                                          const std::string &outDir,
1707                                          const gl::Context *context,
1708                                          const std::string &captureLabel,
1709                                          uint32_t frameIndex,
1710                                          const std::vector<CallCapture> &setupCalls,
1711                                          std::vector<uint8_t> *binaryData,
1712                                          bool serializeStateEnabled,
1713                                          const FrameCaptureShared &frameCaptureShared,
1714                                          size_t *maxResourceIDBufferSize)
1715 {
1716     ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
1717 
1718     {
1719         std::stringstream filenameStream;
1720         filenameStream << outDir << FmtCapturePrefix(context->id(), captureLabel);
1721         std::string filenamePattern = filenameStream.str();
1722         replayWriter.setFilenamePattern(filenamePattern);
1723     }
1724 
1725     {
1726         std::stringstream include;
1727         include << "#include \""
1728                 << FmtCapturePrefix(frameCaptureShared.getWindowSurfaceContextID(), captureLabel)
1729                 << ".h\"\n";
1730         include << "#include \"angle_trace_gl.h\"\n";
1731 
1732         std::string frameIncludes = include.str();
1733         replayWriter.setSourcePrologue(frameIncludes);
1734         replayWriter.setHeaderPrologue(frameIncludes);
1735     }
1736 
1737     {
1738         std::stringstream protoStream;
1739         std::stringstream headerStream;
1740         std::stringstream bodyStream;
1741 
1742         protoStream << "void " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Prototype);
1743         std::string proto = protoStream.str();
1744 
1745         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, replayWriter, frameIndex,
1746                                         binaryData, setupCalls, headerStream, bodyStream,
1747                                         maxResourceIDBufferSize);
1748 
1749         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1750     }
1751 
1752     replayWriter.saveFrame();
1753 }
1754 
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,size_t * maxResourceIDBufferSize)1755 void WriteShareGroupCppSetupReplay(ReplayWriter &replayWriter,
1756                                    bool compression,
1757                                    const std::string &outDir,
1758                                    const std::string &captureLabel,
1759                                    uint32_t frameIndex,
1760                                    uint32_t frameCount,
1761                                    const std::vector<CallCapture> &setupCalls,
1762                                    ResourceTracker *resourceTracker,
1763                                    std::vector<uint8_t> *binaryData,
1764                                    bool serializeStateEnabled,
1765                                    gl::ContextID windowSurfaceContextID,
1766                                    size_t *maxResourceIDBufferSize)
1767 {
1768     {
1769         std::stringstream include;
1770 
1771         include << "#include \"angle_trace_gl.h\"\n";
1772         include << "#include \"" << FmtCapturePrefix(windowSurfaceContextID, captureLabel)
1773                 << ".h\"\n";
1774 
1775         std::string includeString = include.str();
1776 
1777         replayWriter.setSourcePrologue(includeString);
1778     }
1779 
1780     {
1781         std::stringstream protoStream;
1782         std::stringstream headerStream;
1783         std::stringstream bodyStream;
1784 
1785         protoStream << "void "
1786                     << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
1787         std::string proto = protoStream.str();
1788 
1789         WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, replayWriter,
1790                                         frameIndex, binaryData, setupCalls, headerStream,
1791                                         bodyStream, maxResourceIDBufferSize);
1792 
1793         replayWriter.addPrivateFunction(proto, headerStream, bodyStream);
1794     }
1795 
1796     {
1797         std::stringstream filenameStream;
1798         filenameStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel);
1799 
1800         std::string filenamePattern = filenameStream.str();
1801 
1802         replayWriter.setFilenamePattern(filenamePattern);
1803     }
1804 
1805     replayWriter.saveSetupFile();
1806 }
1807 
GetAttachedProgramSources(const gl::Program * program)1808 ProgramSources GetAttachedProgramSources(const gl::Program *program)
1809 {
1810     ProgramSources sources;
1811     for (gl::ShaderType shaderType : gl::AllShaderTypes())
1812     {
1813         const gl::Shader *shader = program->getAttachedShader(shaderType);
1814         if (shader)
1815         {
1816             sources[shaderType] = shader->getSourceString();
1817         }
1818     }
1819     return sources;
1820 }
1821 
1822 template <typename IDType>
CaptureUpdateResourceIDs(const gl::Context * context,const CallCapture & call,const ParamCapture & param,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1823 void CaptureUpdateResourceIDs(const gl::Context *context,
1824                               const CallCapture &call,
1825                               const ParamCapture &param,
1826                               ResourceTracker *resourceTracker,
1827                               std::vector<CallCapture> *callsOut)
1828 {
1829     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1830     ASSERT(param.data.size() == 1);
1831     ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1832     ASSERT(resourceIDType != ResourceIDType::InvalidEnum &&
1833            resourceIDType != ResourceIDType::ShaderProgram);
1834     const char *resourceName = GetResourceIDTypeName(resourceIDType);
1835 
1836     std::stringstream updateFuncNameStr;
1837     updateFuncNameStr << "Update" << resourceName << "ID";
1838     std::string updateFuncName = updateFuncNameStr.str();
1839 
1840     const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1841 
1842     ResourceSet &startingSet =
1843         resourceTracker->getTrackedResource(context->id(), resourceIDType).getStartingResources();
1844 
1845     for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1846     {
1847         IDType id                = returnedIDs[idIndex];
1848         GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1849         ParamBuffer params;
1850         params.addValueParam("id", ParamType::TGLuint, id.value);
1851         params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1852         callsOut->emplace_back(updateFuncName, std::move(params));
1853 
1854         // Add only if not in starting resources.
1855         if (startingSet.find(id.value) == startingSet.end())
1856         {
1857             resourceTracker->getTrackedResource(context->id(), resourceIDType)
1858                 .getNewResources()
1859                 .insert(id.value);
1860         }
1861     }
1862 }
1863 
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1864 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1865 {
1866     const std::vector<gl::LinkedUniform> &uniforms     = program->getState().getUniforms();
1867     const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1868 
1869     for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1870     {
1871         const gl::VariableLocation &locationVar = locations[location];
1872 
1873         // This handles the case where the application calls glBindUniformLocationCHROMIUM
1874         // on an unused uniform. We must still store a -1 into gUniformLocations in case the
1875         // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
1876         // force glGetUniformLocation to return -1.
1877         std::string name;
1878         int count = 1;
1879         ParamBuffer params;
1880         params.addValueParam("program", ParamType::TGLuint, program->id().value);
1881 
1882         if (locationVar.index >= uniforms.size())
1883         {
1884             name = "";
1885         }
1886         else
1887         {
1888             const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1889 
1890             name = uniform.name;
1891 
1892             if (uniform.isArray())
1893             {
1894                 if (locationVar.arrayIndex > 0)
1895                 {
1896                     // Non-sequential array uniform locations are not currently handled.
1897                     // In practice array locations shouldn't ever be non-sequential.
1898                     ASSERT(uniform.getLocation() == -1 ||
1899                            location ==
1900                                uniform.getLocation() + static_cast<int>(locationVar.arrayIndex));
1901                     continue;
1902                 }
1903 
1904                 if (uniform.isArrayOfArrays())
1905                 {
1906                     UNIMPLEMENTED();
1907                 }
1908 
1909                 name  = gl::StripLastArrayIndex(name);
1910                 count = uniform.arraySizes[0];
1911             }
1912         }
1913 
1914         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1915         CaptureString(name.c_str(), &nameParam);
1916         params.addParam(std::move(nameParam));
1917         params.addValueParam("location", ParamType::TGLint, location);
1918         params.addValueParam("count", ParamType::TGLint, static_cast<GLint>(count));
1919         callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1920     }
1921 }
1922 
CaptureValidateSerializedState(const gl::Context * context,std::vector<CallCapture> * callsOut)1923 void CaptureValidateSerializedState(const gl::Context *context, std::vector<CallCapture> *callsOut)
1924 {
1925     INFO() << "Capturing validation checkpoint at position " << callsOut->size();
1926 
1927     context->finishImmutable();
1928 
1929     std::string serializedState;
1930     angle::Result result = angle::SerializeContextToString(context, &serializedState);
1931     if (result != angle::Result::Continue)
1932     {
1933         ERR() << "Internal error serializing context state.";
1934         return;
1935     }
1936     ParamCapture serializedStateParam("serializedState", ParamType::TGLcharConstPointer);
1937     CaptureString(serializedState.c_str(), &serializedStateParam);
1938 
1939     ParamBuffer params;
1940     params.addParam(std::move(serializedStateParam));
1941 
1942     callsOut->emplace_back("VALIDATE_CHECKPOINT", std::move(params));
1943 }
1944 
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)1945 void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
1946                                       std::vector<CallCapture> *callsOut)
1947 {
1948     const std::vector<gl::InterfaceBlock> &uniformBlocks = program->getState().getUniformBlocks();
1949 
1950     for (GLuint index = 0; index < uniformBlocks.size(); ++index)
1951     {
1952         ParamBuffer params;
1953 
1954         std::string name;
1955         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1956 
1957         const std::string fullName = uniformBlocks[index].nameWithArrayIndex();
1958         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1959         CaptureString(fullName.c_str(), &nameParam);
1960         params.addParam(std::move(nameParam));
1961 
1962         params.addValueParam("index", ParamType::TGLuint, index);
1963         callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
1964     }
1965 }
1966 
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1967 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1968 {
1969     ParamBuffer params;
1970     params.addValueParam("program", ParamType::TShaderProgramID, program);
1971     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1972 }
1973 
MaybeCaptureUpdateResourceIDs(const gl::Context * context,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)1974 void MaybeCaptureUpdateResourceIDs(const gl::Context *context,
1975                                    ResourceTracker *resourceTracker,
1976                                    std::vector<CallCapture> *callsOut)
1977 {
1978     const CallCapture &call = callsOut->back();
1979 
1980     switch (call.entryPoint)
1981     {
1982         case EntryPoint::GLGenBuffers:
1983         {
1984             const ParamCapture &buffers =
1985                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1986             CaptureUpdateResourceIDs<gl::BufferID>(context, call, buffers, resourceTracker,
1987                                                    callsOut);
1988             break;
1989         }
1990 
1991         case EntryPoint::GLGenFencesNV:
1992         {
1993             const ParamCapture &fences =
1994                 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1995             CaptureUpdateResourceIDs<gl::FenceNVID>(context, call, fences, resourceTracker,
1996                                                     callsOut);
1997             break;
1998         }
1999 
2000         case EntryPoint::GLGenFramebuffers:
2001         case EntryPoint::GLGenFramebuffersOES:
2002         {
2003             const ParamCapture &framebuffers =
2004                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
2005             CaptureUpdateResourceIDs<gl::FramebufferID>(context, call, framebuffers,
2006                                                         resourceTracker, callsOut);
2007             break;
2008         }
2009 
2010         case EntryPoint::GLGenProgramPipelines:
2011         {
2012             const ParamCapture &pipelines =
2013                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
2014             CaptureUpdateResourceIDs<gl::ProgramPipelineID>(context, call, pipelines,
2015                                                             resourceTracker, callsOut);
2016             break;
2017         }
2018 
2019         case EntryPoint::GLGenQueries:
2020         case EntryPoint::GLGenQueriesEXT:
2021         {
2022             const ParamCapture &queries =
2023                 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
2024             CaptureUpdateResourceIDs<gl::QueryID>(context, call, queries, resourceTracker,
2025                                                   callsOut);
2026             break;
2027         }
2028 
2029         case EntryPoint::GLGenRenderbuffers:
2030         case EntryPoint::GLGenRenderbuffersOES:
2031         {
2032             const ParamCapture &renderbuffers =
2033                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
2034             CaptureUpdateResourceIDs<gl::RenderbufferID>(context, call, renderbuffers,
2035                                                          resourceTracker, callsOut);
2036             break;
2037         }
2038 
2039         case EntryPoint::GLGenSamplers:
2040         {
2041             const ParamCapture &samplers =
2042                 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
2043             CaptureUpdateResourceIDs<gl::SamplerID>(context, call, samplers, resourceTracker,
2044                                                     callsOut);
2045             break;
2046         }
2047 
2048         case EntryPoint::GLGenSemaphoresEXT:
2049         {
2050             const ParamCapture &semaphores =
2051                 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
2052             CaptureUpdateResourceIDs<gl::SemaphoreID>(context, call, semaphores, resourceTracker,
2053                                                       callsOut);
2054             break;
2055         }
2056 
2057         case EntryPoint::GLGenTextures:
2058         {
2059             const ParamCapture &textures =
2060                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
2061             CaptureUpdateResourceIDs<gl::TextureID>(context, call, textures, resourceTracker,
2062                                                     callsOut);
2063             break;
2064         }
2065 
2066         case EntryPoint::GLGenTransformFeedbacks:
2067         {
2068             const ParamCapture &xfbs =
2069                 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
2070             CaptureUpdateResourceIDs<gl::TransformFeedbackID>(context, call, xfbs, resourceTracker,
2071                                                               callsOut);
2072             break;
2073         }
2074 
2075         case EntryPoint::GLGenVertexArrays:
2076         case EntryPoint::GLGenVertexArraysOES:
2077         {
2078             const ParamCapture &vertexArrays =
2079                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
2080             CaptureUpdateResourceIDs<gl::VertexArrayID>(context, call, vertexArrays,
2081                                                         resourceTracker, callsOut);
2082             break;
2083         }
2084 
2085         case EntryPoint::GLCreateMemoryObjectsEXT:
2086         {
2087             const ParamCapture &memoryObjects =
2088                 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
2089             CaptureUpdateResourceIDs<gl::MemoryObjectID>(context, call, memoryObjects,
2090                                                          resourceTracker, callsOut);
2091             break;
2092         }
2093 
2094         default:
2095             break;
2096     }
2097 }
2098 
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)2099 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
2100 {
2101     if (currentValue.Type != gl::VertexAttribType::Float)
2102         return false;
2103 
2104     return currentValue.Values.FloatValues[0] == 0.0f &&
2105            currentValue.Values.FloatValues[1] == 0.0f &&
2106            currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
2107 }
2108 
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)2109 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
2110 {
2111     const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
2112     for (const auto &activeQueryIter : activeQueries)
2113     {
2114         const gl::Query *activeQuery = activeQueryIter.get();
2115         if (activeQuery && activeQuery->id() == queryID)
2116         {
2117             return true;
2118         }
2119     }
2120 
2121     return false;
2122 }
2123 
IsTextureUpdate(CallCapture & call)2124 bool IsTextureUpdate(CallCapture &call)
2125 {
2126     switch (call.entryPoint)
2127     {
2128         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
2129         case EntryPoint::GLCompressedTexImage1D:
2130         case EntryPoint::GLCompressedTexImage2D:
2131         case EntryPoint::GLCompressedTexImage2DRobustANGLE:
2132         case EntryPoint::GLCompressedTexImage3D:
2133         case EntryPoint::GLCompressedTexImage3DOES:
2134         case EntryPoint::GLCompressedTexImage3DRobustANGLE:
2135         case EntryPoint::GLCompressedTexSubImage1D:
2136         case EntryPoint::GLCompressedTexSubImage2D:
2137         case EntryPoint::GLCompressedTexSubImage2DRobustANGLE:
2138         case EntryPoint::GLCompressedTexSubImage3D:
2139         case EntryPoint::GLCompressedTexSubImage3DOES:
2140         case EntryPoint::GLCompressedTexSubImage3DRobustANGLE:
2141         case EntryPoint::GLCompressedTextureSubImage1D:
2142         case EntryPoint::GLCompressedTextureSubImage2D:
2143         case EntryPoint::GLCompressedTextureSubImage3D:
2144         case EntryPoint::GLCopyTexImage1D:
2145         case EntryPoint::GLCopyTexImage2D:
2146         case EntryPoint::GLCopyTexSubImage1D:
2147         case EntryPoint::GLCopyTexSubImage2D:
2148         case EntryPoint::GLCopyTexSubImage3D:
2149         case EntryPoint::GLCopyTexSubImage3DOES:
2150         case EntryPoint::GLCopyTexture3DANGLE:
2151         case EntryPoint::GLCopyTextureCHROMIUM:
2152         case EntryPoint::GLCopyTextureSubImage1D:
2153         case EntryPoint::GLCopyTextureSubImage2D:
2154         case EntryPoint::GLCopyTextureSubImage3D:
2155         case EntryPoint::GLTexImage1D:
2156         case EntryPoint::GLTexImage2D:
2157         case EntryPoint::GLTexImage2DExternalANGLE:
2158         case EntryPoint::GLTexImage2DMultisample:
2159         case EntryPoint::GLTexImage2DRobustANGLE:
2160         case EntryPoint::GLTexImage3D:
2161         case EntryPoint::GLTexImage3DMultisample:
2162         case EntryPoint::GLTexImage3DOES:
2163         case EntryPoint::GLTexImage3DRobustANGLE:
2164         case EntryPoint::GLTexSubImage1D:
2165         case EntryPoint::GLTexSubImage2D:
2166         case EntryPoint::GLTexSubImage2DRobustANGLE:
2167         case EntryPoint::GLTexSubImage3D:
2168         case EntryPoint::GLTexSubImage3DOES:
2169         case EntryPoint::GLTexSubImage3DRobustANGLE:
2170         case EntryPoint::GLTextureSubImage1D:
2171         case EntryPoint::GLTextureSubImage2D:
2172         case EntryPoint::GLTextureSubImage3D:
2173         case EntryPoint::GLCopyImageSubData:
2174         case EntryPoint::GLCopyImageSubDataEXT:
2175         case EntryPoint::GLCopyImageSubDataOES:
2176             return true;
2177         default:
2178             return false;
2179     }
2180 }
2181 
IsVertexArrayUpdate(CallCapture & call)2182 bool IsVertexArrayUpdate(CallCapture &call)
2183 {
2184     switch (call.entryPoint)
2185     {
2186         case EntryPoint::GLVertexAttribFormat:
2187         case EntryPoint::GLVertexAttribIFormat:
2188         case EntryPoint::GLBindVertexBuffer:
2189         case EntryPoint::GLVertexAttribBinding:
2190         case EntryPoint::GLVertexAttribPointer:
2191         case EntryPoint::GLVertexAttribIPointer:
2192         case EntryPoint::GLEnableVertexAttribArray:
2193         case EntryPoint::GLDisableVertexAttribArray:
2194         case EntryPoint::GLVertexBindingDivisor:
2195         case EntryPoint::GLVertexAttribDivisor:
2196             return true;
2197         default:
2198             return false;
2199     }
2200 }
2201 
IsSharedObjectResource(ResourceIDType type)2202 bool IsSharedObjectResource(ResourceIDType type)
2203 {
2204     // This helper function informs us which objects are shared vs. per context
2205     //
2206     //   OpenGL ES Version 3.2 (October 22, 2019)
2207     //   Chapter 5 Shared Objects and Multiple Contexts:
2208     //
2209     //   - Objects that can be shared between contexts include buffer objects, program
2210     //     and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
2211     //     objects (except for the texture objects named zero).
2212     //   - Objects which contain references to other objects include framebuffer, program
2213     //     pipeline, transform feedback, and vertex array objects. Such objects are called
2214     //     container objects and are not shared.
2215     //
2216     // Notably absent from this list are Sync objects, which are not ResourceIDType, are handled
2217     // elsewhere, and are shared:
2218     //   - 2.6.13 Sync Objects: Sync objects may be shared.
2219 
2220     switch (type)
2221     {
2222         case ResourceIDType::Buffer:
2223             // 2.6.2 Buffer Objects: Buffer objects may be shared.
2224             return true;
2225 
2226         case ResourceIDType::Framebuffer:
2227             // 2.6.9 Framebuffer Objects: Framebuffer objects are container objects including
2228             // references to renderbuffer and / or texture objects, and are not shared.
2229             return false;
2230 
2231         case ResourceIDType::ProgramPipeline:
2232             // 2.6.5 Program Pipeline Objects: Program pipeline objects are container objects
2233             // including references to program objects, and are not shared.
2234             return false;
2235 
2236         case ResourceIDType::TransformFeedback:
2237             // 2.6.11 Transform Feedback Objects: Transform feedback objects are container objects
2238             // including references to buffer objects, and are not shared
2239             return false;
2240 
2241         case ResourceIDType::VertexArray:
2242             // 2.6.10 Vertex Array Objects: Vertex array objects are container objects including
2243             // references to buffer objects, and are not shared
2244             return false;
2245 
2246         case ResourceIDType::FenceNV:
2247             // From https://registry.khronos.org/OpenGL/extensions/NV/NV_fence.txt
2248             //  Are the fences sharable between multiple contexts?
2249             //   RESOLUTION: No.
2250             return false;
2251 
2252         case ResourceIDType::Renderbuffer:
2253             // 2.6.8 Renderbuffer Objects: Renderbuffer objects may be shared.
2254             return true;
2255 
2256         case ResourceIDType::ShaderProgram:
2257             // 2.6.3 Shader Objects: Shader objects may be shared.
2258             // 2.6.4 Program Objects: Program objects may be shared.
2259             return true;
2260 
2261         case ResourceIDType::Sampler:
2262             // 2.6.7 Sampler Objects: Sampler objects may be shared
2263             return true;
2264 
2265         case ResourceIDType::Sync:
2266             // 2.6.13 Sync Objects: Sync objects may be shared.
2267             return true;
2268 
2269         case ResourceIDType::Texture:
2270             // 2.6.6 Texture Objects: Texture objects may be shared
2271             return true;
2272 
2273         case ResourceIDType::Query:
2274             // 2.6.12 Query Objects: Query objects are not shared
2275             return false;
2276 
2277         case ResourceIDType::Semaphore:
2278             // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2279             // 2.6.14 Semaphore Objects: Semaphore objects may be shared.
2280             return true;
2281 
2282         case ResourceIDType::MemoryObject:
2283             // From https://registry.khronos.org/OpenGL/extensions/EXT/EXT_external_objects.txt
2284             // 2.6.15 Memory Objects: Memory objects may be shared.
2285             return true;
2286 
2287         case ResourceIDType::Context:
2288         case ResourceIDType::Image:
2289         case ResourceIDType::Surface:
2290         case ResourceIDType::egl_Sync:
2291             // EGL types are associated with a display and not bound to a context
2292             // For the way this function is used, we can treat them as shared.
2293             return true;
2294 
2295         case ResourceIDType::EnumCount:
2296         default:
2297             ERR() << "Unhandled ResourceIDType= " << static_cast<int>(type);
2298             UNREACHABLE();
2299             return false;
2300     }
2301 }
2302 
2303 enum class DefaultUniformType
2304 {
2305     None,
2306     CurrentProgram,
2307     SpecifiedProgram,
2308 };
2309 
GetDefaultUniformType(const CallCapture & call)2310 DefaultUniformType GetDefaultUniformType(const CallCapture &call)
2311 {
2312     switch (call.entryPoint)
2313     {
2314         case EntryPoint::GLProgramUniform1d:
2315         case EntryPoint::GLProgramUniform1dv:
2316         case EntryPoint::GLProgramUniform1f:
2317         case EntryPoint::GLProgramUniform1fEXT:
2318         case EntryPoint::GLProgramUniform1fv:
2319         case EntryPoint::GLProgramUniform1fvEXT:
2320         case EntryPoint::GLProgramUniform1i:
2321         case EntryPoint::GLProgramUniform1iEXT:
2322         case EntryPoint::GLProgramUniform1iv:
2323         case EntryPoint::GLProgramUniform1ivEXT:
2324         case EntryPoint::GLProgramUniform1ui:
2325         case EntryPoint::GLProgramUniform1uiEXT:
2326         case EntryPoint::GLProgramUniform1uiv:
2327         case EntryPoint::GLProgramUniform1uivEXT:
2328         case EntryPoint::GLProgramUniform2d:
2329         case EntryPoint::GLProgramUniform2dv:
2330         case EntryPoint::GLProgramUniform2f:
2331         case EntryPoint::GLProgramUniform2fEXT:
2332         case EntryPoint::GLProgramUniform2fv:
2333         case EntryPoint::GLProgramUniform2fvEXT:
2334         case EntryPoint::GLProgramUniform2i:
2335         case EntryPoint::GLProgramUniform2iEXT:
2336         case EntryPoint::GLProgramUniform2iv:
2337         case EntryPoint::GLProgramUniform2ivEXT:
2338         case EntryPoint::GLProgramUniform2ui:
2339         case EntryPoint::GLProgramUniform2uiEXT:
2340         case EntryPoint::GLProgramUniform2uiv:
2341         case EntryPoint::GLProgramUniform2uivEXT:
2342         case EntryPoint::GLProgramUniform3d:
2343         case EntryPoint::GLProgramUniform3dv:
2344         case EntryPoint::GLProgramUniform3f:
2345         case EntryPoint::GLProgramUniform3fEXT:
2346         case EntryPoint::GLProgramUniform3fv:
2347         case EntryPoint::GLProgramUniform3fvEXT:
2348         case EntryPoint::GLProgramUniform3i:
2349         case EntryPoint::GLProgramUniform3iEXT:
2350         case EntryPoint::GLProgramUniform3iv:
2351         case EntryPoint::GLProgramUniform3ivEXT:
2352         case EntryPoint::GLProgramUniform3ui:
2353         case EntryPoint::GLProgramUniform3uiEXT:
2354         case EntryPoint::GLProgramUniform3uiv:
2355         case EntryPoint::GLProgramUniform3uivEXT:
2356         case EntryPoint::GLProgramUniform4d:
2357         case EntryPoint::GLProgramUniform4dv:
2358         case EntryPoint::GLProgramUniform4f:
2359         case EntryPoint::GLProgramUniform4fEXT:
2360         case EntryPoint::GLProgramUniform4fv:
2361         case EntryPoint::GLProgramUniform4fvEXT:
2362         case EntryPoint::GLProgramUniform4i:
2363         case EntryPoint::GLProgramUniform4iEXT:
2364         case EntryPoint::GLProgramUniform4iv:
2365         case EntryPoint::GLProgramUniform4ivEXT:
2366         case EntryPoint::GLProgramUniform4ui:
2367         case EntryPoint::GLProgramUniform4uiEXT:
2368         case EntryPoint::GLProgramUniform4uiv:
2369         case EntryPoint::GLProgramUniform4uivEXT:
2370         case EntryPoint::GLProgramUniformMatrix2dv:
2371         case EntryPoint::GLProgramUniformMatrix2fv:
2372         case EntryPoint::GLProgramUniformMatrix2fvEXT:
2373         case EntryPoint::GLProgramUniformMatrix2x3dv:
2374         case EntryPoint::GLProgramUniformMatrix2x3fv:
2375         case EntryPoint::GLProgramUniformMatrix2x3fvEXT:
2376         case EntryPoint::GLProgramUniformMatrix2x4dv:
2377         case EntryPoint::GLProgramUniformMatrix2x4fv:
2378         case EntryPoint::GLProgramUniformMatrix2x4fvEXT:
2379         case EntryPoint::GLProgramUniformMatrix3dv:
2380         case EntryPoint::GLProgramUniformMatrix3fv:
2381         case EntryPoint::GLProgramUniformMatrix3fvEXT:
2382         case EntryPoint::GLProgramUniformMatrix3x2dv:
2383         case EntryPoint::GLProgramUniformMatrix3x2fv:
2384         case EntryPoint::GLProgramUniformMatrix3x2fvEXT:
2385         case EntryPoint::GLProgramUniformMatrix3x4dv:
2386         case EntryPoint::GLProgramUniformMatrix3x4fv:
2387         case EntryPoint::GLProgramUniformMatrix3x4fvEXT:
2388         case EntryPoint::GLProgramUniformMatrix4dv:
2389         case EntryPoint::GLProgramUniformMatrix4fv:
2390         case EntryPoint::GLProgramUniformMatrix4fvEXT:
2391         case EntryPoint::GLProgramUniformMatrix4x2dv:
2392         case EntryPoint::GLProgramUniformMatrix4x2fv:
2393         case EntryPoint::GLProgramUniformMatrix4x2fvEXT:
2394         case EntryPoint::GLProgramUniformMatrix4x3dv:
2395         case EntryPoint::GLProgramUniformMatrix4x3fv:
2396         case EntryPoint::GLProgramUniformMatrix4x3fvEXT:
2397             return DefaultUniformType::SpecifiedProgram;
2398 
2399         case EntryPoint::GLUniform1d:
2400         case EntryPoint::GLUniform1dv:
2401         case EntryPoint::GLUniform1f:
2402         case EntryPoint::GLUniform1fv:
2403         case EntryPoint::GLUniform1i:
2404         case EntryPoint::GLUniform1iv:
2405         case EntryPoint::GLUniform1ui:
2406         case EntryPoint::GLUniform1uiv:
2407         case EntryPoint::GLUniform2d:
2408         case EntryPoint::GLUniform2dv:
2409         case EntryPoint::GLUniform2f:
2410         case EntryPoint::GLUniform2fv:
2411         case EntryPoint::GLUniform2i:
2412         case EntryPoint::GLUniform2iv:
2413         case EntryPoint::GLUniform2ui:
2414         case EntryPoint::GLUniform2uiv:
2415         case EntryPoint::GLUniform3d:
2416         case EntryPoint::GLUniform3dv:
2417         case EntryPoint::GLUniform3f:
2418         case EntryPoint::GLUniform3fv:
2419         case EntryPoint::GLUniform3i:
2420         case EntryPoint::GLUniform3iv:
2421         case EntryPoint::GLUniform3ui:
2422         case EntryPoint::GLUniform3uiv:
2423         case EntryPoint::GLUniform4d:
2424         case EntryPoint::GLUniform4dv:
2425         case EntryPoint::GLUniform4f:
2426         case EntryPoint::GLUniform4fv:
2427         case EntryPoint::GLUniform4i:
2428         case EntryPoint::GLUniform4iv:
2429         case EntryPoint::GLUniform4ui:
2430         case EntryPoint::GLUniform4uiv:
2431         case EntryPoint::GLUniformMatrix2dv:
2432         case EntryPoint::GLUniformMatrix2fv:
2433         case EntryPoint::GLUniformMatrix2x3dv:
2434         case EntryPoint::GLUniformMatrix2x3fv:
2435         case EntryPoint::GLUniformMatrix2x4dv:
2436         case EntryPoint::GLUniformMatrix2x4fv:
2437         case EntryPoint::GLUniformMatrix3dv:
2438         case EntryPoint::GLUniformMatrix3fv:
2439         case EntryPoint::GLUniformMatrix3x2dv:
2440         case EntryPoint::GLUniformMatrix3x2fv:
2441         case EntryPoint::GLUniformMatrix3x4dv:
2442         case EntryPoint::GLUniformMatrix3x4fv:
2443         case EntryPoint::GLUniformMatrix4dv:
2444         case EntryPoint::GLUniformMatrix4fv:
2445         case EntryPoint::GLUniformMatrix4x2dv:
2446         case EntryPoint::GLUniformMatrix4x2fv:
2447         case EntryPoint::GLUniformMatrix4x3dv:
2448         case EntryPoint::GLUniformMatrix4x3fv:
2449         case EntryPoint::GLUniformSubroutinesuiv:
2450             return DefaultUniformType::CurrentProgram;
2451 
2452         default:
2453             return DefaultUniformType::None;
2454     }
2455 }
2456 
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const FramebufferCaptureFuncs & framebufferFuncs,const gl::FramebufferAttachment & attachment)2457 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
2458                                   const gl::State &replayState,
2459                                   const FramebufferCaptureFuncs &framebufferFuncs,
2460                                   const gl::FramebufferAttachment &attachment)
2461 {
2462     GLuint resourceID = attachment.getResource()->getId();
2463 
2464     if (attachment.type() == GL_TEXTURE)
2465     {
2466         gl::ImageIndex index = attachment.getTextureImageIndex();
2467 
2468         if (index.usesTex3D())
2469         {
2470             Capture(setupCalls, CaptureFramebufferTextureLayer(
2471                                     replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2472                                     {resourceID}, index.getLevelIndex(), index.getLayerIndex()));
2473         }
2474         else
2475         {
2476             Capture(setupCalls,
2477                     framebufferFuncs.framebufferTexture2D(
2478                         replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2479                         index.getTargetOrFirstCubeFace(), {resourceID}, index.getLevelIndex()));
2480         }
2481     }
2482     else
2483     {
2484         ASSERT(attachment.type() == GL_RENDERBUFFER);
2485         Capture(setupCalls, framebufferFuncs.framebufferRenderbuffer(
2486                                 replayState, true, GL_FRAMEBUFFER, attachment.getBinding(),
2487                                 GL_RENDERBUFFER, {resourceID}));
2488     }
2489 }
2490 
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,gl::Program * program,ResourceTracker * resourceTracker,std::vector<CallCapture> * callsOut)2491 void CaptureUpdateUniformValues(const gl::State &replayState,
2492                                 const gl::Context *context,
2493                                 gl::Program *program,
2494                                 ResourceTracker *resourceTracker,
2495                                 std::vector<CallCapture> *callsOut)
2496 {
2497     if (!program->isLinked())
2498     {
2499         // We can't populate uniforms if the program hasn't been linked
2500         return;
2501     }
2502 
2503     // We need to bind the program and update its uniforms
2504     if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
2505     {
2506         Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
2507         CaptureUpdateCurrentProgram(callsOut->back(), 0, callsOut);
2508     }
2509 
2510     const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
2511 
2512     for (const gl::LinkedUniform &uniform : uniforms)
2513     {
2514         std::string uniformName = uniform.name;
2515 
2516         int uniformCount = 1;
2517         if (uniform.isArray())
2518         {
2519             if (uniform.isArrayOfArrays())
2520             {
2521                 UNIMPLEMENTED();
2522                 continue;
2523             }
2524 
2525             uniformCount = uniform.arraySizes[0];
2526             uniformName  = gl::StripLastArrayIndex(uniformName);
2527         }
2528 
2529         gl::UniformLocation uniformLoc      = program->getUniformLocation(uniformName);
2530         const gl::UniformTypeInfo *typeInfo = uniform.typeInfo;
2531         int componentCount                  = typeInfo->componentCount;
2532         int uniformSize                     = uniformCount * componentCount;
2533 
2534         // For arrayed uniforms, we'll need to increment a read location
2535         gl::UniformLocation readLoc = uniformLoc;
2536 
2537         // If the uniform is unused, just continue
2538         if (readLoc.value == -1)
2539         {
2540             continue;
2541         }
2542 
2543         // Image uniforms are special and cannot be set this way
2544         if (typeInfo->isImageType)
2545         {
2546             continue;
2547         }
2548 
2549         DefaultUniformCallsPerLocationMap &resetCalls =
2550             resourceTracker->getDefaultUniformResetCalls(program->id());
2551 
2552         // Create two lists of calls for uniforms, one for Setup, one for Reset
2553         CallVector defaultUniformCalls({callsOut, &resetCalls[uniformLoc]});
2554 
2555         // Samplers should be populated with GL_INT, regardless of return type
2556         if (typeInfo->isSampler)
2557         {
2558             std::vector<GLint> uniformBuffer(uniformSize);
2559             for (int index = 0; index < uniformCount; index++, readLoc.value++)
2560             {
2561                 program->getUniformiv(context, readLoc,
2562                                       uniformBuffer.data() + index * componentCount);
2563                 resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc, uniformLoc);
2564             }
2565 
2566             for (std::vector<CallCapture> *calls : defaultUniformCalls)
2567             {
2568                 Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
2569                                                  uniformBuffer.data()));
2570             }
2571 
2572             continue;
2573         }
2574 
2575         switch (typeInfo->componentType)
2576         {
2577             case GL_FLOAT:
2578             {
2579                 std::vector<GLfloat> uniformBuffer(uniformSize);
2580                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2581                 {
2582                     program->getUniformfv(context, readLoc,
2583                                           uniformBuffer.data() + index * componentCount);
2584                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2585                                                                    uniformLoc);
2586                 }
2587                 switch (typeInfo->type)
2588                 {
2589                     // Note: All matrix uniforms are populated without transpose
2590                     case GL_FLOAT_MAT4x3:
2591                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2592                         {
2593                             Capture(calls, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
2594                                                                      uniformCount, false,
2595                                                                      uniformBuffer.data()));
2596                         }
2597                         break;
2598                     case GL_FLOAT_MAT4x2:
2599                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2600                         {
2601                             Capture(calls, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
2602                                                                      uniformCount, false,
2603                                                                      uniformBuffer.data()));
2604                         }
2605                         break;
2606                     case GL_FLOAT_MAT4:
2607                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2608                         {
2609                             Capture(calls, CaptureUniformMatrix4fv(replayState, true, uniformLoc,
2610                                                                    uniformCount, false,
2611                                                                    uniformBuffer.data()));
2612                         }
2613                         break;
2614                     case GL_FLOAT_MAT3x4:
2615                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2616                         {
2617                             Capture(calls, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
2618                                                                      uniformCount, false,
2619                                                                      uniformBuffer.data()));
2620                         }
2621                         break;
2622                     case GL_FLOAT_MAT3x2:
2623                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2624                         {
2625                             Capture(calls, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
2626                                                                      uniformCount, false,
2627                                                                      uniformBuffer.data()));
2628                         }
2629                         break;
2630                     case GL_FLOAT_MAT3:
2631                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2632                         {
2633                             Capture(calls, CaptureUniformMatrix3fv(replayState, true, uniformLoc,
2634                                                                    uniformCount, false,
2635                                                                    uniformBuffer.data()));
2636                         }
2637                         break;
2638                     case GL_FLOAT_MAT2x4:
2639                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2640                         {
2641                             Capture(calls, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
2642                                                                      uniformCount, false,
2643                                                                      uniformBuffer.data()));
2644                         }
2645                         break;
2646                     case GL_FLOAT_MAT2x3:
2647                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2648                         {
2649                             Capture(calls, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
2650                                                                      uniformCount, false,
2651                                                                      uniformBuffer.data()));
2652                         }
2653                         break;
2654                     case GL_FLOAT_MAT2:
2655                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2656                         {
2657                             Capture(calls, CaptureUniformMatrix2fv(replayState, true, uniformLoc,
2658                                                                    uniformCount, false,
2659                                                                    uniformBuffer.data()));
2660                         }
2661                         break;
2662                     case GL_FLOAT_VEC4:
2663                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2664                         {
2665                             Capture(calls, CaptureUniform4fv(replayState, true, uniformLoc,
2666                                                              uniformCount, uniformBuffer.data()));
2667                         }
2668                         break;
2669                     case GL_FLOAT_VEC3:
2670                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2671                         {
2672                             Capture(calls, CaptureUniform3fv(replayState, true, uniformLoc,
2673                                                              uniformCount, uniformBuffer.data()));
2674                         }
2675                         break;
2676                     case GL_FLOAT_VEC2:
2677                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2678                         {
2679                             Capture(calls, CaptureUniform2fv(replayState, true, uniformLoc,
2680                                                              uniformCount, uniformBuffer.data()));
2681                         }
2682                         break;
2683                     case GL_FLOAT:
2684                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2685                         {
2686                             Capture(calls, CaptureUniform1fv(replayState, true, uniformLoc,
2687                                                              uniformCount, uniformBuffer.data()));
2688                         }
2689                         break;
2690                     default:
2691                         UNIMPLEMENTED();
2692                         break;
2693                 }
2694                 break;
2695             }
2696             case GL_INT:
2697             {
2698                 std::vector<GLint> uniformBuffer(uniformSize);
2699                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2700                 {
2701                     program->getUniformiv(context, readLoc,
2702                                           uniformBuffer.data() + index * componentCount);
2703                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2704                                                                    uniformLoc);
2705                 }
2706                 switch (componentCount)
2707                 {
2708                     case 4:
2709                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2710                         {
2711                             Capture(calls, CaptureUniform4iv(replayState, true, uniformLoc,
2712                                                              uniformCount, uniformBuffer.data()));
2713                         }
2714                         break;
2715                     case 3:
2716                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2717                         {
2718                             Capture(calls, CaptureUniform3iv(replayState, true, uniformLoc,
2719                                                              uniformCount, uniformBuffer.data()));
2720                         }
2721                         break;
2722                     case 2:
2723                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2724                         {
2725                             Capture(calls, CaptureUniform2iv(replayState, true, uniformLoc,
2726                                                              uniformCount, uniformBuffer.data()));
2727                         }
2728                         break;
2729                     case 1:
2730                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2731                         {
2732                             Capture(calls, CaptureUniform1iv(replayState, true, uniformLoc,
2733                                                              uniformCount, uniformBuffer.data()));
2734                         }
2735                         break;
2736                     default:
2737                         UNIMPLEMENTED();
2738                         break;
2739                 }
2740                 break;
2741             }
2742             case GL_BOOL:
2743             case GL_UNSIGNED_INT:
2744             {
2745                 std::vector<GLuint> uniformBuffer(uniformSize);
2746                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
2747                 {
2748                     program->getUniformuiv(context, readLoc,
2749                                            uniformBuffer.data() + index * componentCount);
2750                     resourceTracker->setDefaultUniformBaseLocation(program->id(), readLoc,
2751                                                                    uniformLoc);
2752                 }
2753                 switch (componentCount)
2754                 {
2755                     case 4:
2756                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2757                         {
2758                             Capture(calls, CaptureUniform4uiv(replayState, true, uniformLoc,
2759                                                               uniformCount, uniformBuffer.data()));
2760                         }
2761                         break;
2762                     case 3:
2763                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2764                         {
2765                             Capture(calls, CaptureUniform3uiv(replayState, true, uniformLoc,
2766                                                               uniformCount, uniformBuffer.data()));
2767                         }
2768                         break;
2769                     case 2:
2770                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2771                         {
2772                             Capture(calls, CaptureUniform2uiv(replayState, true, uniformLoc,
2773                                                               uniformCount, uniformBuffer.data()));
2774                         }
2775                         break;
2776                     case 1:
2777                         for (std::vector<CallCapture> *calls : defaultUniformCalls)
2778                         {
2779                             Capture(calls, CaptureUniform1uiv(replayState, true, uniformLoc,
2780                                                               uniformCount, uniformBuffer.data()));
2781                         }
2782                         break;
2783                     default:
2784                         UNIMPLEMENTED();
2785                         break;
2786                 }
2787                 break;
2788             }
2789             default:
2790                 UNIMPLEMENTED();
2791                 break;
2792         }
2793     }
2794 }
2795 
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2796 void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
2797                              gl::State *replayState,
2798                              GLuint attribIndex,
2799                              const gl::VertexAttribute &attrib,
2800                              const gl::VertexBinding &binding)
2801 {
2802     switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
2803     {
2804         case gl::ClientVertexArrayType::Vertex:
2805             Capture(setupCalls,
2806                     CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
2807                                          attrib.format->vertexAttribType, binding.getStride(),
2808                                          attrib.pointer));
2809             break;
2810         case gl::ClientVertexArrayType::Normal:
2811             Capture(setupCalls,
2812                     CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
2813                                          binding.getStride(), attrib.pointer));
2814             break;
2815         case gl::ClientVertexArrayType::Color:
2816             Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
2817                                                     attrib.format->vertexAttribType,
2818                                                     binding.getStride(), attrib.pointer));
2819             break;
2820         case gl::ClientVertexArrayType::PointSize:
2821             Capture(setupCalls,
2822                     CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
2823                                                binding.getStride(), attrib.pointer));
2824             break;
2825         case gl::ClientVertexArrayType::TextureCoord:
2826             Capture(setupCalls,
2827                     CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
2828                                            attrib.format->vertexAttribType, binding.getStride(),
2829                                            attrib.pointer));
2830             break;
2831         default:
2832             UNREACHABLE();
2833     }
2834 }
2835 
CaptureTextureEnvironmentState(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::State * apiState,unsigned int unit)2836 void CaptureTextureEnvironmentState(std::vector<CallCapture> *setupCalls,
2837                                     gl::State *replayState,
2838                                     const gl::State *apiState,
2839                                     unsigned int unit)
2840 {
2841     const gl::TextureEnvironmentParameters &currentEnv = apiState->gles1().textureEnvironment(unit);
2842     const gl::TextureEnvironmentParameters &defaultEnv =
2843         replayState->gles1().textureEnvironment(unit);
2844 
2845     if (currentEnv == defaultEnv)
2846     {
2847         return;
2848     }
2849 
2850     auto capIfNe = [setupCalls](auto currentState, auto defaultState, CallCapture &&call) {
2851         if (currentState != defaultState)
2852         {
2853             setupCalls->emplace_back(std::move(call));
2854         }
2855     };
2856 
2857     // When the texture env state differs on a non-default sampler unit, emit an ActiveTexture call.
2858     // The default sampler unit is GL_TEXTURE0.
2859     GLenum currentUnit = GL_TEXTURE0 + static_cast<GLenum>(unit);
2860     GLenum defaultUnit = GL_TEXTURE0 + static_cast<GLenum>(replayState->getActiveSampler());
2861     capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, currentUnit));
2862 
2863     auto capEnum = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
2864                                           auto defaultState) {
2865         capIfNe(currentState, defaultState,
2866                 CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::Env, pname,
2867                                ToGLenum(currentState)));
2868     };
2869 
2870     capEnum(gl::TextureEnvParameter::Mode, currentEnv.mode, defaultEnv.mode);
2871 
2872     capEnum(gl::TextureEnvParameter::CombineRgb, currentEnv.combineRgb, defaultEnv.combineRgb);
2873     capEnum(gl::TextureEnvParameter::CombineAlpha, currentEnv.combineAlpha,
2874             defaultEnv.combineAlpha);
2875 
2876     capEnum(gl::TextureEnvParameter::Src0Rgb, currentEnv.src0Rgb, defaultEnv.src0Rgb);
2877     capEnum(gl::TextureEnvParameter::Src1Rgb, currentEnv.src1Rgb, defaultEnv.src1Rgb);
2878     capEnum(gl::TextureEnvParameter::Src2Rgb, currentEnv.src2Rgb, defaultEnv.src2Rgb);
2879 
2880     capEnum(gl::TextureEnvParameter::Src0Alpha, currentEnv.src0Alpha, defaultEnv.src0Alpha);
2881     capEnum(gl::TextureEnvParameter::Src1Alpha, currentEnv.src1Alpha, defaultEnv.src1Alpha);
2882     capEnum(gl::TextureEnvParameter::Src2Alpha, currentEnv.src2Alpha, defaultEnv.src2Alpha);
2883 
2884     capEnum(gl::TextureEnvParameter::Op0Rgb, currentEnv.op0Rgb, defaultEnv.op0Rgb);
2885     capEnum(gl::TextureEnvParameter::Op1Rgb, currentEnv.op1Rgb, defaultEnv.op1Rgb);
2886     capEnum(gl::TextureEnvParameter::Op2Rgb, currentEnv.op2Rgb, defaultEnv.op2Rgb);
2887 
2888     capEnum(gl::TextureEnvParameter::Op0Alpha, currentEnv.op0Alpha, defaultEnv.op0Alpha);
2889     capEnum(gl::TextureEnvParameter::Op1Alpha, currentEnv.op1Alpha, defaultEnv.op1Alpha);
2890     capEnum(gl::TextureEnvParameter::Op2Alpha, currentEnv.op2Alpha, defaultEnv.op2Alpha);
2891 
2892     auto capFloat = [capIfNe, replayState](gl::TextureEnvParameter pname, auto currentState,
2893                                            auto defaultState) {
2894         capIfNe(currentState, defaultState,
2895                 CaptureTexEnvf(*replayState, true, gl::TextureEnvTarget::Env, pname, currentState));
2896     };
2897 
2898     capFloat(gl::TextureEnvParameter::RgbScale, currentEnv.rgbScale, defaultEnv.rgbScale);
2899     capFloat(gl::TextureEnvParameter::AlphaScale, currentEnv.alphaScale, defaultEnv.alphaScale);
2900 
2901     capIfNe(currentEnv.color, defaultEnv.color,
2902             CaptureTexEnvfv(*replayState, true, gl::TextureEnvTarget::Env,
2903                             gl::TextureEnvParameter::Color, currentEnv.color.data()));
2904 
2905     // PointCoordReplace is the only parameter that uses the PointSprite TextureEnvTarget.
2906     capIfNe(currentEnv.pointSpriteCoordReplace, defaultEnv.pointSpriteCoordReplace,
2907             CaptureTexEnvi(*replayState, true, gl::TextureEnvTarget::PointSprite,
2908                            gl::TextureEnvParameter::PointCoordReplace,
2909                            currentEnv.pointSpriteCoordReplace));
2910 
2911     // In case of non-default sampler units, the default unit must be set back here.
2912     capIfNe(currentUnit, defaultUnit, CaptureActiveTexture(*replayState, true, defaultUnit));
2913 }
2914 
VertexBindingMatchesAttribStride(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)2915 bool VertexBindingMatchesAttribStride(const gl::VertexAttribute &attrib,
2916                                       const gl::VertexBinding &binding)
2917 {
2918     if (attrib.vertexAttribArrayStride == 0 &&
2919         binding.getStride() == ComputeVertexAttributeTypeSize(attrib))
2920     {
2921         return true;
2922     }
2923 
2924     return attrib.vertexAttribArrayStride == binding.getStride();
2925 }
2926 
CaptureVertexArrayState(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)2927 void CaptureVertexArrayState(std::vector<CallCapture> *setupCalls,
2928                              const gl::Context *context,
2929                              const gl::VertexArray *vertexArray,
2930                              gl::State *replayState)
2931 {
2932     const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
2933     const std::vector<gl::VertexBinding> &vertexBindings  = vertexArray->getVertexBindings();
2934 
2935     gl::AttributesMask vertexPointerBindings;
2936 
2937     ASSERT(vertexAttribs.size() <= vertexBindings.size());
2938     for (GLuint attribIndex = 0; attribIndex < vertexAttribs.size(); ++attribIndex)
2939     {
2940         const gl::VertexAttribute defaultAttrib(attribIndex);
2941         const gl::VertexBinding defaultBinding;
2942 
2943         const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
2944         const gl::VertexBinding &binding  = vertexBindings[attrib.bindingIndex];
2945 
2946         if (attrib.enabled != defaultAttrib.enabled)
2947         {
2948             if (context->isGLES1())
2949             {
2950                 Capture(setupCalls,
2951                         CaptureEnableClientState(*replayState, false,
2952                                                  gl::GLES1Renderer::VertexArrayType(attribIndex)));
2953             }
2954             else
2955             {
2956                 Capture(setupCalls,
2957                         CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
2958             }
2959         }
2960 
2961         // Don't capture CaptureVertexAttribPointer calls when a non-default VAO is bound, the array
2962         // buffer is null and a non-null attrib pointer is used.
2963         bool skipInvalidAttrib = vertexArray->id().value != 0 &&
2964                                  binding.getBuffer().get() == nullptr && attrib.pointer != nullptr;
2965 
2966         if (!skipInvalidAttrib &&
2967             (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
2968              binding.getStride() != defaultBinding.getStride() ||
2969              attrib.bindingIndex != defaultAttrib.bindingIndex ||
2970              binding.getBuffer().get() != nullptr))
2971         {
2972             // Each attribute can pull from a separate buffer, so check the binding
2973             gl::Buffer *buffer = binding.getBuffer().get();
2974             if (buffer != replayState->getArrayBuffer())
2975             {
2976                 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
2977 
2978                 gl::BufferID bufferID = {0};
2979                 if (buffer)
2980                 {
2981                     bufferID = buffer->id();
2982                 }
2983                 Capture(setupCalls,
2984                         CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array, bufferID));
2985             }
2986 
2987             // Establish the relationship between currently bound buffer and the VAO
2988             if (context->isGLES1())
2989             {
2990                 // Track indexes that used ES1 calls
2991                 vertexPointerBindings.set(attribIndex);
2992 
2993                 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
2994             }
2995             else if (attrib.bindingIndex == attribIndex &&
2996                      VertexBindingMatchesAttribStride(attrib, binding) &&
2997                      (!buffer || binding.getOffset() == reinterpret_cast<GLintptr>(attrib.pointer)))
2998             {
2999                 // Check if we can use strictly ES2 semantics, and track indexes that do.
3000                 vertexPointerBindings.set(attribIndex);
3001 
3002                 if (attrib.format->isPureInt())
3003                 {
3004                     Capture(setupCalls, CaptureVertexAttribIPointer(*replayState, true, attribIndex,
3005                                                                     attrib.format->channelCount,
3006                                                                     attrib.format->vertexAttribType,
3007                                                                     attrib.vertexAttribArrayStride,
3008                                                                     attrib.pointer));
3009                 }
3010                 else
3011                 {
3012                     Capture(setupCalls,
3013                             CaptureVertexAttribPointer(
3014                                 *replayState, true, attribIndex, attrib.format->channelCount,
3015                                 attrib.format->vertexAttribType, attrib.format->isNorm(),
3016                                 attrib.vertexAttribArrayStride, attrib.pointer));
3017                 }
3018 
3019                 if (binding.getDivisor() != 0)
3020                 {
3021                     Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
3022                                                                    binding.getDivisor()));
3023                 }
3024             }
3025             else
3026             {
3027                 ASSERT(context->getClientVersion() >= gl::ES_3_1);
3028 
3029                 if (attrib.format->isPureInt())
3030                 {
3031                     Capture(setupCalls, CaptureVertexAttribIFormat(*replayState, true, attribIndex,
3032                                                                    attrib.format->channelCount,
3033                                                                    attrib.format->vertexAttribType,
3034                                                                    attrib.relativeOffset));
3035                 }
3036                 else
3037                 {
3038                     Capture(setupCalls, CaptureVertexAttribFormat(*replayState, true, attribIndex,
3039                                                                   attrib.format->channelCount,
3040                                                                   attrib.format->vertexAttribType,
3041                                                                   attrib.format->isNorm(),
3042                                                                   attrib.relativeOffset));
3043                 }
3044 
3045                 Capture(setupCalls, CaptureVertexAttribBinding(*replayState, true, attribIndex,
3046                                                                attrib.bindingIndex));
3047             }
3048         }
3049     }
3050 
3051     // The loop below expects attribs and bindings to have equal counts
3052     static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
3053                   "Max vertex attribs and bindings count mismatch");
3054 
3055     // Loop through binding indices that weren't used by VertexAttribPointer
3056     for (size_t bindingIndex : vertexPointerBindings.flip())
3057     {
3058         const gl::VertexBinding &binding = vertexBindings[bindingIndex];
3059 
3060         if (binding.getBuffer().id().value != 0)
3061         {
3062             Capture(setupCalls,
3063                     CaptureBindVertexBuffer(*replayState, true, static_cast<GLuint>(bindingIndex),
3064                                             binding.getBuffer().id(), binding.getOffset(),
3065                                             binding.getStride()));
3066         }
3067 
3068         if (binding.getDivisor() != 0)
3069         {
3070             Capture(setupCalls, CaptureVertexBindingDivisor(*replayState, true,
3071                                                             static_cast<GLuint>(bindingIndex),
3072                                                             binding.getDivisor()));
3073         }
3074     }
3075 
3076     // The element array buffer is not per attribute, but per VAO
3077     gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
3078     if (elementArrayBuffer)
3079     {
3080         Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
3081                                               elementArrayBuffer->id()));
3082     }
3083 }
3084 
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)3085 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
3086                            gl::State *replayState,
3087                            const gl::Texture *texture)
3088 {
3089     // Use mip-level 0 for the base dimensions
3090     gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
3091     const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
3092 
3093     switch (texture->getType())
3094     {
3095         case gl::TextureType::_2D:
3096         case gl::TextureType::CubeMap:
3097         {
3098             Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
3099                                                     texture->getImmutableLevels(),
3100                                                     desc.format.info->internalFormat,
3101                                                     desc.size.width, desc.size.height));
3102             break;
3103         }
3104         case gl::TextureType::_3D:
3105         case gl::TextureType::_2DArray:
3106         case gl::TextureType::CubeMapArray:
3107         {
3108             Capture(setupCalls, CaptureTexStorage3D(
3109                                     *replayState, true, texture->getType(),
3110                                     texture->getImmutableLevels(), desc.format.info->internalFormat,
3111                                     desc.size.width, desc.size.height, desc.size.depth));
3112             break;
3113         }
3114         case gl::TextureType::Buffer:
3115         {
3116             // Do nothing. This will already be captured as a buffer.
3117             break;
3118         }
3119         default:
3120             UNIMPLEMENTED();
3121             break;
3122     }
3123 }
3124 
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)3125 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
3126                             gl::State *replayState,
3127                             const gl::Texture *texture,
3128                             const gl::ImageIndex &index,
3129                             const gl::ImageDesc &desc,
3130                             GLuint size,
3131                             const void *data)
3132 {
3133     const gl::InternalFormat &format = *desc.format.info;
3134 
3135     if (index.getType() == gl::TextureType::Buffer)
3136     {
3137         // Zero binding size indicates full buffer bound
3138         if (texture->getBuffer().getSize() == 0)
3139         {
3140             Capture(setupCalls,
3141                     CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
3142                                         texture->getBuffer().get()->id()));
3143         }
3144         else
3145         {
3146             Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
3147                                                          format.internalFormat,
3148                                                          texture->getBuffer().get()->id(),
3149                                                          texture->getBuffer().getOffset(),
3150                                                          texture->getBuffer().getSize()));
3151         }
3152 
3153         // For buffers, we're done
3154         return;
3155     }
3156 
3157     if (index.getType() == gl::TextureType::External)
3158     {
3159         // The generated glTexImage2D call is for creating the staging texture
3160         Capture(setupCalls,
3161                 CaptureTexImage2D(*replayState, true, gl::TextureTarget::_2D, index.getLevelIndex(),
3162                                   format.internalFormat, desc.size.width, desc.size.height, 0,
3163                                   format.format, format.type, data));
3164 
3165         // For external textures, we're done
3166         return;
3167     }
3168 
3169     bool is3D =
3170         (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
3171          index.getType() == gl::TextureType::CubeMapArray);
3172 
3173     if (format.compressed || format.paletted)
3174     {
3175         if (is3D)
3176         {
3177             if (texture->getImmutableFormat())
3178             {
3179                 Capture(setupCalls,
3180                         CaptureCompressedTexSubImage3D(
3181                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
3182                             desc.size.width, desc.size.height, desc.size.depth,
3183                             format.internalFormat, size, data));
3184             }
3185             else
3186             {
3187                 Capture(setupCalls,
3188                         CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
3189                                                     index.getLevelIndex(), format.internalFormat,
3190                                                     desc.size.width, desc.size.height,
3191                                                     desc.size.depth, 0, size, data));
3192             }
3193         }
3194         else
3195         {
3196             if (texture->getImmutableFormat())
3197             {
3198                 Capture(setupCalls,
3199                         CaptureCompressedTexSubImage2D(
3200                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
3201                             desc.size.width, desc.size.height, format.internalFormat, size, data));
3202             }
3203             else
3204             {
3205                 Capture(setupCalls, CaptureCompressedTexImage2D(
3206                                         *replayState, true, index.getTarget(),
3207                                         index.getLevelIndex(), format.internalFormat,
3208                                         desc.size.width, desc.size.height, 0, size, data));
3209             }
3210         }
3211     }
3212     else
3213     {
3214         if (is3D)
3215         {
3216             if (texture->getImmutableFormat())
3217             {
3218                 Capture(setupCalls,
3219                         CaptureTexSubImage3D(*replayState, true, index.getTarget(),
3220                                              index.getLevelIndex(), 0, 0, 0, desc.size.width,
3221                                              desc.size.height, desc.size.depth, format.format,
3222                                              format.type, data));
3223             }
3224             else
3225             {
3226                 Capture(
3227                     setupCalls,
3228                     CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
3229                                       format.internalFormat, desc.size.width, desc.size.height,
3230                                       desc.size.depth, 0, format.format, format.type, data));
3231             }
3232         }
3233         else
3234         {
3235             if (texture->getImmutableFormat())
3236             {
3237                 Capture(setupCalls,
3238                         CaptureTexSubImage2D(*replayState, true, index.getTarget(),
3239                                              index.getLevelIndex(), 0, 0, desc.size.width,
3240                                              desc.size.height, format.format, format.type, data));
3241             }
3242             else
3243             {
3244                 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
3245                                                       index.getLevelIndex(), format.internalFormat,
3246                                                       desc.size.width, desc.size.height, 0,
3247                                                       format.format, format.type, data));
3248             }
3249         }
3250     }
3251 }
3252 
CaptureCustomUniformBlockBinding(const CallCapture & callIn,std::vector<CallCapture> & callsOut)3253 void CaptureCustomUniformBlockBinding(const CallCapture &callIn, std::vector<CallCapture> &callsOut)
3254 {
3255     const ParamBuffer &paramsIn = callIn.params;
3256 
3257     const ParamCapture &programID =
3258         paramsIn.getParam("programPacked", ParamType::TShaderProgramID, 0);
3259     const ParamCapture &blockIndex =
3260         paramsIn.getParam("uniformBlockIndexPacked", ParamType::TUniformBlockIndex, 1);
3261     const ParamCapture &blockBinding =
3262         paramsIn.getParam("uniformBlockBinding", ParamType::TGLuint, 2);
3263 
3264     ParamBuffer params;
3265     params.addValueParam("program", ParamType::TGLuint, programID.value.ShaderProgramIDVal.value);
3266     params.addValueParam("uniformBlockIndex", ParamType::TGLuint,
3267                          blockIndex.value.UniformBlockIndexVal.value);
3268     params.addValueParam("uniformBlockBinding", ParamType::TGLuint, blockBinding.value.GLuintVal);
3269 
3270     callsOut.emplace_back("UniformBlockBinding", std::move(params));
3271 }
3272 
CaptureCustomMapBuffer(const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut,gl::BufferID mappedBufferID)3273 void CaptureCustomMapBuffer(const char *entryPointName,
3274                             CallCapture &call,
3275                             std::vector<CallCapture> &callsOut,
3276                             gl::BufferID mappedBufferID)
3277 {
3278     call.params.addValueParam("buffer", ParamType::TGLuint, mappedBufferID.value);
3279     callsOut.emplace_back(entryPointName, std::move(call.params));
3280 }
3281 
CaptureCustomShaderProgram(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3282 void CaptureCustomShaderProgram(const char *name,
3283                                 CallCapture &call,
3284                                 std::vector<CallCapture> &callsOut)
3285 {
3286     call.params.addValueParam("shaderProgram", ParamType::TGLuint,
3287                               call.params.getReturnValue().value.GLuintVal);
3288     call.customFunctionName = name;
3289     callsOut.emplace_back(std::move(call));
3290 }
3291 
CaptureCustomFenceSync(CallCapture & call,std::vector<CallCapture> & callsOut)3292 void CaptureCustomFenceSync(CallCapture &call, std::vector<CallCapture> &callsOut)
3293 {
3294     ParamBuffer &&params = std::move(call.params);
3295     params.addValueParam("fenceSync", ParamType::TGLuint64,
3296                          params.getReturnValue().value.GLuint64Val);
3297     call.customFunctionName = "FenceSync2";
3298     callsOut.emplace_back(std::move(call));
3299 }
3300 
CaptureCustomCreateEGLImage(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3301 void CaptureCustomCreateEGLImage(const char *name,
3302                                  CallCapture &call,
3303                                  std::vector<CallCapture> &callsOut)
3304 {
3305     ParamBuffer &&params = std::move(call.params);
3306     EGLImage returnVal   = params.getReturnValue().value.EGLImageVal;
3307     egl::ImageID imageID = egl::PackParam<egl::ImageID>(returnVal);
3308     params.addValueParam("image", ParamType::TGLuint, imageID.value);
3309     call.customFunctionName = name;
3310     callsOut.emplace_back(std::move(call));
3311 }
3312 
CaptureCustomCreateEGLSync(const char * name,CallCapture & call,std::vector<CallCapture> & callsOut)3313 void CaptureCustomCreateEGLSync(const char *name,
3314                                 CallCapture &call,
3315                                 std::vector<CallCapture> &callsOut)
3316 {
3317     ParamBuffer &&params = std::move(call.params);
3318     EGLSync returnVal    = params.getReturnValue().value.EGLSyncVal;
3319     egl::SyncID syncID   = egl::PackParam<egl::SyncID>(returnVal);
3320     params.addValueParam("sync", ParamType::TGLuint, syncID.value);
3321     call.customFunctionName = name;
3322     callsOut.emplace_back(std::move(call));
3323 }
3324 
CaptureCustomCreatePbufferSurface(CallCapture & call,std::vector<CallCapture> & callsOut)3325 void CaptureCustomCreatePbufferSurface(CallCapture &call, std::vector<CallCapture> &callsOut)
3326 {
3327     ParamBuffer &&params     = std::move(call.params);
3328     EGLSurface returnVal     = params.getReturnValue().value.EGLSurfaceVal;
3329     egl::SurfaceID surfaceID = egl::PackParam<egl::SurfaceID>(returnVal);
3330 
3331     params.addValueParam("surface", ParamType::TGLuint, surfaceID.value);
3332     call.customFunctionName = "CreatePbufferSurface";
3333     callsOut.emplace_back(std::move(call));
3334 }
3335 
CaptureCustomCreateNativeClientbuffer(CallCapture & call,std::vector<CallCapture> & callsOut)3336 void CaptureCustomCreateNativeClientbuffer(CallCapture &call, std::vector<CallCapture> &callsOut)
3337 {
3338     ParamBuffer &&params = std::move(call.params);
3339     params.addValueParam("clientBuffer", ParamType::TEGLClientBuffer,
3340                          params.getReturnValue().value.EGLClientBufferVal);
3341     call.customFunctionName = "CreateNativeClientBufferANDROID";
3342     callsOut.emplace_back(std::move(call));
3343 }
3344 
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)3345 void GenerateLinkedProgram(const gl::Context *context,
3346                            const gl::State &replayState,
3347                            ResourceTracker *resourceTracker,
3348                            std::vector<CallCapture> *setupCalls,
3349                            gl::Program *program,
3350                            gl::ShaderProgramID id,
3351                            gl::ShaderProgramID tempIDStart,
3352                            const ProgramSources &linkedSources)
3353 {
3354     // A map to store the gShaderProgram map lookup index of the temp shaders we attached below. We
3355     // need this map to retrieve the lookup index to pass to CaptureDetachShader calls at the end of
3356     // GenerateLinkedProgram.
3357     PackedEnumMap<gl::ShaderType, gl::ShaderProgramID> tempShaderIDTracker;
3358 
3359     // Compile with last linked sources.
3360     for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
3361     {
3362         // Bump the max shader program id for each new tempIDStart we use to create, compile, and
3363         // attach the temp shader object.
3364         resourceTracker->onShaderProgramAccess(tempIDStart);
3365         // Store the tempIDStart in the tempShaderIDTracker to retrieve for CaptureDetachShader
3366         // calls later.
3367         tempShaderIDTracker[shaderType] = tempIDStart;
3368         const std::string &sourceString = linkedSources[shaderType];
3369         const char *sourcePointer       = sourceString.c_str();
3370 
3371         if (sourceString.empty())
3372         {
3373             // If we don't have source for this shader, that means it was populated by the app
3374             // using glProgramBinary.  We need to look it up from our cached copy.
3375             const ProgramSources &cachedLinkedSources =
3376                 context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
3377 
3378             const std::string &cachedSourceString = cachedLinkedSources[shaderType];
3379             sourcePointer                         = cachedSourceString.c_str();
3380             ASSERT(!cachedSourceString.empty());
3381         }
3382 
3383         // Compile and attach the temporary shader. Then free it immediately.
3384         CallCapture createShader =
3385             CaptureCreateShader(replayState, true, shaderType, tempIDStart.value);
3386         CaptureCustomShaderProgram("CreateShader", createShader, *setupCalls);
3387         Capture(setupCalls,
3388                 CaptureShaderSource(replayState, true, tempIDStart, 1, &sourcePointer, nullptr));
3389         Capture(setupCalls, CaptureCompileShader(replayState, true, tempIDStart));
3390         Capture(setupCalls, CaptureAttachShader(replayState, true, id, tempIDStart));
3391         // Increment tempIDStart to get a new gShaderProgram map index for the next linked stage
3392         // shader object. We can't reuse the same tempIDStart as we need to retrieve the index of
3393         // each attached shader object later to pass to CaptureDetachShader calls.
3394         tempIDStart.value += 1;
3395     }
3396 
3397     // Gather XFB varyings
3398     std::vector<std::string> xfbVaryings;
3399     for (const gl::TransformFeedbackVarying &xfbVarying :
3400          program->getState().getLinkedTransformFeedbackVaryings())
3401     {
3402         xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
3403     }
3404 
3405     if (!xfbVaryings.empty())
3406     {
3407         std::vector<const char *> varyingsStrings;
3408         for (const std::string &varyingString : xfbVaryings)
3409         {
3410             varyingsStrings.push_back(varyingString.data());
3411         }
3412 
3413         GLenum xfbMode = program->getState().getTransformFeedbackBufferMode();
3414         Capture(setupCalls, CaptureTransformFeedbackVaryings(replayState, true, id,
3415                                                              static_cast<GLint>(xfbVaryings.size()),
3416                                                              varyingsStrings.data(), xfbMode));
3417     }
3418 
3419     // Force the attributes to be bound the same way as in the existing program.
3420     // This can affect attributes that are optimized out in some implementations.
3421     for (const sh::ShaderVariable &attrib : program->getState().getProgramInputs())
3422     {
3423         if (gl::IsBuiltInName(attrib.name))
3424         {
3425             // Don't try to bind built-in attributes
3426             continue;
3427         }
3428 
3429         // Separable programs may not have a VS, meaning it may not have attributes.
3430         if (program->getExecutable().hasLinkedShaderStage(gl::ShaderType::Vertex))
3431         {
3432             ASSERT(attrib.location != -1);
3433             Capture(setupCalls, CaptureBindAttribLocation(replayState, true, id,
3434                                                           static_cast<GLuint>(attrib.location),
3435                                                           attrib.name.c_str()));
3436         }
3437     }
3438 
3439     if (program->isSeparable())
3440     {
3441         // MEC manually recreates separable programs, rather than attempting to recreate a call
3442         // to glCreateShaderProgramv(), so insert a call to mark it separable.
3443         Capture(setupCalls,
3444                 CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
3445     }
3446 
3447     Capture(setupCalls, CaptureLinkProgram(replayState, true, id));
3448     CaptureUpdateUniformLocations(program, setupCalls);
3449     CaptureUpdateUniformValues(replayState, context, program, resourceTracker, setupCalls);
3450     CaptureUpdateUniformBlockIndexes(program, setupCalls);
3451 
3452     // Capture uniform block bindings for each program
3453     for (unsigned int uniformBlockIndex = 0;
3454          uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
3455     {
3456         GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
3457         CallCapture updateCallCapture =
3458             CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex}, blockBinding);
3459         CaptureCustomUniformBlockBinding(updateCallCapture, *setupCalls);
3460     }
3461 
3462     // Add DetachShader call if that's what the app does, so that the
3463     // ResourceManagerBase::mHandleAllocator can release the ShaderProgramID handle assigned to the
3464     // shader object when glDeleteShader is called. This ensures the ShaderProgramID handles used in
3465     // SetupReplayContextShared() are consistent with the ShaderProgramID handles used by the app.
3466     for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
3467     {
3468         gl::Shader *attachedShader = program->getAttachedShader(shaderType);
3469         if (attachedShader == nullptr)
3470         {
3471             Capture(setupCalls,
3472                     CaptureDetachShader(replayState, true, id, tempShaderIDTracker[shaderType]));
3473         }
3474         Capture(setupCalls,
3475                 CaptureDeleteShader(replayState, true, tempShaderIDTracker[shaderType]));
3476     }
3477 }
3478 
3479 // TODO(http://anglebug.com/4599): Improve reset/restore call generation
3480 // There are multiple ways to track reset calls for individual resources. For now, we are tracking
3481 // separate lists of instructions that mirror the calls created during mid-execution setup. Other
3482 // methods could involve passing the original CallCaptures to this function, or tracking the
3483 // indices of original setup calls.
CaptureBufferResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)3484 void CaptureBufferResetCalls(const gl::Context *context,
3485                              const gl::State &replayState,
3486                              ResourceTracker *resourceTracker,
3487                              gl::BufferID *id,
3488                              const gl::Buffer *buffer)
3489 {
3490     GLuint bufferID = (*id).value;
3491 
3492     // Track this as a starting resource that may need to be restored.
3493     TrackedResource &trackedBuffers =
3494         resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer);
3495 
3496     // Track calls to regenerate a given buffer
3497     ResourceCalls &bufferRegenCalls = trackedBuffers.getResourceRegenCalls();
3498     Capture(&bufferRegenCalls[bufferID], CaptureGenBuffers(replayState, true, 1, id));
3499     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &bufferRegenCalls[bufferID]);
3500 
3501     // Call glBufferStorageEXT when regenerating immutable buffers,
3502     // as we can't call glBufferData on restore.
3503     if (buffer->isImmutable())
3504     {
3505         Capture(&bufferRegenCalls[bufferID],
3506                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3507         Capture(
3508             &bufferRegenCalls[bufferID],
3509             CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3510                                     static_cast<GLsizeiptr>(buffer->getSize()),
3511                                     buffer->getMapPointer(), buffer->getStorageExtUsageFlags()));
3512     }
3513 
3514     // Track calls to restore a given buffer's contents
3515     ResourceCalls &bufferRestoreCalls = trackedBuffers.getResourceRestoreCalls();
3516     Capture(&bufferRestoreCalls[bufferID],
3517             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3518 
3519     // Mutable buffers will be restored here using glBufferData.
3520     // Immutable buffers need to be restored below, after maping.
3521     if (!buffer->isImmutable())
3522     {
3523         Capture(&bufferRestoreCalls[bufferID],
3524                 CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3525                                   static_cast<GLsizeiptr>(buffer->getSize()),
3526                                   buffer->getMapPointer(), buffer->getUsage()));
3527     }
3528 
3529     if (buffer->isMapped())
3530     {
3531         // Track calls to remap a buffer that started as mapped
3532         BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
3533 
3534         Capture(&bufferMapCalls[bufferID],
3535                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3536 
3537         void *dontCare             = nullptr;
3538         CallCapture mapBufferRange = CaptureMapBufferRange(
3539             replayState, true, gl::BufferBinding::Array,
3540             static_cast<GLsizeiptr>(buffer->getMapOffset()),
3541             static_cast<GLsizeiptr>(buffer->getMapLength()), buffer->getAccessFlags(), dontCare);
3542         CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, bufferMapCalls[bufferID],
3543                                buffer->id());
3544 
3545         // Restore immutable mapped buffers. Needs to happen after mapping.
3546         if (buffer->isImmutable())
3547         {
3548             ParamBuffer dataParamBuffer;
3549             dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
3550             ParamCapture captureData("source", ParamType::TvoidConstPointer);
3551             CaptureMemory(buffer->getMapPointer(), static_cast<GLsizeiptr>(buffer->getSize()),
3552                           &captureData);
3553             dataParamBuffer.addParam(std::move(captureData));
3554             dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
3555                                                       static_cast<GLsizeiptr>(buffer->getSize()));
3556             bufferMapCalls[bufferID].emplace_back("UpdateClientBufferData",
3557                                                   std::move(dataParamBuffer));
3558         }
3559     }
3560 
3561     // Track calls unmap a buffer that started as unmapped
3562     BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
3563     Capture(&bufferUnmapCalls[bufferID],
3564             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
3565     Capture(&bufferUnmapCalls[bufferID],
3566             CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
3567 }
3568 
CaptureFenceSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,gl::SyncID syncID,GLsync syncObject,const gl::Sync * sync)3569 void CaptureFenceSyncResetCalls(const gl::Context *context,
3570                                 const gl::State &replayState,
3571                                 ResourceTracker *resourceTracker,
3572                                 gl::SyncID syncID,
3573                                 GLsync syncObject,
3574                                 const gl::Sync *sync)
3575 {
3576     // Track calls to regenerate a given fence sync
3577     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
3578     CallCapture fenceSync =
3579         CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
3580     CaptureCustomFenceSync(fenceSync, fenceSyncRegenCalls[syncID]);
3581     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &fenceSyncRegenCalls[syncID]);
3582 }
3583 
CaptureEGLSyncResetCalls(const gl::Context * context,const gl::State & replayState,ResourceTracker * resourceTracker,egl::SyncID eglSyncID,EGLSync eglSyncObject,const egl::Sync * eglSync)3584 void CaptureEGLSyncResetCalls(const gl::Context *context,
3585                               const gl::State &replayState,
3586                               ResourceTracker *resourceTracker,
3587                               egl::SyncID eglSyncID,
3588                               EGLSync eglSyncObject,
3589                               const egl::Sync *eglSync)
3590 {
3591     // Track this as a starting resource that may need to be restored.
3592     TrackedResource &trackedEGLSyncs =
3593         resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync);
3594 
3595     // Track calls to regenerate a given buffer
3596     ResourceCalls &eglSyncRegenCalls = trackedEGLSyncs.getResourceRegenCalls();
3597 
3598     CallCapture createEGLSync =
3599         CaptureCreateSyncKHR(nullptr, true, context->getDisplay(), eglSync->getType(),
3600                              eglSync->getAttributeMap(), eglSyncObject);
3601     CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync,
3602                                eglSyncRegenCalls[eglSyncID.value]);
3603     MaybeCaptureUpdateResourceIDs(context, resourceTracker, &eglSyncRegenCalls[eglSyncID.value]);
3604 }
3605 
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)3606 void CaptureBufferBindingResetCalls(const gl::State &replayState,
3607                                     ResourceTracker *resourceTracker,
3608                                     gl::BufferBinding binding,
3609                                     gl::BufferID id)
3610 {
3611     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
3612     Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
3613 }
3614 
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)3615 void CaptureIndexedBuffers(const gl::State &glState,
3616                            const gl::BufferVector &indexedBuffers,
3617                            gl::BufferBinding binding,
3618                            std::vector<CallCapture> *setupCalls)
3619 {
3620     for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
3621     {
3622         const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
3623 
3624         if (buffer.get() == nullptr)
3625         {
3626             continue;
3627         }
3628 
3629         GLintptr offset       = buffer.getOffset();
3630         GLsizeiptr size       = buffer.getSize();
3631         gl::BufferID bufferID = buffer.get()->id();
3632 
3633         // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
3634         if ((offset == 0) && (size == 0))
3635         {
3636             Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
3637         }
3638         else
3639         {
3640             Capture(setupCalls,
3641                     CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
3642         }
3643     }
3644 }
3645 
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)3646 void CaptureDefaultVertexAttribs(const gl::State &replayState,
3647                                  const gl::State &apiState,
3648                                  std::vector<CallCapture> *setupCalls)
3649 {
3650     const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
3651         apiState.getVertexAttribCurrentValues();
3652 
3653     for (GLuint attribIndex = 0; attribIndex < currentValues.size(); ++attribIndex)
3654     {
3655         const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
3656         if (!IsDefaultCurrentValue(defaultValue))
3657         {
3658             Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
3659                                                        defaultValue.Values.FloatValues));
3660         }
3661     }
3662 }
3663 
CompressPalettedTexture(angle::MemoryBuffer & data,angle::MemoryBuffer & tmp,const gl::InternalFormat & compressedFormat,const gl::Extents & extents)3664 void CompressPalettedTexture(angle::MemoryBuffer &data,
3665                              angle::MemoryBuffer &tmp,
3666                              const gl::InternalFormat &compressedFormat,
3667                              const gl::Extents &extents)
3668 {
3669     constexpr int uncompressedChannelCount = 4;
3670 
3671     uint32_t indexBits = 0, redBlueBits = 0, greenBits = 0, alphaBits = 0;
3672     switch (compressedFormat.internalFormat)
3673     {
3674         case GL_PALETTE4_RGB8_OES:
3675             indexBits   = 4;
3676             redBlueBits = 8;
3677             greenBits   = 8;
3678             alphaBits   = 0;
3679             break;
3680         case GL_PALETTE4_RGBA8_OES:
3681             indexBits   = 4;
3682             redBlueBits = 8;
3683             greenBits   = 8;
3684             alphaBits   = 8;
3685             break;
3686         case GL_PALETTE4_R5_G6_B5_OES:
3687             indexBits   = 4;
3688             redBlueBits = 5;
3689             greenBits   = 6;
3690             alphaBits   = 0;
3691             break;
3692         case GL_PALETTE4_RGBA4_OES:
3693             indexBits   = 4;
3694             redBlueBits = 4;
3695             greenBits   = 4;
3696             alphaBits   = 4;
3697             break;
3698         case GL_PALETTE4_RGB5_A1_OES:
3699             indexBits   = 4;
3700             redBlueBits = 5;
3701             greenBits   = 5;
3702             alphaBits   = 1;
3703             break;
3704         case GL_PALETTE8_RGB8_OES:
3705             indexBits   = 8;
3706             redBlueBits = 8;
3707             greenBits   = 8;
3708             alphaBits   = 0;
3709             break;
3710         case GL_PALETTE8_RGBA8_OES:
3711             indexBits   = 8;
3712             redBlueBits = 8;
3713             greenBits   = 8;
3714             alphaBits   = 8;
3715             break;
3716         case GL_PALETTE8_R5_G6_B5_OES:
3717             indexBits   = 8;
3718             redBlueBits = 5;
3719             greenBits   = 6;
3720             alphaBits   = 0;
3721             break;
3722         case GL_PALETTE8_RGBA4_OES:
3723             indexBits   = 8;
3724             redBlueBits = 4;
3725             greenBits   = 4;
3726             alphaBits   = 4;
3727             break;
3728         case GL_PALETTE8_RGB5_A1_OES:
3729             indexBits   = 8;
3730             redBlueBits = 5;
3731             greenBits   = 5;
3732             alphaBits   = 1;
3733             break;
3734 
3735         default:
3736             UNREACHABLE();
3737             break;
3738     }
3739 
3740     bool result = data.resize(
3741         // Palette size
3742         (1 << indexBits) * (2 * redBlueBits + greenBits + alphaBits) / 8 +
3743         // Texels size
3744         indexBits * extents.width * extents.height * extents.depth / 8);
3745     ASSERT(result);
3746 
3747     angle::StoreRGBA8ToPalettedImpl(
3748         extents.width, extents.height, extents.depth, indexBits, redBlueBits, greenBits, alphaBits,
3749         tmp.data(),
3750         uncompressedChannelCount * extents.width,                   // inputRowPitch
3751         uncompressedChannelCount * extents.width * extents.height,  // inputDepthPitch
3752         data.data(),                                                // output
3753         indexBits * extents.width / 8,                              // outputRowPitch
3754         indexBits * extents.width * extents.height / 8              // outputDepthPitch
3755     );
3756 }
3757 
3758 // Capture the setup of the state that's shared by all of the contexts in the share group
3759 // See IsSharedObjectResource for the list of objects covered here.
CaptureShareGroupMidExecutionSetup(gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker,gl::State & replayState,const PackedEnumMap<ResourceIDType,uint32_t> & maxAccessedResourceIDs)3760 void CaptureShareGroupMidExecutionSetup(
3761     gl::Context *context,
3762     std::vector<CallCapture> *setupCalls,
3763     ResourceTracker *resourceTracker,
3764     gl::State &replayState,
3765     const PackedEnumMap<ResourceIDType, uint32_t> &maxAccessedResourceIDs)
3766 {
3767     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
3768     const gl::State &apiState              = context->getState();
3769 
3770     // Small helper function to make the code more readable.
3771     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
3772 
3773     // Capture Buffer data.
3774     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
3775     for (const auto &bufferIter : buffers)
3776     {
3777         gl::BufferID id    = {bufferIter.first};
3778         gl::Buffer *buffer = bufferIter.second;
3779 
3780         if (id.value == 0)
3781         {
3782             continue;
3783         }
3784 
3785         // Generate binding.
3786         cap(CaptureGenBuffers(replayState, true, 1, &id));
3787 
3788         resourceTracker->getTrackedResource(context->id(), ResourceIDType::Buffer)
3789             .getStartingResources()
3790             .insert(id.value);
3791 
3792         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
3793 
3794         // glBufferData. Would possibly be better implemented using a getData impl method.
3795         // Saving buffers that are mapped during a swap is not yet handled.
3796         if (buffer->getSize() == 0)
3797         {
3798             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
3799             continue;
3800         }
3801 
3802         // Remember if the buffer was already mapped
3803         GLboolean bufferMapped = buffer->isMapped();
3804 
3805         // If needed, map the buffer so we can capture its contents
3806         if (!bufferMapped)
3807         {
3808             (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
3809                                    GL_MAP_READ_BIT);
3810         }
3811 
3812         // Always use the array buffer binding point to upload data to keep things simple.
3813         if (buffer != replayState.getArrayBuffer())
3814         {
3815             replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
3816             cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
3817         }
3818 
3819         if (buffer->isImmutable())
3820         {
3821             cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
3822                                         static_cast<GLsizeiptr>(buffer->getSize()),
3823                                         buffer->getMapPointer(),
3824                                         buffer->getStorageExtUsageFlags()));
3825         }
3826         else
3827         {
3828             cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
3829                                   static_cast<GLsizeiptr>(buffer->getSize()),
3830                                   buffer->getMapPointer(), buffer->getUsage()));
3831         }
3832 
3833         if (bufferMapped)
3834         {
3835             void *dontCare = nullptr;
3836             CallCapture mapBufferRange =
3837                 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
3838                                       static_cast<GLsizeiptr>(buffer->getMapOffset()),
3839                                       static_cast<GLsizeiptr>(buffer->getMapLength()),
3840                                       buffer->getAccessFlags(), dontCare);
3841             CaptureCustomMapBuffer("MapBufferRange", mapBufferRange, *setupCalls, buffer->id());
3842 
3843             resourceTracker->setStartingBufferMapped(buffer->id().value, true);
3844 
3845             frameCaptureShared->trackBufferMapping(
3846                 context, &setupCalls->back(), buffer->id(), buffer,
3847                 static_cast<GLsizeiptr>(buffer->getMapOffset()),
3848                 static_cast<GLsizeiptr>(buffer->getMapLength()),
3849                 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0,
3850                 (buffer->getStorageExtUsageFlags() & GL_MAP_COHERENT_BIT_EXT) != 0);
3851         }
3852         else
3853         {
3854             resourceTracker->setStartingBufferMapped(buffer->id().value, false);
3855         }
3856 
3857         // Generate the calls needed to restore this buffer to original state for frame looping
3858         CaptureBufferResetCalls(context, replayState, resourceTracker, &id, buffer);
3859 
3860         // Unmap the buffer if it wasn't already mapped
3861         if (!bufferMapped)
3862         {
3863             GLboolean dontCare;
3864             (void)buffer->unmap(context, &dontCare);
3865         }
3866     }
3867 
3868     // Clear the array buffer binding.
3869     if (replayState.getTargetBuffer(gl::BufferBinding::Array))
3870     {
3871         cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, {0}));
3872         replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
3873     }
3874 
3875     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
3876     // leading to a crash in memcpy() when capturing the texture contents.
3877     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
3878     if (currentUnpackState.alignment != 1)
3879     {
3880         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
3881         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
3882     }
3883 
3884     // Capture Texture setup and data.
3885     const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
3886 
3887     for (const auto &textureIter : textures)
3888     {
3889         gl::TextureID id     = {textureIter.first};
3890         gl::Texture *texture = textureIter.second;
3891 
3892         if (id.value == 0)
3893         {
3894             continue;
3895         }
3896 
3897         // Track this as a starting resource that may need to be restored.
3898         TrackedResource &trackedTextures =
3899             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Texture);
3900         ResourceSet &startingTextures = trackedTextures.getStartingResources();
3901         startingTextures.insert(id.value);
3902 
3903         // For the initial texture creation calls, track in the generate list
3904         ResourceCalls &textureRegenCalls = trackedTextures.getResourceRegenCalls();
3905         CallVector texGenCalls({setupCalls, &textureRegenCalls[id.value]});
3906 
3907         // Gen the Texture.
3908         for (std::vector<CallCapture> *calls : texGenCalls)
3909         {
3910             Capture(calls, CaptureGenTextures(replayState, true, 1, &id));
3911             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
3912         }
3913 
3914         // For the remaining texture setup calls, track in the restore list
3915         ResourceCalls &textureRestoreCalls = trackedTextures.getResourceRestoreCalls();
3916         CallVector texSetupCalls({setupCalls, &textureRestoreCalls[id.value]});
3917 
3918         for (std::vector<CallCapture> *calls : texSetupCalls)
3919         {
3920             Capture(calls, CaptureBindTexture(replayState, true, texture->getType(), id));
3921         }
3922         replayState.setSamplerTexture(context, texture->getType(), texture);
3923 
3924         // Capture sampler parameter states.
3925         // TODO(jmadill): More sampler / texture states. http://anglebug.com/3662
3926         gl::SamplerState defaultSamplerState =
3927             gl::SamplerState::CreateDefaultForTarget(texture->getType());
3928         const gl::SamplerState &textureSamplerState = texture->getSamplerState();
3929 
3930         auto capTexParam = [&replayState, texture, &texSetupCalls](GLenum pname, GLint param) {
3931             for (std::vector<CallCapture> *calls : texSetupCalls)
3932             {
3933                 Capture(calls,
3934                         CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
3935             }
3936         };
3937 
3938         auto capTexParamf = [&replayState, texture, &texSetupCalls](GLenum pname, GLfloat param) {
3939             for (std::vector<CallCapture> *calls : texSetupCalls)
3940             {
3941                 Capture(calls,
3942                         CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
3943             }
3944         };
3945 
3946         if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
3947         {
3948             capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
3949         }
3950 
3951         if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
3952         {
3953             capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
3954         }
3955 
3956         if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
3957         {
3958             capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
3959         }
3960 
3961         if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
3962         {
3963             capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
3964         }
3965 
3966         if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
3967         {
3968             capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
3969         }
3970 
3971         if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
3972         {
3973             capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
3974         }
3975 
3976         if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
3977         {
3978             capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
3979         }
3980 
3981         if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
3982         {
3983             capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
3984         }
3985 
3986         if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
3987         {
3988             capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
3989         }
3990 
3991         // Texture parameters
3992         if (texture->getSwizzleRed() != GL_RED)
3993         {
3994             capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
3995         }
3996 
3997         if (texture->getSwizzleGreen() != GL_GREEN)
3998         {
3999             capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
4000         }
4001 
4002         if (texture->getSwizzleBlue() != GL_BLUE)
4003         {
4004             capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
4005         }
4006 
4007         if (texture->getSwizzleAlpha() != GL_ALPHA)
4008         {
4009             capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
4010         }
4011 
4012         if (texture->getBaseLevel() != 0)
4013         {
4014             capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
4015         }
4016 
4017         if (texture->getMaxLevel() != 1000)
4018         {
4019             capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
4020         }
4021 
4022         // If the texture is immutable, initialize it with TexStorage
4023         if (texture->getImmutableFormat())
4024         {
4025             // We can only call TexStorage *once* on an immutable texture, so it needs special
4026             // handling. To solve this, immutable textures will have a BindTexture and TexStorage as
4027             // part of their textureRegenCalls. The resulting regen sequence will be:
4028             //
4029             //    const GLuint glDeleteTextures_texturesPacked_0[] = { gTextureMap[52] };
4030             //    glDeleteTextures(1, glDeleteTextures_texturesPacked_0);
4031             //    glGenTextures(1, reinterpret_cast<GLuint *>(gReadBuffer));
4032             //    UpdateTextureID(52, 0);
4033             //    glBindTexture(GL_TEXTURE_2D, gTextureMap[52]);
4034             //    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, 256, 512);
4035 
4036             // Bind the texture first just for textureRegenCalls
4037             Capture(&textureRegenCalls[id.value],
4038                     CaptureBindTexture(replayState, true, texture->getType(), id));
4039 
4040             // Then add TexStorage to texGenCalls instead of texSetupCalls
4041             for (std::vector<CallCapture> *calls : texGenCalls)
4042             {
4043                 CaptureTextureStorage(calls, &replayState, texture);
4044             }
4045         }
4046 
4047         // Iterate texture levels and layers.
4048         gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
4049             texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
4050             gl::ImageIndex::kEntireLevel);
4051         while (imageIter.hasNext())
4052         {
4053             gl::ImageIndex index = imageIter.next();
4054 
4055             const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
4056 
4057             if (desc.size.empty())
4058             {
4059                 continue;
4060             }
4061 
4062             const gl::InternalFormat &format = *desc.format.info;
4063 
4064             bool supportedType = (index.getType() == gl::TextureType::_2D ||
4065                                   index.getType() == gl::TextureType::_3D ||
4066                                   index.getType() == gl::TextureType::_2DArray ||
4067                                   index.getType() == gl::TextureType::Buffer ||
4068                                   index.getType() == gl::TextureType::CubeMap ||
4069                                   index.getType() == gl::TextureType::CubeMapArray ||
4070                                   index.getType() == gl::TextureType::External);
4071 
4072             // Check for supported textures
4073             if (!supportedType)
4074             {
4075                 ERR() << "Unsupported texture type: " << index.getType();
4076                 UNREACHABLE();
4077             }
4078 
4079             if (index.getType() == gl::TextureType::Buffer)
4080             {
4081                 // The buffer contents are already backed up, but we need to emit the TexBuffer
4082                 // binding calls
4083                 for (std::vector<CallCapture> *calls : texSetupCalls)
4084                 {
4085                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, 0);
4086                 }
4087                 continue;
4088             }
4089 
4090             // create a staging GL_TEXTURE_2D texture to create the eglImage with
4091             gl::TextureID stagingTexId = {maxAccessedResourceIDs[ResourceIDType::Texture] + 1};
4092             if (index.getType() == gl::TextureType::External)
4093             {
4094                 Capture(setupCalls, CaptureGenTextures(replayState, true, 1, &stagingTexId));
4095                 MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4096                 Capture(setupCalls,
4097                         CaptureBindTexture(replayState, true, gl::TextureType::_2D, stagingTexId));
4098                 Capture(setupCalls, CaptureTexParameteri(replayState, true, gl::TextureType::_2D,
4099                                                          GL_TEXTURE_MIN_FILTER, GL_NEAREST));
4100                 Capture(setupCalls, CaptureTexParameteri(replayState, true, gl::TextureType::_2D,
4101                                                          GL_TEXTURE_MAG_FILTER, GL_NEAREST));
4102             }
4103 
4104             if (context->getExtensions().getImageANGLE)
4105             {
4106                 // Use ANGLE_get_image to read back pixel data.
4107                 angle::MemoryBuffer data;
4108 
4109                 const gl::Extents extents(desc.size.width, desc.size.height, desc.size.depth);
4110 
4111                 gl::PixelPackState packState;
4112                 packState.alignment = 1;
4113 
4114                 if (format.paletted)
4115                 {
4116                     // Read back the uncompressed texture, then re-compress it
4117                     // to store in the trace.
4118 
4119                     angle::MemoryBuffer tmp;
4120 
4121                     // The uncompressed format (R8G8B8A8) is 4 bytes per texel
4122                     bool result = tmp.resize(4 * extents.width * extents.height * extents.depth);
4123                     ASSERT(result);
4124 
4125                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4126                                                index.getLevelIndex(), GL_RGBA, GL_UNSIGNED_BYTE,
4127                                                tmp.data());
4128 
4129                     CompressPalettedTexture(data, tmp, format, extents);
4130                 }
4131                 else if (format.compressed)
4132                 {
4133                     // Calculate the size needed to store the compressed level
4134                     GLuint sizeInBytes;
4135                     bool result = format.computeCompressedImageSize(extents, &sizeInBytes);
4136                     ASSERT(result);
4137 
4138                     result = data.resize(sizeInBytes);
4139                     ASSERT(result);
4140 
4141                     (void)texture->getCompressedTexImage(context, packState, nullptr,
4142                                                          index.getTarget(), index.getLevelIndex(),
4143                                                          data.data());
4144                 }
4145                 else
4146                 {
4147                     GLenum getFormat = format.format;
4148                     GLenum getType   = format.type;
4149 
4150                     const gl::PixelUnpackState &unpack = apiState.getUnpackState();
4151 
4152                     GLuint endByte = 0;
4153                     bool unpackSize =
4154                         format.computePackUnpackEndByte(getType, extents, unpack, true, &endByte);
4155                     ASSERT(unpackSize);
4156 
4157                     bool result = data.resize(endByte);
4158                     ASSERT(result);
4159 
4160                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
4161                                                index.getLevelIndex(), getFormat, getType,
4162                                                data.data());
4163                 }
4164 
4165                 for (std::vector<CallCapture> *calls : texSetupCalls)
4166                 {
4167                     CaptureTextureContents(calls, &replayState, texture, index, desc,
4168                                            static_cast<GLuint>(data.size()), data.data());
4169                 }
4170 
4171                 if (index.getType() == gl::TextureType::External)
4172                 {
4173                     // Look up the attribs used when the image was created
4174                     // Firstly, lookup the eglImage ID associated with this texture when the app
4175                     // issued glEGLImageTargetTexture2DOES()
4176                     auto eglImageIter = resourceTracker->getTextureIDToImageTable().find(id.value);
4177                     ASSERT(eglImageIter != resourceTracker->getTextureIDToImageTable().end());
4178 
4179                     const egl::ImageID eglImageID = eglImageIter->second;
4180                     const EGLImage eglImage =
4181                         reinterpret_cast<EGLImage>(static_cast<uintptr_t>(eglImageID.value));
4182 
4183                     // Secondly, lookup the attrib we used to create the eglImage
4184                     auto eglImageAttribIter =
4185                         resourceTracker->getImageToAttribTable().find(eglImage);
4186                     ASSERT(eglImageAttribIter != resourceTracker->getImageToAttribTable().end());
4187 
4188                     const egl::AttributeMap &retrievedAttribs = eglImageAttribIter->second;
4189 
4190                     // Create the image on demand with the same attrib retrieved above
4191                     CallCapture eglCreateImageKHRCall = egl::CaptureCreateImageKHR(
4192                         nullptr, true, nullptr, context->id(), EGL_GL_TEXTURE_2D_KHR,
4193                         reinterpret_cast<EGLClientBuffer>(
4194                             static_cast<GLuint64>(stagingTexId.value)),
4195                         retrievedAttribs, eglImage);
4196 
4197                     // Convert the CaptureCreateImageKHR CallCapture to the customized CallCapture
4198                     std::vector<CallCapture> eglCustomCreateImageKHRCall;
4199                     CaptureCustomCreateEGLImage("CreateEGLImageKHR", eglCreateImageKHRCall,
4200                                                 eglCustomCreateImageKHRCall);
4201                     ASSERT(eglCustomCreateImageKHRCall.size() > 0);
4202 
4203                     // Append the customized CallCapture to the setupCalls list
4204                     Capture(setupCalls, std::move(eglCustomCreateImageKHRCall[0]));
4205 
4206                     // Pass the eglImage to the texture that is bound to GL_TEXTURE_EXTERNAL_OES
4207                     // target
4208                     for (std::vector<CallCapture> *calls : texSetupCalls)
4209                     {
4210                         Capture(calls,
4211                                 CaptureEGLImageTargetTexture2DOES(
4212                                     replayState, true, gl::TextureType::External, eglImageID));
4213                     }
4214 
4215                     // Delete the staging texture
4216                     Capture(setupCalls, CaptureDeleteTextures(replayState, true, 1, &stagingTexId));
4217                 }
4218             }
4219             else
4220             {
4221                 for (std::vector<CallCapture> *calls : texSetupCalls)
4222                 {
4223                     CaptureTextureContents(calls, &replayState, texture, index, desc, 0, nullptr);
4224                 }
4225             }
4226         }
4227     }
4228 
4229     // Capture Renderbuffers.
4230     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4231     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4232 
4233     for (const auto &renderbufIter : renderbuffers)
4234     {
4235         gl::RenderbufferID id                = {renderbufIter.first};
4236         const gl::Renderbuffer *renderbuffer = renderbufIter.second;
4237 
4238         // Track this as a starting resource that may need to be restored.
4239         TrackedResource &trackedRenderbuffers =
4240             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Renderbuffer);
4241         ResourceSet &startingRenderbuffers = trackedRenderbuffers.getStartingResources();
4242         startingRenderbuffers.insert(id.value);
4243 
4244         // For the initial renderbuffer creation calls, track in the generate list
4245         ResourceCalls &renderbufferRegenCalls = trackedRenderbuffers.getResourceRegenCalls();
4246         CallVector rbGenCalls({setupCalls, &renderbufferRegenCalls[id.value]});
4247 
4248         // Generate renderbuffer id.
4249         for (std::vector<CallCapture> *calls : rbGenCalls)
4250         {
4251             Capture(calls, framebufferFuncs.genRenderbuffers(replayState, true, 1, &id));
4252             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4253             Capture(calls,
4254                     framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
4255         }
4256 
4257         GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
4258 
4259         if (renderbuffer->getSamples() > 0)
4260         {
4261             // Note: We could also use extensions if available.
4262             for (std::vector<CallCapture> *calls : rbGenCalls)
4263             {
4264                 Capture(calls,
4265                         CaptureRenderbufferStorageMultisample(
4266                             replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(),
4267                             internalformat, renderbuffer->getWidth(), renderbuffer->getHeight()));
4268             }
4269         }
4270         else
4271         {
4272             for (std::vector<CallCapture> *calls : rbGenCalls)
4273             {
4274                 Capture(calls, framebufferFuncs.renderbufferStorage(
4275                                    replayState, true, GL_RENDERBUFFER, internalformat,
4276                                    renderbuffer->getWidth(), renderbuffer->getHeight()));
4277             }
4278         }
4279 
4280         // TODO: Capture renderbuffer contents. http://anglebug.com/3662
4281     }
4282 
4283     // Capture Shaders and Programs.
4284     const gl::ShaderProgramManager &shadersAndPrograms =
4285         apiState.getShaderProgramManagerForCapture();
4286     const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
4287         shadersAndPrograms.getShadersForCapture();
4288     const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
4289         shadersAndPrograms.getProgramsForCaptureAndPerf();
4290 
4291     TrackedResource &trackedShaderPrograms =
4292         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
4293 
4294     // Capture Program binary state.
4295     gl::ShaderProgramID tempShaderStartID = {resourceTracker->getMaxShaderPrograms()};
4296     for (const auto &programIter : programs)
4297     {
4298         gl::ShaderProgramID id = {programIter.first};
4299         gl::Program *program   = programIter.second;
4300 
4301         // Unlinked programs don't have an executable. Thus they don't need to be captured.
4302         // Programs are shared by contexts in the share group and only need to be captured once.
4303         if (!program->isLinked())
4304         {
4305             continue;
4306         }
4307 
4308         size_t programSetupStart = setupCalls->size();
4309 
4310         // Get last linked shader source.
4311         const ProgramSources &linkedSources =
4312             context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
4313 
4314         // Create two lists for program regen calls
4315         ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4316         CallVector programRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4317 
4318         for (std::vector<CallCapture> *calls : programRegenCalls)
4319         {
4320             CallCapture createProgram = CaptureCreateProgram(replayState, true, id.value);
4321             CaptureCustomShaderProgram("CreateProgram", createProgram, *calls);
4322         }
4323 
4324         // Create two lists for program restore calls
4325         ResourceCalls &shaderProgramRestoreCalls = trackedShaderPrograms.getResourceRestoreCalls();
4326         CallVector programRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4327 
4328         for (std::vector<CallCapture> *calls : programRestoreCalls)
4329         {
4330             GenerateLinkedProgram(context, replayState, resourceTracker, calls, program, id,
4331                                   tempShaderStartID, linkedSources);
4332         }
4333 
4334         // Update the program in replayState
4335         if (!replayState.getProgram() || replayState.getProgram()->id() != program->id())
4336         {
4337             // Note: We don't do this in GenerateLinkedProgram because it can't modify state
4338             (void)replayState.setProgram(context, program);
4339         }
4340 
4341         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4342             .getStartingResources()
4343             .insert(id.value);
4344         resourceTracker->setShaderProgramType(id, ShaderProgramType::ProgramType);
4345 
4346         size_t programSetupEnd = setupCalls->size();
4347 
4348         // Mark the range of calls used to setup this program
4349         frameCaptureShared->markResourceSetupCallsInactive(
4350             setupCalls, ResourceIDType::ShaderProgram, id.value,
4351             gl::Range<size_t>(programSetupStart, programSetupEnd));
4352     }
4353 
4354     // Handle shaders.
4355     for (const auto &shaderIter : shaders)
4356     {
4357         gl::ShaderProgramID id = {shaderIter.first};
4358         gl::Shader *shader     = shaderIter.second;
4359 
4360         // Skip shaders scheduled for deletion.
4361         // Shaders are shared by contexts in the share group and only need to be captured once.
4362         if (shader->hasBeenDeleted())
4363         {
4364             continue;
4365         }
4366 
4367         size_t shaderSetupStart = setupCalls->size();
4368 
4369         // Create two lists for shader regen calls
4370         ResourceCalls &shaderProgramRegenCalls = trackedShaderPrograms.getResourceRegenCalls();
4371         CallVector shaderRegenCalls({setupCalls, &shaderProgramRegenCalls[id.value]});
4372 
4373         for (std::vector<CallCapture> *calls : shaderRegenCalls)
4374         {
4375             CallCapture createShader =
4376                 CaptureCreateShader(replayState, true, shader->getType(), id.value);
4377             CaptureCustomShaderProgram("CreateShader", createShader, *calls);
4378         }
4379 
4380         std::string shaderSource  = shader->getSourceString();
4381         const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
4382 
4383         // Create two lists for shader restore calls
4384         ResourceCalls &shaderProgramRestoreCalls = trackedShaderPrograms.getResourceRestoreCalls();
4385         CallVector shaderRestoreCalls({setupCalls, &shaderProgramRestoreCalls[id.value]});
4386 
4387         // This does not handle some more tricky situations like attaching shaders to a non-linked
4388         // program. Or attaching uncompiled shaders. Or attaching and then deleting a shader.
4389         // TODO(jmadill): Handle trickier program uses. http://anglebug.com/3662
4390         if (shader->isCompiled(context))
4391         {
4392             const std::string &capturedSource =
4393                 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
4394             if (capturedSource != shaderSource)
4395             {
4396                 ASSERT(!capturedSource.empty());
4397                 sourcePointer = capturedSource.c_str();
4398             }
4399 
4400             for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4401             {
4402                 Capture(calls,
4403                         CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4404                 Capture(calls, CaptureCompileShader(replayState, true, id));
4405             }
4406         }
4407 
4408         if (sourcePointer &&
4409             (!shader->isCompiled(context) || sourcePointer != shaderSource.c_str()))
4410         {
4411             for (std::vector<CallCapture> *calls : shaderRestoreCalls)
4412             {
4413                 Capture(calls,
4414                         CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
4415             }
4416         }
4417 
4418         size_t shaderSetupEnd = setupCalls->size();
4419 
4420         // Mark the range of calls used to setup this shader
4421         frameCaptureShared->markResourceSetupCallsInactive(
4422             setupCalls, ResourceIDType::ShaderProgram, id.value,
4423             gl::Range<size_t>(shaderSetupStart, shaderSetupEnd));
4424 
4425         resourceTracker->getTrackedResource(context->id(), ResourceIDType::ShaderProgram)
4426             .getStartingResources()
4427             .insert(id.value);
4428         resourceTracker->setShaderProgramType(id, ShaderProgramType::ShaderType);
4429     }
4430 
4431     // Capture Sampler Objects
4432     const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
4433     for (const auto &samplerIter : samplers)
4434     {
4435         gl::SamplerID samplerID = {samplerIter.first};
4436 
4437         // Don't gen the sampler if we've seen it before, since they are shared across the context
4438         // share group.
4439         cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
4440         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4441 
4442         gl::Sampler *sampler = samplerIter.second;
4443         if (!sampler)
4444         {
4445             continue;
4446         }
4447 
4448         gl::SamplerState defaultSamplerState;
4449         if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
4450         {
4451             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
4452                                          sampler->getMinFilter()));
4453         }
4454         if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
4455         {
4456             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
4457                                          sampler->getMagFilter()));
4458         }
4459         if (sampler->getWrapS() != defaultSamplerState.getWrapS())
4460         {
4461             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
4462                                          sampler->getWrapS()));
4463         }
4464         if (sampler->getWrapR() != defaultSamplerState.getWrapR())
4465         {
4466             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
4467                                          sampler->getWrapR()));
4468         }
4469         if (sampler->getWrapT() != defaultSamplerState.getWrapT())
4470         {
4471             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
4472                                          sampler->getWrapT()));
4473         }
4474         if (sampler->getMinLod() != defaultSamplerState.getMinLod())
4475         {
4476             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
4477                                          sampler->getMinLod()));
4478         }
4479         if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
4480         {
4481             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
4482                                          sampler->getMaxLod()));
4483         }
4484         if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
4485         {
4486             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
4487                                          sampler->getCompareMode()));
4488         }
4489         if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
4490         {
4491             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
4492                                          sampler->getCompareFunc()));
4493         }
4494     }
4495 
4496     // Capture Sync Objects
4497     const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
4498     for (const auto &syncIter : syncs)
4499     {
4500         gl::SyncID syncID    = {syncIter.first};
4501         const gl::Sync *sync = syncIter.second;
4502         GLsync syncObject    = gl::unsafe_int_to_pointer_cast<GLsync>(syncID.value);
4503 
4504         if (!sync)
4505         {
4506             continue;
4507         }
4508         CallCapture fenceSync =
4509             CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncObject);
4510         CaptureCustomFenceSync(fenceSync, *setupCalls);
4511         CaptureFenceSyncResetCalls(context, replayState, resourceTracker, syncID, syncObject, sync);
4512         resourceTracker->getStartingFenceSyncs().insert(syncID);
4513     }
4514 
4515     // Capture EGL Sync Objects
4516     const egl::SyncMap eglSyncMap = context->getDisplay()->getSyncsForCapture();
4517     for (const auto &eglSyncIter : eglSyncMap)
4518     {
4519         egl::SyncID eglSyncID    = {eglSyncIter.first};
4520         const egl::Sync *eglSync = eglSyncIter.second;
4521         EGLSync eglSyncObject    = gl::unsafe_int_to_pointer_cast<EGLSync>(eglSyncID.value);
4522 
4523         if (!eglSync)
4524         {
4525             continue;
4526         }
4527         CallCapture createEGLSync =
4528             CaptureCreateSync(nullptr, true, context->getDisplay(), eglSync->getType(),
4529                               eglSync->getAttributeMap(), eglSyncObject);
4530         CaptureCustomCreateEGLSync("CreateEGLSyncKHR", createEGLSync, *setupCalls);
4531         CaptureEGLSyncResetCalls(context, replayState, resourceTracker, eglSyncID, eglSyncObject,
4532                                  eglSync);
4533         resourceTracker->getTrackedResource(context->id(), ResourceIDType::egl_Sync)
4534             .getStartingResources()
4535             .insert(eglSyncID.value);
4536     }
4537 
4538     GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
4539     if (currentUnpackState.alignment != contextUnpackAlignment)
4540     {
4541         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
4542         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
4543     }
4544 }
4545 
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,CallResetMap & resetCalls,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls,ResourceTracker * resourceTracker,gl::State & replayState,bool validationEnabled)4546 void CaptureMidExecutionSetup(const gl::Context *context,
4547                               std::vector<CallCapture> *setupCalls,
4548                               CallResetMap &resetCalls,
4549                               std::vector<CallCapture> *shareGroupSetupCalls,
4550                               ResourceIDToSetupCallsMap *resourceIDToSetupCalls,
4551                               ResourceTracker *resourceTracker,
4552                               gl::State &replayState,
4553                               bool validationEnabled)
4554 {
4555     const gl::State &apiState = context->getState();
4556 
4557     // Small helper function to make the code more readable.
4558     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
4559 
4560     cap(egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, context->id(), EGL_TRUE));
4561 
4562     // Vertex input states. Must happen after buffer data initialization. Do not capture on GLES1.
4563     if (!context->isGLES1())
4564     {
4565         CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
4566     }
4567 
4568     // Capture vertex array objects
4569     VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
4570 
4571     const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
4572     gl::VertexArrayID boundVertexArrayID     = {0};
4573     for (const auto &vertexArrayIter : vertexArrayMap)
4574     {
4575         TrackedResource &trackedVertexArrays =
4576             resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray);
4577 
4578         gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
4579 
4580         // Track this as a starting resource that may need to be restored
4581         resourceTracker->getTrackedResource(context->id(), ResourceIDType::VertexArray)
4582             .getStartingResources()
4583             .insert(vertexArrayID.value);
4584 
4585         // Create two lists of calls for initial setup
4586         ResourceCalls &vertexArrayRegenCalls = trackedVertexArrays.getResourceRegenCalls();
4587         CallVector vertexArrayGenCalls({setupCalls, &vertexArrayRegenCalls[vertexArrayID.value]});
4588 
4589         if (vertexArrayID.value != 0)
4590         {
4591             // Gen the vertex array
4592             for (std::vector<CallCapture> *calls : vertexArrayGenCalls)
4593             {
4594                 Capture(calls,
4595                         vertexArrayFuncs.genVertexArrays(replayState, true, 1, &vertexArrayID));
4596                 MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4597             }
4598         }
4599 
4600         // Create two lists of calls for populating the vertex array
4601         ResourceCalls &vertexArrayRestoreCalls = trackedVertexArrays.getResourceRestoreCalls();
4602         CallVector vertexArraySetupCalls(
4603             {setupCalls, &vertexArrayRestoreCalls[vertexArrayID.value]});
4604 
4605         if (vertexArrayIter.second)
4606         {
4607             const gl::VertexArray *vertexArray = vertexArrayIter.second;
4608 
4609             // Populate the vertex array
4610             for (std::vector<CallCapture> *calls : vertexArraySetupCalls)
4611             {
4612                 // Bind the vertexArray (if needed) and populate it
4613                 if (vertexArrayID != boundVertexArrayID)
4614                 {
4615                     Capture(calls,
4616                             vertexArrayFuncs.bindVertexArray(replayState, true, vertexArrayID));
4617                 }
4618                 CaptureVertexArrayState(calls, context, vertexArray, &replayState);
4619             }
4620             boundVertexArrayID = vertexArrayID;
4621         }
4622     }
4623 
4624     // Bind the current vertex array
4625     const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
4626     if (currentVertexArray->id() != boundVertexArrayID)
4627     {
4628         cap(vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
4629     }
4630 
4631     // Track the calls necessary to bind the vertex array back to initial state
4632     Capture(&resetCalls[angle::EntryPoint::GLBindVertexArray],
4633             vertexArrayFuncs.bindVertexArray(replayState, true, currentVertexArray->id()));
4634 
4635     // Capture indexed buffer bindings.
4636     const gl::BufferVector &uniformIndexedBuffers =
4637         apiState.getOffsetBindingPointerUniformBuffers();
4638     const gl::BufferVector &atomicCounterIndexedBuffers =
4639         apiState.getOffsetBindingPointerAtomicCounterBuffers();
4640     const gl::BufferVector &shaderStorageIndexedBuffers =
4641         apiState.getOffsetBindingPointerShaderStorageBuffers();
4642     CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
4643                           setupCalls);
4644     CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
4645                           gl::BufferBinding::AtomicCounter, setupCalls);
4646     CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
4647                           gl::BufferBinding::ShaderStorage, setupCalls);
4648 
4649     // Capture Buffer bindings.
4650     const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
4651     for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
4652     {
4653         gl::BufferID bufferID = boundBuffers[binding].id();
4654 
4655         // Filter out redundant buffer binding commands. Note that the code in the previous section
4656         // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
4657         // we set earlier.
4658         bool isArray                  = binding == gl::BufferBinding::Array;
4659         const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
4660         if ((isArray && arrayBuffer && arrayBuffer->id() != bufferID) ||
4661             (!isArray && bufferID.value != 0))
4662         {
4663             cap(CaptureBindBuffer(replayState, true, binding, bufferID));
4664             replayState.setBufferBinding(context, binding, boundBuffers[binding].get());
4665         }
4666 
4667         // Restore all buffer bindings for Reset
4668         if (bufferID.value != 0)
4669         {
4670             CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
4671         }
4672     }
4673 
4674     // Set a unpack alignment of 1. Otherwise, computeRowPitch() will compute the wrong value,
4675     // leading to a crash in memcpy() when capturing the texture contents.
4676     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
4677     if (currentUnpackState.alignment != 1)
4678     {
4679         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
4680         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(1);
4681     }
4682 
4683     // Capture Texture setup and data.
4684     const gl::TextureBindingMap &apiBoundTextures = apiState.getBoundTexturesForCapture();
4685 
4686     // Set Texture bindings.
4687     for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
4688     {
4689         const gl::TextureBindingVector &apiBindings = apiBoundTextures[textureType];
4690         const gl::TextureBindingVector &replayBindings =
4691             replayState.getBoundTexturesForCapture()[textureType];
4692         ASSERT(apiBindings.size() == replayBindings.size());
4693         for (size_t bindingIndex = 0; bindingIndex < apiBindings.size(); ++bindingIndex)
4694         {
4695             gl::TextureID apiTextureID    = apiBindings[bindingIndex].id();
4696             gl::TextureID replayTextureID = replayBindings[bindingIndex].id();
4697 
4698             if (apiTextureID != replayTextureID)
4699             {
4700                 if (replayState.getActiveSampler() != bindingIndex)
4701                 {
4702                     cap(CaptureActiveTexture(replayState, true,
4703                                              GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
4704                     replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4705                         static_cast<unsigned int>(bindingIndex));
4706                 }
4707 
4708                 cap(CaptureBindTexture(replayState, true, textureType, apiTextureID));
4709                 replayState.setSamplerTexture(context, textureType,
4710                                               apiBindings[bindingIndex].get());
4711             }
4712         }
4713     }
4714 
4715     // Capture Texture Environment
4716     if (context->isGLES1())
4717     {
4718         const gl::Caps &caps = context->getCaps();
4719         for (GLuint unit = 0; unit < caps.maxMultitextureUnits; ++unit)
4720         {
4721             CaptureTextureEnvironmentState(setupCalls, &replayState, &apiState, unit);
4722         }
4723     }
4724 
4725     // Set active Texture.
4726     if (replayState.getActiveSampler() != apiState.getActiveSampler())
4727     {
4728         cap(CaptureActiveTexture(replayState, true,
4729                                  GL_TEXTURE0 + static_cast<GLenum>(apiState.getActiveSampler())));
4730         replayState.getMutablePrivateStateForCapture()->setActiveSampler(
4731             apiState.getActiveSampler());
4732     }
4733 
4734     // Set Renderbuffer binding.
4735     FramebufferCaptureFuncs framebufferFuncs(context->isGLES1());
4736 
4737     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
4738     gl::RenderbufferID currentRenderbuffer       = {0};
4739     for (const auto &renderbufIter : renderbuffers)
4740     {
4741         currentRenderbuffer = renderbufIter.second->id();
4742     }
4743 
4744     if (currentRenderbuffer != apiState.getRenderbufferId())
4745     {
4746         cap(framebufferFuncs.bindRenderbuffer(replayState, true, GL_RENDERBUFFER,
4747                                               apiState.getRenderbufferId()));
4748     }
4749 
4750     // Capture Framebuffers.
4751     const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
4752 
4753     gl::FramebufferID currentDrawFramebuffer = {0};
4754     gl::FramebufferID currentReadFramebuffer = {0};
4755 
4756     for (const auto &framebufferIter : framebuffers)
4757     {
4758         gl::FramebufferID id               = {framebufferIter.first};
4759         const gl::Framebuffer *framebuffer = framebufferIter.second;
4760 
4761         // The default Framebuffer exists (by default).
4762         if (framebuffer->isDefault())
4763         {
4764             continue;
4765         }
4766 
4767         // Track this as a starting resource that may need to be restored
4768         TrackedResource &trackedFramebuffers =
4769             resourceTracker->getTrackedResource(context->id(), ResourceIDType::Framebuffer);
4770         ResourceSet &startingFramebuffers = trackedFramebuffers.getStartingResources();
4771         startingFramebuffers.insert(id.value);
4772 
4773         // Create two lists of calls for initial setup
4774         ResourceCalls &framebufferRegenCalls = trackedFramebuffers.getResourceRegenCalls();
4775         CallVector framebufferGenCalls({setupCalls, &framebufferRegenCalls[id.value]});
4776 
4777         // Gen the framebuffer
4778         for (std::vector<CallCapture> *calls : framebufferGenCalls)
4779         {
4780             Capture(calls, framebufferFuncs.genFramebuffers(replayState, true, 1, &id));
4781             MaybeCaptureUpdateResourceIDs(context, resourceTracker, calls);
4782         }
4783 
4784         // Create two lists of calls for remaining setup calls.  One for setup, and one for restore
4785         // during reset.
4786         ResourceCalls &framebufferRestoreCalls = trackedFramebuffers.getResourceRestoreCalls();
4787         CallVector framebufferSetupCalls({setupCalls, &framebufferRestoreCalls[id.value]});
4788 
4789         for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4790         {
4791             Capture(calls, framebufferFuncs.bindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
4792         }
4793         currentDrawFramebuffer = currentReadFramebuffer = id;
4794 
4795         // Color Attachments.
4796         for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
4797         {
4798             if (!colorAttachment.isAttached())
4799             {
4800                 continue;
4801             }
4802 
4803             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4804             {
4805                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs, colorAttachment);
4806             }
4807         }
4808 
4809         const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
4810         if (depthAttachment)
4811         {
4812             ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
4813                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
4814             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4815             {
4816                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
4817                                              *depthAttachment);
4818             }
4819         }
4820 
4821         const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
4822         if (stencilAttachment)
4823         {
4824             ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
4825                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
4826             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4827             {
4828                 CaptureFramebufferAttachment(calls, replayState, framebufferFuncs,
4829                                              *stencilAttachment);
4830             }
4831         }
4832 
4833         gl::FramebufferState defaultFramebufferState(
4834             context->getCaps(), framebuffer->getState().id(),
4835             framebuffer->getState().getFramebufferSerial());
4836         const gl::DrawBuffersVector<GLenum> &defaultDrawBufferStates =
4837             defaultFramebufferState.getDrawBufferStates();
4838         const gl::DrawBuffersVector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
4839 
4840         if (drawBufferStates != defaultDrawBufferStates)
4841         {
4842             for (std::vector<CallCapture> *calls : framebufferSetupCalls)
4843             {
4844                 Capture(calls, CaptureDrawBuffers(replayState, true,
4845                                                   static_cast<GLsizei>(drawBufferStates.size()),
4846                                                   drawBufferStates.data()));
4847             }
4848         }
4849     }
4850 
4851     // Capture framebuffer bindings.
4852     if (apiState.getDrawFramebuffer())
4853     {
4854         ASSERT(apiState.getReadFramebuffer());
4855         gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
4856         gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
4857         if (stateDrawFramebuffer == stateReadFramebuffer)
4858         {
4859             if (currentDrawFramebuffer != stateDrawFramebuffer ||
4860                 currentReadFramebuffer != stateReadFramebuffer)
4861             {
4862                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_FRAMEBUFFER,
4863                                                      stateDrawFramebuffer));
4864                 currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
4865             }
4866         }
4867         else
4868         {
4869             if (currentDrawFramebuffer != stateDrawFramebuffer)
4870             {
4871                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
4872                                                      currentDrawFramebuffer));
4873                 currentDrawFramebuffer = stateDrawFramebuffer;
4874             }
4875 
4876             if (currentReadFramebuffer != stateReadFramebuffer)
4877             {
4878                 cap(framebufferFuncs.bindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
4879                                                      replayState.getReadFramebuffer()->id()));
4880                 currentReadFramebuffer = stateReadFramebuffer;
4881             }
4882         }
4883     }
4884 
4885     // Capture Program Pipelines
4886     const gl::ProgramPipelineManager *programPipelineManager =
4887         apiState.getProgramPipelineManagerForCapture();
4888 
4889     for (const auto &ppoIterator : *programPipelineManager)
4890     {
4891         gl::ProgramPipeline *pipeline = ppoIterator.second;
4892         gl::ProgramPipelineID id      = {ppoIterator.first};
4893         cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
4894         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4895 
4896         // PPOs can contain graphics and compute programs, so loop through all shader types rather
4897         // than just the linked ones since getLinkedShaderStages() will return either only graphics
4898         // or compute stages.
4899         for (gl::ShaderType shaderType : gl::AllShaderTypes())
4900         {
4901             gl::Program *program = pipeline->getShaderProgram(shaderType);
4902             if (!program)
4903             {
4904                 continue;
4905             }
4906             ASSERT(program->isLinked());
4907             GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
4908             cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
4909                                         program->id()));
4910 
4911             // Set this program as active so it will be generated in Setup
4912             // Note: We aren't filtering ProgramPipelines, so this could be setting programs
4913             // active that aren't actually used.
4914             MarkResourceIDActive(ResourceIDType::ShaderProgram, program->id().value,
4915                                  shareGroupSetupCalls, resourceIDToSetupCalls);
4916         }
4917 
4918         gl::Program *program = pipeline->getActiveShaderProgram();
4919         if (program)
4920         {
4921             cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
4922         }
4923     }
4924 
4925     // For now we assume the installed program executable is the same as the current program.
4926     // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
4927     if (!context->isGLES1())
4928     {
4929         // If we have a program bound in the API, or if there is no program bound to the API at
4930         // time of capture and we bound a program for uniform updates during MEC, we must add
4931         // a set program call to replay the correct states.
4932         GLuint currentProgram = 0;
4933         if (apiState.getProgram())
4934         {
4935             cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
4936             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
4937             (void)replayState.setProgram(context, apiState.getProgram());
4938 
4939             // Set this program as active so it will be generated in Setup
4940             MarkResourceIDActive(ResourceIDType::ShaderProgram, apiState.getProgram()->id().value,
4941                                  shareGroupSetupCalls, resourceIDToSetupCalls);
4942 
4943             currentProgram = apiState.getProgram()->id().value;
4944         }
4945         else if (replayState.getProgram())
4946         {
4947             cap(CaptureUseProgram(replayState, true, {0}));
4948             CaptureUpdateCurrentProgram(setupCalls->back(), 0, setupCalls);
4949             (void)replayState.setProgram(context, nullptr);
4950         }
4951 
4952         // Track the calls necessary to reset active program back to initial state
4953         Capture(&resetCalls[angle::EntryPoint::GLUseProgram],
4954                 CaptureUseProgram(replayState, true, {currentProgram}));
4955         CaptureUpdateCurrentProgram((&resetCalls[angle::EntryPoint::GLUseProgram])->back(), 0,
4956                                     &resetCalls[angle::EntryPoint::GLUseProgram]);
4957 
4958         // Same for program pipelines as for programs, see comment above.
4959         if (apiState.getProgramPipeline())
4960         {
4961             cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
4962         }
4963         else if (replayState.getProgramPipeline())
4964         {
4965             cap(CaptureBindProgramPipeline(replayState, true, {0}));
4966         }
4967     }
4968 
4969     // Create existing queries. Note that queries may be genned and not yet started. In that
4970     // case the queries will exist in the query map as nullptr entries.
4971     const gl::QueryMap &queryMap = context->getQueriesForCapture();
4972     for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
4973          queryIter != queryMap.endWithNull(); ++queryIter)
4974     {
4975         ASSERT(queryIter->first);
4976         gl::QueryID queryID = {queryIter->first};
4977 
4978         cap(CaptureGenQueries(replayState, true, 1, &queryID));
4979         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
4980 
4981         gl::Query *query = queryIter->second;
4982         if (query)
4983         {
4984             gl::QueryType queryType = query->getType();
4985 
4986             // Begin the query to generate the object
4987             cap(CaptureBeginQuery(replayState, true, queryType, queryID));
4988 
4989             // End the query if it was not active
4990             if (!IsQueryActive(apiState, queryID))
4991             {
4992                 cap(CaptureEndQuery(replayState, true, queryType));
4993             }
4994         }
4995     }
4996 
4997     // Transform Feedback
4998     const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
4999     for (const auto &xfbIter : xfbMap)
5000     {
5001         gl::TransformFeedbackID xfbID = {xfbIter.first};
5002 
5003         // Do not capture the default XFB object.
5004         if (xfbID.value == 0)
5005         {
5006             continue;
5007         }
5008 
5009         cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
5010         MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
5011 
5012         gl::TransformFeedback *xfb = xfbIter.second;
5013         if (!xfb)
5014         {
5015             // The object was never created
5016             continue;
5017         }
5018 
5019         // Bind XFB to create the object
5020         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
5021 
5022         // Bind the buffers associated with this XFB object
5023         for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
5024         {
5025             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
5026 
5027             // Note: Buffers bound with BindBufferBase can be used with BindBuffer
5028             cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
5029                                        xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
5030         }
5031 
5032         if (xfb->isActive() || xfb->isPaused())
5033         {
5034             // We don't support active XFB in MEC yet
5035             UNIMPLEMENTED();
5036         }
5037     }
5038 
5039     // Bind the current XFB buffer after populating XFB objects
5040     gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
5041     if (currentXFB)
5042     {
5043         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
5044                                          currentXFB->id()));
5045     }
5046 
5047     // Bind samplers
5048     const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
5049     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
5050          ++bindingIndex)
5051     {
5052         gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
5053         if (samplerID.value != 0)
5054         {
5055             cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
5056         }
5057     }
5058 
5059     // Capture Image Texture bindings
5060     const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
5061     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
5062          ++bindingIndex)
5063     {
5064         const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
5065 
5066         if (imageUnit.texture == 0)
5067         {
5068             continue;
5069         }
5070 
5071         cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
5072                                     imageUnit.level, imageUnit.layered, imageUnit.layer,
5073                                     imageUnit.access, imageUnit.format));
5074     }
5075 
5076     // Capture GL Context states.
5077     auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
5078         if (capValue)
5079         {
5080             cap(CaptureEnable(replayState, true, capEnum));
5081         }
5082         else
5083         {
5084             cap(CaptureDisable(replayState, true, capEnum));
5085         }
5086     };
5087 
5088     // Capture GLES1 context states.
5089     if (context->isGLES1())
5090     {
5091         const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
5092         const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
5093         if (currentTextureState != defaultTextureState)
5094         {
5095             capCap(GL_TEXTURE_2D, currentTextureState);
5096         }
5097 
5098         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Projection));
5099         for (angle::Mat4 projectionMatrix :
5100              apiState.gles1().getMatrixStack(gl::MatrixType::Projection))
5101         {
5102             cap(CapturePushMatrix(replayState, true));
5103             cap(CaptureLoadMatrixf(replayState, true, projectionMatrix.elements().data()));
5104         }
5105 
5106         cap(CaptureMatrixMode(replayState, true, gl::MatrixType::Modelview));
5107         for (angle::Mat4 modelViewMatrix :
5108              apiState.gles1().getMatrixStack(gl::MatrixType::Modelview))
5109         {
5110             cap(CapturePushMatrix(replayState, true));
5111             cap(CaptureLoadMatrixf(replayState, true, modelViewMatrix.elements().data()));
5112         }
5113 
5114         gl::MatrixType currentMatrixMode = apiState.gles1().getMatrixMode();
5115         if (currentMatrixMode != gl::MatrixType::Modelview)
5116         {
5117             cap(CaptureMatrixMode(replayState, true, currentMatrixMode));
5118         }
5119 
5120         // Alpha Test state
5121         const bool currentAlphaTestState = apiState.getEnableFeature(GL_ALPHA_TEST);
5122         const bool defaultAlphaTestState = replayState.getEnableFeature(GL_ALPHA_TEST);
5123 
5124         if (currentAlphaTestState != defaultAlphaTestState)
5125         {
5126             capCap(GL_ALPHA_TEST, currentAlphaTestState);
5127         }
5128 
5129         const gl::AlphaTestParameters currentAlphaTestParameters =
5130             apiState.gles1().getAlphaTestParameters();
5131         const gl::AlphaTestParameters defaultAlphaTestParameters =
5132             replayState.gles1().getAlphaTestParameters();
5133 
5134         if (currentAlphaTestParameters != defaultAlphaTestParameters)
5135         {
5136             cap(CaptureAlphaFunc(replayState, true, currentAlphaTestParameters.func,
5137                                  currentAlphaTestParameters.ref));
5138         }
5139     }
5140 
5141     // Rasterizer state. Missing ES 3.x features.
5142     const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
5143     const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
5144     if (currentRasterState.cullFace != defaultRasterState.cullFace)
5145     {
5146         capCap(GL_CULL_FACE, currentRasterState.cullFace);
5147     }
5148 
5149     if (currentRasterState.cullMode != defaultRasterState.cullMode)
5150     {
5151         cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
5152     }
5153 
5154     if (currentRasterState.frontFace != defaultRasterState.frontFace)
5155     {
5156         cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
5157     }
5158 
5159     if (currentRasterState.polygonMode != defaultRasterState.polygonMode)
5160     {
5161         if (context->getExtensions().polygonModeNV)
5162         {
5163             cap(CapturePolygonModeNV(replayState, true, GL_FRONT_AND_BACK,
5164                                      currentRasterState.polygonMode));
5165         }
5166         else if (context->getExtensions().polygonModeANGLE)
5167         {
5168             cap(CapturePolygonModeANGLE(replayState, true, GL_FRONT_AND_BACK,
5169                                         currentRasterState.polygonMode));
5170         }
5171         else
5172         {
5173             UNREACHABLE();
5174         }
5175     }
5176 
5177     if (currentRasterState.polygonOffsetPoint != defaultRasterState.polygonOffsetPoint)
5178     {
5179         capCap(GL_POLYGON_OFFSET_POINT_NV, currentRasterState.polygonOffsetPoint);
5180     }
5181 
5182     if (currentRasterState.polygonOffsetLine != defaultRasterState.polygonOffsetLine)
5183     {
5184         capCap(GL_POLYGON_OFFSET_LINE_NV, currentRasterState.polygonOffsetLine);
5185     }
5186 
5187     if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
5188     {
5189         capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
5190     }
5191 
5192     if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
5193         currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits ||
5194         currentRasterState.polygonOffsetClamp != defaultRasterState.polygonOffsetClamp)
5195     {
5196         if (currentRasterState.polygonOffsetClamp == 0.0f)
5197         {
5198             cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
5199                                      currentRasterState.polygonOffsetUnits));
5200         }
5201         else
5202         {
5203             cap(CapturePolygonOffsetClampEXT(
5204                 replayState, true, currentRasterState.polygonOffsetFactor,
5205                 currentRasterState.polygonOffsetUnits, currentRasterState.polygonOffsetClamp));
5206         }
5207     }
5208 
5209     if (currentRasterState.depthClamp != defaultRasterState.depthClamp)
5210     {
5211         capCap(GL_DEPTH_CLAMP_EXT, currentRasterState.depthClamp);
5212     }
5213 
5214     // pointDrawMode/multiSample are only used in the D3D back-end right now.
5215 
5216     if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
5217     {
5218         capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
5219     }
5220 
5221     if (currentRasterState.dither != defaultRasterState.dither)
5222     {
5223         capCap(GL_DITHER, currentRasterState.dither);
5224     }
5225 
5226     // Depth/stencil state.
5227     const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
5228     const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
5229     if (defaultDSState.depthFunc != currentDSState.depthFunc)
5230     {
5231         cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
5232     }
5233 
5234     if (defaultDSState.depthMask != currentDSState.depthMask)
5235     {
5236         cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
5237     }
5238 
5239     if (defaultDSState.depthTest != currentDSState.depthTest)
5240     {
5241         capCap(GL_DEPTH_TEST, currentDSState.depthTest);
5242     }
5243 
5244     if (defaultDSState.stencilTest != currentDSState.stencilTest)
5245     {
5246         capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
5247     }
5248 
5249     if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
5250         currentDSState.stencilMask == currentDSState.stencilBackMask)
5251     {
5252         // Front and back are equal
5253         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5254             defaultDSState.stencilMask != currentDSState.stencilMask ||
5255             apiState.getStencilRef() != 0)
5256         {
5257             cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
5258                                    apiState.getStencilRef(), currentDSState.stencilMask));
5259         }
5260     }
5261     else
5262     {
5263         // Front and back are separate
5264         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
5265             defaultDSState.stencilMask != currentDSState.stencilMask ||
5266             apiState.getStencilRef() != 0)
5267         {
5268             cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
5269                                            apiState.getStencilRef(), currentDSState.stencilMask));
5270         }
5271 
5272         if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
5273             defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
5274             apiState.getStencilBackRef() != 0)
5275         {
5276             cap(CaptureStencilFuncSeparate(
5277                 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
5278                 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
5279         }
5280     }
5281 
5282     if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
5283         currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
5284         currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
5285     {
5286         // Front and back are equal
5287         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5288             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5289             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5290         {
5291             cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
5292                                  currentDSState.stencilPassDepthFail,
5293                                  currentDSState.stencilPassDepthPass));
5294         }
5295     }
5296     else
5297     {
5298         // Front and back are separate
5299         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
5300             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
5301             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
5302         {
5303             cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
5304                                          currentDSState.stencilPassDepthFail,
5305                                          currentDSState.stencilPassDepthPass));
5306         }
5307 
5308         if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
5309             defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
5310             defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
5311         {
5312             cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
5313                                          currentDSState.stencilBackPassDepthFail,
5314                                          currentDSState.stencilBackPassDepthPass));
5315         }
5316     }
5317 
5318     if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
5319     {
5320         // Front and back are equal
5321         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5322         {
5323             cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
5324         }
5325     }
5326     else
5327     {
5328         // Front and back are separate
5329         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
5330         {
5331             cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
5332                                            currentDSState.stencilWritemask));
5333         }
5334 
5335         if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
5336         {
5337             cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
5338                                            currentDSState.stencilBackWritemask));
5339         }
5340     }
5341 
5342     // Blend state.
5343     const gl::BlendState &defaultBlendState = replayState.getBlendState();
5344     const gl::BlendState &currentBlendState = apiState.getBlendState();
5345 
5346     if (currentBlendState.blend != defaultBlendState.blend)
5347     {
5348         capCap(GL_BLEND, currentBlendState.blend);
5349     }
5350 
5351     if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
5352         currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
5353         currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
5354         currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
5355     {
5356         if (context->isGLES1())
5357         {
5358             // Even though their states are tracked independently, in GLES1 blendAlpha
5359             // and blendRGB cannot be set separately and are always equal
5360             cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5361                                  currentBlendState.destBlendRGB));
5362             Capture(&resetCalls[angle::EntryPoint::GLBlendFunc],
5363                     CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
5364                                      currentBlendState.destBlendRGB));
5365         }
5366         else
5367         {
5368             // Always use BlendFuncSeparate for non-GLES1 as it covers all cases
5369             cap(CaptureBlendFuncSeparate(
5370                 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
5371                 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
5372             Capture(&resetCalls[angle::EntryPoint::GLBlendFuncSeparate],
5373                     CaptureBlendFuncSeparate(replayState, true, currentBlendState.sourceBlendRGB,
5374                                              currentBlendState.destBlendRGB,
5375                                              currentBlendState.sourceBlendAlpha,
5376                                              currentBlendState.destBlendAlpha));
5377         }
5378     }
5379 
5380     if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
5381         currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
5382     {
5383         // Similarly to BlendFunc, using BlendEquation in some cases complicates Reset.
5384         cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5385                                          currentBlendState.blendEquationAlpha));
5386         Capture(&resetCalls[angle::EntryPoint::GLBlendEquationSeparate],
5387                 CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
5388                                              currentBlendState.blendEquationAlpha));
5389     }
5390 
5391     if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
5392         currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
5393         currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
5394         currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
5395     {
5396         cap(CaptureColorMask(replayState, true,
5397                              gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5398                              gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5399                              gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5400                              gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5401         Capture(&resetCalls[angle::EntryPoint::GLColorMask],
5402                 CaptureColorMask(replayState, true,
5403                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
5404                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
5405                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
5406                                  gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
5407     }
5408 
5409     const gl::ColorF &currentBlendColor = apiState.getBlendColor();
5410     if (currentBlendColor != gl::ColorF())
5411     {
5412         cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5413                               currentBlendColor.blue, currentBlendColor.alpha));
5414         Capture(&resetCalls[angle::EntryPoint::GLBlendColor],
5415                 CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
5416                                   currentBlendColor.blue, currentBlendColor.alpha));
5417     }
5418 
5419     // Pixel storage states.
5420     gl::PixelPackState &currentPackState = replayState.getPackState();
5421     if (currentPackState.alignment != apiState.getPackAlignment())
5422     {
5423         cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
5424         currentPackState.alignment = apiState.getPackAlignment();
5425     }
5426 
5427     if (currentPackState.rowLength != apiState.getPackRowLength())
5428     {
5429         cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
5430         currentPackState.rowLength = apiState.getPackRowLength();
5431     }
5432 
5433     if (currentPackState.skipRows != apiState.getPackSkipRows())
5434     {
5435         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
5436         currentPackState.skipRows = apiState.getPackSkipRows();
5437     }
5438 
5439     if (currentPackState.skipPixels != apiState.getPackSkipPixels())
5440     {
5441         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
5442                                apiState.getPackSkipPixels()));
5443         currentPackState.skipPixels = apiState.getPackSkipPixels();
5444     }
5445 
5446     // We set unpack alignment above, no need to change it here
5447     ASSERT(currentUnpackState.alignment == 1);
5448     if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
5449     {
5450         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
5451                                apiState.getUnpackRowLength()));
5452         currentUnpackState.rowLength = apiState.getUnpackRowLength();
5453     }
5454 
5455     if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
5456     {
5457         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
5458                                apiState.getUnpackSkipRows()));
5459         currentUnpackState.skipRows = apiState.getUnpackSkipRows();
5460     }
5461 
5462     if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
5463     {
5464         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
5465                                apiState.getUnpackSkipPixels()));
5466         currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
5467     }
5468 
5469     if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
5470     {
5471         cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
5472                                apiState.getUnpackImageHeight()));
5473         currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
5474     }
5475 
5476     if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
5477     {
5478         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
5479                                apiState.getUnpackSkipImages()));
5480         currentUnpackState.skipImages = apiState.getUnpackSkipImages();
5481     }
5482 
5483     // Clear state. Missing ES 3.x features.
5484     // TODO(http://anglebug.com/3662): Complete state capture.
5485     const gl::ColorF &currentClearColor = apiState.getColorClearValue();
5486     if (currentClearColor != gl::ColorF())
5487     {
5488         cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
5489                               currentClearColor.blue, currentClearColor.alpha));
5490     }
5491 
5492     if (apiState.getDepthClearValue() != 1.0f)
5493     {
5494         cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
5495     }
5496 
5497     if (apiState.getStencilClearValue() != 0)
5498     {
5499         cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
5500     }
5501 
5502     // Viewport / scissor / clipping planes.
5503     const gl::Rectangle &currentViewport = apiState.getViewport();
5504     if (currentViewport != gl::Rectangle())
5505     {
5506         cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
5507                             currentViewport.width, currentViewport.height));
5508     }
5509 
5510     if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
5511     {
5512         cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
5513     }
5514 
5515     if (apiState.getClipOrigin() != gl::ClipOrigin::LowerLeft ||
5516         apiState.getClipDepthMode() != gl::ClipDepthMode::NegativeOneToOne)
5517     {
5518         cap(CaptureClipControlEXT(replayState, true, apiState.getClipOrigin(),
5519                                   apiState.getClipDepthMode()));
5520     }
5521 
5522     if (apiState.isScissorTestEnabled())
5523     {
5524         capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
5525     }
5526 
5527     const gl::Rectangle &currentScissor = apiState.getScissor();
5528     if (currentScissor != gl::Rectangle())
5529     {
5530         cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
5531                            currentScissor.width, currentScissor.height));
5532     }
5533 
5534     // Allow the replayState object to be destroyed conveniently.
5535     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
5536 
5537     // Clean up the replay state.
5538     replayState.reset(context);
5539 
5540     GLint contextUnpackAlignment = context->getState().getUnpackState().alignment;
5541     if (currentUnpackState.alignment != contextUnpackAlignment)
5542     {
5543         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, contextUnpackAlignment));
5544         replayState.getMutablePrivateStateForCapture()->setUnpackAlignment(contextUnpackAlignment);
5545     }
5546 
5547     if (validationEnabled)
5548     {
5549         CaptureValidateSerializedState(context, setupCalls);
5550     }
5551 }
5552 
SkipCall(EntryPoint entryPoint)5553 bool SkipCall(EntryPoint entryPoint)
5554 {
5555     switch (entryPoint)
5556     {
5557         case EntryPoint::GLDebugMessageCallback:
5558         case EntryPoint::GLDebugMessageCallbackKHR:
5559         case EntryPoint::GLDebugMessageControl:
5560         case EntryPoint::GLDebugMessageControlKHR:
5561         case EntryPoint::GLDebugMessageInsert:
5562         case EntryPoint::GLDebugMessageInsertKHR:
5563         case EntryPoint::GLGetDebugMessageLog:
5564         case EntryPoint::GLGetDebugMessageLogKHR:
5565         case EntryPoint::GLGetObjectLabel:
5566         case EntryPoint::GLGetObjectLabelEXT:
5567         case EntryPoint::GLGetObjectLabelKHR:
5568         case EntryPoint::GLGetObjectPtrLabelKHR:
5569         case EntryPoint::GLGetPointervKHR:
5570         case EntryPoint::GLInsertEventMarkerEXT:
5571         case EntryPoint::GLLabelObjectEXT:
5572         case EntryPoint::GLObjectLabel:
5573         case EntryPoint::GLObjectLabelKHR:
5574         case EntryPoint::GLObjectPtrLabelKHR:
5575         case EntryPoint::GLPopDebugGroupKHR:
5576         case EntryPoint::GLPopGroupMarkerEXT:
5577         case EntryPoint::GLPushDebugGroupKHR:
5578         case EntryPoint::GLPushGroupMarkerEXT:
5579             // Purposefully skip entry points from:
5580             // - KHR_debug
5581             // - EXT_debug_label
5582             // - EXT_debug_marker
5583             // There is no need to capture these for replaying a trace in our harness
5584             return true;
5585 
5586         case EntryPoint::GLGetActiveUniform:
5587         case EntryPoint::GLGetActiveUniformsiv:
5588             // Skip these calls because:
5589             // - We don't use the return values.
5590             // - Active uniform counts can vary between platforms due to cross stage optimizations
5591             //   and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
5592             return true;
5593 
5594         case EntryPoint::GLGetActiveAttrib:
5595             // Skip these calls because:
5596             // - We don't use the return values.
5597             // - Same as uniforms, the value can vary, asking above GL_ACTIVE_ATTRIBUTES is an error
5598             return true;
5599 
5600         case EntryPoint::GLGetActiveUniformBlockiv:
5601         case EntryPoint::GLGetActiveUniformName:
5602         case EntryPoint::GLGetActiveUniformBlockName:
5603             // Skip these calls because:
5604             // - We don't use the return values.
5605             // - It reduces the number of references to the uniform block index map.
5606             return true;
5607 
5608         case EntryPoint::EGLChooseConfig:
5609         case EntryPoint::EGLGetProcAddress:
5610         case EntryPoint::EGLGetConfigAttrib:
5611         case EntryPoint::EGLGetConfigs:
5612         case EntryPoint::EGLGetSyncAttrib:
5613         case EntryPoint::EGLGetSyncAttribKHR:
5614         case EntryPoint::EGLQuerySurface:
5615             // Skip these calls because:
5616             // - Some EGL types and pointer parameters aren't yet implemented in EGL capture.
5617             return true;
5618 
5619         case EntryPoint::EGLPrepareSwapBuffersANGLE:
5620             // Skip this call because:
5621             // - eglPrepareSwapBuffersANGLE is automatically called by eglSwapBuffers
5622             return true;
5623 
5624         case EntryPoint::EGLSwapBuffers:
5625             // Skip these calls because:
5626             // - Swap is handled specially by the trace harness.
5627             return true;
5628 
5629         default:
5630             break;
5631     }
5632 
5633     return false;
5634 }
5635 
5636 template <typename ParamValueType>
5637 struct ParamValueTrait
5638 {
5639     static_assert(sizeof(ParamValueType) == 0, "invalid ParamValueType");
5640 };
5641 
5642 template <>
5643 struct ParamValueTrait<gl::FramebufferID>
5644 {
5645     static constexpr const char *name = "framebufferPacked";
5646     static const ParamType typeID     = ParamType::TFramebufferID;
5647 };
5648 
GetBaseName(const std::string & nameWithPath)5649 std::string GetBaseName(const std::string &nameWithPath)
5650 {
5651     std::vector<std::string> result = angle::SplitString(
5652         nameWithPath, "/\\", WhitespaceHandling::TRIM_WHITESPACE, SplitResult::SPLIT_WANT_NONEMPTY);
5653     ASSERT(!result.empty());
5654     return result.back();
5655 }
5656 
5657 template <>
5658 struct ParamValueTrait<gl::BufferID>
5659 {
5660     static constexpr const char *name = "bufferPacked";
5661     static const ParamType typeID     = ParamType::TBufferID;
5662 };
5663 
5664 template <>
5665 struct ParamValueTrait<gl::RenderbufferID>
5666 {
5667     static constexpr const char *name = "renderbufferPacked";
5668     static const ParamType typeID     = ParamType::TRenderbufferID;
5669 };
5670 
5671 template <>
5672 struct ParamValueTrait<gl::TextureID>
5673 {
5674     static constexpr const char *name = "texturePacked";
5675     static const ParamType typeID     = ParamType::TTextureID;
5676 };
5677 }  // namespace
5678 
5679 FrameCapture::FrameCapture()  = default;
5680 FrameCapture::~FrameCapture() = default;
5681 
reset()5682 void FrameCapture::reset()
5683 {
5684     mSetupCalls.clear();
5685 }
5686 
FrameCaptureShared()5687 FrameCaptureShared::FrameCaptureShared()
5688     : mLastContextId{0},
5689       mEnabled(true),
5690       mSerializeStateEnabled(false),
5691       mCompression(true),
5692       mClientVertexArrayMap{},
5693       mFrameIndex(1),
5694       mCaptureStartFrame(1),
5695       mCaptureEndFrame(0),
5696       mClientArraySizes{},
5697       mReadBufferSize(0),
5698       mResourceIDBufferSize(0),
5699       mHasResourceType{},
5700       mResourceIDToSetupCalls{},
5701       mMaxAccessedResourceIDs{},
5702       mCaptureTrigger(0),
5703       mCaptureActive(false),
5704       mWindowSurfaceContextID({0})
5705 {
5706     reset();
5707 
5708     std::string enabledFromEnv =
5709         GetEnvironmentVarOrUnCachedAndroidProperty(kEnabledVarName, kAndroidEnabled);
5710     if (enabledFromEnv == "0")
5711     {
5712         mEnabled = false;
5713     }
5714 
5715     std::string pathFromEnv =
5716         GetEnvironmentVarOrUnCachedAndroidProperty(kOutDirectoryVarName, kAndroidOutDir);
5717     if (pathFromEnv.empty())
5718     {
5719         mOutDirectory = GetDefaultOutDirectory();
5720     }
5721     else
5722     {
5723         mOutDirectory = pathFromEnv;
5724     }
5725 
5726     // Ensure the capture path ends with a slash.
5727     if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
5728     {
5729         mOutDirectory += '/';
5730     }
5731 
5732     std::string startFromEnv =
5733         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameStartVarName, kAndroidFrameStart);
5734     if (!startFromEnv.empty())
5735     {
5736         mCaptureStartFrame = atoi(startFromEnv.c_str());
5737     }
5738     if (mCaptureStartFrame < 1)
5739     {
5740         WARN() << "Cannot use a capture start frame less than 1.";
5741         mCaptureStartFrame = 1;
5742     }
5743 
5744     std::string endFromEnv =
5745         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameEndVarName, kAndroidFrameEnd);
5746     if (!endFromEnv.empty())
5747     {
5748         mCaptureEndFrame = atoi(endFromEnv.c_str());
5749     }
5750 
5751     std::string captureTriggerFromEnv =
5752         GetEnvironmentVarOrUnCachedAndroidProperty(kTriggerVarName, kAndroidTrigger);
5753     if (!captureTriggerFromEnv.empty())
5754     {
5755         mCaptureTrigger = atoi(captureTriggerFromEnv.c_str());
5756 
5757         // If the trigger has been populated, ignore the other frame range variables by setting them
5758         // to unreasonable values. This isn't perfect, but it is effective.
5759         mCaptureStartFrame = mCaptureEndFrame = std::numeric_limits<uint32_t>::max();
5760         INFO() << "Capture trigger detected, disabling capture start/end frame.";
5761     }
5762 
5763     std::string labelFromEnv =
5764         GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureLabelVarName, kAndroidCaptureLabel);
5765     if (!labelFromEnv.empty())
5766     {
5767         // Optional label to provide unique file names and namespaces
5768         mCaptureLabel = labelFromEnv;
5769     }
5770 
5771     std::string compressionFromEnv =
5772         GetEnvironmentVarOrUnCachedAndroidProperty(kCompressionVarName, kAndroidCompression);
5773     if (compressionFromEnv == "0")
5774     {
5775         mCompression = false;
5776     }
5777     std::string serializeStateFromEnv = angle::GetEnvironmentVar(kSerializeStateVarName);
5778     if (serializeStateFromEnv == "1")
5779     {
5780         mSerializeStateEnabled = true;
5781     }
5782 
5783     std::string validateSerialiedStateFromEnv =
5784         GetEnvironmentVarOrUnCachedAndroidProperty(kValidationVarName, kAndroidValidation);
5785     if (validateSerialiedStateFromEnv == "1")
5786     {
5787         mValidateSerializedState = true;
5788     }
5789 
5790     mValidationExpression =
5791         GetEnvironmentVarOrUnCachedAndroidProperty(kValidationExprVarName, kAndroidValidationExpr);
5792 
5793     if (!mValidationExpression.empty())
5794     {
5795         INFO() << "Validation expression is " << kValidationExprVarName;
5796     }
5797 
5798     std::string trimEnabledFromEnv =
5799         GetEnvironmentVarOrUnCachedAndroidProperty(kTrimEnabledVarName, kAndroidTrimEnabled);
5800     if (trimEnabledFromEnv == "0")
5801     {
5802         mTrimEnabled = false;
5803     }
5804 
5805     // TODO: Remove. http://anglebug.com/7753
5806     std::string sourceExtFromEnv =
5807         GetEnvironmentVarOrUnCachedAndroidProperty(kSourceExtVarName, kAndroidSourceExt);
5808     if (!sourceExtFromEnv.empty())
5809     {
5810         if (sourceExtFromEnv == "c" || sourceExtFromEnv == "cpp")
5811         {
5812             mReplayWriter.setSourceFileExtension(sourceExtFromEnv.c_str());
5813         }
5814         else
5815         {
5816             WARN() << "Invalid capture source extension: " << sourceExtFromEnv;
5817         }
5818     }
5819 
5820     std::string sourceSizeFromEnv =
5821         GetEnvironmentVarOrUnCachedAndroidProperty(kSourceSizeVarName, kAndroidSourceSize);
5822     if (!sourceSizeFromEnv.empty())
5823     {
5824         int sourceSize = atoi(sourceSizeFromEnv.c_str());
5825         if (sourceSize < 0)
5826         {
5827             WARN() << "Invalid capture source size: " << sourceSize;
5828         }
5829         else
5830         {
5831             mReplayWriter.setSourceFileSizeThreshold(sourceSize);
5832         }
5833     }
5834 
5835     std::string forceShadowFromEnv =
5836         GetEnvironmentVarOrUnCachedAndroidProperty(kForceShadowVarName, kAndroidForceShadow);
5837     if (forceShadowFromEnv == "1")
5838     {
5839         INFO() << "Force enabling shadow memory for coherent buffer tracking.";
5840         mCoherentBufferTracker.enableShadowMemory();
5841     }
5842 
5843     if (mFrameIndex == mCaptureStartFrame)
5844     {
5845         // Capture is starting from the first frame, so set the capture active to ensure all GLES
5846         // commands issued are handled correctly by maybeCapturePreCallUpdates() and
5847         // maybeCapturePostCallUpdates().
5848         setCaptureActive();
5849     }
5850 
5851     if (mCaptureEndFrame < mCaptureStartFrame)
5852     {
5853         mEnabled = false;
5854     }
5855 
5856     mReplayWriter.setCaptureLabel(mCaptureLabel);
5857 }
5858 
5859 FrameCaptureShared::~FrameCaptureShared() = default;
5860 
PageRange(size_t start,size_t end)5861 PageRange::PageRange(size_t start, size_t end) : start(start), end(end) {}
5862 PageRange::~PageRange() = default;
5863 
AddressRange()5864 AddressRange::AddressRange() {}
AddressRange(uintptr_t start,size_t size)5865 AddressRange::AddressRange(uintptr_t start, size_t size) : start(start), size(size) {}
5866 AddressRange::~AddressRange() = default;
5867 
end()5868 uintptr_t AddressRange::end()
5869 {
5870     return start + size;
5871 }
5872 
CoherentBuffer(uintptr_t start,size_t size,size_t pageSize,bool isShadowMemoryEnabled)5873 CoherentBuffer::CoherentBuffer(uintptr_t start,
5874                                size_t size,
5875                                size_t pageSize,
5876                                bool isShadowMemoryEnabled)
5877     : mPageSize(pageSize),
5878       mShadowMemoryEnabled(isShadowMemoryEnabled),
5879       mBufferStart(start),
5880       mShadowMemory(nullptr),
5881       mShadowDirty(false)
5882 {
5883     if (mShadowMemoryEnabled)
5884     {
5885         // Shadow memory needs to have at least the size of one page, to not protect outside.
5886         size_t numShadowPages = (size / pageSize) + 1;
5887         mShadowMemory         = AlignedAlloc(numShadowPages * pageSize, pageSize);
5888         ASSERT(mShadowMemory != nullptr);
5889         start = reinterpret_cast<uintptr_t>(mShadowMemory);
5890     }
5891 
5892     mRange.start           = start;
5893     mRange.size            = size;
5894     mProtectionRange.start = rx::roundDownPow2(start, pageSize);
5895 
5896     uintptr_t protectionEnd = rx::roundUpPow2(start + size, pageSize);
5897 
5898     mProtectionRange.size = protectionEnd - mProtectionRange.start;
5899     mPageCount            = mProtectionRange.size / pageSize;
5900 
5901     mProtectionStartPage = mProtectionRange.start / mPageSize;
5902     mProtectionEndPage   = mProtectionStartPage + mPageCount;
5903 
5904     mDirtyPages = std::vector<bool>(mPageCount);
5905     mDirtyPages.assign(mPageCount, true);
5906 }
5907 
getDirtyPageRanges()5908 std::vector<PageRange> CoherentBuffer::getDirtyPageRanges()
5909 {
5910     std::vector<PageRange> dirtyPageRanges;
5911 
5912     bool inDirty = false;
5913     for (size_t i = 0; i < mPageCount; i++)
5914     {
5915         if (!inDirty && mDirtyPages[i])
5916         {
5917             // Found start of a dirty range
5918             inDirty = true;
5919             // Set end page as last page initially
5920             dirtyPageRanges.push_back(PageRange(i, mPageCount));
5921         }
5922         else if (inDirty && !mDirtyPages[i])
5923         {
5924             // Found end of a dirty range
5925             inDirty                    = false;
5926             dirtyPageRanges.back().end = i;
5927         }
5928     }
5929 
5930     return dirtyPageRanges;
5931 }
5932 
getRange()5933 AddressRange CoherentBuffer::getRange()
5934 {
5935     return mRange;
5936 }
5937 
getDirtyAddressRange(const PageRange & dirtyPageRange)5938 AddressRange CoherentBuffer::getDirtyAddressRange(const PageRange &dirtyPageRange)
5939 {
5940     AddressRange range;
5941 
5942     if (dirtyPageRange.start == 0)
5943     {
5944         // First page, use non page aligned buffer start.
5945         range.start = mRange.start;
5946     }
5947     else
5948     {
5949         range.start = mProtectionRange.start + dirtyPageRange.start * mPageSize;
5950     }
5951 
5952     if (dirtyPageRange.end == mPageCount)
5953     {
5954         // Last page, use non page aligned buffer end.
5955         range.size = mRange.end() - range.start;
5956     }
5957     else
5958     {
5959         range.size = (dirtyPageRange.end - dirtyPageRange.start) * mPageSize;
5960         // This occurs when a buffer occupies 2 pages, but is smaller than a page.
5961         if (mRange.end() < range.end())
5962         {
5963             range.size = mRange.end() - range.start;
5964         }
5965     }
5966 
5967     // Dirty range must be in buffer
5968     ASSERT(range.start >= mRange.start && mRange.end() >= range.end());
5969 
5970     return range;
5971 }
5972 
~CoherentBuffer()5973 CoherentBuffer::~CoherentBuffer()
5974 {
5975     if (mShadowMemory != nullptr)
5976     {
5977         AlignedFree(mShadowMemory);
5978     }
5979 }
5980 
isDirty()5981 bool CoherentBuffer::isDirty()
5982 {
5983     return std::find(mDirtyPages.begin(), mDirtyPages.end(), true) != mDirtyPages.end();
5984 }
5985 
contains(size_t page,size_t * relativePage)5986 bool CoherentBuffer::contains(size_t page, size_t *relativePage)
5987 {
5988     bool isInProtectionRange = page >= mProtectionStartPage && page < mProtectionEndPage;
5989     if (!isInProtectionRange)
5990     {
5991         return false;
5992     }
5993 
5994     *relativePage = page - mProtectionStartPage;
5995 
5996     ASSERT(page >= mProtectionStartPage);
5997 
5998     return true;
5999 }
6000 
protectPageRange(const PageRange & pageRange)6001 void CoherentBuffer::protectPageRange(const PageRange &pageRange)
6002 {
6003     for (size_t i = pageRange.start; i < pageRange.end; i++)
6004     {
6005         setDirty(i, false);
6006     }
6007 }
6008 
protectAll()6009 void CoherentBuffer::protectAll()
6010 {
6011     for (size_t i = 0; i < mPageCount; i++)
6012     {
6013         setDirty(i, false);
6014     }
6015 }
6016 
updateBufferMemory()6017 void CoherentBuffer::updateBufferMemory()
6018 {
6019     memcpy(reinterpret_cast<void *>(mBufferStart), reinterpret_cast<void *>(mRange.start),
6020            mRange.size);
6021 }
6022 
updateShadowMemory()6023 void CoherentBuffer::updateShadowMemory()
6024 {
6025     memcpy(reinterpret_cast<void *>(mRange.start), reinterpret_cast<void *>(mBufferStart),
6026            mRange.size);
6027     mShadowDirty = false;
6028 }
6029 
setDirty(size_t relativePage,bool dirty)6030 void CoherentBuffer::setDirty(size_t relativePage, bool dirty)
6031 {
6032     if (mDirtyPages[relativePage] == dirty)
6033     {
6034         // The page is already set.
6035         // This can happen when tracked buffers overlap in a page.
6036         return;
6037     }
6038 
6039     uintptr_t pageStart = mProtectionRange.start + relativePage * mPageSize;
6040 
6041     // Last page end must be the same as protection end
6042     if (relativePage + 1 == mPageCount)
6043     {
6044         ASSERT(mProtectionRange.end() == pageStart + mPageSize);
6045     }
6046 
6047     bool ret;
6048     if (dirty)
6049     {
6050         ret = UnprotectMemory(pageStart, mPageSize);
6051     }
6052     else
6053     {
6054         ret = ProtectMemory(pageStart, mPageSize);
6055     }
6056 
6057     if (!ret)
6058     {
6059         ERR() << "Could not set protection for buffer page " << relativePage << " at "
6060               << reinterpret_cast<void *>(pageStart) << " with size " << mPageSize;
6061     }
6062     mDirtyPages[relativePage] = dirty;
6063 }
6064 
removeProtection(PageSharingType sharingType)6065 void CoherentBuffer::removeProtection(PageSharingType sharingType)
6066 {
6067     uintptr_t start = mProtectionRange.start;
6068     size_t size     = mProtectionRange.size;
6069 
6070     switch (sharingType)
6071     {
6072         case PageSharingType::FirstShared:
6073         case PageSharingType::FirstAndLastShared:
6074             start += mPageSize;
6075             break;
6076         default:
6077             break;
6078     }
6079 
6080     switch (sharingType)
6081     {
6082         case PageSharingType::FirstShared:
6083         case PageSharingType::LastShared:
6084             size -= mPageSize;
6085             break;
6086         case PageSharingType::FirstAndLastShared:
6087             size -= (2 * mPageSize);
6088             break;
6089         default:
6090             break;
6091     }
6092 
6093     if (size == 0)
6094     {
6095         return;
6096     }
6097 
6098     if (!UnprotectMemory(start, size))
6099     {
6100         ERR() << "Could not remove protection for buffer at " << start << " with size " << size;
6101     }
6102 }
6103 
canProtectDirectly(gl::Context * context)6104 bool CoherentBufferTracker::canProtectDirectly(gl::Context *context)
6105 {
6106     gl::BufferID bufferId = context->createBuffer();
6107 
6108     gl::BufferBinding targetPacked = gl::BufferBinding::Array;
6109     context->bindBuffer(targetPacked, bufferId);
6110 
6111     // Allocate 2 pages so we will always have a full aligned page to protect
6112     GLsizei size = static_cast<GLsizei>(mPageSize * 2);
6113 
6114     context->bufferStorage(targetPacked, size, nullptr,
6115                            GL_DYNAMIC_STORAGE_BIT_EXT | GL_MAP_WRITE_BIT |
6116                                GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
6117 
6118     gl::Buffer *buffer = context->getBuffer(bufferId);
6119 
6120     angle::Result result = buffer->mapRange(
6121         context, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
6122     if (result != angle::Result::Continue)
6123     {
6124         ERR() << "Failed to mapRange of buffer.";
6125     }
6126 
6127     void *map = buffer->getMapPointer();
6128     if (map == nullptr)
6129     {
6130         ERR() << "Failed to getMapPointer of buffer.";
6131     }
6132 
6133     // Test mprotect
6134     auto start = reinterpret_cast<uintptr_t>(map);
6135 
6136     // Only protect a whole page inside the allocated memory
6137     uintptr_t protectionStart = rx::roundUpPow2(start, mPageSize);
6138     uintptr_t protectionEnd   = protectionStart + mPageSize;
6139 
6140     ASSERT(protectionStart < protectionEnd);
6141 
6142     angle::PageFaultCallback callback = [](uintptr_t address) {
6143         return angle::PageFaultHandlerRangeType::InRange;
6144     };
6145 
6146     std::unique_ptr<angle::PageFaultHandler> handler(CreatePageFaultHandler(callback));
6147 
6148     if (!handler->enable())
6149     {
6150         GLboolean unmapResult;
6151         if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
6152         {
6153             ERR() << "Could not unmap buffer.";
6154         }
6155         context->bindBuffer(targetPacked, {0});
6156 
6157         // Page fault handler could not be enabled, memory can't be protected directly.
6158         return false;
6159     }
6160 
6161     size_t protectionSize = protectionEnd - protectionStart;
6162 
6163     ASSERT(protectionSize == mPageSize);
6164 
6165     bool canProtect = angle::ProtectMemory(protectionStart, protectionSize);
6166     if (canProtect)
6167     {
6168         angle::UnprotectMemory(protectionStart, protectionSize);
6169     }
6170 
6171     // Clean up
6172     handler->disable();
6173 
6174     GLboolean unmapResult;
6175     if (buffer->unmap(context, &unmapResult) != angle::Result::Continue)
6176     {
6177         ERR() << "Could not unmap buffer.";
6178     }
6179     context->bindBuffer(targetPacked, {0});
6180     context->deleteBuffer(buffer->id());
6181 
6182     return canProtect;
6183 }
6184 
CoherentBufferTracker()6185 CoherentBufferTracker::CoherentBufferTracker() : mEnabled(false), mShadowMemoryEnabled(false)
6186 {
6187     mPageSize = GetPageSize();
6188 }
6189 
~CoherentBufferTracker()6190 CoherentBufferTracker::~CoherentBufferTracker()
6191 {
6192     disable();
6193 }
6194 
handleWrite(uintptr_t address)6195 PageFaultHandlerRangeType CoherentBufferTracker::handleWrite(uintptr_t address)
6196 {
6197     std::lock_guard<std::mutex> lock(mMutex);
6198     auto pagesInBuffers = getBufferPagesForAddress(address);
6199 
6200     if (pagesInBuffers.empty())
6201     {
6202         ERR() << "Didn't find a tracked buffer containing " << reinterpret_cast<void *>(address);
6203     }
6204 
6205     for (const auto &page : pagesInBuffers)
6206     {
6207         std::shared_ptr<CoherentBuffer> buffer = page.first;
6208         size_t relativePage                    = page.second;
6209         buffer->setDirty(relativePage, true);
6210     }
6211 
6212     return pagesInBuffers.empty() ? PageFaultHandlerRangeType::OutOfRange
6213                                   : PageFaultHandlerRangeType::InRange;
6214 }
6215 
getBufferPagesForAddress(uintptr_t address)6216 HashMap<std::shared_ptr<CoherentBuffer>, size_t> CoherentBufferTracker::getBufferPagesForAddress(
6217     uintptr_t address)
6218 {
6219     HashMap<std::shared_ptr<CoherentBuffer>, size_t> foundPages;
6220 
6221 #if defined(ANGLE_PLATFORM_ANDROID)
6222     size_t page;
6223     if (mShadowMemoryEnabled)
6224     {
6225         // Starting with Android 11 heap pointers get a tag which is stripped by the POSIX mprotect
6226         // callback. We need to add this tag manually to the untagged pointer in order to determine
6227         // the corresponding page.
6228         // See: https://source.android.com/docs/security/test/tagged-pointers
6229         // TODO(http://anglebug.com/7402): Determine when heap pointer tagging is not enabled.
6230         constexpr unsigned long long POINTER_TAG = 0xb400000000000000;
6231         unsigned long long taggedAddress         = address | POINTER_TAG;
6232         page                                     = static_cast<size_t>(taggedAddress / mPageSize);
6233     }
6234     else
6235     {
6236         // VMA allocated memory pointers are not tagged.
6237         page = address / mPageSize;
6238     }
6239 #else
6240     size_t page = address / mPageSize;
6241 #endif
6242 
6243     for (const auto &pair : mBuffers)
6244     {
6245         std::shared_ptr<CoherentBuffer> buffer = pair.second;
6246         size_t relativePage;
6247         if (buffer->contains(page, &relativePage))
6248         {
6249             foundPages.insert(std::make_pair(buffer, relativePage));
6250         }
6251     }
6252 
6253     return foundPages;
6254 }
6255 
isDirty(gl::BufferID id)6256 bool CoherentBufferTracker::isDirty(gl::BufferID id)
6257 {
6258     return mBuffers[id.value]->isDirty();
6259 }
6260 
enable()6261 void CoherentBufferTracker::enable()
6262 {
6263     if (mEnabled)
6264     {
6265         return;
6266     }
6267 
6268     PageFaultCallback callback = [this](uintptr_t address) { return handleWrite(address); };
6269 
6270     // This needs to be initialized after canProtectDirectly ran and can only be initialized once.
6271     if (!mPageFaultHandler)
6272     {
6273         mPageFaultHandler = std::unique_ptr<PageFaultHandler>(CreatePageFaultHandler(callback));
6274     }
6275 
6276     bool ret = mPageFaultHandler->enable();
6277     if (ret)
6278     {
6279         mEnabled = true;
6280     }
6281     else
6282     {
6283         ERR() << "Could not enable page fault handler.";
6284     }
6285 }
6286 
haveBuffer(gl::BufferID id)6287 bool CoherentBufferTracker::haveBuffer(gl::BufferID id)
6288 {
6289     return mBuffers.find(id.value) != mBuffers.end();
6290 }
6291 
onEndFrame()6292 void CoherentBufferTracker::onEndFrame()
6293 {
6294     std::lock_guard<std::mutex> lock(mMutex);
6295 
6296     if (!mEnabled)
6297     {
6298         return;
6299     }
6300 
6301     // Remove protection from all buffers
6302     for (const auto &pair : mBuffers)
6303     {
6304         std::shared_ptr<CoherentBuffer> buffer = pair.second;
6305         buffer->removeProtection(PageSharingType::NoneShared);
6306     }
6307 
6308     disable();
6309 }
6310 
disable()6311 void CoherentBufferTracker::disable()
6312 {
6313     if (!mEnabled)
6314     {
6315         return;
6316     }
6317 
6318     if (mPageFaultHandler->disable())
6319     {
6320         mEnabled = false;
6321     }
6322     else
6323     {
6324         ERR() << "Could not disable page fault handler.";
6325     }
6326 
6327     if (mShadowMemoryEnabled && mBuffers.size() > 0)
6328     {
6329         WARN() << "Disabling coherent buffer tracking while leaving shadow memory without "
6330                   "synchronization. Expect rendering artifacts after capture ends.";
6331     }
6332 }
6333 
addBuffer(gl::BufferID id,uintptr_t start,size_t size)6334 uintptr_t CoherentBufferTracker::addBuffer(gl::BufferID id, uintptr_t start, size_t size)
6335 {
6336     std::lock_guard<std::mutex> lock(mMutex);
6337 
6338     if (haveBuffer(id))
6339     {
6340         auto buffer = mBuffers[id.value];
6341         return buffer->getRange().start;
6342     }
6343 
6344     auto buffer = std::make_shared<CoherentBuffer>(start, size, mPageSize, mShadowMemoryEnabled);
6345     uintptr_t realOrShadowStart = buffer->getRange().start;
6346 
6347     mBuffers.insert(std::make_pair(id.value, std::move(buffer)));
6348 
6349     return realOrShadowStart;
6350 }
6351 
maybeUpdateShadowMemory()6352 void CoherentBufferTracker::maybeUpdateShadowMemory()
6353 {
6354     for (const auto &pair : mBuffers)
6355     {
6356         std::shared_ptr<CoherentBuffer> cb = pair.second;
6357         if (cb->isShadowDirty())
6358         {
6359             cb->removeProtection(PageSharingType::NoneShared);
6360             cb->updateShadowMemory();
6361             cb->protectAll();
6362         }
6363     }
6364 }
6365 
markAllShadowDirty()6366 void CoherentBufferTracker::markAllShadowDirty()
6367 {
6368     for (const auto &pair : mBuffers)
6369     {
6370         std::shared_ptr<CoherentBuffer> cb = pair.second;
6371         cb->markShadowDirty();
6372     }
6373 }
6374 
doesBufferSharePage(gl::BufferID id)6375 PageSharingType CoherentBufferTracker::doesBufferSharePage(gl::BufferID id)
6376 {
6377     bool firstPageShared = false;
6378     bool lastPageShared  = false;
6379 
6380     std::shared_ptr<CoherentBuffer> buffer = mBuffers[id.value];
6381 
6382     AddressRange range = buffer->getRange();
6383 
6384     size_t firstPage = range.start / mPageSize;
6385     size_t lastPage  = range.end() / mPageSize;
6386 
6387     for (const auto &pair : mBuffers)
6388     {
6389         gl::BufferID otherId = {pair.first};
6390         if (otherId != id)
6391         {
6392             std::shared_ptr<CoherentBuffer> otherBuffer = pair.second;
6393             size_t relativePage;
6394             if (otherBuffer->contains(firstPage, &relativePage))
6395             {
6396                 firstPageShared = true;
6397             }
6398             else if (otherBuffer->contains(lastPage, &relativePage))
6399             {
6400                 lastPageShared = true;
6401             }
6402         }
6403     }
6404 
6405     if (firstPageShared && !lastPageShared)
6406     {
6407         return PageSharingType::FirstShared;
6408     }
6409     else if (!firstPageShared && lastPageShared)
6410     {
6411         return PageSharingType::LastShared;
6412     }
6413     else if (firstPageShared && lastPageShared)
6414     {
6415         return PageSharingType::FirstAndLastShared;
6416     }
6417     else
6418     {
6419         return PageSharingType::NoneShared;
6420     }
6421 }
6422 
removeBuffer(gl::BufferID id)6423 void CoherentBufferTracker::removeBuffer(gl::BufferID id)
6424 {
6425     std::lock_guard<std::mutex> lock(mMutex);
6426 
6427     if (!haveBuffer(id))
6428     {
6429         return;
6430     }
6431 
6432     // Synchronize graphics buffer memory before the buffer is removed from the tracker.
6433     if (mShadowMemoryEnabled)
6434     {
6435         mBuffers[id.value]->updateBufferMemory();
6436     }
6437 
6438     // If the buffer shares pages with other tracked buffers,
6439     // don't unprotect the overlapping pages.
6440     PageSharingType sharingType = doesBufferSharePage(id);
6441     mBuffers[id.value]->removeProtection(sharingType);
6442     mBuffers.erase(id.value);
6443 }
6444 
maybeGetShadowMemoryPointer(gl::Buffer * buffer,GLsizeiptr length,GLbitfield access)6445 void *FrameCaptureShared::maybeGetShadowMemoryPointer(gl::Buffer *buffer,
6446                                                       GLsizeiptr length,
6447                                                       GLbitfield access)
6448 {
6449     if (!(access & GL_MAP_COHERENT_BIT_EXT) || !mCoherentBufferTracker.isShadowMemoryEnabled())
6450     {
6451         return buffer->getMapPointer();
6452     }
6453 
6454     mCoherentBufferTracker.enable();
6455     uintptr_t realMapPointer = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
6456     return (void *)mCoherentBufferTracker.addBuffer(buffer->id(), realMapPointer, length);
6457 }
6458 
determineMemoryProtectionSupport(gl::Context * context)6459 void FrameCaptureShared::determineMemoryProtectionSupport(gl::Context *context)
6460 {
6461     // Skip this test if shadow memory was force enabled or shadow memory requirement was detected
6462     // previously
6463     if (mCoherentBufferTracker.isShadowMemoryEnabled())
6464     {
6465         return;
6466     }
6467 
6468     // These known devices must use shadow memory
6469     HashMap<std::string, std::vector<std::string>> denyList = {
6470         {"Google", {"Pixel 6", "Pixel 6 Pro", "Pixel 6a", "Pixel 7", "Pixel 7 Pro"}},
6471     };
6472 
6473     angle::SystemInfo info;
6474     angle::GetSystemInfo(&info);
6475     bool isDeviceDenyListed = false;
6476 
6477     if (denyList.find(info.machineManufacturer) != denyList.end())
6478     {
6479         const std::vector<std::string> &models = denyList[info.machineManufacturer];
6480         isDeviceDenyListed =
6481             std::find(models.begin(), models.end(), info.machineModelName) != models.end();
6482     }
6483 
6484     if (isDeviceDenyListed)
6485     {
6486         WARN() << "Direct memory protection not possible on deny listed device '"
6487                << info.machineModelName
6488                << "', enabling shadow memory for coherent buffer tracking.";
6489         mCoherentBufferTracker.enableShadowMemory();
6490     }
6491     else
6492     {
6493         // Device is not on deny listed. Run a test if we actually can protect directly. Do this
6494         // only on assertion enabled builds.
6495         ASSERT(mCoherentBufferTracker.canProtectDirectly(context));
6496     }
6497 }
6498 
trackBufferMapping(const gl::Context * context,CallCapture * call,gl::BufferID id,gl::Buffer * buffer,GLintptr offset,GLsizeiptr length,bool writable,bool coherent)6499 void FrameCaptureShared::trackBufferMapping(const gl::Context *context,
6500                                             CallCapture *call,
6501                                             gl::BufferID id,
6502                                             gl::Buffer *buffer,
6503                                             GLintptr offset,
6504                                             GLsizeiptr length,
6505                                             bool writable,
6506                                             bool coherent)
6507 {
6508     // Track that the buffer was mapped
6509     mResourceTracker.setBufferMapped(context->id(), id.value);
6510 
6511     if (writable)
6512     {
6513         // If this buffer was mapped writable, we don't have any visibility into what
6514         // happens to it. Therefore, remember the details about it, and we'll read it back
6515         // on Unmap to repopulate it during replay.
6516         mBufferDataMap[id] = std::make_pair(offset, length);
6517 
6518         // Track that this buffer was potentially modified
6519         mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
6520             .setModifiedResource(id.value);
6521 
6522         // Track coherent buffer
6523         // Check if capture is active to not initialize the coherent buffer tracker on the
6524         // first coherent glMapBufferRange call.
6525         if (coherent && isCaptureActive())
6526         {
6527             mCoherentBufferTracker.enable();
6528             // When not using shadow memory, adding buffers to the tracking happens here instead of
6529             // during mapping
6530             if (!mCoherentBufferTracker.isShadowMemoryEnabled())
6531             {
6532                 uintptr_t data = reinterpret_cast<uintptr_t>(buffer->getMapPointer());
6533                 mCoherentBufferTracker.addBuffer(id, data, length);
6534             }
6535         }
6536     }
6537 }
6538 
trackTextureUpdate(const gl::Context * context,const CallCapture & call)6539 void FrameCaptureShared::trackTextureUpdate(const gl::Context *context, const CallCapture &call)
6540 {
6541     int index             = 0;
6542     std::string paramName = "targetPacked";
6543     ParamType paramType   = ParamType::TTextureTarget;
6544 
6545     // Some calls provide the textureID directly
6546     // For the rest, look it up based on the currently bound texture
6547     switch (call.entryPoint)
6548     {
6549         case EntryPoint::GLCompressedCopyTextureCHROMIUM:
6550             index     = 1;
6551             paramName = "destIdPacked";
6552             paramType = ParamType::TTextureID;
6553             break;
6554         case EntryPoint::GLCopyTextureCHROMIUM:
6555         case EntryPoint::GLCopySubTextureCHROMIUM:
6556         case EntryPoint::GLCopyTexture3DANGLE:
6557             index     = 3;
6558             paramName = "destIdPacked";
6559             paramType = ParamType::TTextureID;
6560             break;
6561         case EntryPoint::GLCopyImageSubData:
6562         case EntryPoint::GLCopyImageSubDataEXT:
6563         case EntryPoint::GLCopyImageSubDataOES:
6564             index     = 7;
6565             paramName = "dstTarget";
6566             paramType = ParamType::TGLenum;
6567             break;
6568         default:
6569             break;
6570     }
6571 
6572     GLuint id = 0;
6573     switch (paramType)
6574     {
6575         case ParamType::TTextureTarget:
6576         {
6577             gl::TextureTarget targetPacked =
6578                 call.params.getParam(paramName.c_str(), ParamType::TTextureTarget, index)
6579                     .value.TextureTargetVal;
6580             gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
6581             gl::Texture *texture        = context->getState().getTargetTexture(textureType);
6582             id                          = texture->id().value;
6583             break;
6584         }
6585         case ParamType::TTextureID:
6586         {
6587             gl::TextureID destIDPacked =
6588                 call.params.getParam(paramName.c_str(), ParamType::TTextureID, index)
6589                     .value.TextureIDVal;
6590             id = destIDPacked.value;
6591             break;
6592         }
6593         case ParamType::TGLenum:
6594         {
6595             GLenum target =
6596                 call.params.getParam(paramName.c_str(), ParamType::TGLenum, index).value.GLenumVal;
6597 
6598             if (target == GL_TEXTURE_CUBE_MAP)
6599             {
6600                 // CopyImageSubData doesn't support cube faces, but PackedParams requires one
6601                 target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
6602             }
6603 
6604             gl::TextureTarget targetPacked = gl::PackParam<gl::TextureTarget>(target);
6605             gl::TextureType textureType    = gl::TextureTargetToType(targetPacked);
6606             gl::Texture *texture           = context->getState().getTargetTexture(textureType);
6607             id                             = texture->id().value;
6608             break;
6609         }
6610         default:
6611             ERR() << "Unhandled paramType= " << static_cast<int>(paramType);
6612             UNREACHABLE();
6613             break;
6614     }
6615 
6616     // Mark it as modified
6617     mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Texture)
6618         .setModifiedResource(id);
6619 }
6620 
trackDefaultUniformUpdate(const gl::Context * context,const CallCapture & call)6621 void FrameCaptureShared::trackDefaultUniformUpdate(const gl::Context *context,
6622                                                    const CallCapture &call)
6623 {
6624     DefaultUniformType defaultUniformType = GetDefaultUniformType(call);
6625 
6626     GLuint programID = 0;
6627     int location     = 0;
6628 
6629     // We track default uniform updates by program and location, so look them up in parameters
6630     if (defaultUniformType == DefaultUniformType::CurrentProgram)
6631     {
6632         programID = context->getActiveLinkedProgram()->id().value;
6633 
6634         location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 0)
6635                        .value.UniformLocationVal.value;
6636     }
6637     else
6638     {
6639         ASSERT(defaultUniformType == DefaultUniformType::SpecifiedProgram);
6640 
6641         programID = call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
6642                         .value.ShaderProgramIDVal.value;
6643 
6644         location = call.params.getParam("locationPacked", ParamType::TUniformLocation, 1)
6645                        .value.UniformLocationVal.value;
6646     }
6647 
6648     const TrackedResource &trackedShaderProgram =
6649         mResourceTracker.getTrackedResource(context->id(), ResourceIDType::ShaderProgram);
6650     const ResourceSet &startingPrograms = trackedShaderProgram.getStartingResources();
6651     const ResourceSet &programsToRegen  = trackedShaderProgram.getResourcesToRegen();
6652 
6653     // If this program was in our starting set, track its uniform updates. Unless it was deleted,
6654     // then its uniforms will all be regenned along wih with the program.
6655     if (startingPrograms.find(programID) != startingPrograms.end() &&
6656         programsToRegen.find(programID) == programsToRegen.end())
6657     {
6658         // Track that we need to set this default uniform value again
6659         mResourceTracker.setModifiedDefaultUniform({programID}, {location});
6660     }
6661 }
6662 
trackVertexArrayUpdate(const gl::Context * context,const CallCapture & call)6663 void FrameCaptureShared::trackVertexArrayUpdate(const gl::Context *context, const CallCapture &call)
6664 {
6665     // Look up the currently bound vertex array
6666     gl::VertexArrayID id = context->getState().getVertexArray()->id();
6667 
6668     // Mark it as modified
6669     mResourceTracker.getTrackedResource(context->id(), ResourceIDType::VertexArray)
6670         .setModifiedResource(id.value);
6671 }
6672 
updateCopyImageSubData(CallCapture & call)6673 void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
6674 {
6675     // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
6676     // packed types that can remapped using gTextureMap and gRenderbufferMap
6677 
6678     GLint srcName    = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
6679     GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
6680     switch (srcTarget)
6681     {
6682         case GL_RENDERBUFFER:
6683         {
6684             // Convert the GLuint to RenderbufferID
6685             gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
6686             call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
6687                                              srcRenderbufferID, 0);
6688             break;
6689         }
6690         case GL_TEXTURE_2D:
6691         case GL_TEXTURE_2D_ARRAY:
6692         case GL_TEXTURE_3D:
6693         case GL_TEXTURE_CUBE_MAP:
6694         {
6695             // Convert the GLuint to TextureID
6696             gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
6697             call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
6698             break;
6699         }
6700         default:
6701             ERR() << "Unhandled srcTarget = " << srcTarget;
6702             UNREACHABLE();
6703             break;
6704     }
6705 
6706     // Change dstName to the appropriate type based on dstTarget
6707     GLint dstName    = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
6708     GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
6709     switch (dstTarget)
6710     {
6711         case GL_RENDERBUFFER:
6712         {
6713             // Convert the GLuint to RenderbufferID
6714             gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
6715             call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
6716                                              dstRenderbufferID, 6);
6717             break;
6718         }
6719         case GL_TEXTURE_2D:
6720         case GL_TEXTURE_2D_ARRAY:
6721         case GL_TEXTURE_3D:
6722         case GL_TEXTURE_CUBE_MAP:
6723         {
6724             // Convert the GLuint to TextureID
6725             gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
6726             call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
6727             break;
6728         }
6729         default:
6730             ERR() << "Unhandled dstTarget = " << dstTarget;
6731             UNREACHABLE();
6732             break;
6733     }
6734 }
6735 
overrideProgramBinary(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)6736 void FrameCaptureShared::overrideProgramBinary(const gl::Context *context,
6737                                                CallCapture &inCall,
6738                                                std::vector<CallCapture> &outCalls)
6739 {
6740     // Program binaries are inherently non-portable, even between two ANGLE builds.
6741     // If an application is using glProgramBinary in the middle of a trace, we need to replace
6742     // those calls with an equivalent sequence of portable calls.
6743     //
6744     // For example, here is a sequence an app could use for glProgramBinary:
6745     //
6746     //   gShaderProgramMap[42] = glCreateProgram();
6747     //   glProgramBinary(gShaderProgramMap[42], GL_PROGRAM_BINARY_ANGLE, gBinaryData[x], 1000);
6748     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
6749     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
6750     //
6751     // With this override, the glProgramBinary call will be replaced like so:
6752     //
6753     //   gShaderProgramMap[42] = glCreateProgram();
6754     //   === Begin override ===
6755     //   gShaderProgramMap[43] = glCreateShader(GL_VERTEX_SHADER);
6756     //   glShaderSource(gShaderProgramMap[43], 1, string_0, &gBinaryData[100]);
6757     //   glCompileShader(gShaderProgramMap[43]);
6758     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
6759     //   glDeleteShader(gShaderProgramMap[43]);
6760     //   gShaderProgramMap[43] = glCreateShader(GL_FRAGMENT_SHADER);
6761     //   glShaderSource(gShaderProgramMap[43], 1, string_1, &gBinaryData[200]);
6762     //   glCompileShader(gShaderProgramMap[43]);
6763     //   glAttachShader(gShaderProgramMap[42], gShaderProgramMap[43]);
6764     //   glDeleteShader(gShaderProgramMap[43]);
6765     //   glBindAttribLocation(gShaderProgramMap[42], 0, "attrib1");
6766     //   glBindAttribLocation(gShaderProgramMap[42], 1, "attrib2");
6767     //   glLinkProgram(gShaderProgramMap[42]);
6768     //   UpdateUniformLocation(gShaderProgramMap[42], "foo", 0, 20);
6769     //   UpdateUniformLocation(gShaderProgramMap[42], "bar", 72, 1);
6770     //   glUseProgram(gShaderProgramMap[42]);
6771     //   UpdateCurrentProgram(gShaderProgramMap[42]);
6772     //   glUniform4fv(gUniformLocations[gCurrentProgram][0], 20, &gBinaryData[300]);
6773     //   glUniform1iv(gUniformLocations[gCurrentProgram][72], 1, &gBinaryData[400]);
6774     //   === End override ===
6775     //   glGetProgramiv(gShaderProgramMap[42], GL_LINK_STATUS, gReadBuffer);
6776     //   glGetProgramiv(gShaderProgramMap[42], GL_PROGRAM_BINARY_LENGTH, gReadBuffer);
6777     //
6778     // To facilitate this override, we are serializing each shader stage source into the binary
6779     // itself.  See Program::serialize and Program::deserialize.  Once extracted from the binary,
6780     // they will be available via getProgramSources.
6781 
6782     gl::ShaderProgramID id = inCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
6783                                  .value.ShaderProgramIDVal;
6784 
6785     gl::Program *program = context->getProgramResolveLink(id);
6786     ASSERT(program);
6787 
6788     mResourceTracker.onShaderProgramAccess(id);
6789     gl::ShaderProgramID tempShaderStartID = {mResourceTracker.getMaxShaderPrograms()};
6790     GenerateLinkedProgram(context, context->getState(), &mResourceTracker, &outCalls, program, id,
6791                           tempShaderStartID, getProgramSources(id));
6792 }
6793 
captureCustomMapBufferFromContext(const gl::Context * context,const char * entryPointName,CallCapture & call,std::vector<CallCapture> & callsOut)6794 void FrameCaptureShared::captureCustomMapBufferFromContext(const gl::Context *context,
6795                                                            const char *entryPointName,
6796                                                            CallCapture &call,
6797                                                            std::vector<CallCapture> &callsOut)
6798 {
6799     gl::BufferBinding binding =
6800         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
6801     gl::Buffer *buffer = context->getState().getTargetBuffer(binding);
6802 
6803     if (call.entryPoint == EntryPoint::GLMapBufferRange ||
6804         call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
6805     {
6806         GLintptr offset = call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
6807         GLsizeiptr length =
6808             call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
6809         GLbitfield access =
6810             call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
6811 
6812         trackBufferMapping(context, &call, buffer->id(), buffer, offset, length,
6813                            access & GL_MAP_WRITE_BIT, access & GL_MAP_COHERENT_BIT_EXT);
6814     }
6815     else
6816     {
6817         ASSERT(call.entryPoint == EntryPoint::GLMapBufferOES);
6818         GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
6819         bool writeAccess =
6820             (access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE);
6821         trackBufferMapping(context, &call, buffer->id(), buffer, 0,
6822                            static_cast<GLsizeiptr>(buffer->getSize()), writeAccess, false);
6823     }
6824 
6825     CaptureCustomMapBuffer(entryPointName, call, callsOut, buffer->id());
6826 }
6827 
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & inCall,std::vector<CallCapture> & outCalls)6828 void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context,
6829                                                  CallCapture &inCall,
6830                                                  std::vector<CallCapture> &outCalls)
6831 {
6832     switch (inCall.entryPoint)
6833     {
6834         case EntryPoint::GLCopyImageSubData:
6835         case EntryPoint::GLCopyImageSubDataEXT:
6836         case EntryPoint::GLCopyImageSubDataOES:
6837         {
6838             // We must look at the src and dst target types to determine which remap table to use
6839             updateCopyImageSubData(inCall);
6840             outCalls.emplace_back(std::move(inCall));
6841             break;
6842         }
6843         case EntryPoint::GLProgramBinary:
6844         case EntryPoint::GLProgramBinaryOES:
6845         {
6846             // Binary formats are not portable at all, so replace the calls with full linking
6847             // sequence
6848             overrideProgramBinary(context, inCall, outCalls);
6849             break;
6850         }
6851         case EntryPoint::GLUniformBlockBinding:
6852         {
6853             CaptureCustomUniformBlockBinding(inCall, outCalls);
6854             break;
6855         }
6856         case EntryPoint::GLMapBufferRange:
6857         {
6858             captureCustomMapBufferFromContext(context, "MapBufferRange", inCall, outCalls);
6859             break;
6860         }
6861         case EntryPoint::GLMapBufferRangeEXT:
6862         {
6863             captureCustomMapBufferFromContext(context, "MapBufferRangeEXT", inCall, outCalls);
6864             break;
6865         }
6866         case EntryPoint::GLMapBuffer:
6867         {
6868             // Currently desktop GL is not implemented.
6869             UNREACHABLE();
6870             break;
6871         }
6872         case EntryPoint::GLMapBufferOES:
6873         {
6874             captureCustomMapBufferFromContext(context, "MapBufferOES", inCall, outCalls);
6875             break;
6876         }
6877         case EntryPoint::GLCreateShader:
6878         {
6879             CaptureCustomShaderProgram("CreateShader", inCall, outCalls);
6880             break;
6881         }
6882         case EntryPoint::GLCreateProgram:
6883         {
6884             CaptureCustomShaderProgram("CreateProgram", inCall, outCalls);
6885             break;
6886         }
6887         case EntryPoint::GLCreateShaderProgramv:
6888         {
6889             CaptureCustomShaderProgram("CreateShaderProgramv", inCall, outCalls);
6890             break;
6891         }
6892         case EntryPoint::GLFenceSync:
6893         {
6894             CaptureCustomFenceSync(inCall, outCalls);
6895             break;
6896         }
6897         case EntryPoint::EGLCreateImage:
6898         {
6899             CaptureCustomCreateEGLImage("CreateEGLImage", inCall, outCalls);
6900             break;
6901         }
6902         case EntryPoint::EGLCreateImageKHR:
6903         {
6904             CaptureCustomCreateEGLImage("CreateEGLImageKHR", inCall, outCalls);
6905             break;
6906         }
6907         case EntryPoint::EGLCreateSync:
6908         {
6909             CaptureCustomCreateEGLSync("CreateEGLSync", inCall, outCalls);
6910             break;
6911         }
6912         case EntryPoint::EGLCreateSyncKHR:
6913         {
6914             CaptureCustomCreateEGLSync("CreateEGLSyncKHR", inCall, outCalls);
6915             break;
6916         }
6917         case EntryPoint::EGLCreatePbufferSurface:
6918         {
6919             CaptureCustomCreatePbufferSurface(inCall, outCalls);
6920             break;
6921         }
6922         case EntryPoint::EGLCreateNativeClientBufferANDROID:
6923         {
6924             CaptureCustomCreateNativeClientbuffer(inCall, outCalls);
6925             break;
6926         }
6927 
6928         default:
6929         {
6930             // Pass the single call through
6931             outCalls.emplace_back(std::move(inCall));
6932             break;
6933         }
6934     }
6935 }
6936 
maybeCaptureCoherentBuffers(const gl::Context * context)6937 void FrameCaptureShared::maybeCaptureCoherentBuffers(const gl::Context *context)
6938 {
6939     if (!isCaptureActive())
6940     {
6941         return;
6942     }
6943 
6944     std::lock_guard<std::mutex> lock(mCoherentBufferTracker.mMutex);
6945 
6946     for (const auto &pair : mCoherentBufferTracker.mBuffers)
6947     {
6948         gl::BufferID id = {pair.first};
6949         if (mCoherentBufferTracker.isDirty(id))
6950         {
6951             captureCoherentBufferSnapshot(context, id);
6952         }
6953     }
6954 }
6955 
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)6956 void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
6957                                                           CallCapture &call,
6958                                                           size_t instanceCount)
6959 {
6960     if (!context->getStateCache().hasAnyActiveClientAttrib())
6961     {
6962         return;
6963     }
6964 
6965     // Get counts from paramBuffer.
6966     GLint firstVertex =
6967         call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
6968     GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
6969     captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
6970 }
6971 
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)6972 void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
6973                                                             CallCapture &call,
6974                                                             size_t instanceCount)
6975 {
6976     if (!context->getStateCache().hasAnyActiveClientAttrib())
6977     {
6978         return;
6979     }
6980 
6981     // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
6982     // anything anyway, so skip capturing
6983     GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
6984     if (count == 0)
6985     {
6986         return;
6987     }
6988 
6989     gl::DrawElementsType drawElementsType =
6990         call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
6991             .value.DrawElementsTypeVal;
6992     const void *indices =
6993         call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
6994 
6995     gl::IndexRange indexRange;
6996 
6997     bool restart = context->getState().isPrimitiveRestartEnabled();
6998 
6999     gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
7000     if (elementArrayBuffer)
7001     {
7002         size_t offset = reinterpret_cast<size_t>(indices);
7003         (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
7004                                                 &indexRange);
7005     }
7006     else
7007     {
7008         ASSERT(indices);
7009         indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
7010     }
7011 
7012     // index starts from 0
7013     captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
7014 }
7015 
7016 template <typename AttribT, typename FactoryT>
CreateEGLImagePreCallUpdate(const CallCapture & call,ResourceTracker & resourceTracker,ParamType paramType,FactoryT factory)7017 void CreateEGLImagePreCallUpdate(const CallCapture &call,
7018                                  ResourceTracker &resourceTracker,
7019                                  ParamType paramType,
7020                                  FactoryT factory)
7021 {
7022     EGLImage image            = call.params.getReturnValue().value.EGLImageVal;
7023     const ParamCapture &param = call.params.getParam("attrib_list", paramType, 4);
7024     const AttribT *attribs =
7025         param.data.empty() ? nullptr : reinterpret_cast<const AttribT *>(param.data[0].data());
7026     egl::AttributeMap attributeMap = factory(attribs);
7027     attributeMap.initializeWithoutValidation();
7028     resourceTracker.getImageToAttribTable().insert(
7029         std::pair<EGLImage, egl::AttributeMap>(image, attributeMap));
7030 }
7031 
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call,std::vector<CallCapture> * shareGroupSetupCalls,ResourceIDToSetupCallsMap * resourceIDToSetupCalls)7032 void FrameCaptureShared::maybeCapturePreCallUpdates(
7033     const gl::Context *context,
7034     CallCapture &call,
7035     std::vector<CallCapture> *shareGroupSetupCalls,
7036     ResourceIDToSetupCallsMap *resourceIDToSetupCalls)
7037 {
7038     switch (call.entryPoint)
7039     {
7040         case EntryPoint::GLVertexAttribPointer:
7041         case EntryPoint::GLVertexPointer:
7042         case EntryPoint::GLColorPointer:
7043         case EntryPoint::GLTexCoordPointer:
7044         case EntryPoint::GLNormalPointer:
7045         case EntryPoint::GLPointSizePointerOES:
7046         {
7047             // Get array location
7048             GLuint index = 0;
7049             if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
7050             {
7051                 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
7052             }
7053             else
7054             {
7055                 gl::ClientVertexArrayType type;
7056                 switch (call.entryPoint)
7057                 {
7058                     case EntryPoint::GLVertexPointer:
7059                         type = gl::ClientVertexArrayType::Vertex;
7060                         break;
7061                     case EntryPoint::GLColorPointer:
7062                         type = gl::ClientVertexArrayType::Color;
7063                         break;
7064                     case EntryPoint::GLTexCoordPointer:
7065                         type = gl::ClientVertexArrayType::TextureCoord;
7066                         break;
7067                     case EntryPoint::GLNormalPointer:
7068                         type = gl::ClientVertexArrayType::Normal;
7069                         break;
7070                     case EntryPoint::GLPointSizePointerOES:
7071                         type = gl::ClientVertexArrayType::PointSize;
7072                         break;
7073                     default:
7074                         UNREACHABLE();
7075                         type = gl::ClientVertexArrayType::InvalidEnum;
7076                 }
7077                 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
7078             }
7079 
7080             if (call.params.hasClientArrayData())
7081             {
7082                 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
7083             }
7084             else
7085             {
7086                 mClientVertexArrayMap[index] = -1;
7087             }
7088             break;
7089         }
7090 
7091         case EntryPoint::GLGenFramebuffers:
7092         case EntryPoint::GLGenFramebuffersOES:
7093         {
7094             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7095             const gl::FramebufferID *framebufferIDs =
7096                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1)
7097                     .value.FramebufferIDPointerVal;
7098             for (GLsizei i = 0; i < count; i++)
7099             {
7100                 handleGennedResource(context, framebufferIDs[i]);
7101             }
7102             break;
7103         }
7104 
7105         case EntryPoint::GLBindFramebuffer:
7106         case EntryPoint::GLBindFramebufferOES:
7107             maybeGenResourceOnBind<gl::FramebufferID>(context, call);
7108             break;
7109 
7110         case EntryPoint::GLGenRenderbuffers:
7111         case EntryPoint::GLGenRenderbuffersOES:
7112         {
7113             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7114             const gl::RenderbufferID *renderbufferIDs =
7115                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1)
7116                     .value.RenderbufferIDPointerVal;
7117             for (GLsizei i = 0; i < count; i++)
7118             {
7119                 handleGennedResource(context, renderbufferIDs[i]);
7120             }
7121             break;
7122         }
7123 
7124         case EntryPoint::GLBindRenderbuffer:
7125         case EntryPoint::GLBindRenderbufferOES:
7126             maybeGenResourceOnBind<gl::RenderbufferID>(context, call);
7127             break;
7128 
7129         case EntryPoint::GLDeleteRenderbuffers:
7130         case EntryPoint::GLDeleteRenderbuffersOES:
7131         {
7132             // Look up how many renderbuffers are being deleted
7133             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7134 
7135             // Look up the pointer to list of renderbuffers
7136             const gl::RenderbufferID *renderbufferIDs =
7137                 call.params
7138                     .getParam("renderbuffersPacked", ParamType::TRenderbufferIDConstPointer, 1)
7139                     .value.RenderbufferIDConstPointerVal;
7140 
7141             // For each renderbuffer listed for deletion
7142             for (int32_t i = 0; i < n; ++i)
7143             {
7144                 // If we're capturing, track what renderbuffers have been deleted
7145                 handleDeletedResource(context, renderbufferIDs[i]);
7146             }
7147             break;
7148         }
7149 
7150         case EntryPoint::GLGenTextures:
7151         {
7152             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7153             const gl::TextureID *textureIDs =
7154                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1)
7155                     .value.TextureIDPointerVal;
7156             for (GLsizei i = 0; i < count; i++)
7157             {
7158                 // If we're capturing, track what new textures have been genned
7159                 handleGennedResource(context, textureIDs[i]);
7160             }
7161             break;
7162         }
7163 
7164         case EntryPoint::GLBindTexture:
7165             maybeGenResourceOnBind<gl::TextureID>(context, call);
7166             break;
7167 
7168         case EntryPoint::GLDeleteBuffers:
7169         {
7170             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7171             const gl::BufferID *bufferIDs =
7172                 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
7173                     .value.BufferIDConstPointerVal;
7174             for (GLsizei i = 0; i < count; i++)
7175             {
7176                 // For each buffer being deleted, check our backup of data and remove it
7177                 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
7178                 if (bufferDataInfo != mBufferDataMap.end())
7179                 {
7180                     mBufferDataMap.erase(bufferDataInfo);
7181                 }
7182                 // If we're capturing, track what buffers have been deleted
7183                 handleDeletedResource(context, bufferIDs[i]);
7184             }
7185             break;
7186         }
7187 
7188         case EntryPoint::GLGenBuffers:
7189         {
7190             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7191             const gl::BufferID *bufferIDs =
7192                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
7193                     .value.BufferIDPointerVal;
7194             for (GLsizei i = 0; i < count; i++)
7195             {
7196                 handleGennedResource(context, bufferIDs[i]);
7197             }
7198             break;
7199         }
7200 
7201         case EntryPoint::GLBindBuffer:
7202             maybeGenResourceOnBind<gl::BufferID>(context, call);
7203             break;
7204 
7205         case EntryPoint::GLDeleteProgramPipelines:
7206         case EntryPoint::GLDeleteProgramPipelinesEXT:
7207         {
7208             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7209             const gl::ProgramPipelineID *pipelineIDs =
7210                 call.params
7211                     .getParam("pipelinesPacked", ParamType::TProgramPipelineIDConstPointer, 1)
7212                     .value.ProgramPipelineIDPointerVal;
7213             for (GLsizei i = 0; i < count; i++)
7214             {
7215                 handleDeletedResource(context, pipelineIDs[i]);
7216             }
7217             break;
7218         }
7219 
7220         case EntryPoint::GLGenProgramPipelines:
7221         case EntryPoint::GLGenProgramPipelinesEXT:
7222         {
7223             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7224             const gl::ProgramPipelineID *pipelineIDs =
7225                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1)
7226                     .value.ProgramPipelineIDPointerVal;
7227             for (GLsizei i = 0; i < count; i++)
7228             {
7229                 handleGennedResource(context, pipelineIDs[i]);
7230             }
7231             break;
7232         }
7233 
7234         case EntryPoint::GLDeleteSync:
7235         {
7236             gl::SyncID sync =
7237                 call.params.getParam("syncPacked", ParamType::TSyncID, 0).value.SyncIDVal;
7238             FrameCaptureShared *frameCaptureShared =
7239                 context->getShareGroup()->getFrameCaptureShared();
7240             // If we're capturing, track which fence sync has been deleted
7241             if (frameCaptureShared->isCaptureActive())
7242             {
7243                 mResourceTracker.setDeletedFenceSync(sync);
7244             }
7245             break;
7246         }
7247 
7248         case EntryPoint::GLDrawArrays:
7249         {
7250             maybeCaptureDrawArraysClientData(context, call, 1);
7251             maybeCaptureCoherentBuffers(context);
7252             break;
7253         }
7254 
7255         case EntryPoint::GLDrawArraysInstanced:
7256         case EntryPoint::GLDrawArraysInstancedANGLE:
7257         case EntryPoint::GLDrawArraysInstancedEXT:
7258         {
7259             GLsizei instancecount =
7260                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
7261                     .value.GLsizeiVal;
7262 
7263             maybeCaptureDrawArraysClientData(context, call, instancecount);
7264             maybeCaptureCoherentBuffers(context);
7265             break;
7266         }
7267 
7268         case EntryPoint::GLDrawElements:
7269         {
7270             maybeCaptureDrawElementsClientData(context, call, 1);
7271             maybeCaptureCoherentBuffers(context);
7272             break;
7273         }
7274 
7275         case EntryPoint::GLDrawElementsInstanced:
7276         case EntryPoint::GLDrawElementsInstancedANGLE:
7277         case EntryPoint::GLDrawElementsInstancedEXT:
7278         {
7279             GLsizei instancecount =
7280                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
7281                     .value.GLsizeiVal;
7282 
7283             maybeCaptureDrawElementsClientData(context, call, instancecount);
7284             maybeCaptureCoherentBuffers(context);
7285             break;
7286         }
7287 
7288         case EntryPoint::GLCreateShaderProgramv:
7289         {
7290             // Refresh the cached shader sources.
7291             // The command CreateShaderProgramv() creates a stand-alone program from an array of
7292             // null-terminated source code strings for a single shader type, so we need update the
7293             // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
7294             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7295             const ParamCapture &paramCapture =
7296                 call.params.getParam("typePacked", ParamType::TShaderType, 0);
7297             const ParamCapture &lineCount = call.params.getParam("count", ParamType::TGLsizei, 1);
7298             const ParamCapture &strings =
7299                 call.params.getParam("strings", ParamType::TGLcharConstPointerPointer, 2);
7300 
7301             std::ostringstream sourceString;
7302             for (int i = 0; i < lineCount.value.GLsizeiVal; ++i)
7303             {
7304                 sourceString << strings.value.GLcharConstPointerPointerVal[i];
7305             }
7306 
7307             gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
7308             ProgramSources source;
7309             source[shaderType] = sourceString.str();
7310             setProgramSources(programID, source);
7311             handleGennedResource(context, programID);
7312             mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7313             break;
7314         }
7315 
7316         case EntryPoint::GLCreateProgram:
7317         {
7318             // If we're capturing, track which programs have been created
7319             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
7320             handleGennedResource(context, programID);
7321 
7322             mResourceTracker.setShaderProgramType(programID, ShaderProgramType::ProgramType);
7323             break;
7324         }
7325 
7326         case EntryPoint::GLDeleteProgram:
7327         {
7328             // If we're capturing, track which programs have been deleted
7329             const ParamCapture &param =
7330                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7331             handleDeletedResource(context, param.value.ShaderProgramIDVal);
7332 
7333             // If this assert fires, it means a ShaderProgramID has changed from program to shader
7334             // which is unsupported
7335             ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7336                    ShaderProgramType::ProgramType);
7337 
7338             break;
7339         }
7340 
7341         case EntryPoint::GLCreateShader:
7342         {
7343             // If we're capturing, track which shaders have been created
7344             gl::ShaderProgramID shaderID = {call.params.getReturnValue().value.GLuintVal};
7345             handleGennedResource(context, shaderID);
7346 
7347             mResourceTracker.setShaderProgramType(shaderID, ShaderProgramType::ShaderType);
7348             break;
7349         }
7350 
7351         case EntryPoint::GLDeleteShader:
7352         {
7353             // If we're capturing, track which shaders have been deleted
7354             const ParamCapture &param =
7355                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0);
7356             handleDeletedResource(context, param.value.ShaderProgramIDVal);
7357 
7358             // If this assert fires, it means a ShaderProgramID has changed from shader to program
7359             // which is unsupported
7360             ASSERT(mResourceTracker.getShaderProgramType(param.value.ShaderProgramIDVal) ==
7361                    ShaderProgramType::ShaderType);
7362             break;
7363         }
7364 
7365         case EntryPoint::GLCompileShader:
7366         {
7367             // Refresh the cached shader sources.
7368             gl::ShaderProgramID shaderID =
7369                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
7370                     .value.ShaderProgramIDVal;
7371             const gl::Shader *shader = context->getShader(shaderID);
7372             // Shaders compiled for ProgramBinary will not have a shader created
7373             if (shader)
7374             {
7375                 setShaderSource(shaderID, shader->getSourceString());
7376             }
7377             break;
7378         }
7379 
7380         case EntryPoint::GLLinkProgram:
7381         {
7382             // Refresh the cached program sources.
7383             gl::ShaderProgramID programID =
7384                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
7385                     .value.ShaderProgramIDVal;
7386             const gl::Program *program = context->getProgramResolveLink(programID);
7387             // Programs linked in support of ProgramBinary will not have attached shaders
7388             if (program->getState().hasAttachedShader())
7389             {
7390                 setProgramSources(programID, GetAttachedProgramSources(program));
7391             }
7392             break;
7393         }
7394 
7395         case EntryPoint::GLCompressedTexImage1D:
7396         case EntryPoint::GLCompressedTexSubImage1D:
7397         {
7398             UNIMPLEMENTED();
7399             break;
7400         }
7401 
7402         case EntryPoint::GLDeleteTextures:
7403         {
7404             // Free any TextureLevelDataMap entries being tracked for this texture
7405             // This is to cover the scenario where a texture has been created, its
7406             // levels cached, then texture deleted and recreated, receiving the same ID
7407 
7408             // Look up how many textures are being deleted
7409             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7410 
7411             // Look up the pointer to list of textures
7412             const gl::TextureID *textureIDs =
7413                 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
7414                     .value.TextureIDConstPointerVal;
7415 
7416             // For each texture listed for deletion
7417             for (int32_t i = 0; i < n; ++i)
7418             {
7419                 // If we're capturing, track what textures have been deleted
7420                 handleDeletedResource(context, textureIDs[i]);
7421             }
7422             break;
7423         }
7424 
7425         case EntryPoint::GLMapBuffer:
7426         case EntryPoint::GLMapBufferOES:
7427         {
7428             gl::BufferBinding target =
7429                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7430                     .value.BufferBindingVal;
7431 
7432             GLbitfield access =
7433                 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
7434 
7435             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7436 
7437             GLintptr offset   = 0;
7438             GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
7439 
7440             bool writable =
7441                 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
7442 
7443             FrameCaptureShared *frameCaptureShared =
7444                 context->getShareGroup()->getFrameCaptureShared();
7445             frameCaptureShared->trackBufferMapping(context, &call, buffer->id(), buffer, offset,
7446                                                    length, writable, false);
7447             break;
7448         }
7449 
7450         case EntryPoint::GLUnmapNamedBuffer:
7451         {
7452             UNIMPLEMENTED();
7453             break;
7454         }
7455 
7456         case EntryPoint::GLUnmapBuffer:
7457         case EntryPoint::GLUnmapBufferOES:
7458         {
7459             // See if we need to capture the buffer contents
7460             captureMappedBufferSnapshot(context, call);
7461 
7462             // Track that the buffer was unmapped, for use during state reset
7463             gl::BufferBinding target =
7464                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7465                     .value.BufferBindingVal;
7466             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7467             mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
7468 
7469             // Remove from CoherentBufferTracker
7470             mCoherentBufferTracker.removeBuffer(buffer->id());
7471             break;
7472         }
7473 
7474         case EntryPoint::GLBufferData:
7475         case EntryPoint::GLBufferSubData:
7476         {
7477             gl::BufferBinding target =
7478                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7479                     .value.BufferBindingVal;
7480 
7481             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7482 
7483             // Track that this buffer's contents have been modified
7484             mResourceTracker.getTrackedResource(context->id(), ResourceIDType::Buffer)
7485                 .setModifiedResource(buffer->id().value);
7486 
7487             // BufferData is equivalent to UnmapBuffer, for what we're tracking.
7488             // From the ES 3.1 spec in BufferData section:
7489             //     If any portion of the buffer object is mapped in the current context or any
7490             //     context current to another thread, it is as though UnmapBuffer (see section
7491             //     6.3.1) is executed in each such context prior to deleting the existing data
7492             //     store.
7493             // Track that the buffer was unmapped, for use during state reset
7494             mResourceTracker.setBufferUnmapped(context->id(), buffer->id().value);
7495 
7496             break;
7497         }
7498 
7499         case EntryPoint::GLCopyBufferSubData:
7500         {
7501             maybeCaptureCoherentBuffers(context);
7502             break;
7503         }
7504         case EntryPoint::GLFinish:
7505         {
7506             // When using shadow memory we might need to synchronize it here.
7507             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7508             {
7509                 mCoherentBufferTracker.maybeUpdateShadowMemory();
7510             }
7511             break;
7512         }
7513         case EntryPoint::GLDeleteFramebuffers:
7514         case EntryPoint::GLDeleteFramebuffersOES:
7515         {
7516             // Look up how many framebuffers are being deleted
7517             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7518 
7519             // Look up the pointer to list of framebuffers
7520             const gl::FramebufferID *framebufferIDs =
7521                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDConstPointer, 1)
7522                     .value.FramebufferIDConstPointerVal;
7523 
7524             // For each framebuffer listed for deletion
7525             for (int32_t i = 0; i < n; ++i)
7526             {
7527                 // If we're capturing, track what framebuffers have been deleted
7528                 handleDeletedResource(context, framebufferIDs[i]);
7529             }
7530             break;
7531         }
7532 
7533         case EntryPoint::GLUseProgram:
7534         {
7535             if (isCaptureActive())
7536             {
7537                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7538                     EntryPoint::GLUseProgram);
7539             }
7540             break;
7541         }
7542 
7543         case EntryPoint::GLGenVertexArrays:
7544         case EntryPoint::GLGenVertexArraysOES:
7545         {
7546             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7547             const gl::VertexArrayID *arrayIDs =
7548                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1)
7549                     .value.VertexArrayIDPointerVal;
7550             for (GLsizei i = 0; i < count; i++)
7551             {
7552                 handleGennedResource(context, arrayIDs[i]);
7553             }
7554             break;
7555         }
7556 
7557         case EntryPoint::GLDeleteVertexArrays:
7558         case EntryPoint::GLDeleteVertexArraysOES:
7559         {
7560             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
7561             const gl::VertexArrayID *arrayIDs =
7562                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDConstPointer, 1)
7563                     .value.VertexArrayIDConstPointerVal;
7564             for (GLsizei i = 0; i < count; i++)
7565             {
7566                 // If we're capturing, track which vertex arrays have been deleted
7567                 handleDeletedResource(context, arrayIDs[i]);
7568             }
7569             break;
7570         }
7571 
7572         case EntryPoint::GLBindVertexArray:
7573         case EntryPoint::GLBindVertexArrayOES:
7574         {
7575             if (isCaptureActive())
7576             {
7577                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7578                     EntryPoint::GLBindVertexArray);
7579             }
7580             break;
7581         }
7582         case EntryPoint::GLBlendFunc:
7583         {
7584             if (isCaptureActive())
7585             {
7586                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7587                     EntryPoint::GLBlendFunc);
7588             }
7589             break;
7590         }
7591         case EntryPoint::GLBlendFuncSeparate:
7592         {
7593             if (isCaptureActive())
7594             {
7595                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7596                     EntryPoint::GLBlendFuncSeparate);
7597             }
7598             break;
7599         }
7600         case EntryPoint::GLBlendEquation:
7601         case EntryPoint::GLBlendEquationSeparate:
7602         {
7603             if (isCaptureActive())
7604             {
7605                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7606                     EntryPoint::GLBlendEquationSeparate);
7607             }
7608             break;
7609         }
7610         case EntryPoint::GLColorMask:
7611         {
7612             if (isCaptureActive())
7613             {
7614                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7615                     EntryPoint::GLColorMask);
7616             }
7617             break;
7618         }
7619         case EntryPoint::GLBlendColor:
7620         {
7621             if (isCaptureActive())
7622             {
7623                 context->getFrameCapture()->getStateResetHelper().setEntryPointDirty(
7624                     EntryPoint::GLBlendColor);
7625             }
7626             break;
7627         }
7628 
7629         case EntryPoint::GLEGLImageTargetTexture2DOES:
7630         {
7631             gl::TextureType target =
7632                 call.params.getParam("targetPacked", ParamType::TTextureType, 0)
7633                     .value.TextureTypeVal;
7634             egl::ImageID imageID =
7635                 call.params.getParam("imagePacked", ParamType::TImageID, 1).value.ImageIDVal;
7636             mResourceTracker.getTextureIDToImageTable().insert(std::pair<GLuint, egl::ImageID>(
7637                 context->getState().getTargetTexture(target)->getId(), imageID));
7638             break;
7639         }
7640 
7641         case EntryPoint::EGLCreateImage:
7642         {
7643             CreateEGLImagePreCallUpdate<EGLAttrib>(call, mResourceTracker,
7644                                                    ParamType::TEGLAttribPointer,
7645                                                    egl::AttributeMap::CreateFromAttribArray);
7646             break;
7647         }
7648         case EntryPoint::EGLCreateImageKHR:
7649         {
7650             CreateEGLImagePreCallUpdate<EGLint>(call, mResourceTracker, ParamType::TEGLintPointer,
7651                                                 egl::AttributeMap::CreateFromIntArray);
7652             break;
7653         }
7654         case EntryPoint::EGLCreateSync:
7655         case EntryPoint::EGLCreateSyncKHR:
7656         {
7657             egl::SyncID eglSyncID = call.params.getReturnValue().value.egl_SyncIDVal;
7658             FrameCaptureShared *frameCaptureShared =
7659                 context->getShareGroup()->getFrameCaptureShared();
7660             // If we're capturing, track which egl sync has been created
7661             if (frameCaptureShared->isCaptureActive())
7662             {
7663                 handleGennedResource(context, eglSyncID);
7664             }
7665             break;
7666         }
7667         case EntryPoint::EGLDestroySync:
7668         case EntryPoint::EGLDestroySyncKHR:
7669         {
7670             egl::SyncID eglSyncID =
7671                 call.params.getParam("syncPacked", ParamType::Tegl_SyncID, 1).value.egl_SyncIDVal;
7672             FrameCaptureShared *frameCaptureShared =
7673                 context->getShareGroup()->getFrameCaptureShared();
7674             // If we're capturing, track which EGL sync has been deleted
7675             if (frameCaptureShared->isCaptureActive())
7676             {
7677                 handleDeletedResource(context, eglSyncID);
7678             }
7679             break;
7680         }
7681         case EntryPoint::GLDispatchCompute:
7682         {
7683             // When using shadow memory we need to update the real memory here
7684             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7685             {
7686                 maybeCaptureCoherentBuffers(context);
7687             }
7688             break;
7689         }
7690         default:
7691             break;
7692     }
7693 
7694     if (IsTextureUpdate(call))
7695     {
7696         // If this call modified texture contents, track it for possible reset
7697         trackTextureUpdate(context, call);
7698     }
7699 
7700     if (isCaptureActive() && GetDefaultUniformType(call) != DefaultUniformType::None)
7701     {
7702         trackDefaultUniformUpdate(context, call);
7703     }
7704 
7705     if (IsVertexArrayUpdate(call))
7706     {
7707         trackVertexArrayUpdate(context, call);
7708     }
7709 
7710     updateReadBufferSize(call.params.getReadBufferSize());
7711 
7712     std::vector<gl::ShaderProgramID> shaderProgramIDs;
7713     if (FindShaderProgramIDsInCall(call, shaderProgramIDs))
7714     {
7715         for (gl::ShaderProgramID shaderProgramID : shaderProgramIDs)
7716         {
7717             mResourceTracker.onShaderProgramAccess(shaderProgramID);
7718 
7719             if (isCaptureActive())
7720             {
7721                 // Track that this call referenced a ShaderProgram, setting it active for Setup
7722                 MarkResourceIDActive(ResourceIDType::ShaderProgram, shaderProgramID.value,
7723                                      shareGroupSetupCalls, resourceIDToSetupCalls);
7724             }
7725         }
7726     }
7727 }
7728 
7729 template <typename ParamValueType>
maybeGenResourceOnBind(const gl::Context * context,CallCapture & call)7730 void FrameCaptureShared::maybeGenResourceOnBind(const gl::Context *context, CallCapture &call)
7731 {
7732     const char *paramName     = ParamValueTrait<ParamValueType>::name;
7733     const ParamType paramType = ParamValueTrait<ParamValueType>::typeID;
7734 
7735     const ParamCapture &param = call.params.getParam(paramName, paramType, 1);
7736     const ParamValueType id   = AccessParamValue<ParamValueType>(paramType, param.value);
7737 
7738     // Don't inject the default resource or resources that are already generated
7739     if (id.value != 0 && !resourceIsGenerated(context, id))
7740     {
7741         handleGennedResource(context, id);
7742 
7743         ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
7744         const char *resourceName      = GetResourceIDTypeName(resourceIDType);
7745 
7746         std::stringstream updateFuncNameStr;
7747         updateFuncNameStr << "Set" << resourceName << "ID";
7748         std::string updateFuncName = updateFuncNameStr.str();
7749 
7750         ParamBuffer params;
7751         params.addValueParam("id", ParamType::TGLuint, id.value);
7752         mFrameCalls.emplace_back(updateFuncName, std::move(params));
7753     }
7754 }
7755 
updateResourceCountsFromParamCapture(const ParamCapture & param,ResourceIDType idType)7756 void FrameCaptureShared::updateResourceCountsFromParamCapture(const ParamCapture &param,
7757                                                               ResourceIDType idType)
7758 {
7759     if (idType != ResourceIDType::InvalidEnum)
7760     {
7761         mHasResourceType.set(idType);
7762 
7763         // Capture resource IDs for non-pointer types.
7764         if (strcmp(ParamTypeToString(param.type), "GLuint") == 0)
7765         {
7766             mMaxAccessedResourceIDs[idType] =
7767                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
7768         }
7769         // Capture resource IDs for pointer types.
7770         if (strstr(ParamTypeToString(param.type), "GLuint *") != nullptr)
7771         {
7772             if (param.data.size() == 1u)
7773             {
7774                 const GLuint *dataPtr = reinterpret_cast<const GLuint *>(param.data[0].data());
7775                 size_t numHandles     = param.data[0].size() / sizeof(GLuint);
7776                 for (size_t handleIndex = 0; handleIndex < numHandles; ++handleIndex)
7777                 {
7778                     mMaxAccessedResourceIDs[idType] =
7779                         std::max(mMaxAccessedResourceIDs[idType], dataPtr[handleIndex]);
7780                 }
7781             }
7782         }
7783         if (idType == ResourceIDType::Sync)
7784         {
7785             mMaxAccessedResourceIDs[idType] =
7786                 std::max(mMaxAccessedResourceIDs[idType], param.value.GLuintVal);
7787         }
7788     }
7789 }
7790 
updateResourceCountsFromCallCapture(const CallCapture & call)7791 void FrameCaptureShared::updateResourceCountsFromCallCapture(const CallCapture &call)
7792 {
7793     for (const ParamCapture &param : call.params.getParamCaptures())
7794     {
7795         ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
7796         updateResourceCountsFromParamCapture(param, idType);
7797     }
7798 
7799     // Update resource IDs in the return value. Return values types are not stored as resource IDs,
7800     // but instead are stored as GLuints. Therefore we need to explicitly label the resource ID type
7801     // when we call update. Currently only shader and program creation are explicitly tracked.
7802     switch (call.entryPoint)
7803     {
7804         case EntryPoint::GLCreateShader:
7805         case EntryPoint::GLCreateProgram:
7806             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7807                                                  ResourceIDType::ShaderProgram);
7808             break;
7809 
7810         case EntryPoint::GLFenceSync:
7811             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7812                                                  ResourceIDType::Sync);
7813             break;
7814         case EntryPoint::EGLCreateSync:
7815         case EntryPoint::EGLCreateSyncKHR:
7816             updateResourceCountsFromParamCapture(call.params.getReturnValue(),
7817                                                  ResourceIDType::egl_Sync);
7818             break;
7819         default:
7820             break;
7821     }
7822 }
7823 
captureCall(gl::Context * context,CallCapture && inCall,bool isCallValid)7824 void FrameCaptureShared::captureCall(gl::Context *context, CallCapture &&inCall, bool isCallValid)
7825 {
7826     if (SkipCall(inCall.entryPoint))
7827     {
7828         return;
7829     }
7830 
7831     if (isCallValid)
7832     {
7833         // If the context ID has changed, then we need to inject an eglMakeCurrent() call. Only do
7834         // this if there is more than 1 context in the share group to avoid unnecessary
7835         // eglMakeCurrent() calls.
7836         size_t contextCount = context->getShareGroup()->getContexts().size();
7837         if (contextCount > 1 && mLastContextId != context->id())
7838         {
7839             // Inject the eglMakeCurrent() call. Ignore the display and surface.
7840             CallCapture makeCurrentCall =
7841                 egl::CaptureMakeCurrent(nullptr, true, nullptr, {0}, {0}, context->id(), EGL_TRUE);
7842             mFrameCalls.emplace_back(std::move(makeCurrentCall));
7843             mLastContextId = context->id();
7844         }
7845 
7846         // Update resource counts before we override entry points with custom calls.
7847         updateResourceCountsFromCallCapture(inCall);
7848 
7849         std::vector<CallCapture> outCalls;
7850         maybeOverrideEntryPoint(context, inCall, outCalls);
7851 
7852         // Need to loop on any new calls we added during override
7853         for (CallCapture &call : outCalls)
7854         {
7855             // During capture, consider all frame calls active
7856             if (isCaptureActive())
7857             {
7858                 call.isActive = true;
7859             }
7860 
7861             maybeCapturePreCallUpdates(context, call, &mShareGroupSetupCalls,
7862                                        &mResourceIDToSetupCalls);
7863             mFrameCalls.emplace_back(std::move(call));
7864             maybeCapturePostCallUpdates(context);
7865         }
7866 
7867         // Evaluate the validation expression to determine if we insert a validation checkpoint.
7868         // This lets the user pick a subset of calls to check instead of checking every call.
7869         if (mValidateSerializedState && !mValidationExpression.empty())
7870         {
7871             // Example substitution for frame #2, call #110:
7872             // Before: (call == 2) && (frame >= 100) && (frame <= 120) && ((frame % 10) == 0)
7873             // After:  (2 == 2) && (110 >= 100) && (110 <= 120) && ((110 % 10) == 0)
7874             // Evaluates to 1.0.
7875             std::string expression = mValidationExpression;
7876 
7877             angle::ReplaceAllSubstrings(&expression, "frame", std::to_string(mFrameIndex));
7878             angle::ReplaceAllSubstrings(&expression, "call", std::to_string(mFrameCalls.size()));
7879 
7880             double result = ceval_result(expression);
7881             if (result > 0)
7882             {
7883                 CaptureValidateSerializedState(context, &mFrameCalls);
7884             }
7885         }
7886     }
7887     else
7888     {
7889         const int maxInvalidCallLogs = 3;
7890         size_t &callCount = isCaptureActive() ? mInvalidCallCountsActive[inCall.entryPoint]
7891                                               : mInvalidCallCountsInactive[inCall.entryPoint];
7892         callCount++;
7893         if (callCount <= maxInvalidCallLogs)
7894         {
7895             std::ostringstream msg;
7896             msg << "FrameCapture (capture " << (isCaptureActive() ? "active" : "inactive")
7897                 << "): Not capturing invalid call to " << GetEntryPointName(inCall.entryPoint);
7898             if (callCount == maxInvalidCallLogs)
7899             {
7900                 msg << " (will no longer repeat for this entry point)";
7901             }
7902             INFO() << msg.str();
7903         }
7904     }
7905 }
7906 
maybeCapturePostCallUpdates(const gl::Context * context)7907 void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
7908 {
7909     // Process resource ID updates.
7910     if (isCaptureActive())
7911     {
7912         MaybeCaptureUpdateResourceIDs(context, &mResourceTracker, &mFrameCalls);
7913     }
7914 
7915     CallCapture &lastCall = mFrameCalls.back();
7916     switch (lastCall.entryPoint)
7917     {
7918         case EntryPoint::GLCreateShaderProgramv:
7919         {
7920             gl::ShaderProgramID programId;
7921             programId.value            = lastCall.params.getReturnValue().value.GLuintVal;
7922             const gl::Program *program = context->getProgramResolveLink(programId);
7923             CaptureUpdateUniformLocations(program, &mFrameCalls);
7924             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
7925             break;
7926         }
7927         case EntryPoint::GLLinkProgram:
7928         {
7929             const ParamCapture &param =
7930                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7931             const gl::Program *program =
7932                 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
7933             CaptureUpdateUniformLocations(program, &mFrameCalls);
7934             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
7935             break;
7936         }
7937         case EntryPoint::GLUseProgram:
7938             CaptureUpdateCurrentProgram(lastCall, 0, &mFrameCalls);
7939             break;
7940         case EntryPoint::GLActiveShaderProgram:
7941             CaptureUpdateCurrentProgram(lastCall, 1, &mFrameCalls);
7942             break;
7943         case EntryPoint::GLDeleteProgram:
7944         {
7945             const ParamCapture &param =
7946                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
7947             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
7948             break;
7949         }
7950         case EntryPoint::GLShaderSource:
7951         {
7952             lastCall.params.setValueParamAtIndex("count", ParamType::TGLsizei, 1, 1);
7953 
7954             ParamCapture &paramLength =
7955                 lastCall.params.getParam("length", ParamType::TGLintConstPointer, 3);
7956             paramLength.data.resize(1);
7957             // Set the length parameter to {-1} to signal that the actual string length
7958             // is to be used. Since we store the parameter blob as an array of four uint8_t
7959             // values, we have to pass the binary equivalent of -1.
7960             paramLength.data[0] = {0xff, 0xff, 0xff, 0xff};
7961             break;
7962         }
7963         case EntryPoint::GLBufferData:
7964         case EntryPoint::GLBufferSubData:
7965         {
7966             // When using shadow memory we need to update it from real memory here
7967             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7968             {
7969                 gl::BufferBinding target =
7970                     lastCall.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
7971                         .value.BufferBindingVal;
7972 
7973                 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7974                 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
7975                 {
7976                     std::shared_ptr<CoherentBuffer> cb =
7977                         mCoherentBufferTracker.mBuffers[buffer->id().value];
7978                     cb->removeProtection(PageSharingType::NoneShared);
7979                     cb->updateShadowMemory();
7980                     cb->protectAll();
7981                 }
7982             }
7983             break;
7984         }
7985 
7986         case EntryPoint::GLCopyBufferSubData:
7987         {
7988             // When using shadow memory, we need to mark the buffer shadowDirty bit to true
7989             // so it will be synchronized with real memory on the next glFinish call.
7990             if (mCoherentBufferTracker.isShadowMemoryEnabled())
7991             {
7992                 gl::BufferBinding target =
7993                     lastCall.params.getParam("writeTargetPacked", ParamType::TBufferBinding, 1)
7994                         .value.BufferBindingVal;
7995 
7996                 gl::Buffer *buffer = context->getState().getTargetBuffer(target);
7997                 if (mCoherentBufferTracker.haveBuffer(buffer->id()))
7998                 {
7999                     std::shared_ptr<CoherentBuffer> cb =
8000                         mCoherentBufferTracker.mBuffers[buffer->id().value];
8001                     // This needs to be synced on glFinish
8002                     cb->markShadowDirty();
8003                 }
8004             }
8005             break;
8006         }
8007         case EntryPoint::GLDispatchCompute:
8008         {
8009             // When using shadow memory, we need to mark all buffer's shadowDirty bit to true
8010             // so they will be synchronized with real memory on the next glFinish call.
8011             if (mCoherentBufferTracker.isShadowMemoryEnabled())
8012             {
8013                 mCoherentBufferTracker.markAllShadowDirty();
8014             }
8015             break;
8016         }
8017         default:
8018             break;
8019     }
8020 }
8021 
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)8022 void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
8023                                                     size_t vertexCount,
8024                                                     size_t instanceCount)
8025 {
8026     const gl::VertexArray *vao = context->getState().getVertexArray();
8027 
8028     // Capture client array data.
8029     for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
8030     {
8031         const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
8032         const gl::VertexBinding &binding  = vao->getVertexBinding(attrib.bindingIndex);
8033 
8034         int callIndex = mClientVertexArrayMap[attribIndex];
8035 
8036         if (callIndex != -1)
8037         {
8038             size_t count = vertexCount;
8039 
8040             if (binding.getDivisor() > 0)
8041             {
8042                 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
8043                                                binding.getDivisor());
8044             }
8045 
8046             // The last capture element doesn't take up the full stride.
8047             size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
8048 
8049             CallCapture &call   = mFrameCalls[callIndex];
8050             ParamCapture &param = call.params.getClientArrayPointerParameter();
8051             ASSERT(param.type == ParamType::TvoidConstPointer);
8052 
8053             ParamBuffer updateParamBuffer;
8054             updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
8055                                                    static_cast<uint32_t>(attribIndex));
8056 
8057             ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
8058             CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
8059             updateParamBuffer.addParam(std::move(updateMemory));
8060 
8061             updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
8062 
8063             mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
8064 
8065             mClientArraySizes[attribIndex] =
8066                 std::max(mClientArraySizes[attribIndex], bytesToCapture);
8067         }
8068     }
8069 }
8070 
captureCoherentBufferSnapshot(const gl::Context * context,gl::BufferID id)8071 void FrameCaptureShared::captureCoherentBufferSnapshot(const gl::Context *context, gl::BufferID id)
8072 {
8073     if (!hasBufferData(id))
8074     {
8075         // This buffer was not marked writable
8076         return;
8077     }
8078 
8079     const gl::State &apiState        = context->getState();
8080     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
8081     gl::Buffer *buffer               = buffers.getBuffer(id);
8082     if (!buffer)
8083     {
8084         // Could not find buffer binding
8085         return;
8086     }
8087 
8088     ASSERT(buffer->isMapped());
8089 
8090     std::shared_ptr<angle::CoherentBuffer> coherentBuffer =
8091         mCoherentBufferTracker.mBuffers[id.value];
8092 
8093     std::vector<PageRange> dirtyPageRanges = coherentBuffer->getDirtyPageRanges();
8094 
8095     if (mCoherentBufferTracker.isShadowMemoryEnabled() && !dirtyPageRanges.empty())
8096     {
8097         coherentBuffer->updateBufferMemory();
8098     }
8099 
8100     AddressRange wholeRange = coherentBuffer->getRange();
8101 
8102     for (PageRange &pageRange : dirtyPageRanges)
8103     {
8104         // Write protect the memory already, so the app is blocked on writing during our capture
8105         coherentBuffer->protectPageRange(pageRange);
8106 
8107         // Create the parameters to our helper for use during replay
8108         ParamBuffer dataParamBuffer;
8109 
8110         // Pass in the target buffer ID
8111         dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
8112 
8113         // Capture the current buffer data with a binary param
8114         ParamCapture captureData("source", ParamType::TvoidConstPointer);
8115 
8116         AddressRange dirtyRange = coherentBuffer->getDirtyAddressRange(pageRange);
8117         CaptureMemory(reinterpret_cast<void *>(dirtyRange.start), dirtyRange.size, &captureData);
8118         dataParamBuffer.addParam(std::move(captureData));
8119 
8120         // Also track its size for use with memcpy
8121         dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr,
8122                                                   static_cast<GLsizeiptr>(dirtyRange.size));
8123 
8124         if (wholeRange.start != dirtyRange.start)
8125         {
8126             // Capture with offset
8127             GLsizeiptr offset = dirtyRange.start - wholeRange.start;
8128 
8129             ASSERT(offset > 0);
8130 
8131             // The dirty page range is not at the start of the buffer, track the offset.
8132             dataParamBuffer.addValueParam<GLsizeiptr>("offset", ParamType::TGLsizeiptr, offset);
8133 
8134             // Call the helper that populates the buffer with captured data
8135             mFrameCalls.emplace_back("UpdateClientBufferDataWithOffset",
8136                                      std::move(dataParamBuffer));
8137         }
8138         else
8139         {
8140             // Call the helper that populates the buffer with captured data
8141             mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
8142         }
8143     }
8144 }
8145 
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)8146 void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
8147                                                      const CallCapture &call)
8148 {
8149     // If the buffer was mapped writable, we need to restore its data, since we have no
8150     // visibility into what the client did to the buffer while mapped.
8151     // This sequence will result in replay calls like this:
8152     //   ...
8153     //   gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
8154     //                                                        GL_MAP_WRITE_BIT);
8155     //   ...
8156     //   UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
8157     //   glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
8158     //   ...
8159 
8160     // Re-map the buffer, using the info we tracked about the buffer
8161     gl::BufferBinding target =
8162         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
8163 
8164     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
8165     gl::Buffer *buffer                     = context->getState().getTargetBuffer(target);
8166     if (!frameCaptureShared->hasBufferData(buffer->id()))
8167     {
8168         // This buffer was not marked writable, so we did not back it up
8169         return;
8170     }
8171 
8172     std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
8173         frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
8174     GLintptr offset   = bufferDataOffsetAndLength.first;
8175     GLsizeiptr length = bufferDataOffsetAndLength.second;
8176 
8177     // Map the buffer so we can copy its contents out
8178     ASSERT(!buffer->isMapped());
8179     angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
8180     if (result != angle::Result::Continue)
8181     {
8182         ERR() << "Failed to mapRange of buffer" << std::endl;
8183     }
8184     const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
8185 
8186     // Create the parameters to our helper for use during replay
8187     ParamBuffer dataParamBuffer;
8188 
8189     // Pass in the target buffer ID
8190     dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
8191 
8192     // Capture the current buffer data with a binary param
8193     ParamCapture captureData("source", ParamType::TvoidConstPointer);
8194     CaptureMemory(data, length, &captureData);
8195     dataParamBuffer.addParam(std::move(captureData));
8196 
8197     // Also track its size for use with memcpy
8198     dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
8199 
8200     // Call the helper that populates the buffer with captured data
8201     mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
8202 
8203     // Unmap the buffer and move on
8204     GLboolean dontCare;
8205     (void)buffer->unmap(context, &dontCare);
8206 }
8207 
checkForCaptureTrigger()8208 void FrameCaptureShared::checkForCaptureTrigger()
8209 {
8210     // If the capture trigger has not been set, move on
8211     if (mCaptureTrigger == 0)
8212     {
8213         return;
8214     }
8215 
8216     // Otherwise, poll the value for a change
8217     std::string captureTriggerStr = GetCaptureTrigger();
8218     if (captureTriggerStr.empty())
8219     {
8220         return;
8221     }
8222 
8223     // If the value has changed, use the original value as the frame count
8224     // TODO (anglebug.com/4949): Improve capture at unknown frame time. It is good to
8225     // avoid polling if the feature is not enabled, but not entirely intuitive to set
8226     // a value to zero when you want to trigger it.
8227     uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
8228     if (captureTrigger != mCaptureTrigger)
8229     {
8230         // Start mid-execution capture for the current frame
8231         mCaptureStartFrame = mFrameIndex + 1;
8232 
8233         // Use the original trigger value as the frame count
8234         mCaptureEndFrame = mCaptureStartFrame + mCaptureTrigger - 1;
8235 
8236         INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
8237                << " frames";
8238 
8239         // Stop polling
8240         mCaptureTrigger = 0;
8241     }
8242 }
8243 
scanSetupCalls(std::vector<CallCapture> & setupCalls)8244 void FrameCaptureShared::scanSetupCalls(std::vector<CallCapture> &setupCalls)
8245 {
8246     // Scan all the instructions in the list for tracking
8247     for (CallCapture &call : setupCalls)
8248     {
8249         updateReadBufferSize(call.params.getReadBufferSize());
8250         updateResourceCountsFromCallCapture(call);
8251     }
8252 }
8253 
runMidExecutionCapture(gl::Context * mainContext)8254 void FrameCaptureShared::runMidExecutionCapture(gl::Context *mainContext)
8255 {
8256     // Set the capture active to ensure all GLES commands issued by the next frame are
8257     // handled correctly by maybeCapturePreCallUpdates() and maybeCapturePostCallUpdates().
8258     setCaptureActive();
8259 
8260     // Make sure all pending work for every Context in the share group has completed so all data
8261     // (buffers, textures, etc.) has been updated and no resources are in use.
8262     egl::ShareGroup *shareGroup = mainContext->getShareGroup();
8263     shareGroup->finishAllContexts();
8264 
8265     const gl::State &contextState = mainContext->getState();
8266     gl::State mainContextReplayState(
8267         nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, contextState.getClientType(),
8268         contextState.getClientVersion(), contextState.getProfileMask(), false, true, true, true,
8269         false, EGL_CONTEXT_PRIORITY_MEDIUM_IMG, contextState.hasRobustAccess(),
8270         contextState.hasProtectedContent());
8271     mainContextReplayState.initializeForCapture(mainContext);
8272 
8273     CaptureShareGroupMidExecutionSetup(mainContext, &mShareGroupSetupCalls, &mResourceTracker,
8274                                        mainContextReplayState, mMaxAccessedResourceIDs);
8275 
8276     scanSetupCalls(mShareGroupSetupCalls);
8277 
8278     egl::Display *display = mainContext->getDisplay();
8279     egl::Surface *draw    = mainContext->getCurrentDrawSurface();
8280     egl::Surface *read    = mainContext->getCurrentReadSurface();
8281 
8282     for (auto shareContext : shareGroup->getContexts())
8283     {
8284         FrameCapture *frameCapture = shareContext.second->getFrameCapture();
8285         ASSERT(frameCapture->getSetupCalls().empty());
8286 
8287         if (shareContext.second->id() == mainContext->id())
8288         {
8289             CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8290                                      frameCapture->getStateResetHelper().getResetCalls(),
8291                                      &mShareGroupSetupCalls, &mResourceIDToSetupCalls,
8292                                      &mResourceTracker, mainContextReplayState,
8293                                      mValidateSerializedState);
8294             scanSetupCalls(frameCapture->getSetupCalls());
8295 
8296             std::stringstream protoStream;
8297             std::stringstream headerStream;
8298             std::stringstream bodyStream;
8299 
8300             protoStream << "void "
8301                         << FmtSetupFunction(kNoPartId, mainContext->id(), FuncUsage::Prototype);
8302             std::string proto = protoStream.str();
8303 
8304             WriteCppReplayFunctionWithParts(mainContext->id(), ReplayFunc::Setup, mReplayWriter, 1,
8305                                             &mBinaryData, frameCapture->getSetupCalls(),
8306                                             headerStream, bodyStream, &mResourceIDBufferSize);
8307 
8308             mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
8309         }
8310         else
8311         {
8312             const gl::State &shareContextState = shareContext.second->getState();
8313             gl::State auxContextReplayState(
8314                 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8315                 shareContextState.getClientType(), shareContextState.getClientVersion(),
8316                 shareContextState.getProfileMask(), false, true, true, true, false,
8317                 EGL_CONTEXT_PRIORITY_MEDIUM_IMG, shareContextState.hasRobustAccess(),
8318                 shareContextState.hasProtectedContent());
8319             auxContextReplayState.initializeForCapture(shareContext.second);
8320 
8321             egl::Error error = shareContext.second->makeCurrent(display, draw, read);
8322             if (error.isError())
8323             {
8324                 INFO() << "MEC unable to make secondary context current";
8325             }
8326 
8327             CaptureMidExecutionSetup(shareContext.second, &frameCapture->getSetupCalls(),
8328                                      frameCapture->getStateResetHelper().getResetCalls(),
8329                                      &mShareGroupSetupCalls, &mResourceIDToSetupCalls,
8330                                      &mResourceTracker, auxContextReplayState,
8331                                      mValidateSerializedState);
8332 
8333             scanSetupCalls(frameCapture->getSetupCalls());
8334 
8335             WriteAuxiliaryContextCppSetupReplay(
8336                 mReplayWriter, mCompression, mOutDirectory, shareContext.second, mCaptureLabel, 1,
8337                 frameCapture->getSetupCalls(), &mBinaryData, mSerializeStateEnabled, *this,
8338                 &mResourceIDBufferSize);
8339         }
8340         // Track that this context was created before MEC started
8341         mActiveContexts.insert(shareContext.first);
8342     }
8343 
8344     egl::Error error = mainContext->makeCurrent(display, draw, read);
8345     if (error.isError())
8346     {
8347         INFO() << "MEC unable to make main context current again";
8348     }
8349 }
8350 
onEndFrame(gl::Context * context)8351 void FrameCaptureShared::onEndFrame(gl::Context *context)
8352 {
8353     if (!enabled() || mFrameIndex > mCaptureEndFrame)
8354     {
8355         setCaptureInactive();
8356         mCoherentBufferTracker.onEndFrame();
8357         return;
8358     }
8359 
8360     FrameCapture *frameCapture = context->getFrameCapture();
8361 
8362     // Count resource IDs. This is also done on every frame. It could probably be done by
8363     // checking the GL state instead of the calls.
8364     for (const CallCapture &call : mFrameCalls)
8365     {
8366         for (const ParamCapture &param : call.params.getParamCaptures())
8367         {
8368             ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
8369             if (idType != ResourceIDType::InvalidEnum)
8370             {
8371                 mHasResourceType.set(idType);
8372             }
8373         }
8374     }
8375 
8376     mWindowSurfaceContextID = context->id();
8377 
8378     // On Android, we can trigger a capture during the run
8379     checkForCaptureTrigger();
8380 
8381     // Check for MEC. Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
8382     if (mFrameIndex < mCaptureStartFrame)
8383     {
8384         if (mFrameIndex == mCaptureStartFrame - 1)
8385         {
8386             // Trigger MEC.
8387             runMidExecutionCapture(context);
8388         }
8389         mFrameIndex++;
8390         reset();
8391         return;
8392     }
8393 
8394     ASSERT(isCaptureActive());
8395 
8396     if (!mFrameCalls.empty())
8397     {
8398         mActiveFrameIndices.push_back(getReplayFrameIndex());
8399     }
8400 
8401     // Make sure all pending work for every Context in the share group has completed so all data
8402     // (buffers, textures, etc.) has been updated and no resources are in use.
8403     egl::ShareGroup *shareGroup = context->getShareGroup();
8404     shareGroup->finishAllContexts();
8405 
8406     // Only validate the first frame for now to save on retracing time.
8407     if (mValidateSerializedState && mFrameIndex == mCaptureStartFrame)
8408     {
8409         CaptureValidateSerializedState(context, &mFrameCalls);
8410     }
8411 
8412     writeMainContextCppReplay(context, frameCapture->getSetupCalls(),
8413                               frameCapture->getStateResetHelper());
8414 
8415     if (mFrameIndex == mCaptureEndFrame)
8416     {
8417         // Write shared MEC after frame sequence so we can eliminate unused assets like programs
8418         WriteShareGroupCppSetupReplay(mReplayWriter, mCompression, mOutDirectory, mCaptureLabel, 1,
8419                                       1, mShareGroupSetupCalls, &mResourceTracker, &mBinaryData,
8420                                       mSerializeStateEnabled, mWindowSurfaceContextID,
8421                                       &mResourceIDBufferSize);
8422 
8423         // Save the index files after the last frame.
8424         writeCppReplayIndexFiles(context, false);
8425         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
8426         mBinaryData.clear();
8427         mWroteIndexFile = true;
8428     }
8429 
8430     reset();
8431     mFrameIndex++;
8432 }
8433 
onDestroyContext(const gl::Context * context)8434 void FrameCaptureShared::onDestroyContext(const gl::Context *context)
8435 {
8436     if (!mEnabled)
8437     {
8438         return;
8439     }
8440     if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
8441     {
8442         // If context is destroyed before end frame is reached and at least
8443         // 1 frame has been recorded, then write the index files.
8444         // It doesn't make sense to write the index files when no frame has been recorded
8445         mFrameIndex -= 1;
8446         mCaptureEndFrame = mFrameIndex;
8447         writeCppReplayIndexFiles(context, true);
8448         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
8449         mBinaryData.clear();
8450         mWroteIndexFile = true;
8451     }
8452 }
8453 
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)8454 void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
8455 {
8456     if (!drawSurface)
8457     {
8458         return;
8459     }
8460 
8461     // Track the width, height and color space of the draw surface as provided to makeCurrent
8462     SurfaceParams &params = mDrawSurfaceParams[context->id()];
8463     params.extents        = gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
8464     params.colorSpace     = egl::FromEGLenum<egl::ColorSpace>(drawSurface->getGLColorspace());
8465 }
8466 
8467 DataCounters::DataCounters() = default;
8468 
8469 DataCounters::~DataCounters() = default;
8470 
getAndIncrement(EntryPoint entryPoint,const std::string & paramName)8471 int DataCounters::getAndIncrement(EntryPoint entryPoint, const std::string &paramName)
8472 {
8473     Counter counterKey = {entryPoint, paramName};
8474     return mData[counterKey]++;
8475 }
8476 
8477 DataTracker::DataTracker() = default;
8478 
8479 DataTracker::~DataTracker() = default;
8480 
8481 StringCounters::StringCounters() = default;
8482 
8483 StringCounters::~StringCounters() = default;
8484 
getStringCounter(const std::vector<std::string> & strings)8485 int StringCounters::getStringCounter(const std::vector<std::string> &strings)
8486 {
8487     const auto &id = mStringCounterMap.find(strings);
8488     if (id == mStringCounterMap.end())
8489     {
8490         return kStringsNotFound;
8491     }
8492     else
8493     {
8494         return mStringCounterMap[strings];
8495     }
8496 }
8497 
setStringCounter(const std::vector<std::string> & strings,int & counter)8498 void StringCounters::setStringCounter(const std::vector<std::string> &strings, int &counter)
8499 {
8500     ASSERT(counter >= 0);
8501     mStringCounterMap[strings] = counter;
8502 }
8503 
8504 TrackedResource::TrackedResource() = default;
8505 
8506 TrackedResource::~TrackedResource() = default;
8507 
8508 ResourceTracker::ResourceTracker() = default;
8509 
8510 ResourceTracker::~ResourceTracker() = default;
8511 
8512 StateResetHelper::StateResetHelper()  = default;
8513 StateResetHelper::~StateResetHelper() = default;
8514 
setDefaultResetCalls(const gl::Context * context,angle::EntryPoint entryPoint)8515 void StateResetHelper::setDefaultResetCalls(const gl::Context *context,
8516                                             angle::EntryPoint entryPoint)
8517 {
8518     static const gl::BlendState kDefaultBlendState;
8519 
8520     // Populate default reset calls for entrypoints to support looping to beginning
8521     switch (entryPoint)
8522     {
8523         case angle::EntryPoint::GLUseProgram:
8524         {
8525             if (context->getActiveLinkedProgram() &&
8526                 context->getActiveLinkedProgram()->id().value != 0)
8527             {
8528                 Capture(&mResetCalls[angle::EntryPoint::GLUseProgram],
8529                         gl::CaptureUseProgram(context->getState(), true, {0}));
8530             }
8531             break;
8532         }
8533         case angle::EntryPoint::GLBindVertexArray:
8534         {
8535             if (context->getState().getVertexArray()->id().value != 0)
8536             {
8537                 VertexArrayCaptureFuncs vertexArrayFuncs(context->isGLES1());
8538                 Capture(&mResetCalls[angle::EntryPoint::GLBindVertexArray],
8539                         vertexArrayFuncs.bindVertexArray(context->getState(), true, {0}));
8540             }
8541             break;
8542         }
8543         case angle::EntryPoint::GLBlendFunc:
8544         {
8545             Capture(&mResetCalls[angle::EntryPoint::GLBlendFunc],
8546                     CaptureBlendFunc(context->getState(), true, kDefaultBlendState.sourceBlendRGB,
8547                                      kDefaultBlendState.destBlendRGB));
8548             break;
8549         }
8550         case angle::EntryPoint::GLBlendFuncSeparate:
8551         {
8552             Capture(&mResetCalls[angle::EntryPoint::GLBlendFuncSeparate],
8553                     CaptureBlendFuncSeparate(
8554                         context->getState(), true, kDefaultBlendState.sourceBlendRGB,
8555                         kDefaultBlendState.destBlendRGB, kDefaultBlendState.sourceBlendAlpha,
8556                         kDefaultBlendState.destBlendAlpha));
8557             break;
8558         }
8559         case angle::EntryPoint::GLBlendEquation:
8560         {
8561             UNREACHABLE();  // GLBlendEquationSeparate is always used instead
8562             break;
8563         }
8564         case angle::EntryPoint::GLBlendEquationSeparate:
8565         {
8566             Capture(&mResetCalls[angle::EntryPoint::GLBlendEquationSeparate],
8567                     CaptureBlendEquationSeparate(context->getState(), true,
8568                                                  kDefaultBlendState.blendEquationRGB,
8569                                                  kDefaultBlendState.blendEquationAlpha));
8570             break;
8571         }
8572         case angle::EntryPoint::GLColorMask:
8573         {
8574             Capture(&mResetCalls[angle::EntryPoint::GLColorMask],
8575                     CaptureColorMask(context->getState(), true,
8576                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskRed),
8577                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskGreen),
8578                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskBlue),
8579                                      gl::ConvertToGLBoolean(kDefaultBlendState.colorMaskAlpha)));
8580             break;
8581         }
8582         case angle::EntryPoint::GLBlendColor:
8583         {
8584             Capture(&mResetCalls[angle::EntryPoint::GLBlendColor],
8585                     CaptureBlendColor(context->getState(), true, 0, 0, 0, 0));
8586             break;
8587         }
8588         default:
8589             ERR() << "Unhandled entry point in setDefaultResetCalls: "
8590                   << GetEntryPointName(entryPoint);
8591             UNREACHABLE();
8592             break;
8593     }
8594 }
8595 
setDeletedFenceSync(gl::SyncID sync)8596 void ResourceTracker::setDeletedFenceSync(gl::SyncID sync)
8597 {
8598     ASSERT(sync.value != 0);
8599     if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
8600     {
8601         // This is a fence sync created after MEC was initialized. Ignore it.
8602         return;
8603     }
8604 
8605     // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
8606     mFenceSyncsToRegen.insert(sync);
8607 }
8608 
setModifiedDefaultUniform(gl::ShaderProgramID programID,gl::UniformLocation location)8609 void ResourceTracker::setModifiedDefaultUniform(gl::ShaderProgramID programID,
8610                                                 gl::UniformLocation location)
8611 {
8612     // Pull up or create the list of uniform locations for this program and mark one dirty
8613     mDefaultUniformsToReset[programID].insert(location);
8614 }
8615 
setDefaultUniformBaseLocation(gl::ShaderProgramID programID,gl::UniformLocation location,gl::UniformLocation baseLocation)8616 void ResourceTracker::setDefaultUniformBaseLocation(gl::ShaderProgramID programID,
8617                                                     gl::UniformLocation location,
8618                                                     gl::UniformLocation baseLocation)
8619 {
8620     // Track the base location used to populate arrayed uniforms in Setup
8621     mDefaultUniformBaseLocations[{programID, location}] = baseLocation;
8622 }
8623 
getTrackedResource(gl::ContextID contextID,ResourceIDType type)8624 TrackedResource &ResourceTracker::getTrackedResource(gl::ContextID contextID, ResourceIDType type)
8625 {
8626     if (IsSharedObjectResource(type))
8627     {
8628         // No need to index with context if shared
8629         return mTrackedResourcesShared[static_cast<uint32_t>(type)];
8630     }
8631     else
8632     {
8633         // For per-context objects, track the resource per-context
8634         return mTrackedResourcesPerContext[contextID][static_cast<uint32_t>(type)];
8635     }
8636 }
8637 
getContextIDs(std::set<gl::ContextID> & idsOut)8638 void ResourceTracker::getContextIDs(std::set<gl::ContextID> &idsOut)
8639 {
8640     for (const auto &trackedResourceIterator : mTrackedResourcesPerContext)
8641     {
8642         gl::ContextID contextID = trackedResourceIterator.first;
8643         idsOut.insert(contextID);
8644     }
8645 }
8646 
setGennedResource(GLuint id)8647 void TrackedResource::setGennedResource(GLuint id)
8648 {
8649     if (mStartingResources.find(id) == mStartingResources.end())
8650     {
8651         // This is a resource created after MEC was initialized, track it
8652         mNewResources.insert(id);
8653     }
8654     else
8655     {
8656         // In this case, the app is genning a resource with starting ID after previously deleting it
8657         ASSERT(mResourcesToRegen.find(id) != mResourcesToRegen.end());
8658 
8659         // For this, we need to delete it again to recreate it.
8660         mResourcesToDelete.insert(id);
8661     }
8662 }
8663 
resourceIsGenerated(GLuint id)8664 bool TrackedResource::resourceIsGenerated(GLuint id)
8665 {
8666     return mStartingResources.find(id) != mStartingResources.end() ||
8667            mNewResources.find(id) != mNewResources.end();
8668 }
8669 
setDeletedResource(GLuint id)8670 void TrackedResource::setDeletedResource(GLuint id)
8671 {
8672     if (id == 0)
8673     {
8674         // Ignore ID 0
8675         return;
8676     }
8677 
8678     if (mNewResources.find(id) != mNewResources.end())
8679     {
8680         // This is a resource created after MEC was initialized, just clear it, since there will be
8681         // no actions required for it to return to starting state.
8682         mNewResources.erase(id);
8683         return;
8684     }
8685 
8686     if (mStartingResources.find(id) != mStartingResources.end())
8687     {
8688         // In this case, the app is deleting a resource we started with, we need to regen on loop
8689 
8690         // Mark that we don't need to delete this
8691         mResourcesToDelete.erase(id);
8692 
8693         // Generate the resource again
8694         mResourcesToRegen.insert(id);
8695 
8696         // Also restore its contents
8697         mResourcesToRestore.insert(id);
8698     }
8699 
8700     // If none of the above is true, the app is deleting a resource that was never genned.
8701 }
8702 
setModifiedResource(GLuint id)8703 void TrackedResource::setModifiedResource(GLuint id)
8704 {
8705     // If this was a starting resource, we need to track it for restore
8706     if (mStartingResources.find(id) != mStartingResources.end())
8707     {
8708         mResourcesToRestore.insert(id);
8709     }
8710 }
8711 
setBufferMapped(gl::ContextID contextID,GLuint id)8712 void ResourceTracker::setBufferMapped(gl::ContextID contextID, GLuint id)
8713 {
8714     // If this was a starting buffer, we may need to restore it to original state during Reset.
8715     // Skip buffers that were deleted after the starting point.
8716     const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
8717     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
8718     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
8719     if (startingBuffers.find(id) != startingBuffers.end() &&
8720         buffersToRegen.find(id) == buffersToRegen.end())
8721     {
8722         // Track that its current state is mapped (true)
8723         mStartingBuffersMappedCurrent[id] = true;
8724     }
8725 }
8726 
setBufferUnmapped(gl::ContextID contextID,GLuint id)8727 void ResourceTracker::setBufferUnmapped(gl::ContextID contextID, GLuint id)
8728 {
8729     // If this was a starting buffer, we may need to restore it to original state during Reset.
8730     // Skip buffers that were deleted after the starting point.
8731     const TrackedResource &trackedBuffers = getTrackedResource(contextID, ResourceIDType::Buffer);
8732     const ResourceSet &startingBuffers    = trackedBuffers.getStartingResources();
8733     const ResourceSet &buffersToRegen     = trackedBuffers.getResourcesToRegen();
8734     if (startingBuffers.find(id) != startingBuffers.end() &&
8735         buffersToRegen.find(id) == buffersToRegen.end())
8736     {
8737         // Track that its current state is unmapped (false)
8738         mStartingBuffersMappedCurrent[id] = false;
8739     }
8740 }
8741 
getStartingBuffersMappedCurrent(GLuint id) const8742 bool ResourceTracker::getStartingBuffersMappedCurrent(GLuint id) const
8743 {
8744     const auto &foundBool = mStartingBuffersMappedCurrent.find(id);
8745     ASSERT(foundBool != mStartingBuffersMappedCurrent.end());
8746     return foundBool->second;
8747 }
8748 
getStartingBuffersMappedInitial(GLuint id) const8749 bool ResourceTracker::getStartingBuffersMappedInitial(GLuint id) const
8750 {
8751     const auto &foundBool = mStartingBuffersMappedInitial.find(id);
8752     ASSERT(foundBool != mStartingBuffersMappedInitial.end());
8753     return foundBool->second;
8754 }
8755 
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)8756 void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
8757 {
8758     mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
8759 }
8760 
isCapturing() const8761 bool FrameCaptureShared::isCapturing() const
8762 {
8763     // Currently we will always do a capture up until the last frame. In the future we could improve
8764     // mid execution capture by only capturing between the start and end frames. The only necessary
8765     // reason we need to capture before the start is for attached program and shader sources.
8766     return mEnabled && mFrameIndex <= mCaptureEndFrame;
8767 }
8768 
getFrameCount() const8769 uint32_t FrameCaptureShared::getFrameCount() const
8770 {
8771     return mCaptureEndFrame - mCaptureStartFrame + 1;
8772 }
8773 
getReplayFrameIndex() const8774 uint32_t FrameCaptureShared::getReplayFrameIndex() const
8775 {
8776     return mFrameIndex - mCaptureStartFrame + 1;
8777 }
8778 
8779 // Serialize trace metadata into a JSON file. The JSON file will be named "trace_prefix.json".
8780 //
8781 // As of writing, it will have the format like so:
8782 // {
8783 //     "TraceMetadata":
8784 //     {
8785 //         "AreClientArraysEnabled" : 1, "CaptureRevision" : 16631, "ConfigAlphaBits" : 8,
8786 //             "ConfigBlueBits" : 8, "ConfigDepthBits" : 24, "ConfigGreenBits" : 8,
8787 // ... etc ...
writeJSON(const gl::Context * context)8788 void FrameCaptureShared::writeJSON(const gl::Context *context)
8789 {
8790     const gl::ContextID contextId           = context->id();
8791     const SurfaceParams &surfaceParams      = mDrawSurfaceParams.at(contextId);
8792     const gl::State &glState                = context->getState();
8793     const egl::Config *config               = context->getConfig();
8794     const egl::AttributeMap &displayAttribs = context->getDisplay()->getAttributeMap();
8795 
8796     unsigned int frameCount = getFrameCount();
8797 
8798     JsonSerializer json;
8799     json.startGroup("TraceMetadata");
8800     json.addScalar("CaptureRevision", GetANGLERevision());
8801     json.addScalar("ContextClientMajorVersion", context->getClientMajorVersion());
8802     json.addScalar("ContextClientMinorVersion", context->getClientMinorVersion());
8803     json.addHexValue("DisplayPlatformType", displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE));
8804     json.addHexValue("DisplayDeviceType",
8805                      displayAttribs.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE));
8806     json.addScalar("FrameStart", 1);
8807     json.addScalar("FrameEnd", frameCount);
8808     json.addScalar("DrawSurfaceWidth", surfaceParams.extents.width);
8809     json.addScalar("DrawSurfaceHeight", surfaceParams.extents.height);
8810     json.addHexValue("DrawSurfaceColorSpace", ToEGLenum(surfaceParams.colorSpace));
8811     if (config)
8812     {
8813         json.addScalar("ConfigRedBits", config->redSize);
8814         json.addScalar("ConfigGreenBits", config->greenSize);
8815         json.addScalar("ConfigBlueBits", config->blueSize);
8816         json.addScalar("ConfigAlphaBits", config->alphaSize);
8817         json.addScalar("ConfigDepthBits", config->depthSize);
8818         json.addScalar("ConfigStencilBits", config->stencilSize);
8819     }
8820     else
8821     {
8822         json.addScalar("ConfigRedBits", EGL_DONT_CARE);
8823         json.addScalar("ConfigGreenBits", EGL_DONT_CARE);
8824         json.addScalar("ConfigBlueBits", EGL_DONT_CARE);
8825         json.addScalar("ConfigAlphaBits", EGL_DONT_CARE);
8826         json.addScalar("ConfigDepthBits", EGL_DONT_CARE);
8827         json.addScalar("ConfigStencilBits", EGL_DONT_CARE);
8828     }
8829     json.addBool("IsBinaryDataCompressed", mCompression);
8830     json.addBool("AreClientArraysEnabled", glState.areClientArraysEnabled());
8831     json.addBool("IsBindGeneratesResourcesEnabled", glState.isBindGeneratesResourceEnabled());
8832     json.addBool("IsWebGLCompatibilityEnabled", glState.isWebGL());
8833     json.addBool("IsRobustResourceInitEnabled", glState.isRobustResourceInitEnabled());
8834     json.addBool("IsTrimmingEnabled", mTrimEnabled);
8835     json.endGroup();
8836 
8837     {
8838         const std::vector<std::string> &traceFiles = mReplayWriter.getAndResetWrittenFiles();
8839         json.addVectorOfStrings("TraceFiles", traceFiles);
8840     }
8841 
8842     json.addScalar("WindowSurfaceContextID", contextId.value);
8843 
8844     {
8845         std::stringstream jsonFileNameStream;
8846         jsonFileNameStream << mOutDirectory << FmtCapturePrefix(kNoContextId, mCaptureLabel)
8847                            << ".json";
8848         std::string jsonFileName = jsonFileNameStream.str();
8849 
8850         SaveFileHelper saveData(jsonFileName);
8851         saveData.write(reinterpret_cast<const uint8_t *>(json.data()), json.length());
8852     }
8853 }
8854 
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)8855 void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
8856                                                   bool writeResetContextCall)
8857 {
8858     // Ensure the last frame is written. This will no-op if the frame is already written.
8859     mReplayWriter.saveFrame();
8860 
8861     const gl::ContextID contextId = context->id();
8862 
8863     {
8864         std::stringstream header;
8865 
8866         header << "#pragma once\n";
8867         header << "\n";
8868         header << "#include <EGL/egl.h>\n";
8869         header << "#include <stdint.h>\n";
8870 
8871         std::string includes = header.str();
8872         mReplayWriter.setHeaderPrologue(includes);
8873     }
8874 
8875     {
8876         std::stringstream source;
8877 
8878         source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
8879         source << "#include \"trace_fixture.h\"\n";
8880         source << "#include \"angle_trace_gl.h\"\n";
8881 
8882         std::string sourcePrologue = source.str();
8883         mReplayWriter.setSourcePrologue(sourcePrologue);
8884     }
8885 
8886     {
8887         std::string proto = "void InitReplay(void)";
8888 
8889         std::stringstream source;
8890         source << proto << "\n";
8891         source << "{\n";
8892         WriteInitReplayCall(mCompression, source, context->id(), mCaptureLabel,
8893                             MaxClientArraySize(mClientArraySizes), mReadBufferSize,
8894                             mResourceIDBufferSize, mMaxAccessedResourceIDs);
8895         source << "}\n";
8896 
8897         mReplayWriter.addPrivateFunction(proto, std::stringstream(), source);
8898     }
8899 
8900     {
8901         std::string proto = "void ReplayFrame(uint32_t frameIndex)";
8902 
8903         std::stringstream source;
8904 
8905         source << proto << "\n";
8906         source << "{\n";
8907         source << "    switch (frameIndex)\n";
8908         source << "    {\n";
8909         for (uint32_t frameIndex : mActiveFrameIndices)
8910         {
8911             source << "        case " << frameIndex << ":\n";
8912             source << "            " << FmtReplayFunction(contextId, FuncUsage::Call, frameIndex)
8913                    << ";\n";
8914             source << "            break;\n";
8915         }
8916         source << "        default:\n";
8917         source << "            break;\n";
8918         source << "    }\n";
8919         source << "}\n";
8920 
8921         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8922     }
8923 
8924     if (writeResetContextCall)
8925     {
8926         std::string proto = "void ResetReplay(void)";
8927 
8928         std::stringstream source;
8929 
8930         source << proto << "\n";
8931         source << "{\n";
8932         source << "    // Reset context is empty because context is destroyed before end "
8933                   "frame is reached\n";
8934         source << "}\n";
8935 
8936         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8937     }
8938 
8939     if (mSerializeStateEnabled)
8940     {
8941         std::string proto = "const char *GetSerializedContextState(uint32_t frameIndex)";
8942 
8943         std::stringstream source;
8944 
8945         source << proto << "\n";
8946         source << "{\n";
8947         source << "    switch (frameIndex)\n";
8948         source << "    {\n";
8949         for (uint32_t frameIndex = 1; frameIndex <= getFrameCount(); ++frameIndex)
8950         {
8951             source << "        case " << frameIndex << ":\n";
8952             source << "            return "
8953                    << FmtGetSerializedContextStateFunction(contextId, FuncUsage::Call, frameIndex)
8954                    << ";\n";
8955         }
8956         source << "        default:\n";
8957         source << "            return NULL;\n";
8958         source << "    }\n";
8959         source << "}\n";
8960 
8961         mReplayWriter.addPublicFunction(proto, std::stringstream(), source);
8962     }
8963 
8964     {
8965         std::stringstream fnameStream;
8966         fnameStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel);
8967         std::string fnamePattern = fnameStream.str();
8968 
8969         mReplayWriter.setFilenamePattern(fnamePattern);
8970     }
8971 
8972     mReplayWriter.saveIndexFilesAndHeader();
8973 
8974     writeJSON(context);
8975 }
8976 
writeMainContextCppReplay(const gl::Context * context,const std::vector<CallCapture> & setupCalls,StateResetHelper & stateResetHelper)8977 void FrameCaptureShared::writeMainContextCppReplay(const gl::Context *context,
8978                                                    const std::vector<CallCapture> &setupCalls,
8979                                                    StateResetHelper &stateResetHelper)
8980 {
8981     ASSERT(mWindowSurfaceContextID == context->id());
8982 
8983     {
8984         std::stringstream header;
8985 
8986         header << "#include \"" << FmtCapturePrefix(context->id(), mCaptureLabel) << ".h\"\n";
8987         header << "#include \"angle_trace_gl.h\"\n";
8988 
8989         std::string headerString = header.str();
8990         mReplayWriter.setSourcePrologue(headerString);
8991     }
8992 
8993     uint32_t frameCount = getFrameCount();
8994     uint32_t frameIndex = getReplayFrameIndex();
8995 
8996     if (frameIndex == 1)
8997     {
8998         {
8999             std::string proto = "void SetupReplay(void)";
9000 
9001             std::stringstream out;
9002 
9003             out << proto << "\n";
9004             out << "{\n";
9005 
9006             // Setup all of the shared objects.
9007             out << "    InitReplay();\n";
9008             if (usesMidExecutionCapture())
9009             {
9010                 out << "    " << FmtSetupFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
9011                     << ";\n";
9012                 // Make sure that the current context is mapped correctly
9013                 out << "    SetCurrentContextID(" << context->id() << ");\n";
9014             }
9015 
9016             // Setup each of the auxiliary contexts.
9017             egl::ShareGroup *shareGroup            = context->getShareGroup();
9018             const egl::ContextMap &shareContextMap = shareGroup->getContexts();
9019             for (auto shareContext : shareContextMap)
9020             {
9021                 if (shareContext.first == context->id().value)
9022                 {
9023                     if (usesMidExecutionCapture())
9024                     {
9025                         // Setup the presentation (this) context first.
9026                         out << "    " << FmtSetupFunction(kNoPartId, context->id(), FuncUsage::Call)
9027                             << ";\n";
9028                         out << "\n";
9029                     }
9030 
9031                     continue;
9032                 }
9033 
9034                 // The SetupReplayContextXX() calls only exist if this is a mid-execution capture
9035                 // and we can only call them if they exist, so only output the calls if this is a
9036                 // MEC.
9037                 if (usesMidExecutionCapture())
9038                 {
9039                     // Only call SetupReplayContext for secondary contexts that were current before
9040                     // MEC started
9041                     if (mActiveContexts.find(shareContext.first) != mActiveContexts.end())
9042                     {
9043                         // TODO(http://anglebug.com/5878): Support capture/replay of
9044                         // eglCreateContext() so this block can be moved into SetupReplayContextXX()
9045                         // by injecting them into the beginning of the setup call stream.
9046                         out << "    CreateContext(" << shareContext.first << ");\n";
9047 
9048                         out << "    "
9049                             << FmtSetupFunction(kNoPartId, shareContext.second->id(),
9050                                                 FuncUsage::Call)
9051                             << ";\n";
9052                     }
9053                 }
9054             }
9055 
9056             // If there are other contexts that were initialized, we need to make the main context
9057             // current again.
9058             if (shareContextMap.size() > 1)
9059             {
9060                 out << "\n";
9061                 out << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2[" << context->id()
9062                     << "]);\n";
9063             }
9064 
9065             out << "}\n";
9066 
9067             mReplayWriter.addPublicFunction(proto, std::stringstream(), out);
9068         }
9069     }
9070 
9071     // Emit code to reset back to starting state
9072     if (frameIndex == frameCount)
9073     {
9074         std::stringstream resetProtoStream;
9075         std::stringstream resetHeaderStream;
9076         std::stringstream resetBodyStream;
9077 
9078         resetProtoStream << "void ResetReplay(void)";
9079 
9080         resetBodyStream << resetProtoStream.str() << "\n";
9081         resetBodyStream << "{\n";
9082 
9083         // Grab the list of contexts to be reset
9084         std::set<gl::ContextID> contextIDs;
9085         mResourceTracker.getContextIDs(contextIDs);
9086 
9087         // TODO(http://anglebug.com/5878): Look at moving this into the shared context file since
9088         // it's resetting shared objects.
9089 
9090         // TODO(http://anglebug.com/4599): Support function parts when writing Reset functions
9091 
9092         // Track whether anything was written during Reset
9093         bool anyResourceReset = false;
9094 
9095         // Track whether we changed contexts during Reset
9096         bool contextChanged = false;
9097 
9098         // First emit shared object reset, including opaque and context state
9099         {
9100             std::stringstream protoStream;
9101             std::stringstream headerStream;
9102             std::stringstream bodyStream;
9103 
9104             protoStream << "void "
9105                         << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Prototype);
9106             bodyStream << protoStream.str() << "\n";
9107             bodyStream << "{\n";
9108 
9109             for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
9110             {
9111                 if (!IsSharedObjectResource(resourceType))
9112                 {
9113                     continue;
9114                 }
9115                 // Use current context for shared reset
9116                 MaybeResetResources(context->id(), resourceType, mReplayWriter, bodyStream,
9117                                     headerStream, &mResourceTracker, &mBinaryData, anyResourceReset,
9118                                     &mResourceIDBufferSize);
9119             }
9120 
9121             // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
9122             MaybeResetOpaqueTypeObjects(mReplayWriter, bodyStream, headerStream, context,
9123                                         &mResourceTracker, &mBinaryData, &mResourceIDBufferSize);
9124 
9125             bodyStream << "}\n";
9126 
9127             mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
9128         }
9129 
9130         // Emit the call to shared object reset
9131         resetBodyStream << "    " << FmtResetFunction(kNoPartId, kSharedContextId, FuncUsage::Call)
9132                         << ";\n";
9133 
9134         // Reset our output tracker (Note: This was unused during shared reset)
9135         anyResourceReset = false;
9136 
9137         // Walk through all contexts that need Reset
9138         for (const gl::ContextID &contextID : contextIDs)
9139         {
9140             // Create a function to reset each context's non-shared objects
9141             {
9142                 std::stringstream protoStream;
9143                 std::stringstream headerStream;
9144                 std::stringstream bodyStream;
9145 
9146                 protoStream << "void "
9147                             << FmtResetFunction(kNoPartId, contextID, FuncUsage::Prototype);
9148                 bodyStream << protoStream.str() << "\n";
9149                 bodyStream << "{\n";
9150 
9151                 // Build the Reset calls in a separate stream so we can insert before them
9152                 std::stringstream resetStream;
9153 
9154                 for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
9155                 {
9156                     if (IsSharedObjectResource(resourceType))
9157                     {
9158                         continue;
9159                     }
9160                     MaybeResetResources(contextID, resourceType, mReplayWriter, resetStream,
9161                                         headerStream, &mResourceTracker, &mBinaryData,
9162                                         anyResourceReset, &mResourceIDBufferSize);
9163                 }
9164 
9165                 // Only call eglMakeCurrent if anything was actually reset in the function and the
9166                 // context differs from current
9167                 if (anyResourceReset && contextID != context->id())
9168                 {
9169                     contextChanged = true;
9170                     bodyStream << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
9171                                << contextID.value << "]);\n\n";
9172                 }
9173 
9174                 // Then append the Reset calls
9175                 bodyStream << resetStream.str();
9176 
9177                 bodyStream << "}\n";
9178                 mReplayWriter.addPrivateFunction(protoStream.str(), headerStream, bodyStream);
9179             }
9180 
9181             // Emit a call to reset each context's non-shared objects
9182             resetBodyStream << "    " << FmtResetFunction(kNoPartId, contextID, FuncUsage::Call)
9183                             << ";\n";
9184         }
9185 
9186         // Bind the main context again if we bound any additional contexts
9187         if (contextChanged)
9188         {
9189             resetBodyStream << "    eglMakeCurrent(NULL, NULL, NULL, gContextMap2["
9190                             << context->id().value << "]);\n";
9191         }
9192 
9193         // Now that we're back on the main context, reset any additional state
9194         resetBodyStream << "\n    // Reset main context state\n";
9195         MaybeResetContextState(mReplayWriter, resetBodyStream, resetHeaderStream, &mResourceTracker,
9196                                context, &mBinaryData, stateResetHelper, &mResourceIDBufferSize);
9197 
9198         resetBodyStream << "}\n";
9199 
9200         mReplayWriter.addPublicFunction(resetProtoStream.str(), resetHeaderStream, resetBodyStream);
9201     }
9202 
9203     if (!mFrameCalls.empty())
9204     {
9205         std::stringstream protoStream;
9206         protoStream << "void "
9207                     << FmtReplayFunction(context->id(), FuncUsage::Prototype, frameIndex);
9208         std::string proto = protoStream.str();
9209 
9210         std::stringstream headerStream;
9211         std::stringstream bodyStream;
9212 
9213         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, mReplayWriter,
9214                                         frameIndex, &mBinaryData, mFrameCalls, headerStream,
9215                                         bodyStream, &mResourceIDBufferSize);
9216 
9217         mReplayWriter.addPrivateFunction(proto, headerStream, bodyStream);
9218     }
9219 
9220     if (mSerializeStateEnabled)
9221     {
9222         std::string serializedContextString;
9223         if (SerializeContextToString(const_cast<gl::Context *>(context),
9224                                      &serializedContextString) == Result::Continue)
9225         {
9226             std::stringstream protoStream;
9227             protoStream << "const char *"
9228                         << FmtGetSerializedContextStateFunction(context->id(), FuncUsage::Prototype,
9229                                                                 frameIndex);
9230             std::string proto = protoStream.str();
9231 
9232             std::stringstream bodyStream;
9233             bodyStream << proto << "\n";
9234             bodyStream << "{\n";
9235             bodyStream << "    return " << FmtMultiLineString(serializedContextString) << ";\n";
9236             bodyStream << "}\n";
9237 
9238             mReplayWriter.addPrivateFunction(proto, std::stringstream(), bodyStream);
9239         }
9240     }
9241 
9242     {
9243         std::stringstream fnamePatternStream;
9244         fnamePatternStream << mOutDirectory << FmtCapturePrefix(context->id(), mCaptureLabel);
9245         std::string fnamePattern = fnamePatternStream.str();
9246 
9247         mReplayWriter.setFilenamePattern(fnamePattern);
9248     }
9249 
9250     if (mFrameIndex == mCaptureEndFrame)
9251     {
9252         mReplayWriter.saveFrame();
9253     }
9254     else
9255     {
9256         mReplayWriter.saveFrameIfFull();
9257     }
9258 }
9259 
reset()9260 void FrameCaptureShared::reset()
9261 {
9262     mFrameCalls.clear();
9263     mClientVertexArrayMap.fill(-1);
9264 
9265     // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
9266     // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
9267     // necessary.
9268 }
9269 
getShaderSource(gl::ShaderProgramID id) const9270 const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
9271 {
9272     const auto &foundSources = mCachedShaderSource.find(id);
9273     ASSERT(foundSources != mCachedShaderSource.end());
9274     return foundSources->second;
9275 }
9276 
setShaderSource(gl::ShaderProgramID id,std::string source)9277 void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
9278 {
9279     mCachedShaderSource[id] = source;
9280 }
9281 
getProgramSources(gl::ShaderProgramID id) const9282 const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
9283 {
9284     const auto &foundSources = mCachedProgramSources.find(id);
9285     ASSERT(foundSources != mCachedProgramSources.end());
9286     return foundSources->second;
9287 }
9288 
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)9289 void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
9290 {
9291     mCachedProgramSources[id] = sources;
9292 }
9293 
markResourceSetupCallsInactive(std::vector<CallCapture> * setupCalls,ResourceIDType type,GLuint id,gl::Range<size_t> range)9294 void FrameCaptureShared::markResourceSetupCallsInactive(std::vector<CallCapture> *setupCalls,
9295                                                         ResourceIDType type,
9296                                                         GLuint id,
9297                                                         gl::Range<size_t> range)
9298 {
9299     if (!mTrimEnabled)
9300     {
9301         return;
9302     }
9303 
9304     ASSERT(mResourceIDToSetupCalls[type].find(id) == mResourceIDToSetupCalls[type].end());
9305 
9306     // Mark all of the calls that were used to initialize this resource as INACTIVE
9307     for (size_t index : range)
9308     {
9309         (*setupCalls)[index].isActive = false;
9310     }
9311 
9312     mResourceIDToSetupCalls[type][id] = range;
9313 }
9314 
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)9315 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
9316 {
9317     std::vector<uint8_t> data(size);
9318     memcpy(data.data(), source, size);
9319     paramCapture->data.emplace_back(std::move(data));
9320 }
9321 
CaptureString(const GLchar * str,ParamCapture * paramCapture)9322 void CaptureString(const GLchar *str, ParamCapture *paramCapture)
9323 {
9324     // include the '\0' suffix
9325     CaptureMemory(str, strlen(str) + 1, paramCapture);
9326 }
9327 
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)9328 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
9329 {
9330     // Write the incoming string up to limit, including null terminator
9331     size_t length = strlen(str) + 1;
9332 
9333     if (length > limit)
9334     {
9335         // If too many characters, resize the string to fit in the limit
9336         std::string newStr = str;
9337         newStr.resize(limit - 1);
9338         CaptureString(newStr.c_str(), paramCapture);
9339     }
9340     else
9341     {
9342         CaptureMemory(str, length, paramCapture);
9343     }
9344 }
9345 
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)9346 void CaptureVertexPointerGLES1(const gl::State &glState,
9347                                gl::ClientVertexArrayType type,
9348                                const void *pointer,
9349                                ParamCapture *paramCapture)
9350 {
9351     paramCapture->value.voidConstPointerVal = pointer;
9352     if (!glState.getTargetBuffer(gl::BufferBinding::Array))
9353     {
9354         paramCapture->arrayClientPointerIndex =
9355             gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
9356     }
9357 }
9358 
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)9359 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
9360 {
9361     gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
9362     return program;
9363 }
9364 
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)9365 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
9366                                               gl::ShaderProgramID handle,
9367                                               gl::UniformBlockIndex uniformBlockIndex,
9368                                               GLenum pname,
9369                                               ParamCapture *paramCapture)
9370 {
9371     int numParams = 1;
9372 
9373     // From the OpenGL ES 3.0 spec:
9374     // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
9375     // active uniform indices for the uniform block identified by uniformBlockIndex is
9376     // returned. The number of elements that will be written to params is the value of
9377     // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
9378     if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
9379     {
9380         gl::Program *program = GetProgramForCapture(glState, handle);
9381         if (program)
9382         {
9383             gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
9384                                           GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
9385         }
9386     }
9387 
9388     paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
9389 }
9390 
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)9391 void CaptureGetParameter(const gl::State &glState,
9392                          GLenum pname,
9393                          size_t typeSize,
9394                          ParamCapture *paramCapture)
9395 {
9396     // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
9397     // This value needs to be updated if any new extensions are introduced that would allow for
9398     // more compressed texture formats. The current value is taken from:
9399     // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
9400     constexpr unsigned int kMaxReportedCapabilities = 69;
9401     paramCapture->readBufferSizeBytes               = typeSize * kMaxReportedCapabilities;
9402 }
9403 
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)9404 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
9405 {
9406     paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
9407     CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
9408 }
9409 
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)9410 void CaptureShaderStrings(GLsizei count,
9411                           const GLchar *const *strings,
9412                           const GLint *length,
9413                           ParamCapture *paramCapture)
9414 {
9415     // Concat the array elements of the string into one data vector,
9416     // append the terminating zero and use this as the captured shader
9417     // string. The string count and the length array are adjusted
9418     // accordingly in the capture post-processing
9419 
9420     std::vector<uint8_t> data;
9421     size_t offset = 0;
9422     for (GLsizei index = 0; index < count; ++index)
9423     {
9424         size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
9425 
9426         // Count trailing zeros
9427         uint32_t i = 1;
9428         while (i < len && strings[index][len - i] == 0)
9429         {
9430             i++;
9431         }
9432 
9433         // Don't copy trailing zeros
9434         len -= (i - 1);
9435 
9436         data.resize(offset + len);
9437         std::copy(strings[index], strings[index] + len, data.begin() + offset);
9438         offset += len;
9439     }
9440 
9441     data.push_back(0);
9442     paramCapture->data.emplace_back(std::move(data));
9443 }
9444 
9445 // ReplayWriter implementation.
ReplayWriter()9446 ReplayWriter::ReplayWriter()
9447     : mSourceFileExtension(kDefaultSourceFileExt),
9448       mSourceFileSizeThreshold(kDefaultSourceFileSizeThreshold),
9449       mFrameIndex(1)
9450 {}
9451 
~ReplayWriter()9452 ReplayWriter::~ReplayWriter()
9453 {
9454     ASSERT(mPrivateFunctionPrototypes.empty());
9455     ASSERT(mPublicFunctionPrototypes.empty());
9456     ASSERT(mPrivateFunctions.empty());
9457     ASSERT(mPublicFunctions.empty());
9458     ASSERT(mGlobalVariableDeclarations.empty());
9459     ASSERT(mReplayHeaders.empty());
9460 }
9461 
setSourceFileExtension(const char * ext)9462 void ReplayWriter::setSourceFileExtension(const char *ext)
9463 {
9464     mSourceFileExtension = ext;
9465 }
9466 
setSourceFileSizeThreshold(size_t sourceFileSizeThreshold)9467 void ReplayWriter::setSourceFileSizeThreshold(size_t sourceFileSizeThreshold)
9468 {
9469     mSourceFileSizeThreshold = sourceFileSizeThreshold;
9470 }
9471 
setFilenamePattern(const std::string & pattern)9472 void ReplayWriter::setFilenamePattern(const std::string &pattern)
9473 {
9474     if (mFilenamePattern != pattern)
9475     {
9476         mFilenamePattern = pattern;
9477     }
9478 }
9479 
setCaptureLabel(const std::string & label)9480 void ReplayWriter::setCaptureLabel(const std::string &label)
9481 {
9482     mCaptureLabel = label;
9483 }
9484 
setSourcePrologue(const std::string & prologue)9485 void ReplayWriter::setSourcePrologue(const std::string &prologue)
9486 {
9487     mSourcePrologue = prologue;
9488 }
9489 
setHeaderPrologue(const std::string & prologue)9490 void ReplayWriter::setHeaderPrologue(const std::string &prologue)
9491 {
9492     mHeaderPrologue = prologue;
9493 }
9494 
addPublicFunction(const std::string & functionProto,const std::stringstream & headerStream,const std::stringstream & bodyStream)9495 void ReplayWriter::addPublicFunction(const std::string &functionProto,
9496                                      const std::stringstream &headerStream,
9497                                      const std::stringstream &bodyStream)
9498 {
9499     mPublicFunctionPrototypes.push_back(functionProto);
9500 
9501     std::string header = headerStream.str();
9502     std::string body   = bodyStream.str();
9503 
9504     if (!header.empty())
9505     {
9506         mReplayHeaders.emplace_back(header);
9507     }
9508 
9509     if (!body.empty())
9510     {
9511         mPublicFunctions.emplace_back(body);
9512     }
9513 }
9514 
addPrivateFunction(const std::string & functionProto,const std::stringstream & headerStream,const std::stringstream & bodyStream)9515 void ReplayWriter::addPrivateFunction(const std::string &functionProto,
9516                                       const std::stringstream &headerStream,
9517                                       const std::stringstream &bodyStream)
9518 {
9519     mPrivateFunctionPrototypes.push_back(functionProto);
9520 
9521     std::string header = headerStream.str();
9522     std::string body   = bodyStream.str();
9523 
9524     if (!header.empty())
9525     {
9526         mReplayHeaders.emplace_back(header);
9527     }
9528 
9529     if (!body.empty())
9530     {
9531         mPrivateFunctions.emplace_back(body);
9532     }
9533 }
9534 
getInlineVariableName(EntryPoint entryPoint,const std::string & paramName)9535 std::string ReplayWriter::getInlineVariableName(EntryPoint entryPoint, const std::string &paramName)
9536 {
9537     int counter = mDataTracker.getCounters().getAndIncrement(entryPoint, paramName);
9538     return GetVarName(entryPoint, paramName, counter);
9539 }
9540 
getInlineStringSetVariableName(EntryPoint entryPoint,const std::string & paramName,const std::vector<std::string> & strings,bool * isNewEntryOut)9541 std::string ReplayWriter::getInlineStringSetVariableName(EntryPoint entryPoint,
9542                                                          const std::string &paramName,
9543                                                          const std::vector<std::string> &strings,
9544                                                          bool *isNewEntryOut)
9545 {
9546     int counter    = mDataTracker.getStringCounters().getStringCounter(strings);
9547     *isNewEntryOut = (counter == kStringsNotFound);
9548     if (*isNewEntryOut)
9549     {
9550         // This is a unique set of strings, so set up their declaration and update the counter
9551         counter = mDataTracker.getCounters().getAndIncrement(entryPoint, paramName);
9552         mDataTracker.getStringCounters().setStringCounter(strings, counter);
9553 
9554         std::string varName = GetVarName(entryPoint, paramName, counter);
9555 
9556         std::stringstream declStream;
9557         declStream << "const char *const " << varName << "[]";
9558         std::string decl = declStream.str();
9559 
9560         mGlobalVariableDeclarations.push_back(decl);
9561 
9562         return varName;
9563     }
9564     else
9565     {
9566         return GetVarName(entryPoint, paramName, counter);
9567     }
9568 }
9569 
getStoredReplaySourceSize() const9570 size_t ReplayWriter::getStoredReplaySourceSize() const
9571 {
9572     size_t sum = 0;
9573     for (const std::string &header : mReplayHeaders)
9574     {
9575         sum += header.size();
9576     }
9577     for (const std::string &publicFunc : mPublicFunctions)
9578     {
9579         sum += publicFunc.size();
9580     }
9581     for (const std::string &privateFunc : mPrivateFunctions)
9582     {
9583         sum += privateFunc.size();
9584     }
9585     return sum;
9586 }
9587 
9588 // static
GetVarName(EntryPoint entryPoint,const std::string & paramName,int counter)9589 std::string ReplayWriter::GetVarName(EntryPoint entryPoint,
9590                                      const std::string &paramName,
9591                                      int counter)
9592 {
9593     std::stringstream strstr;
9594     strstr << GetEntryPointName(entryPoint) << "_" << paramName << "_" << counter;
9595     return strstr.str();
9596 }
9597 
saveFrame()9598 void ReplayWriter::saveFrame()
9599 {
9600     if (mReplayHeaders.empty() && mPublicFunctions.empty() && mPrivateFunctions.empty())
9601     {
9602         return;
9603     }
9604 
9605     ASSERT(!mSourceFileExtension.empty());
9606 
9607     std::stringstream strstr;
9608     strstr << mFilenamePattern << "_" << std::setfill('0') << std::setw(3) << mFrameIndex++ << "."
9609            << mSourceFileExtension;
9610 
9611     std::string frameFilePath = strstr.str();
9612 
9613     writeReplaySource(frameFilePath);
9614 }
9615 
saveFrameIfFull()9616 void ReplayWriter::saveFrameIfFull()
9617 {
9618     if (getStoredReplaySourceSize() < mSourceFileSizeThreshold)
9619     {
9620         INFO() << "Merging captured frame: " << getStoredReplaySourceSize()
9621                << " less than threshold of " << mSourceFileSizeThreshold << " bytes";
9622         return;
9623     }
9624 
9625     saveFrame();
9626 }
9627 
saveHeader()9628 void ReplayWriter::saveHeader()
9629 {
9630     std::stringstream headerPathStream;
9631     headerPathStream << mFilenamePattern << ".h";
9632     std::string headerPath = headerPathStream.str();
9633 
9634     SaveFileHelper saveH(headerPath);
9635 
9636     saveH << mHeaderPrologue << "\n";
9637 
9638     saveH << "// Public functions are declared in trace_fixture.h.\n";
9639     saveH << "\n";
9640     saveH << "// Private Functions\n";
9641     saveH << "\n";
9642 
9643     for (const std::string &proto : mPrivateFunctionPrototypes)
9644     {
9645         saveH << proto << ";\n";
9646     }
9647 
9648     saveH << "\n";
9649     saveH << "// Global variables\n";
9650     saveH << "\n";
9651 
9652     for (const std::string &globalVar : mGlobalVariableDeclarations)
9653     {
9654         saveH << "extern " << globalVar << ";\n";
9655     }
9656 
9657     mPublicFunctionPrototypes.clear();
9658     mPrivateFunctionPrototypes.clear();
9659     mGlobalVariableDeclarations.clear();
9660 
9661     addWrittenFile(headerPath);
9662 }
9663 
saveIndexFilesAndHeader()9664 void ReplayWriter::saveIndexFilesAndHeader()
9665 {
9666     ASSERT(!mSourceFileExtension.empty());
9667 
9668     std::stringstream sourcePathStream;
9669     sourcePathStream << mFilenamePattern << "." << mSourceFileExtension;
9670     std::string sourcePath = sourcePathStream.str();
9671 
9672     writeReplaySource(sourcePath);
9673     saveHeader();
9674 }
9675 
saveSetupFile()9676 void ReplayWriter::saveSetupFile()
9677 {
9678     ASSERT(!mSourceFileExtension.empty());
9679 
9680     std::stringstream strstr;
9681     strstr << mFilenamePattern << "." << mSourceFileExtension;
9682 
9683     std::string frameFilePath = strstr.str();
9684 
9685     writeReplaySource(frameFilePath);
9686 }
9687 
writeReplaySource(const std::string & filename)9688 void ReplayWriter::writeReplaySource(const std::string &filename)
9689 {
9690     SaveFileHelper saveCpp(filename);
9691 
9692     saveCpp << mSourcePrologue << "\n";
9693 
9694     for (const std::string &header : mReplayHeaders)
9695     {
9696         saveCpp << header << "\n";
9697     }
9698 
9699     saveCpp << "// Private Functions\n";
9700     saveCpp << "\n";
9701 
9702     for (const std::string &func : mPrivateFunctions)
9703     {
9704         saveCpp << func << "\n";
9705     }
9706 
9707     saveCpp << "// Public Functions\n";
9708     saveCpp << "\n";
9709 
9710     if (mFilenamePattern == "cpp")
9711     {
9712         saveCpp << "extern \"C\"\n";
9713         saveCpp << "{\n";
9714     }
9715 
9716     for (const std::string &func : mPublicFunctions)
9717     {
9718         saveCpp << func << "\n";
9719     }
9720 
9721     if (mFilenamePattern == "cpp")
9722     {
9723         saveCpp << "}  // extern \"C\"\n";
9724     }
9725 
9726     mReplayHeaders.clear();
9727     mPrivateFunctions.clear();
9728     mPublicFunctions.clear();
9729 
9730     addWrittenFile(filename);
9731 }
9732 
addWrittenFile(const std::string & filename)9733 void ReplayWriter::addWrittenFile(const std::string &filename)
9734 {
9735     std::string writtenFile = GetBaseName(filename);
9736     ASSERT(std::find(mWrittenFiles.begin(), mWrittenFiles.end(), writtenFile) ==
9737            mWrittenFiles.end());
9738     mWrittenFiles.push_back(writtenFile);
9739 }
9740 
getAndResetWrittenFiles()9741 std::vector<std::string> ReplayWriter::getAndResetWrittenFiles()
9742 {
9743     std::vector<std::string> results = std::move(mWrittenFiles);
9744     std::sort(results.begin(), results.end());
9745     ASSERT(mWrittenFiles.empty());
9746     return results;
9747 }
9748 }  // namespace angle
9749 
9750 namespace egl
9751 {
CaptureAttributeMap(const egl::AttributeMap & attribMap)9752 angle::ParamCapture CaptureAttributeMap(const egl::AttributeMap &attribMap)
9753 {
9754     switch (attribMap.getType())
9755     {
9756         case AttributeMapType::Attrib:
9757         {
9758             angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLAttribPointer);
9759             if (attribMap.isEmpty())
9760             {
9761                 paramCapture.value.EGLAttribPointerVal = nullptr;
9762             }
9763             else
9764             {
9765                 std::vector<EGLAttrib> attribs;
9766                 for (const auto &[key, value] : attribMap)
9767                 {
9768                     attribs.push_back(key);
9769                     attribs.push_back(value);
9770                 }
9771                 attribs.push_back(EGL_NONE);
9772 
9773                 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLAttrib),
9774                                      &paramCapture);
9775             }
9776             return paramCapture;
9777         }
9778 
9779         case AttributeMapType::Int:
9780         {
9781             angle::ParamCapture paramCapture("attrib_list", angle::ParamType::TEGLintPointer);
9782             if (attribMap.isEmpty())
9783             {
9784                 paramCapture.value.EGLintPointerVal = nullptr;
9785             }
9786             else
9787             {
9788                 std::vector<EGLint> attribs;
9789                 for (const auto &[key, value] : attribMap)
9790                 {
9791                     attribs.push_back(static_cast<EGLint>(key));
9792                     attribs.push_back(static_cast<EGLint>(value));
9793                 }
9794                 attribs.push_back(EGL_NONE);
9795 
9796                 angle::CaptureMemory(attribs.data(), attribs.size() * sizeof(EGLint),
9797                                      &paramCapture);
9798             }
9799             return paramCapture;
9800         }
9801 
9802         default:
9803             UNREACHABLE();
9804             return angle::ParamCapture();
9805     }
9806 }
9807 }  // namespace egl
9808