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