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