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