• 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.h"
20 #include "common/mathutil.h"
21 #include "common/string_utils.h"
22 #include "common/system_utils.h"
23 #include "libANGLE/Config.h"
24 #include "libANGLE/Context.h"
25 #include "libANGLE/Display.h"
26 #include "libANGLE/Fence.h"
27 #include "libANGLE/Framebuffer.h"
28 #include "libANGLE/GLES1Renderer.h"
29 #include "libANGLE/Query.h"
30 #include "libANGLE/ResourceMap.h"
31 #include "libANGLE/Shader.h"
32 #include "libANGLE/Surface.h"
33 #include "libANGLE/VertexArray.h"
34 #include "libANGLE/capture/capture_gles_1_0_autogen.h"
35 #include "libANGLE/capture/capture_gles_2_0_autogen.h"
36 #include "libANGLE/capture/capture_gles_3_0_autogen.h"
37 #include "libANGLE/capture/capture_gles_3_1_autogen.h"
38 #include "libANGLE/capture/capture_gles_3_2_autogen.h"
39 #include "libANGLE/capture/capture_gles_ext_autogen.h"
40 #include "libANGLE/capture/frame_capture_utils.h"
41 #include "libANGLE/capture/gl_enum_utils.h"
42 #include "libANGLE/queryconversions.h"
43 #include "libANGLE/queryutils.h"
44 
45 #define USE_SYSTEM_ZLIB
46 #include "compression_utils_portable.h"
47 
48 #if !ANGLE_CAPTURE_ENABLED
49 #    error Frame capture must be enabled to include this file.
50 #endif  // !ANGLE_CAPTURE_ENABLED
51 
52 namespace angle
53 {
54 namespace
55 {
56 
57 constexpr char kEnabledVarName[]               = "ANGLE_CAPTURE_ENABLED";
58 constexpr char kOutDirectoryVarName[]          = "ANGLE_CAPTURE_OUT_DIR";
59 constexpr char kFrameStartVarName[]            = "ANGLE_CAPTURE_FRAME_START";
60 constexpr char kFrameEndVarName[]              = "ANGLE_CAPTURE_FRAME_END";
61 constexpr char kCaptureTriggerVarName[]        = "ANGLE_CAPTURE_TRIGGER";
62 constexpr char kCaptureLabel[]                 = "ANGLE_CAPTURE_LABEL";
63 constexpr char kCompression[]                  = "ANGLE_CAPTURE_COMPRESSION";
64 constexpr char kSerializeStateEnabledVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
65 
66 constexpr size_t kBinaryAlignment   = 16;
67 constexpr size_t kFunctionSizeLimit = 5000;
68 
69 // Limit based on MSVC Compiler Error C2026
70 constexpr size_t kStringLengthLimit = 16380;
71 
72 // Android debug properties that correspond to the above environment variables
73 constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
74 constexpr char kAndroidOutDir[]         = "debug.angle.capture.out_dir";
75 constexpr char kAndroidFrameStart[]     = "debug.angle.capture.frame_start";
76 constexpr char kAndroidFrameEnd[]       = "debug.angle.capture.frame_end";
77 constexpr char kAndroidCaptureTrigger[] = "debug.angle.capture.trigger";
78 constexpr char kAndroidCaptureLabel[]   = "debug.angle.capture.label";
79 constexpr char kAndroidCompression[]    = "debug.angle.capture.compression";
80 
GetDefaultOutDirectory()81 std::string GetDefaultOutDirectory()
82 {
83 #if defined(ANGLE_PLATFORM_ANDROID)
84     std::string path = "/sdcard/Android/data/";
85 
86     // Linux interface to get application id of the running process
87     FILE *cmdline = fopen("/proc/self/cmdline", "r");
88     char applicationId[512];
89     if (cmdline)
90     {
91         fread(applicationId, 1, sizeof(applicationId), cmdline);
92         fclose(cmdline);
93 
94         // Some package may have application id as <app_name>:<cmd_name>
95         char *colonSep = strchr(applicationId, ':');
96         if (colonSep)
97         {
98             *colonSep = '\0';
99         }
100     }
101     else
102     {
103         ERR() << "not able to lookup application id";
104     }
105 
106     constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
107     path += std::string(applicationId) + kAndroidOutputSubdir;
108 
109     // Check for existance of output path
110     struct stat dir_stat;
111     if (stat(path.c_str(), &dir_stat) == -1)
112     {
113         ERR() << "Output directory '" << path
114               << "' does not exist.  Create it over adb using mkdir.";
115     }
116 
117     return path;
118 #else
119     return std::string("./");
120 #endif  // defined(ANGLE_PLATFORM_ANDROID)
121 }
122 
GetCaptureTrigger()123 std::string GetCaptureTrigger()
124 {
125     return GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureTriggerVarName,
126                                                       kAndroidCaptureTrigger);
127 }
128 
operator <<(std::ostream & os,gl::ContextID contextId)129 std::ostream &operator<<(std::ostream &os, gl::ContextID contextId)
130 {
131     os << static_cast<int>(contextId.value);
132     return os;
133 }
134 
135 constexpr static gl::ContextID kSharedContextId = {0};
136 
137 struct FmtCapturePrefix
138 {
FmtCapturePrefixangle::__anond94d34250111::FmtCapturePrefix139     FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
140         : contextId(contextIdIn), captureLabel(captureLabelIn)
141     {}
142     gl::ContextID contextId;
143     const std::string &captureLabel;
144 };
145 
operator <<(std::ostream & os,const FmtCapturePrefix & fmt)146 std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
147 {
148     if (fmt.captureLabel.empty())
149     {
150         os << "angle";
151     }
152     else
153     {
154         os << fmt.captureLabel;
155     }
156 
157     if (fmt.contextId != kSharedContextId)
158     {
159         os << "_capture_context" << fmt.contextId;
160     }
161 
162     return os;
163 }
164 
165 enum class ReplayFunc
166 {
167     Replay,
168     Setup,
169     Reset,
170 };
171 
172 constexpr uint32_t kNoPartId = std::numeric_limits<uint32_t>::max();
173 
174 struct FmtReplayFunction
175 {
FmtReplayFunctionangle::__anond94d34250111::FmtReplayFunction176     FmtReplayFunction(gl::ContextID contextIdIn,
177                       uint32_t frameIndexIn,
178                       uint32_t partIdIn = kNoPartId)
179         : contextId(contextIdIn), frameIndex(frameIndexIn), partId(partIdIn)
180     {}
181     gl::ContextID contextId;
182     uint32_t frameIndex;
183     uint32_t partId;
184 };
185 
operator <<(std::ostream & os,const FmtReplayFunction & fmt)186 std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
187 {
188     os << "ReplayContext";
189 
190     if (fmt.contextId == kSharedContextId)
191     {
192         os << "Shared";
193     }
194     else
195     {
196         os << fmt.contextId;
197     }
198 
199     os << "Frame" << fmt.frameIndex;
200 
201     if (fmt.partId != kNoPartId)
202     {
203         os << "Part" << fmt.partId;
204     }
205     os << "()";
206     return os;
207 }
208 
209 struct FmtSetupFunction
210 {
FmtSetupFunctionangle::__anond94d34250111::FmtSetupFunction211     FmtSetupFunction(uint32_t partIdIn, gl::ContextID contextIdIn)
212         : partId(partIdIn), contextId(contextIdIn)
213     {}
214 
215     uint32_t partId;
216     gl::ContextID contextId;
217 };
218 
operator <<(std::ostream & os,const FmtSetupFunction & fmt)219 std::ostream &operator<<(std::ostream &os, const FmtSetupFunction &fmt)
220 {
221     os << "SetupReplayContext";
222 
223     if (fmt.contextId == kSharedContextId)
224     {
225         os << "Shared";
226     }
227     else
228     {
229         os << fmt.contextId;
230     }
231 
232     if (fmt.partId != kNoPartId)
233     {
234         os << "Part" << fmt.partId;
235     }
236     os << "()";
237     return os;
238 }
239 
240 struct FmtResetFunction
241 {
FmtResetFunctionangle::__anond94d34250111::FmtResetFunction242     FmtResetFunction() {}
243 };
244 
operator <<(std::ostream & os,const FmtResetFunction & fmt)245 std::ostream &operator<<(std::ostream &os, const FmtResetFunction &fmt)
246 {
247     os << "ResetReplay()";
248     return os;
249 }
250 
251 struct FmtFunction
252 {
FmtFunctionangle::__anond94d34250111::FmtFunction253     FmtFunction(ReplayFunc funcTypeIn,
254                 gl::ContextID contextIdIn,
255                 uint32_t frameIndexIn,
256                 uint32_t partIdIn)
257         : funcType(funcTypeIn), contextId(contextIdIn), frameIndex(frameIndexIn), partId(partIdIn)
258     {}
259 
260     ReplayFunc funcType;
261     gl::ContextID contextId;
262     uint32_t frameIndex;
263     uint32_t partId;
264 };
265 
operator <<(std::ostream & os,const FmtFunction & fmt)266 std::ostream &operator<<(std::ostream &os, const FmtFunction &fmt)
267 {
268     switch (fmt.funcType)
269     {
270         case ReplayFunc::Replay:
271             os << FmtReplayFunction(fmt.contextId, fmt.frameIndex, fmt.partId);
272             break;
273 
274         case ReplayFunc::Setup:
275             os << FmtSetupFunction(fmt.partId, fmt.contextId);
276             break;
277 
278         case ReplayFunc::Reset:
279             os << FmtResetFunction();
280             break;
281 
282         default:
283             UNREACHABLE();
284             break;
285     }
286 
287     return os;
288 }
289 
290 struct FmtGetSerializedContextStateFunction
291 {
FmtGetSerializedContextStateFunctionangle::__anond94d34250111::FmtGetSerializedContextStateFunction292     FmtGetSerializedContextStateFunction(gl::ContextID contextIdIn, uint32_t frameIndexIn)
293         : contextId(contextIdIn), frameIndex(frameIndexIn)
294     {}
295     gl::ContextID contextId;
296     uint32_t frameIndex;
297 };
298 
operator <<(std::ostream & os,const FmtGetSerializedContextStateFunction & fmt)299 std::ostream &operator<<(std::ostream &os, const FmtGetSerializedContextStateFunction &fmt)
300 {
301     os << "GetSerializedContext" << fmt.contextId << "StateFrame" << fmt.frameIndex << "Data()";
302     return os;
303 }
304 
GetCaptureFileName(gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)305 std::string GetCaptureFileName(gl::ContextID contextId,
306                                const std::string &captureLabel,
307                                uint32_t frameIndex,
308                                const char *suffix)
309 {
310     std::stringstream fnameStream;
311     fnameStream << FmtCapturePrefix(contextId, captureLabel) << "_frame" << std::setfill('0')
312                 << std::setw(3) << frameIndex << suffix;
313     return fnameStream.str();
314 }
315 
GetCaptureFilePath(const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,uint32_t frameIndex,const char * suffix)316 std::string GetCaptureFilePath(const std::string &outDir,
317                                gl::ContextID contextId,
318                                const std::string &captureLabel,
319                                uint32_t frameIndex,
320                                const char *suffix)
321 {
322     return outDir + GetCaptureFileName(contextId, captureLabel, frameIndex, suffix);
323 }
324 
WriteParamStaticVarName(const CallCapture & call,const ParamCapture & param,int counter,std::ostream & out)325 void WriteParamStaticVarName(const CallCapture &call,
326                              const ParamCapture &param,
327                              int counter,
328                              std::ostream &out)
329 {
330     out << call.name() << "_" << param.name << "_" << counter;
331 }
332 
WriteGLFloatValue(std::ostream & out,GLfloat value)333 void WriteGLFloatValue(std::ostream &out, GLfloat value)
334 {
335     // Check for non-representable values
336     ASSERT(std::numeric_limits<float>::has_infinity);
337     ASSERT(std::numeric_limits<float>::has_quiet_NaN);
338 
339     if (std::isinf(value))
340     {
341         float negativeInf = -std::numeric_limits<float>::infinity();
342         if (value == negativeInf)
343         {
344             out << "-";
345         }
346         out << "std::numeric_limits<float>::infinity()";
347     }
348     else if (std::isnan(value))
349     {
350         out << "std::numeric_limits<float>::quiet_NaN()";
351     }
352     else
353     {
354         out << std::setprecision(16);
355         out << value;
356     }
357 }
358 
359 template <typename T, typename CastT = T>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)360 void WriteInlineData(const std::vector<uint8_t> &vec, std::ostream &out)
361 {
362     const T *data = reinterpret_cast<const T *>(vec.data());
363     size_t count  = vec.size() / sizeof(T);
364 
365     if (data == nullptr)
366     {
367         return;
368     }
369 
370     out << static_cast<CastT>(data[0]);
371 
372     for (size_t dataIndex = 1; dataIndex < count; ++dataIndex)
373     {
374         out << ", " << static_cast<CastT>(data[dataIndex]);
375     }
376 }
377 
378 template <>
WriteInlineData(const std::vector<uint8_t> & vec,std::ostream & out)379 void WriteInlineData<GLchar>(const std::vector<uint8_t> &vec, std::ostream &out)
380 {
381     const GLchar *data = reinterpret_cast<const GLchar *>(vec.data());
382     size_t count       = vec.size() / sizeof(GLchar);
383 
384     if (data == nullptr || data[0] == '\0')
385     {
386         return;
387     }
388 
389     out << "\"";
390 
391     for (size_t dataIndex = 0; dataIndex < count; ++dataIndex)
392     {
393         if (data[dataIndex] == '\0')
394             break;
395 
396         out << static_cast<GLchar>(data[dataIndex]);
397     }
398 
399     out << "\"";
400 }
401 
WriteStringParamReplay(std::ostream & out,const ParamCapture & param)402 void WriteStringParamReplay(std::ostream &out, const ParamCapture &param)
403 {
404     const std::vector<uint8_t> &data = param.data[0];
405     // null terminate C style string
406     ASSERT(data.size() > 0 && data.back() == '\0');
407     std::string str(data.begin(), data.end() - 1);
408     out << "\"" << str << "\"";
409 }
410 
WriteStringPointerParamReplay(DataTracker * dataTracker,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)411 void WriteStringPointerParamReplay(DataTracker *dataTracker,
412                                    std::ostream &out,
413                                    std::ostream &header,
414                                    const CallCapture &call,
415                                    const ParamCapture &param)
416 {
417     // Concatenate the strings to ensure we get an accurate counter
418     std::vector<std::string> strings;
419     for (const std::vector<uint8_t> &data : param.data)
420     {
421         // null terminate C style string
422         ASSERT(data.size() > 0 && data.back() == '\0');
423         strings.emplace_back(data.begin(), data.end() - 1);
424     }
425 
426     int counter = dataTracker->getStringCounters().getStringCounter(strings);
427     if (counter == kStringsNotFound)
428     {
429         // This is a unique set of strings, so set up their declaration and update the counter
430         counter = dataTracker->getCounters().getAndIncrement(call.entryPoint, param.name);
431         dataTracker->getStringCounters().setStringCounter(strings, counter);
432 
433         header << "const char* const ";
434         WriteParamStaticVarName(call, param, counter, header);
435         header << "[] = { \n";
436 
437         for (const std::string &str : strings)
438         {
439             // Break up long strings for MSVC
440             size_t copyLength = 0;
441             std::string separator;
442             for (size_t i = 0; i < str.length(); i += kStringLengthLimit)
443             {
444                 if ((str.length() - i) <= kStringLengthLimit)
445                 {
446                     copyLength = str.length() - i;
447                     separator  = ",";
448                 }
449                 else
450                 {
451                     copyLength = kStringLengthLimit;
452                     separator  = "";
453                 }
454 
455                 header << "    R\"(" << str.substr(i, copyLength) << ")\"" << separator << "\n";
456             }
457         }
458 
459         header << " };\n";
460     }
461 
462     ASSERT(counter >= 0);
463     WriteParamStaticVarName(call, param, counter, out);
464 }
465 
466 template <typename ParamT>
WriteResourceIDPointerParamReplay(DataTracker * dataTracker,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param)467 void WriteResourceIDPointerParamReplay(DataTracker *dataTracker,
468                                        std::ostream &out,
469                                        std::ostream &header,
470                                        const CallCapture &call,
471                                        const ParamCapture &param)
472 {
473     int counter = dataTracker->getCounters().getAndIncrement(call.entryPoint, param.name);
474 
475     header << "const GLuint ";
476     WriteParamStaticVarName(call, param, counter, header);
477     header << "[] = { ";
478 
479     const ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
480     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
481     const char *name = GetResourceIDTypeName(resourceIDType);
482 
483     ASSERT(param.dataNElements > 0);
484     ASSERT(param.data.size() == 1);
485 
486     const ParamT *returnedIDs = reinterpret_cast<const ParamT *>(param.data[0].data());
487     for (GLsizei resIndex = 0; resIndex < param.dataNElements; ++resIndex)
488     {
489         ParamT id = returnedIDs[resIndex];
490         if (resIndex > 0)
491         {
492             header << ", ";
493         }
494         header << "g" << name << "Map[" << id.value << "]";
495     }
496 
497     header << " };\n    ";
498 
499     WriteParamStaticVarName(call, param, counter, out);
500 }
501 
WriteBinaryParamReplay(DataTracker * dataTracker,std::ostream & out,std::ostream & header,const CallCapture & call,const ParamCapture & param,std::vector<uint8_t> * binaryData)502 void WriteBinaryParamReplay(DataTracker *dataTracker,
503                             std::ostream &out,
504                             std::ostream &header,
505                             const CallCapture &call,
506                             const ParamCapture &param,
507                             std::vector<uint8_t> *binaryData)
508 {
509     int counter = dataTracker->getCounters().getAndIncrement(call.entryPoint, param.name);
510 
511     ASSERT(param.data.size() == 1);
512     const std::vector<uint8_t> &data = param.data[0];
513 
514     ParamType overrideType = param.type;
515     if (param.type == ParamType::TGLvoidConstPointer || param.type == ParamType::TvoidConstPointer)
516     {
517         overrideType = ParamType::TGLubyteConstPointer;
518     }
519     if (overrideType == ParamType::TGLenumConstPointer || overrideType == ParamType::TGLcharPointer)
520     {
521         // Inline if data are of type string or enum
522         std::string paramTypeString = ParamTypeToString(param.type);
523         header << paramTypeString.substr(0, paramTypeString.length() - 1);
524         WriteParamStaticVarName(call, param, counter, header);
525         header << "[] = { ";
526         if (overrideType == ParamType::TGLenumConstPointer)
527         {
528             WriteInlineData<GLuint>(data, header);
529         }
530         else
531         {
532             ASSERT(overrideType == ParamType::TGLcharPointer);
533             WriteInlineData<GLchar>(data, header);
534         }
535         header << " };\n";
536         WriteParamStaticVarName(call, param, counter, out);
537     }
538     else
539     {
540         // Store in binary file if data are not of type string or enum
541         // Round up to 16-byte boundary for cross ABI safety
542         size_t offset = rx::roundUpPow2(binaryData->size(), kBinaryAlignment);
543         binaryData->resize(offset + data.size());
544         memcpy(binaryData->data() + offset, data.data(), data.size());
545         out << "reinterpret_cast<" << ParamTypeToString(overrideType) << ">(&gBinaryData[" << offset
546             << "])";
547     }
548 }
549 
SyncIndexValue(GLsync sync)550 uintptr_t SyncIndexValue(GLsync sync)
551 {
552     return reinterpret_cast<uintptr_t>(sync);
553 }
554 
WriteCppReplayForCall(const CallCapture & call,DataTracker * dataTracker,std::ostream & out,std::ostream & header,std::vector<uint8_t> * binaryData)555 void WriteCppReplayForCall(const CallCapture &call,
556                            DataTracker *dataTracker,
557                            std::ostream &out,
558                            std::ostream &header,
559                            std::vector<uint8_t> *binaryData)
560 {
561     std::ostringstream callOut;
562 
563     if (call.entryPoint == EntryPoint::GLCreateShader ||
564         call.entryPoint == EntryPoint::GLCreateProgram ||
565         call.entryPoint == EntryPoint::GLCreateShaderProgramv)
566     {
567         GLuint id = call.params.getReturnValue().value.GLuintVal;
568         callOut << "gShaderProgramMap[" << id << "] = ";
569     }
570 
571     if (call.entryPoint == EntryPoint::GLFenceSync)
572     {
573         GLsync sync = call.params.getReturnValue().value.GLsyncVal;
574         callOut << "gSyncMap[" << SyncIndexValue(sync) << "] = ";
575     }
576 
577     // Depending on how a buffer is mapped, we may need to track its location for readback
578     bool trackBufferPointer = false;
579 
580     if (call.entryPoint == EntryPoint::GLMapBufferRange ||
581         call.entryPoint == EntryPoint::GLMapBufferRangeEXT)
582     {
583         GLbitfield access =
584             call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
585 
586         trackBufferPointer = access & GL_MAP_WRITE_BIT;
587     }
588 
589     if (call.entryPoint == EntryPoint::GLMapBuffer || call.entryPoint == EntryPoint::GLMapBufferOES)
590     {
591         GLenum access = call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
592 
593         trackBufferPointer =
594             access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
595     }
596 
597     if (trackBufferPointer)
598     {
599         // Track the returned pointer so we update its data when unmapped
600         gl::BufferID bufferID = call.params.getMappedBufferID();
601         callOut << "gMappedBufferData[";
602         WriteParamValueReplay<ParamType::TBufferID>(callOut, call, bufferID);
603         callOut << "] = ";
604     }
605 
606     callOut << call.name() << "(";
607 
608     bool first = true;
609     for (const ParamCapture &param : call.params.getParamCaptures())
610     {
611         if (!first)
612         {
613             callOut << ", ";
614         }
615 
616         if (param.arrayClientPointerIndex != -1 && param.value.voidConstPointerVal != nullptr)
617         {
618             callOut << "gClientArrays[" << param.arrayClientPointerIndex << "]";
619         }
620         else if (param.readBufferSizeBytes > 0)
621         {
622             callOut << "reinterpret_cast<" << ParamTypeToString(param.type) << ">(gReadBuffer)";
623         }
624         else if (param.data.empty())
625         {
626             if (param.type == ParamType::TGLenum)
627             {
628                 OutputGLenumString(callOut, param.enumGroup, param.value.GLenumVal);
629             }
630             else if (param.type == ParamType::TGLbitfield)
631             {
632                 OutputGLbitfieldString(callOut, param.enumGroup, param.value.GLbitfieldVal);
633             }
634             else if (param.type == ParamType::TGLfloat)
635             {
636                 WriteGLFloatValue(callOut, param.value.GLfloatVal);
637             }
638             else if (param.type == ParamType::TGLsync)
639             {
640                 callOut << "gSyncMap[" << SyncIndexValue(param.value.GLsyncVal) << "]";
641             }
642             else if (param.type == ParamType::TGLuint64 && param.name == "timeout")
643             {
644                 if (param.value.GLuint64Val == GL_TIMEOUT_IGNORED)
645                 {
646                     callOut << "GL_TIMEOUT_IGNORED";
647                 }
648                 else
649                 {
650                     WriteParamCaptureReplay(callOut, call, param);
651                 }
652             }
653             else
654             {
655                 WriteParamCaptureReplay(callOut, call, param);
656             }
657         }
658         else
659         {
660             switch (param.type)
661             {
662                 case ParamType::TGLcharConstPointer:
663                     WriteStringParamReplay(callOut, param);
664                     break;
665                 case ParamType::TGLcharConstPointerPointer:
666                     WriteStringPointerParamReplay(dataTracker, callOut, header, call, param);
667                     break;
668                 case ParamType::TBufferIDConstPointer:
669                     WriteResourceIDPointerParamReplay<gl::BufferID>(dataTracker, callOut, out, call,
670                                                                     param);
671                     break;
672                 case ParamType::TFenceNVIDConstPointer:
673                     WriteResourceIDPointerParamReplay<gl::FenceNVID>(dataTracker, callOut, out,
674                                                                      call, param);
675                     break;
676                 case ParamType::TFramebufferIDConstPointer:
677                     WriteResourceIDPointerParamReplay<gl::FramebufferID>(dataTracker, callOut, out,
678                                                                          call, param);
679                     break;
680                 case ParamType::TMemoryObjectIDConstPointer:
681                     WriteResourceIDPointerParamReplay<gl::MemoryObjectID>(dataTracker, callOut, out,
682                                                                           call, param);
683                     break;
684                 case ParamType::TProgramPipelineIDConstPointer:
685                     WriteResourceIDPointerParamReplay<gl::ProgramPipelineID>(dataTracker, callOut,
686                                                                              out, call, param);
687                     break;
688                 case ParamType::TQueryIDConstPointer:
689                     WriteResourceIDPointerParamReplay<gl::QueryID>(dataTracker, callOut, out, call,
690                                                                    param);
691                     break;
692                 case ParamType::TRenderbufferIDConstPointer:
693                     WriteResourceIDPointerParamReplay<gl::RenderbufferID>(dataTracker, callOut, out,
694                                                                           call, param);
695                     break;
696                 case ParamType::TSamplerIDConstPointer:
697                     WriteResourceIDPointerParamReplay<gl::SamplerID>(dataTracker, callOut, out,
698                                                                      call, param);
699                     break;
700                 case ParamType::TSemaphoreIDConstPointer:
701                     WriteResourceIDPointerParamReplay<gl::SemaphoreID>(dataTracker, callOut, out,
702                                                                        call, param);
703                     break;
704                 case ParamType::TTextureIDConstPointer:
705                     WriteResourceIDPointerParamReplay<gl::TextureID>(dataTracker, callOut, out,
706                                                                      call, param);
707                     break;
708                 case ParamType::TTransformFeedbackIDConstPointer:
709                     WriteResourceIDPointerParamReplay<gl::TransformFeedbackID>(dataTracker, callOut,
710                                                                                out, call, param);
711                     break;
712                 case ParamType::TVertexArrayIDConstPointer:
713                     WriteResourceIDPointerParamReplay<gl::VertexArrayID>(dataTracker, callOut, out,
714                                                                          call, param);
715                     break;
716                 default:
717                     WriteBinaryParamReplay(dataTracker, callOut, header, call, param, binaryData);
718                     break;
719             }
720         }
721 
722         first = false;
723     }
724 
725     callOut << ")";
726 
727     out << callOut.str();
728 }
729 
MaxClientArraySize(const gl::AttribArray<size_t> & clientArraySizes)730 size_t MaxClientArraySize(const gl::AttribArray<size_t> &clientArraySizes)
731 {
732     size_t found = 0;
733     for (size_t size : clientArraySizes)
734     {
735         if (size > found)
736         {
737             found = size;
738         }
739     }
740 
741     return found;
742 }
743 
744 struct SaveFileHelper
745 {
746   public:
747     // We always use ios::binary to avoid inconsistent line endings when captured on Linux vs Win.
SaveFileHelperangle::__anond94d34250111::SaveFileHelper748     SaveFileHelper(const std::string &filePathIn)
749         : mOfs(filePathIn, std::ios::binary | std::ios::out), mFilePath(filePathIn)
750     {
751         if (!mOfs.is_open())
752         {
753             FATAL() << "Could not open " << filePathIn;
754         }
755     }
756 
~SaveFileHelperangle::__anond94d34250111::SaveFileHelper757     ~SaveFileHelper() { printf("Saved '%s'.\n", mFilePath.c_str()); }
758 
759     template <typename T>
operator <<angle::__anond94d34250111::SaveFileHelper760     SaveFileHelper &operator<<(const T &value)
761     {
762         mOfs << value;
763         if (mOfs.bad())
764         {
765             FATAL() << "Error writing to " << mFilePath;
766         }
767         return *this;
768     }
769 
writeangle::__anond94d34250111::SaveFileHelper770     void write(const uint8_t *data, size_t size)
771     {
772         mOfs.write(reinterpret_cast<const char *>(data), size);
773     }
774 
775   private:
776     std::ofstream mOfs;
777     std::string mFilePath;
778 };
779 
GetBinaryDataFilePath(bool compression,gl::ContextID contextId,const std::string & captureLabel)780 std::string GetBinaryDataFilePath(bool compression,
781                                   gl::ContextID contextId,
782                                   const std::string &captureLabel)
783 {
784     std::stringstream fnameStream;
785     fnameStream << FmtCapturePrefix(contextId, captureLabel) << ".angledata";
786     if (compression)
787     {
788         fnameStream << ".gz";
789     }
790     return fnameStream.str();
791 }
792 
SaveBinaryData(bool compression,const std::string & outDir,gl::ContextID contextId,const std::string & captureLabel,const std::vector<uint8_t> & binaryData)793 void SaveBinaryData(bool compression,
794                     const std::string &outDir,
795                     gl::ContextID contextId,
796                     const std::string &captureLabel,
797                     const std::vector<uint8_t> &binaryData)
798 {
799     std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
800     std::string dataFilepath       = outDir + binaryDataFileName;
801 
802     SaveFileHelper saveData(dataFilepath);
803 
804     if (compression)
805     {
806         // Save compressed data.
807         uLong uncompressedSize       = static_cast<uLong>(binaryData.size());
808         uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
809 
810         std::vector<uint8_t> compressedData(expectedCompressedSize, 0);
811 
812         uLong compressedSize = expectedCompressedSize;
813         int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &compressedSize,
814                                                         binaryData.data(), uncompressedSize,
815                                                         nullptr, nullptr);
816 
817         if (zResult != Z_OK)
818         {
819             FATAL() << "Error compressing binary data: " << zResult;
820         }
821 
822         saveData.write(compressedData.data(), compressedSize);
823     }
824     else
825     {
826         saveData.write(binaryData.data(), binaryData.size());
827     }
828 }
829 
WriteInitReplayCall(bool compression,std::ostream & out,gl::ContextID contextId,const std::string & captureLabel,size_t maxClientArraySize,size_t readBufferSize)830 void WriteInitReplayCall(bool compression,
831                          std::ostream &out,
832                          gl::ContextID contextId,
833                          const std::string &captureLabel,
834                          size_t maxClientArraySize,
835                          size_t readBufferSize)
836 {
837     std::string binaryDataFileName = GetBinaryDataFilePath(compression, contextId, captureLabel);
838     out << "    InitializeReplay(\"" << binaryDataFileName << "\", " << maxClientArraySize << ", "
839         << readBufferSize << ");\n";
840 }
841 
842 // TODO (http://anglebug.com/4599): Reset more state on frame loop
MaybeResetResources(std::stringstream & out,ResourceIDType resourceIDType,DataTracker * dataTracker,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)843 void MaybeResetResources(std::stringstream &out,
844                          ResourceIDType resourceIDType,
845                          DataTracker *dataTracker,
846                          std::stringstream &header,
847                          ResourceTracker *resourceTracker,
848                          std::vector<uint8_t> *binaryData)
849 {
850     switch (resourceIDType)
851     {
852         case ResourceIDType::Buffer:
853         {
854             BufferSet &newBuffers           = resourceTracker->getNewBuffers();
855             BufferCalls &bufferRegenCalls   = resourceTracker->getBufferRegenCalls();
856             BufferCalls &bufferRestoreCalls = resourceTracker->getBufferRestoreCalls();
857             BufferCalls &bufferMapCalls     = resourceTracker->getBufferMapCalls();
858             BufferCalls &bufferUnmapCalls   = resourceTracker->getBufferUnmapCalls();
859 
860             // If we have any new buffers generated and not deleted during the run, delete them now
861             if (!newBuffers.empty())
862             {
863                 out << "    const GLuint deleteBuffers[] = {";
864                 BufferSet::iterator bufferIter = newBuffers.begin();
865                 for (size_t i = 0; bufferIter != newBuffers.end(); ++i, ++bufferIter)
866                 {
867                     if (i > 0)
868                     {
869                         out << ", ";
870                     }
871                     if ((i % 4) == 0)
872                     {
873                         out << "\n        ";
874                     }
875                     out << "gBufferMap[" << (*bufferIter).value << "]";
876                 }
877                 out << "};\n";
878                 out << "    glDeleteBuffers(" << newBuffers.size() << ", deleteBuffers);\n";
879             }
880 
881             // If any of our starting buffers were deleted during the run, recreate them
882             BufferSet &buffersToRegen = resourceTracker->getBuffersToRegen();
883             for (const gl::BufferID id : buffersToRegen)
884             {
885                 // Emit their regen calls
886                 for (CallCapture &call : bufferRegenCalls[id])
887                 {
888                     out << "    ";
889                     WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
890                     out << ";\n";
891                 }
892             }
893 
894             // If any of our starting buffers were modified during the run, restore their contents
895             BufferSet &buffersToRestore = resourceTracker->getBuffersToRestore();
896             for (const gl::BufferID id : buffersToRestore)
897             {
898                 if (resourceTracker->getStartingBuffersMappedCurrent(id))
899                 {
900                     // Some drivers require the buffer to be unmapped before you can update data,
901                     // which violates the spec. See gl::Buffer::bufferDataImpl().
902                     for (CallCapture &call : bufferUnmapCalls[id])
903                     {
904                         out << "    ";
905                         WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
906                         out << ";\n";
907                     }
908                 }
909 
910                 // Emit their restore calls
911                 for (CallCapture &call : bufferRestoreCalls[id])
912                 {
913                     out << "    ";
914                     WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
915                     out << ";\n";
916 
917                     // Also note that this buffer has been implicitly unmapped by this call
918                     resourceTracker->setBufferUnmapped(id);
919                 }
920             }
921 
922             // Update the map/unmap of buffers to match the starting state
923             BufferSet startingBuffers = resourceTracker->getStartingBuffers();
924             for (const gl::BufferID id : startingBuffers)
925             {
926                 // If the buffer was mapped at the start, but is not mapped now, we need to map
927                 if (resourceTracker->getStartingBuffersMappedInitial(id) &&
928                     !resourceTracker->getStartingBuffersMappedCurrent(id))
929                 {
930                     // Emit their map calls
931                     for (CallCapture &call : bufferMapCalls[id])
932                     {
933                         out << "    ";
934                         WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
935                         out << ";\n";
936                     }
937                 }
938                 // If the buffer was unmapped at the start, but is mapped now, we need to unmap
939                 if (!resourceTracker->getStartingBuffersMappedInitial(id) &&
940                     resourceTracker->getStartingBuffersMappedCurrent(id))
941                 {
942                     // Emit their unmap calls
943                     for (CallCapture &call : bufferUnmapCalls[id])
944                     {
945                         out << "    ";
946                         WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
947                         out << ";\n";
948                     }
949                 }
950             }
951 
952             // Restore buffer bindings as seen during MEC
953             std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
954             for (CallCapture &call : bufferBindingCalls)
955             {
956                 out << "    ";
957                 WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
958                 out << ";\n";
959             }
960 
961             break;
962         }
963         case ResourceIDType::ShaderProgram:
964         {
965             ProgramSet &newPrograms = resourceTracker->getNewPrograms();
966 
967             // If we have any new programs created and not deleted during the run, delete them now
968             for (const auto &newProgram : newPrograms)
969             {
970                 out << "    glDeleteProgram(gShaderProgramMap[" << newProgram.value << "]);\n";
971             }
972 
973             // TODO (http://anglebug.com/5968): Handle programs that need regen
974             // This would only happen if a starting program was deleted during the run
975             ASSERT(resourceTracker->getProgramsToRegen().empty());
976             break;
977         }
978         default:
979             // TODO (http://anglebug.com/4599): Reset more than just buffers
980             break;
981     }
982 }
983 
MaybeResetFenceSyncObjects(std::stringstream & out,DataTracker * dataTracker,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)984 void MaybeResetFenceSyncObjects(std::stringstream &out,
985                                 DataTracker *dataTracker,
986                                 std::stringstream &header,
987                                 ResourceTracker *resourceTracker,
988                                 std::vector<uint8_t> *binaryData)
989 {
990     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
991 
992     // If any of our starting fence sync objects were deleted during the run, recreate them
993     FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
994     for (const GLsync sync : fenceSyncsToRegen)
995     {
996         // Emit their regen calls
997         for (CallCapture &call : fenceSyncRegenCalls[sync])
998         {
999             out << "    ";
1000             WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
1001             out << ";\n";
1002         }
1003     }
1004 }
1005 
MaybeResetOpaqueTypeObjects(std::stringstream & out,DataTracker * dataTracker,std::stringstream & header,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData)1006 void MaybeResetOpaqueTypeObjects(std::stringstream &out,
1007                                  DataTracker *dataTracker,
1008                                  std::stringstream &header,
1009                                  ResourceTracker *resourceTracker,
1010                                  std::vector<uint8_t> *binaryData)
1011 {
1012     MaybeResetFenceSyncObjects(out, dataTracker, header, resourceTracker, binaryData);
1013 }
1014 
WriteCppReplayFunctionWithParts(const gl::ContextID contextID,ReplayFunc replayFunc,DataTracker * dataTracker,uint32_t frameIndex,std::vector<uint8_t> * binaryData,const std::vector<CallCapture> & calls,std::stringstream & header,std::stringstream & callStream,std::stringstream & out)1015 void WriteCppReplayFunctionWithParts(const gl::ContextID contextID,
1016                                      ReplayFunc replayFunc,
1017                                      DataTracker *dataTracker,
1018                                      uint32_t frameIndex,
1019                                      std::vector<uint8_t> *binaryData,
1020                                      const std::vector<CallCapture> &calls,
1021                                      std::stringstream &header,
1022                                      std::stringstream &callStream,
1023                                      std::stringstream &out)
1024 {
1025     std::stringstream callStreamParts;
1026 
1027     int callCount = 0;
1028     int partCount = 0;
1029 
1030     // Setup can get quite large. If over a certain size, break up the function to avoid
1031     // overflowing the stack
1032     if (calls.size() > kFunctionSizeLimit)
1033     {
1034         callStreamParts << "void " << FmtFunction(replayFunc, contextID, frameIndex, ++partCount)
1035                         << "\n";
1036         callStreamParts << "{\n";
1037     }
1038 
1039     for (const CallCapture &call : calls)
1040     {
1041         callStreamParts << "    ";
1042         WriteCppReplayForCall(call, dataTracker, callStreamParts, header, binaryData);
1043         callStreamParts << ";\n";
1044 
1045         if (partCount > 0 && ++callCount % kFunctionSizeLimit == 0)
1046         {
1047             callStreamParts << "}\n";
1048             callStreamParts << "\n";
1049             callStreamParts << "void "
1050                             << FmtFunction(replayFunc, contextID, frameIndex, ++partCount) << "\n";
1051             callStreamParts << "{\n";
1052         }
1053     }
1054 
1055     if (partCount > 0)
1056     {
1057         callStreamParts << "}\n";
1058         callStreamParts << "\n";
1059 
1060         // Write out the parts
1061         out << callStreamParts.str();
1062 
1063         // Write out the calls to the parts
1064         for (int i = 1; i <= partCount; i++)
1065         {
1066             callStream << "    " << FmtFunction(replayFunc, contextID, frameIndex, i) << ";\n";
1067         }
1068     }
1069     else
1070     {
1071         // If we didn't chunk it up, write all the calls directly to SetupContext
1072         callStream << callStreamParts.str();
1073     }
1074 }
1075 
1076 // Auxiliary contexts are other contexts in the share group that aren't the context calling
1077 // eglSwapBuffers().
WriteAuxiliaryContextCppSetupReplay(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)1078 void WriteAuxiliaryContextCppSetupReplay(bool compression,
1079                                          const std::string &outDir,
1080                                          const gl::Context *context,
1081                                          const std::string &captureLabel,
1082                                          uint32_t frameIndex,
1083                                          const std::vector<CallCapture> &setupCalls,
1084                                          std::vector<uint8_t> *binaryData,
1085                                          bool serializeStateEnabled,
1086                                          const FrameCaptureShared &frameCaptureShared)
1087 {
1088     ASSERT(frameCaptureShared.getWindowSurfaceContextID() != context->id());
1089 
1090     DataTracker dataTracker;
1091 
1092     std::stringstream out;
1093     std::stringstream include;
1094     std::stringstream header;
1095 
1096     include << "#include \"" << FmtCapturePrefix(context->id(), captureLabel) << ".h\"\n";
1097     include << "#include \"angle_trace_gl.h\"\n";
1098     include << "";
1099     include << "\n";
1100     include << "namespace\n";
1101     include << "{\n";
1102 
1103     if (!captureLabel.empty())
1104     {
1105         header << "namespace " << captureLabel << "\n";
1106         header << "{\n";
1107         out << "namespace " << captureLabel << "\n";
1108         out << "{\n";
1109     }
1110 
1111     std::stringstream setupCallStream;
1112 
1113     header << "void " << FmtSetupFunction(kNoPartId, context->id()) << ";\n";
1114     setupCallStream << "void " << FmtSetupFunction(kNoPartId, context->id()) << "\n";
1115     setupCallStream << "{\n";
1116 
1117     WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, &dataTracker, frameIndex,
1118                                     binaryData, setupCalls, include, setupCallStream, out);
1119 
1120     out << setupCallStream.str();
1121     out << "}\n";
1122     out << "\n";
1123 
1124     if (!captureLabel.empty())
1125     {
1126         header << "} // namespace " << captureLabel << "\n";
1127         out << "} // namespace " << captureLabel << "\n";
1128     }
1129 
1130     include << "}  // namespace\n";
1131 
1132     // Write out the source file.
1133     {
1134         std::string outString    = out.str();
1135         std::string headerString = include.str();
1136 
1137         std::string cppFilePath =
1138             GetCaptureFilePath(outDir, context->id(), captureLabel, frameIndex, ".cpp");
1139 
1140         SaveFileHelper saveCpp(cppFilePath);
1141         saveCpp << headerString << "\n" << outString;
1142     }
1143 
1144     // Write out the header file.
1145     {
1146         std::string headerContents = header.str();
1147 
1148         std::stringstream headerPathStream;
1149         headerPathStream << outDir << FmtCapturePrefix(context->id(), captureLabel) << ".h";
1150         std::string headerPath = headerPathStream.str();
1151 
1152         SaveFileHelper saveHeader(headerPath);
1153         saveHeader << headerContents;
1154     }
1155 }
1156 
WriteWindowSurfaceContextCppReplay(bool compression,const std::string & outDir,const gl::Context * context,const std::string & captureLabel,uint32_t frameIndex,uint32_t frameCount,const std::vector<CallCapture> & frameCalls,const std::vector<CallCapture> & setupCalls,ResourceTracker * resourceTracker,std::vector<uint8_t> * binaryData,bool serializeStateEnabled,const FrameCaptureShared & frameCaptureShared)1157 void WriteWindowSurfaceContextCppReplay(bool compression,
1158                                         const std::string &outDir,
1159                                         const gl::Context *context,
1160                                         const std::string &captureLabel,
1161                                         uint32_t frameIndex,
1162                                         uint32_t frameCount,
1163                                         const std::vector<CallCapture> &frameCalls,
1164                                         const std::vector<CallCapture> &setupCalls,
1165                                         ResourceTracker *resourceTracker,
1166                                         std::vector<uint8_t> *binaryData,
1167                                         bool serializeStateEnabled,
1168                                         const FrameCaptureShared &frameCaptureShared)
1169 {
1170     ASSERT(frameCaptureShared.getWindowSurfaceContextID() == context->id());
1171 
1172     DataTracker dataTracker;
1173 
1174     std::stringstream out;
1175     std::stringstream header;
1176 
1177     egl::ShareGroup *shareGroup      = context->getShareGroup();
1178     egl::ContextSet *shareContextSet = shareGroup->getContexts();
1179 
1180     header << "#include \"" << FmtCapturePrefix(kSharedContextId, captureLabel) << ".h\"\n";
1181     for (gl::Context *shareContext : *shareContextSet)
1182     {
1183         header << "#include \"" << FmtCapturePrefix(shareContext->id(), captureLabel) << ".h\"\n";
1184     }
1185 
1186     header << "#include \"angle_trace_gl.h\"\n";
1187     header << "";
1188     header << "\n";
1189     header << "namespace\n";
1190     header << "{\n";
1191 
1192     if (frameIndex == 1 || frameIndex == frameCount)
1193     {
1194         out << "extern \"C\" {\n";
1195     }
1196 
1197     if (frameIndex == 1)
1198     {
1199         std::stringstream setupCallStream;
1200 
1201         setupCallStream << "void " << FmtSetupFunction(kNoPartId, context->id()) << "\n";
1202         setupCallStream << "{\n";
1203 
1204         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Setup, &dataTracker, frameIndex,
1205                                         binaryData, setupCalls, header, setupCallStream, out);
1206 
1207         out << setupCallStream.str();
1208         out << "}\n";
1209         out << "\n";
1210         out << "void SetupReplay()\n";
1211         out << "{\n";
1212         out << "    " << captureLabel << "::InitReplay();\n";
1213 
1214         // Setup all of the shared objects.
1215         out << "    " << captureLabel << "::" << FmtSetupFunction(kNoPartId, kSharedContextId)
1216             << ";\n";
1217 
1218         // Setup the presentation (this) context before any other contexts in the share group.
1219         out << "    " << FmtSetupFunction(kNoPartId, context->id()) << ";\n";
1220         out << "}\n";
1221         out << "\n";
1222     }
1223 
1224     if (frameIndex == frameCount)
1225     {
1226         // Emit code to reset back to starting state
1227         out << "void " << FmtResetFunction() << "\n";
1228         out << "{\n";
1229 
1230         // TODO(http://anglebug.com/5878): Look at moving this into the shared context file since
1231         // it's resetting shared objects.
1232         std::stringstream restoreCallStream;
1233         for (ResourceIDType resourceType : AllEnums<ResourceIDType>())
1234         {
1235             MaybeResetResources(restoreCallStream, resourceType, &dataTracker, header,
1236                                 resourceTracker, binaryData);
1237         }
1238 
1239         // Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
1240         MaybeResetOpaqueTypeObjects(restoreCallStream, &dataTracker, header, resourceTracker,
1241                                     binaryData);
1242 
1243         out << restoreCallStream.str();
1244         out << "}\n";
1245     }
1246 
1247     if (frameIndex == 1 || frameIndex == frameCount)
1248     {
1249         out << "}  // extern \"C\"\n";
1250         out << "\n";
1251     }
1252 
1253     if (!captureLabel.empty())
1254     {
1255         out << "namespace " << captureLabel << "\n";
1256         out << "{\n";
1257     }
1258 
1259     if (!frameCalls.empty())
1260     {
1261         std::stringstream callStream;
1262 
1263         callStream << "void " << FmtReplayFunction(context->id(), frameIndex) << "\n";
1264         callStream << "{\n";
1265 
1266         WriteCppReplayFunctionWithParts(context->id(), ReplayFunc::Replay, &dataTracker, frameIndex,
1267                                         binaryData, frameCalls, header, callStream, out);
1268 
1269         out << callStream.str();
1270         out << "}\n";
1271     }
1272 
1273     if (serializeStateEnabled)
1274     {
1275         std::string serializedContextString;
1276         if (SerializeContextToString(const_cast<gl::Context *>(context),
1277                                      &serializedContextString) == Result::Continue)
1278         {
1279             out << "const char *" << FmtGetSerializedContextStateFunction(context->id(), frameIndex)
1280                 << "\n";
1281             out << "{\n";
1282             out << "    return R\"(" << serializedContextString << ")\";\n";
1283             out << "}\n";
1284             out << "\n";
1285         }
1286     }
1287 
1288     if (!captureLabel.empty())
1289     {
1290         out << "} // namespace " << captureLabel << "\n";
1291     }
1292 
1293     header << "}  // namespace\n";
1294 
1295     {
1296         std::string outString    = out.str();
1297         std::string headerString = header.str();
1298 
1299         std::string cppFilePath =
1300             GetCaptureFilePath(outDir, context->id(), captureLabel, frameIndex, ".cpp");
1301 
1302         SaveFileHelper saveCpp(cppFilePath);
1303         saveCpp << headerString << "\n" << outString;
1304     }
1305 }
1306 
WriteSharedContextCppReplay(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,const FrameCaptureShared & frameCaptureShared)1307 void WriteSharedContextCppReplay(bool compression,
1308                                  const std::string &outDir,
1309                                  const std::string &captureLabel,
1310                                  uint32_t frameIndex,
1311                                  uint32_t frameCount,
1312                                  const std::vector<CallCapture> &setupCalls,
1313                                  ResourceTracker *resourceTracker,
1314                                  std::vector<uint8_t> *binaryData,
1315                                  bool serializeStateEnabled,
1316                                  const FrameCaptureShared &frameCaptureShared)
1317 {
1318     DataTracker dataTracker;
1319 
1320     std::stringstream out;
1321     std::stringstream include;
1322     std::stringstream header;
1323 
1324     include << "#include \"" << FmtCapturePrefix(kSharedContextId, captureLabel) << ".h\"\n";
1325     include << "#include \"angle_trace_gl.h\"\n";
1326     include << "";
1327     include << "\n";
1328     include << "namespace\n";
1329     include << "{\n";
1330 
1331     if (!captureLabel.empty())
1332     {
1333         header << "namespace " << captureLabel << "\n";
1334         header << "{\n";
1335         out << "namespace " << captureLabel << "\n";
1336         out << "{\n";
1337     }
1338 
1339     std::stringstream setupCallStream;
1340 
1341     header << "void " << FmtSetupFunction(kNoPartId, kSharedContextId) << ";\n";
1342     setupCallStream << "void " << FmtSetupFunction(kNoPartId, kSharedContextId) << "\n";
1343     setupCallStream << "{\n";
1344 
1345     WriteCppReplayFunctionWithParts(kSharedContextId, ReplayFunc::Setup, &dataTracker, frameIndex,
1346                                     binaryData, setupCalls, include, setupCallStream, out);
1347 
1348     out << setupCallStream.str();
1349     out << "}\n";
1350     out << "\n";
1351 
1352     if (!captureLabel.empty())
1353     {
1354         header << "} // namespace " << captureLabel << "\n";
1355         out << "} // namespace " << captureLabel << "\n";
1356     }
1357 
1358     include << "}  // namespace\n";
1359 
1360     // Write out the source file.
1361     {
1362         std::string outString    = out.str();
1363         std::string headerString = include.str();
1364 
1365         std::string cppFilePath =
1366             GetCaptureFilePath(outDir, kSharedContextId, captureLabel, frameIndex, ".cpp");
1367 
1368         SaveFileHelper saveCpp(cppFilePath);
1369         saveCpp << headerString << "\n" << outString;
1370     }
1371 
1372     // Write out the header file.
1373     {
1374         std::string headerContents = header.str();
1375 
1376         std::stringstream headerPathStream;
1377         headerPathStream << outDir << FmtCapturePrefix(kSharedContextId, captureLabel) << ".h";
1378         std::string headerPath = headerPathStream.str();
1379 
1380         SaveFileHelper saveHeader(headerPath);
1381         saveHeader << headerContents;
1382     }
1383 }
1384 
GetAttachedProgramSources(const gl::Program * program)1385 ProgramSources GetAttachedProgramSources(const gl::Program *program)
1386 {
1387     ProgramSources sources;
1388     for (gl::ShaderType shaderType : gl::AllShaderTypes())
1389     {
1390         const gl::Shader *shader = program->getAttachedShader(shaderType);
1391         if (shader)
1392         {
1393             sources[shaderType] = shader->getSourceString();
1394         }
1395     }
1396     return sources;
1397 }
1398 
1399 template <typename IDType>
CaptureUpdateResourceIDs(const CallCapture & call,const ParamCapture & param,std::vector<CallCapture> * callsOut)1400 void CaptureUpdateResourceIDs(const CallCapture &call,
1401                               const ParamCapture &param,
1402                               std::vector<CallCapture> *callsOut)
1403 {
1404     GLsizei n = call.params.getParamFlexName("n", "count", ParamType::TGLsizei, 0).value.GLsizeiVal;
1405     ASSERT(param.data.size() == 1);
1406     ResourceIDType resourceIDType = GetResourceIDTypeFromParamType(param.type);
1407     ASSERT(resourceIDType != ResourceIDType::InvalidEnum);
1408     const char *resourceName = GetResourceIDTypeName(resourceIDType);
1409 
1410     std::stringstream updateFuncNameStr;
1411     updateFuncNameStr << "Update" << resourceName << "ID";
1412     std::string updateFuncName = updateFuncNameStr.str();
1413 
1414     const IDType *returnedIDs = reinterpret_cast<const IDType *>(param.data[0].data());
1415 
1416     for (GLsizei idIndex = 0; idIndex < n; ++idIndex)
1417     {
1418         IDType id                = returnedIDs[idIndex];
1419         GLsizei readBufferOffset = idIndex * sizeof(gl::RenderbufferID);
1420         ParamBuffer params;
1421         params.addValueParam("id", ParamType::TGLuint, id.value);
1422         params.addValueParam("readBufferOffset", ParamType::TGLsizei, readBufferOffset);
1423         callsOut->emplace_back(updateFuncName, std::move(params));
1424     }
1425 }
1426 
CaptureUpdateUniformLocations(const gl::Program * program,std::vector<CallCapture> * callsOut)1427 void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
1428 {
1429     const std::vector<gl::LinkedUniform> &uniforms     = program->getState().getUniforms();
1430     const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
1431 
1432     for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
1433     {
1434         const gl::VariableLocation &locationVar = locations[location];
1435 
1436         // This handles the case where the application calls glBindUniformLocationCHROMIUM
1437         // on an unused uniform. We must still store a -1 into gUniformLocations in case the
1438         // application attempts to call a glUniform* call. To do this we'll pass in a blank name to
1439         // force glGetUniformLocation to return -1.
1440         std::string name;
1441         ParamBuffer params;
1442         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1443 
1444         if (locationVar.index >= uniforms.size())
1445         {
1446             name = "";
1447         }
1448         else
1449         {
1450             const gl::LinkedUniform &uniform = uniforms[locationVar.index];
1451 
1452             name = uniform.name;
1453 
1454             if (uniform.isArray())
1455             {
1456                 if (locationVar.arrayIndex > 0)
1457                 {
1458                     // Non-sequential array uniform locations are not currently handled.
1459                     // In practice array locations shouldn't ever be non-sequential.
1460                     ASSERT(uniform.location == -1 ||
1461                            location == uniform.location + static_cast<int>(locationVar.arrayIndex));
1462                     continue;
1463                 }
1464 
1465                 if (uniform.isArrayOfArrays())
1466                 {
1467                     UNIMPLEMENTED();
1468                 }
1469 
1470                 name = gl::StripLastArrayIndex(name);
1471             }
1472         }
1473 
1474         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1475         CaptureString(name.c_str(), &nameParam);
1476         params.addParam(std::move(nameParam));
1477 
1478         params.addValueParam("location", ParamType::TGLint, location);
1479         callsOut->emplace_back("UpdateUniformLocation", std::move(params));
1480     }
1481 }
1482 
CaptureUpdateUniformBlockIndexes(const gl::Program * program,std::vector<CallCapture> * callsOut)1483 void CaptureUpdateUniformBlockIndexes(const gl::Program *program,
1484                                       std::vector<CallCapture> *callsOut)
1485 {
1486     const std::vector<gl::InterfaceBlock> &uniformBlocks = program->getState().getUniformBlocks();
1487 
1488     for (GLuint index = 0; index < uniformBlocks.size(); ++index)
1489     {
1490         ParamBuffer params;
1491 
1492         std::string name;
1493         params.addValueParam("program", ParamType::TShaderProgramID, program->id());
1494 
1495         ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
1496         CaptureString(uniformBlocks[index].name.c_str(), &nameParam);
1497         params.addParam(std::move(nameParam));
1498 
1499         params.addValueParam("index", ParamType::TGLuint, index);
1500         callsOut->emplace_back("UpdateUniformBlockIndex", std::move(params));
1501     }
1502 }
1503 
CaptureDeleteUniformLocations(gl::ShaderProgramID program,std::vector<CallCapture> * callsOut)1504 void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
1505 {
1506     ParamBuffer params;
1507     params.addValueParam("program", ParamType::TShaderProgramID, program);
1508     callsOut->emplace_back("DeleteUniformLocations", std::move(params));
1509 }
1510 
MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> * callsOut)1511 void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
1512 {
1513     const CallCapture &call = callsOut->back();
1514 
1515     switch (call.entryPoint)
1516     {
1517         case EntryPoint::GLGenBuffers:
1518         {
1519             const ParamCapture &buffers =
1520                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1);
1521             CaptureUpdateResourceIDs<gl::BufferID>(call, buffers, callsOut);
1522             break;
1523         }
1524 
1525         case EntryPoint::GLGenFencesNV:
1526         {
1527             const ParamCapture &fences =
1528                 call.params.getParam("fencesPacked", ParamType::TFenceNVIDPointer, 1);
1529             CaptureUpdateResourceIDs<gl::FenceNVID>(call, fences, callsOut);
1530             break;
1531         }
1532 
1533         case EntryPoint::GLGenFramebuffers:
1534         case EntryPoint::GLGenFramebuffersOES:
1535         {
1536             const ParamCapture &framebuffers =
1537                 call.params.getParam("framebuffersPacked", ParamType::TFramebufferIDPointer, 1);
1538             CaptureUpdateResourceIDs<gl::FramebufferID>(call, framebuffers, callsOut);
1539             break;
1540         }
1541 
1542         case EntryPoint::GLGenProgramPipelines:
1543         {
1544             const ParamCapture &pipelines =
1545                 call.params.getParam("pipelinesPacked", ParamType::TProgramPipelineIDPointer, 1);
1546             CaptureUpdateResourceIDs<gl::ProgramPipelineID>(call, pipelines, callsOut);
1547             break;
1548         }
1549 
1550         case EntryPoint::GLGenQueries:
1551         case EntryPoint::GLGenQueriesEXT:
1552         {
1553             const ParamCapture &queries =
1554                 call.params.getParam("idsPacked", ParamType::TQueryIDPointer, 1);
1555             CaptureUpdateResourceIDs<gl::QueryID>(call, queries, callsOut);
1556             break;
1557         }
1558 
1559         case EntryPoint::GLGenRenderbuffers:
1560         case EntryPoint::GLGenRenderbuffersOES:
1561         {
1562             const ParamCapture &renderbuffers =
1563                 call.params.getParam("renderbuffersPacked", ParamType::TRenderbufferIDPointer, 1);
1564             CaptureUpdateResourceIDs<gl::RenderbufferID>(call, renderbuffers, callsOut);
1565             break;
1566         }
1567 
1568         case EntryPoint::GLGenSamplers:
1569         {
1570             const ParamCapture &samplers =
1571                 call.params.getParam("samplersPacked", ParamType::TSamplerIDPointer, 1);
1572             CaptureUpdateResourceIDs<gl::SamplerID>(call, samplers, callsOut);
1573             break;
1574         }
1575 
1576         case EntryPoint::GLGenSemaphoresEXT:
1577         {
1578             const ParamCapture &semaphores =
1579                 call.params.getParam("semaphoresPacked", ParamType::TSemaphoreIDPointer, 1);
1580             CaptureUpdateResourceIDs<gl::SemaphoreID>(call, semaphores, callsOut);
1581             break;
1582         }
1583 
1584         case EntryPoint::GLGenTextures:
1585         {
1586             const ParamCapture &textures =
1587                 call.params.getParam("texturesPacked", ParamType::TTextureIDPointer, 1);
1588             CaptureUpdateResourceIDs<gl::TextureID>(call, textures, callsOut);
1589             break;
1590         }
1591 
1592         case EntryPoint::GLGenTransformFeedbacks:
1593         {
1594             const ParamCapture &xfbs =
1595                 call.params.getParam("idsPacked", ParamType::TTransformFeedbackIDPointer, 1);
1596             CaptureUpdateResourceIDs<gl::TransformFeedbackID>(call, xfbs, callsOut);
1597             break;
1598         }
1599 
1600         case EntryPoint::GLGenVertexArrays:
1601         case EntryPoint::GLGenVertexArraysOES:
1602         {
1603             const ParamCapture &vertexArrays =
1604                 call.params.getParam("arraysPacked", ParamType::TVertexArrayIDPointer, 1);
1605             CaptureUpdateResourceIDs<gl::VertexArrayID>(call, vertexArrays, callsOut);
1606             break;
1607         }
1608 
1609         case EntryPoint::GLCreateMemoryObjectsEXT:
1610         {
1611             const ParamCapture &memoryObjects =
1612                 call.params.getParam("memoryObjectsPacked", ParamType::TMemoryObjectIDPointer, 1);
1613             CaptureUpdateResourceIDs<gl::MemoryObjectID>(call, memoryObjects, callsOut);
1614             break;
1615         }
1616 
1617         default:
1618             break;
1619     }
1620 }
1621 
CaptureUpdateCurrentProgram(const CallCapture & call,std::vector<CallCapture> * callsOut)1622 void CaptureUpdateCurrentProgram(const CallCapture &call, std::vector<CallCapture> *callsOut)
1623 {
1624     const ParamCapture &param =
1625         call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
1626     gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
1627 
1628     ParamBuffer paramBuffer;
1629     paramBuffer.addValueParam("program", ParamType::TShaderProgramID, programID);
1630 
1631     callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
1632 }
1633 
IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData & currentValue)1634 bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
1635 {
1636     if (currentValue.Type != gl::VertexAttribType::Float)
1637         return false;
1638 
1639     return currentValue.Values.FloatValues[0] == 0.0f &&
1640            currentValue.Values.FloatValues[1] == 0.0f &&
1641            currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
1642 }
1643 
IsQueryActive(const gl::State & glState,gl::QueryID & queryID)1644 bool IsQueryActive(const gl::State &glState, gl::QueryID &queryID)
1645 {
1646     const gl::ActiveQueryMap &activeQueries = glState.getActiveQueriesForCapture();
1647     for (const auto &activeQueryIter : activeQueries)
1648     {
1649         const gl::Query *activeQuery = activeQueryIter.get();
1650         if (activeQuery && activeQuery->id() == queryID)
1651         {
1652             return true;
1653         }
1654     }
1655 
1656     return false;
1657 }
1658 
Capture(std::vector<CallCapture> * setupCalls,CallCapture && call)1659 void Capture(std::vector<CallCapture> *setupCalls, CallCapture &&call)
1660 {
1661     setupCalls->emplace_back(std::move(call));
1662 }
1663 
CaptureFramebufferAttachment(std::vector<CallCapture> * setupCalls,const gl::State & replayState,const gl::FramebufferAttachment & attachment)1664 void CaptureFramebufferAttachment(std::vector<CallCapture> *setupCalls,
1665                                   const gl::State &replayState,
1666                                   const gl::FramebufferAttachment &attachment)
1667 {
1668     GLuint resourceID = attachment.getResource()->getId();
1669 
1670     // TODO(jmadill): Layer attachments. http://anglebug.com/3662
1671     if (attachment.type() == GL_TEXTURE)
1672     {
1673         gl::ImageIndex index = attachment.getTextureImageIndex();
1674 
1675         Capture(setupCalls, CaptureFramebufferTexture2D(replayState, true, GL_FRAMEBUFFER,
1676                                                         attachment.getBinding(), index.getTarget(),
1677                                                         {resourceID}, index.getLevelIndex()));
1678     }
1679     else
1680     {
1681         ASSERT(attachment.type() == GL_RENDERBUFFER);
1682         Capture(setupCalls, CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
1683                                                            attachment.getBinding(), GL_RENDERBUFFER,
1684                                                            {resourceID}));
1685     }
1686 }
1687 
CaptureUpdateUniformValues(const gl::State & replayState,const gl::Context * context,const gl::Program * program,std::vector<CallCapture> * callsOut)1688 void CaptureUpdateUniformValues(const gl::State &replayState,
1689                                 const gl::Context *context,
1690                                 const gl::Program *program,
1691                                 std::vector<CallCapture> *callsOut)
1692 {
1693     if (!program->isLinked())
1694     {
1695         // We can't populate uniforms if the program hasn't been linked
1696         return;
1697     }
1698 
1699     // We need to bind the program and update its uniforms
1700     // TODO (http://anglebug.com/3662): Only bind if different from currently bound
1701     Capture(callsOut, CaptureUseProgram(replayState, true, program->id()));
1702     CaptureUpdateCurrentProgram(callsOut->back(), callsOut);
1703 
1704     const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
1705 
1706     for (const gl::LinkedUniform &uniform : uniforms)
1707     {
1708         std::string uniformName = uniform.name;
1709 
1710         int uniformCount = 1;
1711         if (uniform.isArray())
1712         {
1713             if (uniform.isArrayOfArrays())
1714             {
1715                 UNIMPLEMENTED();
1716                 continue;
1717             }
1718 
1719             uniformCount = uniform.arraySizes[0];
1720             uniformName  = gl::StripLastArrayIndex(uniformName);
1721         }
1722 
1723         gl::UniformLocation uniformLoc      = program->getUniformLocation(uniformName);
1724         const gl::UniformTypeInfo *typeInfo = uniform.typeInfo;
1725         int componentCount                  = typeInfo->componentCount;
1726         int uniformSize                     = uniformCount * componentCount;
1727 
1728         // For arrayed uniforms, we'll need to increment a read location
1729         gl::UniformLocation readLoc = uniformLoc;
1730 
1731         // If the uniform is unused, just continue
1732         if (readLoc.value == -1)
1733         {
1734             continue;
1735         }
1736 
1737         // Image uniforms are special and cannot be set this way
1738         if (typeInfo->isImageType)
1739         {
1740             continue;
1741         }
1742 
1743         // Samplers should be populated with GL_INT, regardless of return type
1744         if (typeInfo->isSampler)
1745         {
1746             std::vector<GLint> uniformBuffer(uniformSize);
1747             for (int index = 0; index < uniformCount; index++, readLoc.value++)
1748             {
1749                 program->getUniformiv(context, readLoc,
1750                                       uniformBuffer.data() + index * componentCount);
1751             }
1752 
1753             Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc, uniformCount,
1754                                                 uniformBuffer.data()));
1755 
1756             continue;
1757         }
1758 
1759         switch (typeInfo->componentType)
1760         {
1761             case GL_FLOAT:
1762             {
1763                 std::vector<GLfloat> uniformBuffer(uniformSize);
1764                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1765                 {
1766                     program->getUniformfv(context, readLoc,
1767                                           uniformBuffer.data() + index * componentCount);
1768                 }
1769                 switch (typeInfo->type)
1770                 {
1771                     // Note: All matrix uniforms are populated without transpose
1772                     case GL_FLOAT_MAT4x3:
1773                         Capture(callsOut, CaptureUniformMatrix4x3fv(replayState, true, uniformLoc,
1774                                                                     uniformCount, false,
1775                                                                     uniformBuffer.data()));
1776                         break;
1777                     case GL_FLOAT_MAT4x2:
1778                         Capture(callsOut, CaptureUniformMatrix4x2fv(replayState, true, uniformLoc,
1779                                                                     uniformCount, false,
1780                                                                     uniformBuffer.data()));
1781                         break;
1782                     case GL_FLOAT_MAT4:
1783                         Capture(callsOut,
1784                                 CaptureUniformMatrix4fv(replayState, true, uniformLoc, uniformCount,
1785                                                         false, uniformBuffer.data()));
1786                         break;
1787                     case GL_FLOAT_MAT3x4:
1788                         Capture(callsOut, CaptureUniformMatrix3x4fv(replayState, true, uniformLoc,
1789                                                                     uniformCount, false,
1790                                                                     uniformBuffer.data()));
1791                         break;
1792                     case GL_FLOAT_MAT3x2:
1793                         Capture(callsOut, CaptureUniformMatrix3x2fv(replayState, true, uniformLoc,
1794                                                                     uniformCount, false,
1795                                                                     uniformBuffer.data()));
1796                         break;
1797                     case GL_FLOAT_MAT3:
1798                         Capture(callsOut,
1799                                 CaptureUniformMatrix3fv(replayState, true, uniformLoc, uniformCount,
1800                                                         false, uniformBuffer.data()));
1801                         break;
1802                     case GL_FLOAT_MAT2x4:
1803                         Capture(callsOut, CaptureUniformMatrix2x4fv(replayState, true, uniformLoc,
1804                                                                     uniformCount, false,
1805                                                                     uniformBuffer.data()));
1806                         break;
1807                     case GL_FLOAT_MAT2x3:
1808                         Capture(callsOut, CaptureUniformMatrix2x3fv(replayState, true, uniformLoc,
1809                                                                     uniformCount, false,
1810                                                                     uniformBuffer.data()));
1811                         break;
1812                     case GL_FLOAT_MAT2:
1813                         Capture(callsOut,
1814                                 CaptureUniformMatrix2fv(replayState, true, uniformLoc, uniformCount,
1815                                                         false, uniformBuffer.data()));
1816                         break;
1817                     case GL_FLOAT_VEC4:
1818                         Capture(callsOut, CaptureUniform4fv(replayState, true, uniformLoc,
1819                                                             uniformCount, uniformBuffer.data()));
1820                         break;
1821                     case GL_FLOAT_VEC3:
1822                         Capture(callsOut, CaptureUniform3fv(replayState, true, uniformLoc,
1823                                                             uniformCount, uniformBuffer.data()));
1824                         break;
1825                     case GL_FLOAT_VEC2:
1826                         Capture(callsOut, CaptureUniform2fv(replayState, true, uniformLoc,
1827                                                             uniformCount, uniformBuffer.data()));
1828                         break;
1829                     case GL_FLOAT:
1830                         Capture(callsOut, CaptureUniform1fv(replayState, true, uniformLoc,
1831                                                             uniformCount, uniformBuffer.data()));
1832                         break;
1833                     default:
1834                         UNIMPLEMENTED();
1835                         break;
1836                 }
1837                 break;
1838             }
1839             case GL_INT:
1840             {
1841                 std::vector<GLint> uniformBuffer(uniformSize);
1842                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1843                 {
1844                     program->getUniformiv(context, readLoc,
1845                                           uniformBuffer.data() + index * componentCount);
1846                 }
1847                 switch (componentCount)
1848                 {
1849                     case 4:
1850                         Capture(callsOut, CaptureUniform4iv(replayState, true, uniformLoc,
1851                                                             uniformCount, uniformBuffer.data()));
1852                         break;
1853                     case 3:
1854                         Capture(callsOut, CaptureUniform3iv(replayState, true, uniformLoc,
1855                                                             uniformCount, uniformBuffer.data()));
1856                         break;
1857                     case 2:
1858                         Capture(callsOut, CaptureUniform2iv(replayState, true, uniformLoc,
1859                                                             uniformCount, uniformBuffer.data()));
1860                         break;
1861                     case 1:
1862                         Capture(callsOut, CaptureUniform1iv(replayState, true, uniformLoc,
1863                                                             uniformCount, uniformBuffer.data()));
1864                         break;
1865                     default:
1866                         UNIMPLEMENTED();
1867                         break;
1868                 }
1869                 break;
1870             }
1871             case GL_BOOL:
1872             case GL_UNSIGNED_INT:
1873             {
1874                 std::vector<GLuint> uniformBuffer(uniformSize);
1875                 for (int index = 0; index < uniformCount; index++, readLoc.value++)
1876                 {
1877                     program->getUniformuiv(context, readLoc,
1878                                            uniformBuffer.data() + index * componentCount);
1879                 }
1880                 switch (componentCount)
1881                 {
1882                     case 4:
1883                         Capture(callsOut, CaptureUniform4uiv(replayState, true, uniformLoc,
1884                                                              uniformCount, uniformBuffer.data()));
1885                         break;
1886                     case 3:
1887                         Capture(callsOut, CaptureUniform3uiv(replayState, true, uniformLoc,
1888                                                              uniformCount, uniformBuffer.data()));
1889                         break;
1890                     case 2:
1891                         Capture(callsOut, CaptureUniform2uiv(replayState, true, uniformLoc,
1892                                                              uniformCount, uniformBuffer.data()));
1893                         break;
1894                     case 1:
1895                         Capture(callsOut, CaptureUniform1uiv(replayState, true, uniformLoc,
1896                                                              uniformCount, uniformBuffer.data()));
1897                         break;
1898                     default:
1899                         UNIMPLEMENTED();
1900                         break;
1901                 }
1902                 break;
1903             }
1904             default:
1905                 UNIMPLEMENTED();
1906                 break;
1907         }
1908     }
1909 }
1910 
CaptureVertexPointerES1(std::vector<CallCapture> * setupCalls,gl::State * replayState,GLuint attribIndex,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)1911 void CaptureVertexPointerES1(std::vector<CallCapture> *setupCalls,
1912                              gl::State *replayState,
1913                              GLuint attribIndex,
1914                              const gl::VertexAttribute &attrib,
1915                              const gl::VertexBinding &binding)
1916 {
1917     switch (gl::GLES1Renderer::VertexArrayType(attribIndex))
1918     {
1919         case gl::ClientVertexArrayType::Vertex:
1920             Capture(setupCalls,
1921                     CaptureVertexPointer(*replayState, true, attrib.format->channelCount,
1922                                          attrib.format->vertexAttribType, binding.getStride(),
1923                                          attrib.pointer));
1924             break;
1925         case gl::ClientVertexArrayType::Normal:
1926             Capture(setupCalls,
1927                     CaptureNormalPointer(*replayState, true, attrib.format->vertexAttribType,
1928                                          binding.getStride(), attrib.pointer));
1929             break;
1930         case gl::ClientVertexArrayType::Color:
1931             Capture(setupCalls, CaptureColorPointer(*replayState, true, attrib.format->channelCount,
1932                                                     attrib.format->vertexAttribType,
1933                                                     binding.getStride(), attrib.pointer));
1934             break;
1935         case gl::ClientVertexArrayType::PointSize:
1936             Capture(setupCalls,
1937                     CapturePointSizePointerOES(*replayState, true, attrib.format->vertexAttribType,
1938                                                binding.getStride(), attrib.pointer));
1939             break;
1940         case gl::ClientVertexArrayType::TextureCoord:
1941             Capture(setupCalls,
1942                     CaptureTexCoordPointer(*replayState, true, attrib.format->channelCount,
1943                                            attrib.format->vertexAttribType, binding.getStride(),
1944                                            attrib.pointer));
1945             break;
1946         default:
1947             UNREACHABLE();
1948     }
1949 }
1950 
CaptureVertexArrayData(std::vector<CallCapture> * setupCalls,const gl::Context * context,const gl::VertexArray * vertexArray,gl::State * replayState)1951 void CaptureVertexArrayData(std::vector<CallCapture> *setupCalls,
1952                             const gl::Context *context,
1953                             const gl::VertexArray *vertexArray,
1954                             gl::State *replayState)
1955 {
1956     const std::vector<gl::VertexAttribute> &vertexAttribs = vertexArray->getVertexAttributes();
1957     const std::vector<gl::VertexBinding> &vertexBindings  = vertexArray->getVertexBindings();
1958 
1959     for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
1960     {
1961         const gl::VertexAttribute defaultAttrib(attribIndex);
1962         const gl::VertexBinding defaultBinding;
1963 
1964         const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
1965         const gl::VertexBinding &binding  = vertexBindings[attrib.bindingIndex];
1966 
1967         if (attrib.enabled != defaultAttrib.enabled)
1968         {
1969             if (context->isGLES1())
1970             {
1971                 Capture(setupCalls,
1972                         CaptureEnableClientState(*replayState, false,
1973                                                  gl::GLES1Renderer::VertexArrayType(attribIndex)));
1974             }
1975             else
1976             {
1977                 Capture(setupCalls,
1978                         CaptureEnableVertexAttribArray(*replayState, false, attribIndex));
1979             }
1980         }
1981 
1982         if (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
1983             binding.getStride() != defaultBinding.getStride() ||
1984             binding.getBuffer().get() != nullptr)
1985         {
1986             // Each attribute can pull from a separate buffer, so check the binding
1987             gl::Buffer *buffer = binding.getBuffer().get();
1988             if (buffer && buffer != replayState->getArrayBuffer())
1989             {
1990                 replayState->setBufferBinding(context, gl::BufferBinding::Array, buffer);
1991 
1992                 Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::Array,
1993                                                       buffer->id()));
1994             }
1995 
1996             // Establish the relationship between currently bound buffer and the VAO
1997             if (context->isGLES1())
1998             {
1999                 CaptureVertexPointerES1(setupCalls, replayState, attribIndex, attrib, binding);
2000             }
2001             else
2002             {
2003                 Capture(setupCalls,
2004                         CaptureVertexAttribPointer(
2005                             *replayState, true, attribIndex, attrib.format->channelCount,
2006                             attrib.format->vertexAttribType, attrib.format->isNorm(),
2007                             binding.getStride(), attrib.pointer));
2008             }
2009         }
2010 
2011         if (binding.getDivisor() != 0)
2012         {
2013             Capture(setupCalls, CaptureVertexAttribDivisor(*replayState, true, attribIndex,
2014                                                            binding.getDivisor()));
2015         }
2016     }
2017 
2018     // The element array buffer is not per attribute, but per VAO
2019     gl::Buffer *elementArrayBuffer = vertexArray->getElementArrayBuffer();
2020     if (elementArrayBuffer)
2021     {
2022         Capture(setupCalls, CaptureBindBuffer(*replayState, true, gl::BufferBinding::ElementArray,
2023                                               elementArrayBuffer->id()));
2024     }
2025 }
2026 
CaptureTextureStorage(std::vector<CallCapture> * setupCalls,gl::State * replayState,const gl::Texture * texture)2027 void CaptureTextureStorage(std::vector<CallCapture> *setupCalls,
2028                            gl::State *replayState,
2029                            const gl::Texture *texture)
2030 {
2031     // Use mip-level 0 for the base dimensions
2032     gl::ImageIndex imageIndex = gl::ImageIndex::MakeFromType(texture->getType(), 0);
2033     const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(imageIndex);
2034 
2035     switch (texture->getType())
2036     {
2037         case gl::TextureType::_2D:
2038         case gl::TextureType::CubeMap:
2039         {
2040             Capture(setupCalls, CaptureTexStorage2D(*replayState, true, texture->getType(),
2041                                                     texture->getImmutableLevels(),
2042                                                     desc.format.info->internalFormat,
2043                                                     desc.size.width, desc.size.height));
2044             break;
2045         }
2046         case gl::TextureType::_3D:
2047         case gl::TextureType::_2DArray:
2048         case gl::TextureType::CubeMapArray:
2049         {
2050             Capture(setupCalls, CaptureTexStorage3D(
2051                                     *replayState, true, texture->getType(),
2052                                     texture->getImmutableLevels(), desc.format.info->internalFormat,
2053                                     desc.size.width, desc.size.height, desc.size.depth));
2054             break;
2055         }
2056         case gl::TextureType::Buffer:
2057         {
2058             // Do nothing. This will already be captured as a buffer.
2059             break;
2060         }
2061         default:
2062             UNIMPLEMENTED();
2063             break;
2064     }
2065 }
2066 
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)2067 void CaptureTextureContents(std::vector<CallCapture> *setupCalls,
2068                             gl::State *replayState,
2069                             const gl::Texture *texture,
2070                             const gl::ImageIndex &index,
2071                             const gl::ImageDesc &desc,
2072                             GLuint size,
2073                             const void *data)
2074 {
2075     const gl::InternalFormat &format = *desc.format.info;
2076 
2077     if (index.getType() == gl::TextureType::Buffer)
2078     {
2079         // Zero binding size indicates full buffer bound
2080         if (texture->getBuffer().getSize() == 0)
2081         {
2082             Capture(setupCalls,
2083                     CaptureTexBufferEXT(*replayState, true, index.getType(), format.internalFormat,
2084                                         texture->getBuffer().get()->id()));
2085         }
2086         else
2087         {
2088             Capture(setupCalls, CaptureTexBufferRangeEXT(*replayState, true, index.getType(),
2089                                                          format.internalFormat,
2090                                                          texture->getBuffer().get()->id(),
2091                                                          texture->getBuffer().getOffset(),
2092                                                          texture->getBuffer().getSize()));
2093         }
2094 
2095         // For buffers, we're done
2096         return;
2097     }
2098 
2099     bool is3D =
2100         (index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
2101          index.getType() == gl::TextureType::CubeMapArray);
2102 
2103     if (format.compressed)
2104     {
2105         if (is3D)
2106         {
2107             if (texture->getImmutableFormat())
2108             {
2109                 Capture(setupCalls,
2110                         CaptureCompressedTexSubImage3D(
2111                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0, 0,
2112                             desc.size.width, desc.size.height, desc.size.depth,
2113                             format.internalFormat, size, data));
2114             }
2115             else
2116             {
2117                 Capture(setupCalls,
2118                         CaptureCompressedTexImage3D(*replayState, true, index.getTarget(),
2119                                                     index.getLevelIndex(), format.internalFormat,
2120                                                     desc.size.width, desc.size.height,
2121                                                     desc.size.depth, 0, size, data));
2122             }
2123         }
2124         else
2125         {
2126             if (texture->getImmutableFormat())
2127             {
2128                 Capture(setupCalls,
2129                         CaptureCompressedTexSubImage2D(
2130                             *replayState, true, index.getTarget(), index.getLevelIndex(), 0, 0,
2131                             desc.size.width, desc.size.height, format.internalFormat, size, data));
2132             }
2133             else
2134             {
2135                 Capture(setupCalls, CaptureCompressedTexImage2D(
2136                                         *replayState, true, index.getTarget(),
2137                                         index.getLevelIndex(), format.internalFormat,
2138                                         desc.size.width, desc.size.height, 0, size, data));
2139             }
2140         }
2141     }
2142     else
2143     {
2144         if (is3D)
2145         {
2146             if (texture->getImmutableFormat())
2147             {
2148                 Capture(setupCalls,
2149                         CaptureTexSubImage3D(*replayState, true, index.getTarget(),
2150                                              index.getLevelIndex(), 0, 0, 0, desc.size.width,
2151                                              desc.size.height, desc.size.depth, format.format,
2152                                              format.type, data));
2153             }
2154             else
2155             {
2156                 Capture(
2157                     setupCalls,
2158                     CaptureTexImage3D(*replayState, true, index.getTarget(), index.getLevelIndex(),
2159                                       format.internalFormat, desc.size.width, desc.size.height,
2160                                       desc.size.depth, 0, format.format, format.type, data));
2161             }
2162         }
2163         else
2164         {
2165             if (texture->getImmutableFormat())
2166             {
2167                 Capture(setupCalls,
2168                         CaptureTexSubImage2D(*replayState, true, index.getTarget(),
2169                                              index.getLevelIndex(), 0, 0, desc.size.width,
2170                                              desc.size.height, format.format, format.type, data));
2171             }
2172             else
2173             {
2174                 Capture(setupCalls, CaptureTexImage2D(*replayState, true, index.getTarget(),
2175                                                       index.getLevelIndex(), format.internalFormat,
2176                                                       desc.size.width, desc.size.height, 0,
2177                                                       format.format, format.type, data));
2178             }
2179         }
2180     }
2181 }
2182 
2183 // TODO(http://anglebug.com/4599): Improve reset/restore call generation
2184 // There are multiple ways to track reset calls for individual resources. For now, we are tracking
2185 // separate lists of instructions that mirror the calls created during mid-execution setup. Other
2186 // methods could involve passing the original CallCaptures to this function, or tracking the
2187 // indices of original setup calls.
CaptureBufferResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferID * id,const gl::Buffer * buffer)2188 void CaptureBufferResetCalls(const gl::State &replayState,
2189                              ResourceTracker *resourceTracker,
2190                              gl::BufferID *id,
2191                              const gl::Buffer *buffer)
2192 {
2193     // Track this as a starting resource that may need to be restored.
2194     BufferSet &startingBuffers = resourceTracker->getStartingBuffers();
2195     startingBuffers.insert(*id);
2196 
2197     // Track calls to regenerate a given buffer
2198     BufferCalls &bufferRegenCalls = resourceTracker->getBufferRegenCalls();
2199     Capture(&bufferRegenCalls[*id], CaptureDeleteBuffers(replayState, true, 1, id));
2200     Capture(&bufferRegenCalls[*id], CaptureGenBuffers(replayState, true, 1, id));
2201     MaybeCaptureUpdateResourceIDs(&bufferRegenCalls[*id]);
2202 
2203     // Track calls to restore a given buffer's contents
2204     BufferCalls &bufferRestoreCalls = resourceTracker->getBufferRestoreCalls();
2205     Capture(&bufferRestoreCalls[*id],
2206             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2207     Capture(&bufferRestoreCalls[*id],
2208             CaptureBufferData(replayState, true, gl::BufferBinding::Array,
2209                               static_cast<GLsizeiptr>(buffer->getSize()), buffer->getMapPointer(),
2210                               buffer->getUsage()));
2211 
2212     if (buffer->isMapped())
2213     {
2214         // Track calls to remap a buffer that started as mapped
2215         BufferCalls &bufferMapCalls = resourceTracker->getBufferMapCalls();
2216 
2217         Capture(&bufferMapCalls[*id],
2218                 CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2219 
2220         void *dontCare = nullptr;
2221         Capture(&bufferMapCalls[*id],
2222                 CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
2223                                       static_cast<GLsizeiptr>(buffer->getMapOffset()),
2224                                       static_cast<GLsizeiptr>(buffer->getMapLength()),
2225                                       buffer->getAccessFlags(), dontCare));
2226 
2227         // Track the bufferID that was just mapped
2228         bufferMapCalls[*id].back().params.setMappedBufferID(buffer->id());
2229     }
2230 
2231     // Track calls unmap a buffer that started as unmapped
2232     BufferCalls &bufferUnmapCalls = resourceTracker->getBufferUnmapCalls();
2233     Capture(&bufferUnmapCalls[*id],
2234             CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, *id));
2235     Capture(&bufferUnmapCalls[*id],
2236             CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
2237 }
2238 
CaptureFenceSyncResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,GLsync syncID,const gl::Sync * sync)2239 void CaptureFenceSyncResetCalls(const gl::State &replayState,
2240                                 ResourceTracker *resourceTracker,
2241                                 GLsync syncID,
2242                                 const gl::Sync *sync)
2243 {
2244     // Track calls to regenerate a given fence sync
2245     FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
2246     Capture(&fenceSyncRegenCalls[syncID],
2247             CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
2248     MaybeCaptureUpdateResourceIDs(&fenceSyncRegenCalls[syncID]);
2249 }
2250 
CaptureBufferBindingResetCalls(const gl::State & replayState,ResourceTracker * resourceTracker,gl::BufferBinding binding,gl::BufferID id)2251 void CaptureBufferBindingResetCalls(const gl::State &replayState,
2252                                     ResourceTracker *resourceTracker,
2253                                     gl::BufferBinding binding,
2254                                     gl::BufferID id)
2255 {
2256     std::vector<CallCapture> &bufferBindingCalls = resourceTracker->getBufferBindingCalls();
2257     Capture(&bufferBindingCalls, CaptureBindBuffer(replayState, true, binding, id));
2258 }
2259 
CaptureIndexedBuffers(const gl::State & glState,const gl::BufferVector & indexedBuffers,gl::BufferBinding binding,std::vector<CallCapture> * setupCalls)2260 void CaptureIndexedBuffers(const gl::State &glState,
2261                            const gl::BufferVector &indexedBuffers,
2262                            gl::BufferBinding binding,
2263                            std::vector<CallCapture> *setupCalls)
2264 {
2265     for (unsigned int index = 0; index < indexedBuffers.size(); ++index)
2266     {
2267         const gl::OffsetBindingPointer<gl::Buffer> &buffer = indexedBuffers[index];
2268 
2269         if (buffer.get() == nullptr)
2270         {
2271             continue;
2272         }
2273 
2274         GLintptr offset       = buffer.getOffset();
2275         GLsizeiptr size       = buffer.getSize();
2276         gl::BufferID bufferID = buffer.get()->id();
2277 
2278         // Context::bindBufferBase() calls Context::bindBufferRange() with size and offset = 0.
2279         if ((offset == 0) && (size == 0))
2280         {
2281             Capture(setupCalls, CaptureBindBufferBase(glState, true, binding, index, bufferID));
2282         }
2283         else
2284         {
2285             Capture(setupCalls,
2286                     CaptureBindBufferRange(glState, true, binding, index, bufferID, offset, size));
2287         }
2288     }
2289 }
2290 
CaptureDefaultVertexAttribs(const gl::State & replayState,const gl::State & apiState,std::vector<CallCapture> * setupCalls)2291 void CaptureDefaultVertexAttribs(const gl::State &replayState,
2292                                  const gl::State &apiState,
2293                                  std::vector<CallCapture> *setupCalls)
2294 {
2295     const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
2296         apiState.getVertexAttribCurrentValues();
2297 
2298     for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
2299     {
2300         const gl::VertexAttribCurrentValueData &defaultValue = currentValues[attribIndex];
2301         if (!IsDefaultCurrentValue(defaultValue))
2302         {
2303             Capture(setupCalls, CaptureVertexAttrib4fv(replayState, true, attribIndex,
2304                                                        defaultValue.Values.FloatValues));
2305         }
2306     }
2307 }
2308 
2309 // Capture the setup of the state that's shared by all of the contexts in the share group:
2310 // OpenGL ES Version 3.2 (October 22, 2019)
2311 // Chapter 5 Shared Objects and Multiple Contexts
2312 //     Objects that can be shared between contexts include buffer objects, program
2313 //   and shader objects, renderbuffer objects, sampler objects, sync objects, and texture
2314 //   objects (except for the texture objects named zero).
2315 //     Objects which contain references to other objects include framebuffer, program
2316 //   pipeline, transform feedback, and vertex array objects. Such objects are called
2317 //   container objects and are not shared.
CaptureSharedContextMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker)2318 void CaptureSharedContextMidExecutionSetup(const gl::Context *context,
2319                                            std::vector<CallCapture> *setupCalls,
2320                                            ResourceTracker *resourceTracker)
2321 {
2322 
2323     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
2324     const gl::State &apiState              = context->getState();
2325     gl::State replayState(nullptr, nullptr, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
2326                           apiState.getClientVersion(), false, true, true, true, false,
2327                           EGL_CONTEXT_PRIORITY_MEDIUM_IMG, apiState.hasProtectedContent());
2328 
2329     // Small helper function to make the code more readable.
2330     auto cap = [frameCaptureShared, setupCalls](CallCapture &&call) {
2331         frameCaptureShared->updateReadBufferSize(call.params.getReadBufferSize());
2332         setupCalls->emplace_back(std::move(call));
2333     };
2334 
2335     // Capture Buffer data.
2336     const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
2337     for (const auto &bufferIter : buffers)
2338     {
2339         gl::BufferID id    = {bufferIter.first};
2340         gl::Buffer *buffer = bufferIter.second;
2341 
2342         if (id.value == 0)
2343         {
2344             continue;
2345         }
2346 
2347         // glBufferData. Would possibly be better implemented using a getData impl method.
2348         // Saving buffers that are mapped during a swap is not yet handled.
2349         if (buffer->getSize() == 0)
2350         {
2351             continue;
2352         }
2353 
2354         // Remember if the buffer was already mapped
2355         GLboolean bufferMapped = buffer->isMapped();
2356 
2357         // If needed, map the buffer so we can capture its contents
2358         if (!bufferMapped)
2359         {
2360             (void)buffer->mapRange(context, 0, static_cast<GLsizeiptr>(buffer->getSize()),
2361                                    GL_MAP_READ_BIT);
2362         }
2363 
2364         // Generate binding.
2365         cap(CaptureGenBuffers(replayState, true, 1, &id));
2366         MaybeCaptureUpdateResourceIDs(setupCalls);
2367 
2368         // Always use the array buffer binding point to upload data to keep things simple.
2369         if (buffer != replayState.getArrayBuffer())
2370         {
2371             replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
2372             cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
2373         }
2374 
2375         if (buffer->isImmutable())
2376         {
2377             cap(CaptureBufferStorageEXT(replayState, true, gl::BufferBinding::Array,
2378                                         static_cast<GLsizeiptr>(buffer->getSize()),
2379                                         buffer->getMapPointer(),
2380                                         buffer->getStorageExtUsageFlags()));
2381         }
2382         else
2383         {
2384             cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
2385                                   static_cast<GLsizeiptr>(buffer->getSize()),
2386                                   buffer->getMapPointer(), buffer->getUsage()));
2387         }
2388 
2389         if (bufferMapped)
2390         {
2391             void *dontCare = nullptr;
2392             Capture(setupCalls,
2393                     CaptureMapBufferRange(replayState, true, gl::BufferBinding::Array,
2394                                           static_cast<GLsizeiptr>(buffer->getMapOffset()),
2395                                           static_cast<GLsizeiptr>(buffer->getMapLength()),
2396                                           buffer->getAccessFlags(), dontCare));
2397 
2398             resourceTracker->setStartingBufferMapped(buffer->id(), true);
2399 
2400             frameCaptureShared->trackBufferMapping(
2401                 &setupCalls->back(), buffer->id(), static_cast<GLsizeiptr>(buffer->getMapOffset()),
2402                 static_cast<GLsizeiptr>(buffer->getMapLength()),
2403                 (buffer->getAccessFlags() & GL_MAP_WRITE_BIT) != 0);
2404         }
2405         else
2406         {
2407             resourceTracker->setStartingBufferMapped(buffer->id(), false);
2408         }
2409 
2410         // Generate the calls needed to restore this buffer to original state for frame looping
2411         CaptureBufferResetCalls(replayState, resourceTracker, &id, buffer);
2412 
2413         // Unmap the buffer if it wasn't already mapped
2414         if (!bufferMapped)
2415         {
2416             GLboolean dontCare;
2417             (void)buffer->unmap(context, &dontCare);
2418         }
2419     }
2420 
2421     // Capture Texture setup and data.
2422     const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
2423 
2424     for (const auto &textureIter : textures)
2425     {
2426         gl::TextureID id     = {textureIter.first};
2427         gl::Texture *texture = textureIter.second;
2428 
2429         if (id.value == 0)
2430         {
2431             continue;
2432         }
2433 
2434         // Gen the Texture.
2435         cap(CaptureGenTextures(replayState, true, 1, &id));
2436         MaybeCaptureUpdateResourceIDs(setupCalls);
2437 
2438         cap(CaptureBindTexture(replayState, true, texture->getType(), id));
2439 
2440         // Capture sampler parameter states.
2441         // TODO(jmadill): More sampler / texture states. http://anglebug.com/3662
2442         gl::SamplerState defaultSamplerState =
2443             gl::SamplerState::CreateDefaultForTarget(texture->getType());
2444         const gl::SamplerState &textureSamplerState = texture->getSamplerState();
2445 
2446         auto capTexParam = [cap, &replayState, texture](GLenum pname, GLint param) {
2447             cap(CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
2448         };
2449 
2450         auto capTexParamf = [cap, &replayState, texture](GLenum pname, GLfloat param) {
2451             cap(CaptureTexParameterf(replayState, true, texture->getType(), pname, param));
2452         };
2453 
2454         if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
2455         {
2456             capTexParam(GL_TEXTURE_MIN_FILTER, textureSamplerState.getMinFilter());
2457         }
2458 
2459         if (textureSamplerState.getMagFilter() != defaultSamplerState.getMagFilter())
2460         {
2461             capTexParam(GL_TEXTURE_MAG_FILTER, textureSamplerState.getMagFilter());
2462         }
2463 
2464         if (textureSamplerState.getWrapR() != defaultSamplerState.getWrapR())
2465         {
2466             capTexParam(GL_TEXTURE_WRAP_R, textureSamplerState.getWrapR());
2467         }
2468 
2469         if (textureSamplerState.getWrapS() != defaultSamplerState.getWrapS())
2470         {
2471             capTexParam(GL_TEXTURE_WRAP_S, textureSamplerState.getWrapS());
2472         }
2473 
2474         if (textureSamplerState.getWrapT() != defaultSamplerState.getWrapT())
2475         {
2476             capTexParam(GL_TEXTURE_WRAP_T, textureSamplerState.getWrapT());
2477         }
2478 
2479         if (textureSamplerState.getMinLod() != defaultSamplerState.getMinLod())
2480         {
2481             capTexParamf(GL_TEXTURE_MIN_LOD, textureSamplerState.getMinLod());
2482         }
2483 
2484         if (textureSamplerState.getMaxLod() != defaultSamplerState.getMaxLod())
2485         {
2486             capTexParamf(GL_TEXTURE_MAX_LOD, textureSamplerState.getMaxLod());
2487         }
2488 
2489         if (textureSamplerState.getCompareMode() != defaultSamplerState.getCompareMode())
2490         {
2491             capTexParam(GL_TEXTURE_COMPARE_MODE, textureSamplerState.getCompareMode());
2492         }
2493 
2494         if (textureSamplerState.getCompareFunc() != defaultSamplerState.getCompareFunc())
2495         {
2496             capTexParam(GL_TEXTURE_COMPARE_FUNC, textureSamplerState.getCompareFunc());
2497         }
2498 
2499         // Texture parameters
2500         if (texture->getSwizzleRed() != GL_RED)
2501         {
2502             capTexParam(GL_TEXTURE_SWIZZLE_R, texture->getSwizzleRed());
2503         }
2504 
2505         if (texture->getSwizzleGreen() != GL_GREEN)
2506         {
2507             capTexParam(GL_TEXTURE_SWIZZLE_G, texture->getSwizzleGreen());
2508         }
2509 
2510         if (texture->getSwizzleBlue() != GL_BLUE)
2511         {
2512             capTexParam(GL_TEXTURE_SWIZZLE_B, texture->getSwizzleBlue());
2513         }
2514 
2515         if (texture->getSwizzleAlpha() != GL_ALPHA)
2516         {
2517             capTexParam(GL_TEXTURE_SWIZZLE_A, texture->getSwizzleAlpha());
2518         }
2519 
2520         if (texture->getBaseLevel() != 0)
2521         {
2522             capTexParam(GL_TEXTURE_BASE_LEVEL, texture->getBaseLevel());
2523         }
2524 
2525         if (texture->getMaxLevel() != 1000)
2526         {
2527             capTexParam(GL_TEXTURE_MAX_LEVEL, texture->getMaxLevel());
2528         }
2529 
2530         // If the texture is immutable, initialize it with TexStorage
2531         if (texture->getImmutableFormat())
2532         {
2533             CaptureTextureStorage(setupCalls, &replayState, texture);
2534         }
2535 
2536         // Iterate texture levels and layers.
2537         gl::ImageIndexIterator imageIter = gl::ImageIndexIterator::MakeGeneric(
2538             texture->getType(), 0, texture->getMipmapMaxLevel() + 1, gl::ImageIndex::kEntireLevel,
2539             gl::ImageIndex::kEntireLevel);
2540         while (imageIter.hasNext())
2541         {
2542             gl::ImageIndex index = imageIter.next();
2543 
2544             const gl::ImageDesc &desc = texture->getTextureState().getImageDesc(index);
2545 
2546             if (desc.size.empty())
2547             {
2548                 continue;
2549             }
2550 
2551             const gl::InternalFormat &format = *desc.format.info;
2552 
2553             // Check for supported textures
2554             ASSERT(index.getType() == gl::TextureType::_2D ||
2555                    index.getType() == gl::TextureType::_3D ||
2556                    index.getType() == gl::TextureType::_2DArray ||
2557                    index.getType() == gl::TextureType::Buffer ||
2558                    index.getType() == gl::TextureType::CubeMap ||
2559                    index.getType() == gl::TextureType::CubeMapArray);
2560 
2561             if (index.getType() == gl::TextureType::Buffer)
2562             {
2563                 // The buffer contents are already backed up, but we need to emit the TexBuffer
2564                 // binding calls
2565                 CaptureTextureContents(setupCalls, &replayState, texture, index, desc, 0, 0);
2566 
2567                 continue;
2568             }
2569 
2570             if (format.compressed)
2571             {
2572                 // For compressed images, we've tracked a copy of the incoming data, so we can
2573                 // use that rather than try to read data back that may have been converted.
2574                 const std::vector<uint8_t> &capturedTextureLevel =
2575                     context->getShareGroup()->getFrameCaptureShared()->retrieveCachedTextureLevel(
2576                         texture->id(), index.getTarget(), index.getLevelIndex());
2577 
2578                 // Use the shadow copy of the data to populate the call
2579                 CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2580                                        static_cast<GLuint>(capturedTextureLevel.size()),
2581                                        capturedTextureLevel.data());
2582             }
2583             else
2584             {
2585                 // Use ANGLE_get_image to read back pixel data.
2586                 if (context->getExtensions().getImageANGLE)
2587                 {
2588                     GLenum getFormat = format.format;
2589                     GLenum getType   = format.type;
2590 
2591                     angle::MemoryBuffer data;
2592 
2593                     const gl::Extents size(desc.size.width, desc.size.height, desc.size.depth);
2594                     const gl::PixelUnpackState &unpack = apiState.getUnpackState();
2595 
2596                     GLuint endByte = 0;
2597                     bool unpackSize =
2598                         format.computePackUnpackEndByte(getType, size, unpack, true, &endByte);
2599                     ASSERT(unpackSize);
2600 
2601                     bool result = data.resize(endByte);
2602                     ASSERT(result);
2603 
2604                     gl::PixelPackState packState;
2605                     packState.alignment = 1;
2606 
2607                     (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
2608                                                index.getLevelIndex(), getFormat, getType,
2609                                                data.data());
2610 
2611                     CaptureTextureContents(setupCalls, &replayState, texture, index, desc,
2612                                            static_cast<GLuint>(data.size()), data.data());
2613                 }
2614                 else
2615                 {
2616                     CaptureTextureContents(setupCalls, &replayState, texture, index, desc, 0,
2617                                            nullptr);
2618                 }
2619             }
2620         }
2621     }
2622 
2623     // Capture Renderbuffers.
2624     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
2625 
2626     for (const auto &renderbufIter : renderbuffers)
2627     {
2628         gl::RenderbufferID id                = {renderbufIter.first};
2629         const gl::Renderbuffer *renderbuffer = renderbufIter.second;
2630 
2631         // Generate renderbuffer id.
2632         cap(CaptureGenRenderbuffers(replayState, true, 1, &id));
2633         MaybeCaptureUpdateResourceIDs(setupCalls);
2634         cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
2635 
2636         GLenum internalformat = renderbuffer->getFormat().info->internalFormat;
2637 
2638         if (renderbuffer->getSamples() > 0)
2639         {
2640             // Note: We could also use extensions if available.
2641             cap(CaptureRenderbufferStorageMultisample(
2642                 replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat,
2643                 renderbuffer->getWidth(), renderbuffer->getHeight()));
2644         }
2645         else
2646         {
2647             cap(CaptureRenderbufferStorage(replayState, true, GL_RENDERBUFFER, internalformat,
2648                                            renderbuffer->getWidth(), renderbuffer->getHeight()));
2649         }
2650 
2651         // TODO(jmadill): Capture renderbuffer contents. http://anglebug.com/3662
2652     }
2653 
2654     // Capture Shaders and Programs.
2655     const gl::ShaderProgramManager &shadersAndPrograms =
2656         apiState.getShaderProgramManagerForCapture();
2657     const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
2658         shadersAndPrograms.getShadersForCapture();
2659     const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
2660         shadersAndPrograms.getProgramsForCaptureAndPerf();
2661 
2662     // Capture Program binary state. Use max ID as a temporary shader ID.
2663     gl::ShaderProgramID tempShaderID = {resourceTracker->getMaxShaderPrograms()};
2664     for (const auto &programIter : programs)
2665     {
2666         gl::ShaderProgramID id     = {programIter.first};
2667         const gl::Program *program = programIter.second;
2668 
2669         // Unlinked programs don't have an executable. Thus they don't need to be captured.
2670         // Programs are shared by contexts in the share group and only need to be captured once.
2671         if (!program->isLinked())
2672         {
2673             continue;
2674         }
2675 
2676         // Get last linked shader source.
2677         const ProgramSources &linkedSources =
2678             context->getShareGroup()->getFrameCaptureShared()->getProgramSources(id);
2679 
2680         cap(CaptureCreateProgram(replayState, true, id.value));
2681 
2682         // Compile with last linked sources.
2683         for (gl::ShaderType shaderType : program->getExecutable().getLinkedShaderStages())
2684         {
2685             const std::string &sourceString = linkedSources[shaderType];
2686             const char *sourcePointer       = sourceString.c_str();
2687 
2688             // Compile and attach the temporary shader. Then free it immediately.
2689             cap(CaptureCreateShader(replayState, true, shaderType, tempShaderID.value));
2690             cap(CaptureShaderSource(replayState, true, tempShaderID, 1, &sourcePointer, nullptr));
2691             cap(CaptureCompileShader(replayState, true, tempShaderID));
2692             cap(CaptureAttachShader(replayState, true, id, tempShaderID));
2693             cap(CaptureDeleteShader(replayState, true, tempShaderID));
2694         }
2695 
2696         // Gather XFB varyings
2697         std::vector<std::string> xfbVaryings;
2698         for (const gl::TransformFeedbackVarying &xfbVarying :
2699              program->getState().getLinkedTransformFeedbackVaryings())
2700         {
2701             xfbVaryings.push_back(xfbVarying.nameWithArrayIndex());
2702         }
2703 
2704         if (!xfbVaryings.empty())
2705         {
2706             std::vector<const char *> varyingsStrings;
2707             for (const std::string &varyingString : xfbVaryings)
2708             {
2709                 varyingsStrings.push_back(varyingString.data());
2710             }
2711 
2712             GLenum xfbMode = program->getState().getTransformFeedbackBufferMode();
2713             cap(CaptureTransformFeedbackVaryings(replayState, true, id,
2714                                                  static_cast<GLint>(xfbVaryings.size()),
2715                                                  varyingsStrings.data(), xfbMode));
2716         }
2717 
2718         // Force the attributes to be bound the same way as in the existing program.
2719         // This can affect attributes that are optimized out in some implementations.
2720         for (const sh::ShaderVariable &attrib : program->getState().getProgramInputs())
2721         {
2722             if (gl::IsBuiltInName(attrib.name))
2723             {
2724                 // Don't try to bind built-in attributes
2725                 continue;
2726             }
2727 
2728             // Separable programs may not have a VS, meaning it may not have attributes.
2729             if (program->getExecutable().hasLinkedShaderStage(gl::ShaderType::Vertex))
2730             {
2731                 ASSERT(attrib.location != -1);
2732                 cap(CaptureBindAttribLocation(replayState, true, id,
2733                                               static_cast<GLuint>(attrib.location),
2734                                               attrib.name.c_str()));
2735             }
2736         }
2737 
2738         if (program->isSeparable())
2739         {
2740             // MEC manually recreates separable programs, rather than attempting to recreate a call
2741             // to glCreateShaderProgramv(), so insert a call to mark it separable.
2742             cap(CaptureProgramParameteri(replayState, true, id, GL_PROGRAM_SEPARABLE, GL_TRUE));
2743         }
2744 
2745         cap(CaptureLinkProgram(replayState, true, id));
2746         CaptureUpdateUniformLocations(program, setupCalls);
2747         CaptureUpdateUniformValues(replayState, context, program, setupCalls);
2748         CaptureUpdateUniformBlockIndexes(program, setupCalls);
2749 
2750         // Capture uniform block bindings for each program
2751         for (unsigned int uniformBlockIndex = 0;
2752              uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
2753         {
2754             GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
2755             cap(CaptureUniformBlockBinding(replayState, true, id, {uniformBlockIndex},
2756                                            blockBinding));
2757         }
2758 
2759         resourceTracker->onShaderProgramAccess(id);
2760         resourceTracker->getStartingPrograms().insert(id);
2761     }
2762 
2763     // Handle shaders.
2764     for (const auto &shaderIter : shaders)
2765     {
2766         gl::ShaderProgramID id = {shaderIter.first};
2767         gl::Shader *shader     = shaderIter.second;
2768 
2769         // Skip shaders scheduled for deletion.
2770         // Shaders are shared by contexts in the share group and only need to be captured once.
2771         if (shader->hasBeenDeleted())
2772         {
2773             continue;
2774         }
2775 
2776         cap(CaptureCreateShader(replayState, true, shader->getType(), id.value));
2777 
2778         std::string shaderSource  = shader->getSourceString();
2779         const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
2780 
2781         // This does not handle some more tricky situations like attaching shaders to a non-linked
2782         // program. Or attaching uncompiled shaders. Or attaching and then deleting a shader.
2783         // TODO(jmadill): Handle trickier program uses. http://anglebug.com/3662
2784         if (shader->isCompiled())
2785         {
2786             const std::string &capturedSource =
2787                 context->getShareGroup()->getFrameCaptureShared()->getShaderSource(id);
2788             if (capturedSource != shaderSource)
2789             {
2790                 ASSERT(!capturedSource.empty());
2791                 sourcePointer = capturedSource.c_str();
2792             }
2793 
2794             cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2795             cap(CaptureCompileShader(replayState, true, id));
2796         }
2797 
2798         if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str()))
2799         {
2800             cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
2801         }
2802     }
2803 
2804     // Capture Sampler Objects
2805     const gl::SamplerManager &samplers = apiState.getSamplerManagerForCapture();
2806     for (const auto &samplerIter : samplers)
2807     {
2808         gl::SamplerID samplerID = {samplerIter.first};
2809 
2810         // Don't gen the sampler if we've seen it before, since they are shared across the context
2811         // share group.
2812         cap(CaptureGenSamplers(replayState, true, 1, &samplerID));
2813         MaybeCaptureUpdateResourceIDs(setupCalls);
2814 
2815         gl::Sampler *sampler = samplerIter.second;
2816         if (!sampler)
2817         {
2818             continue;
2819         }
2820 
2821         gl::SamplerState defaultSamplerState;
2822         if (sampler->getMinFilter() != defaultSamplerState.getMinFilter())
2823         {
2824             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MIN_FILTER,
2825                                          sampler->getMinFilter()));
2826         }
2827         if (sampler->getMagFilter() != defaultSamplerState.getMagFilter())
2828         {
2829             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_MAG_FILTER,
2830                                          sampler->getMagFilter()));
2831         }
2832         if (sampler->getWrapS() != defaultSamplerState.getWrapS())
2833         {
2834             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_S,
2835                                          sampler->getWrapS()));
2836         }
2837         if (sampler->getWrapR() != defaultSamplerState.getWrapR())
2838         {
2839             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_R,
2840                                          sampler->getWrapR()));
2841         }
2842         if (sampler->getWrapT() != defaultSamplerState.getWrapT())
2843         {
2844             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_WRAP_T,
2845                                          sampler->getWrapT()));
2846         }
2847         if (sampler->getMinLod() != defaultSamplerState.getMinLod())
2848         {
2849             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MIN_LOD,
2850                                          sampler->getMinLod()));
2851         }
2852         if (sampler->getMaxLod() != defaultSamplerState.getMaxLod())
2853         {
2854             cap(CaptureSamplerParameterf(replayState, true, samplerID, GL_TEXTURE_MAX_LOD,
2855                                          sampler->getMaxLod()));
2856         }
2857         if (sampler->getCompareMode() != defaultSamplerState.getCompareMode())
2858         {
2859             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_MODE,
2860                                          sampler->getCompareMode()));
2861         }
2862         if (sampler->getCompareFunc() != defaultSamplerState.getCompareFunc())
2863         {
2864             cap(CaptureSamplerParameteri(replayState, true, samplerID, GL_TEXTURE_COMPARE_FUNC,
2865                                          sampler->getCompareFunc()));
2866         }
2867     }
2868 
2869     // Capture Sync Objects
2870     const gl::SyncManager &syncs = apiState.getSyncManagerForCapture();
2871     for (const auto &syncIter : syncs)
2872     {
2873         GLsync syncID        = gl::bitCast<GLsync>(static_cast<size_t>(syncIter.first));
2874         const gl::Sync *sync = syncIter.second;
2875 
2876         if (!sync)
2877         {
2878             continue;
2879         }
2880         cap(CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
2881         CaptureFenceSyncResetCalls(replayState, resourceTracker, syncID, sync);
2882         resourceTracker->getStartingFenceSyncs().insert(syncID);
2883     }
2884 
2885     // Allow the replayState object to be destroyed conveniently.
2886     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
2887 }
2888 
CaptureMidExecutionSetup(const gl::Context * context,std::vector<CallCapture> * setupCalls,ResourceTracker * resourceTracker)2889 void CaptureMidExecutionSetup(const gl::Context *context,
2890                               std::vector<CallCapture> *setupCalls,
2891                               ResourceTracker *resourceTracker)
2892 {
2893     const gl::State &apiState = context->getState();
2894     gl::State replayState(nullptr, nullptr, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
2895                           context->getState().getClientVersion(), false, true, true, true, false,
2896                           EGL_CONTEXT_PRIORITY_MEDIUM_IMG, apiState.hasProtectedContent());
2897 
2898     // Small helper function to make the code more readable.
2899     auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
2900 
2901     // Currently this code assumes we can use create-on-bind. It does not support 'Gen' usage.
2902     // TODO(jmadill): Use handle mapping for captured objects. http://anglebug.com/3662
2903 
2904     // Vertex input states. Only handles GLES 2.0 states right now.
2905     // Must happen after buffer data initialization.
2906     // TODO(http://anglebug.com/3662): Complete state capture.
2907 
2908     // Capture default vertex attribs. Do not capture on GLES1.
2909     if (!context->isGLES1())
2910     {
2911         CaptureDefaultVertexAttribs(replayState, apiState, setupCalls);
2912     }
2913 
2914     // Capture vertex array objects
2915     const gl::VertexArrayMap &vertexArrayMap = context->getVertexArraysForCapture();
2916     gl::VertexArrayID boundVertexArrayID     = {0};
2917     for (const auto &vertexArrayIter : vertexArrayMap)
2918     {
2919         gl::VertexArrayID vertexArrayID = {vertexArrayIter.first};
2920         if (vertexArrayID.value != 0)
2921         {
2922             cap(CaptureGenVertexArrays(replayState, true, 1, &vertexArrayID));
2923             MaybeCaptureUpdateResourceIDs(setupCalls);
2924         }
2925 
2926         if (vertexArrayIter.second)
2927         {
2928             const gl::VertexArray *vertexArray = vertexArrayIter.second;
2929 
2930             // Bind the vertexArray (unless default) and populate it
2931             if (vertexArrayID.value != 0)
2932             {
2933                 cap(CaptureBindVertexArray(replayState, true, vertexArrayID));
2934                 boundVertexArrayID = vertexArrayID;
2935             }
2936             CaptureVertexArrayData(setupCalls, context, vertexArray, &replayState);
2937         }
2938     }
2939 
2940     // Bind the current vertex array
2941     const gl::VertexArray *currentVertexArray = apiState.getVertexArray();
2942     if (currentVertexArray->id() != boundVertexArrayID)
2943     {
2944         cap(CaptureBindVertexArray(replayState, true, currentVertexArray->id()));
2945     }
2946 
2947     // Capture indexed buffer bindings.
2948     const gl::BufferVector &uniformIndexedBuffers =
2949         apiState.getOffsetBindingPointerUniformBuffers();
2950     const gl::BufferVector &atomicCounterIndexedBuffers =
2951         apiState.getOffsetBindingPointerAtomicCounterBuffers();
2952     const gl::BufferVector &shaderStorageIndexedBuffers =
2953         apiState.getOffsetBindingPointerShaderStorageBuffers();
2954     CaptureIndexedBuffers(replayState, uniformIndexedBuffers, gl::BufferBinding::Uniform,
2955                           setupCalls);
2956     CaptureIndexedBuffers(replayState, atomicCounterIndexedBuffers,
2957                           gl::BufferBinding::AtomicCounter, setupCalls);
2958     CaptureIndexedBuffers(replayState, shaderStorageIndexedBuffers,
2959                           gl::BufferBinding::ShaderStorage, setupCalls);
2960 
2961     // Capture Buffer bindings.
2962     const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
2963     for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
2964     {
2965         gl::BufferID bufferID = boundBuffers[binding].id();
2966 
2967         // Filter out redundant buffer binding commands. Note that the code in the previous section
2968         // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
2969         // we set earlier.
2970         bool isArray                  = binding == gl::BufferBinding::Array;
2971         const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
2972         if ((isArray && arrayBuffer && arrayBuffer->id() != bufferID) ||
2973             (!isArray && bufferID.value != 0))
2974         {
2975             cap(CaptureBindBuffer(replayState, true, binding, bufferID));
2976         }
2977 
2978         // Restore all buffer bindings for Reset
2979         if (bufferID.value != 0)
2980         {
2981             CaptureBufferBindingResetCalls(replayState, resourceTracker, binding, bufferID);
2982         }
2983     }
2984 
2985     // Set a unpack alignment of 1.
2986     gl::PixelUnpackState &currentUnpackState = replayState.getUnpackState();
2987     if (currentUnpackState.alignment != 1)
2988     {
2989         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
2990         currentUnpackState.alignment = 1;
2991     }
2992 
2993     // Capture Texture setup and data.
2994     const gl::TextureBindingMap &boundTextures = apiState.getBoundTexturesForCapture();
2995 
2996     // Set Texture bindings.
2997     size_t currentActiveTexture = 0;
2998     gl::TextureTypeMap<gl::TextureID> currentTextureBindings;
2999     for (gl::TextureType textureType : angle::AllEnums<gl::TextureType>())
3000     {
3001         const gl::TextureBindingVector &bindings = boundTextures[textureType];
3002         for (size_t bindingIndex = 0; bindingIndex < bindings.size(); ++bindingIndex)
3003         {
3004             gl::TextureID textureID = bindings[bindingIndex].id();
3005 
3006             if (textureID.value != 0)
3007             {
3008                 if (currentActiveTexture != bindingIndex)
3009                 {
3010                     cap(CaptureActiveTexture(replayState, true,
3011                                              GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
3012                     currentActiveTexture = bindingIndex;
3013                 }
3014 
3015                 if (currentTextureBindings[textureType] != textureID)
3016                 {
3017                     cap(CaptureBindTexture(replayState, true, textureType, textureID));
3018                     currentTextureBindings[textureType] = textureID;
3019                 }
3020             }
3021         }
3022     }
3023 
3024     // Set active Texture.
3025     size_t stateActiveTexture = apiState.getActiveSampler();
3026     if (currentActiveTexture != stateActiveTexture)
3027     {
3028         cap(CaptureActiveTexture(replayState, true,
3029                                  GL_TEXTURE0 + static_cast<GLenum>(stateActiveTexture)));
3030     }
3031 
3032     // Set Renderbuffer binding.
3033     const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
3034     gl::RenderbufferID currentRenderbuffer       = {0};
3035     for (const auto &renderbufIter : renderbuffers)
3036     {
3037         currentRenderbuffer = renderbufIter.second->id();
3038     }
3039 
3040     if (currentRenderbuffer != apiState.getRenderbufferId())
3041     {
3042         cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER,
3043                                     apiState.getRenderbufferId()));
3044     }
3045 
3046     // Capture Framebuffers.
3047     const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
3048 
3049     gl::FramebufferID currentDrawFramebuffer = {0};
3050     gl::FramebufferID currentReadFramebuffer = {0};
3051 
3052     for (const auto &framebufferIter : framebuffers)
3053     {
3054         gl::FramebufferID id               = {framebufferIter.first};
3055         const gl::Framebuffer *framebuffer = framebufferIter.second;
3056 
3057         // The default Framebuffer exists (by default).
3058         if (framebuffer->isDefault())
3059         {
3060             continue;
3061         }
3062 
3063         cap(CaptureGenFramebuffers(replayState, true, 1, &id));
3064         MaybeCaptureUpdateResourceIDs(setupCalls);
3065         cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
3066         currentDrawFramebuffer = currentReadFramebuffer = id;
3067 
3068         // Color Attachments.
3069         for (const gl::FramebufferAttachment &colorAttachment : framebuffer->getColorAttachments())
3070         {
3071             if (!colorAttachment.isAttached())
3072             {
3073                 continue;
3074             }
3075 
3076             CaptureFramebufferAttachment(setupCalls, replayState, colorAttachment);
3077         }
3078 
3079         const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
3080         if (depthAttachment)
3081         {
3082             ASSERT(depthAttachment->getBinding() == GL_DEPTH_ATTACHMENT ||
3083                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
3084             CaptureFramebufferAttachment(setupCalls, replayState, *depthAttachment);
3085         }
3086 
3087         const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
3088         if (stencilAttachment)
3089         {
3090             ASSERT(stencilAttachment->getBinding() == GL_STENCIL_ATTACHMENT ||
3091                    depthAttachment->getBinding() == GL_DEPTH_STENCIL_ATTACHMENT);
3092             CaptureFramebufferAttachment(setupCalls, replayState, *stencilAttachment);
3093         }
3094 
3095         const std::vector<GLenum> &drawBufferStates = framebuffer->getDrawBufferStates();
3096         cap(CaptureDrawBuffers(replayState, true, static_cast<GLsizei>(drawBufferStates.size()),
3097                                drawBufferStates.data()));
3098     }
3099 
3100     // Capture framebuffer bindings.
3101     gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
3102     gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
3103     if (stateDrawFramebuffer == stateReadFramebuffer)
3104     {
3105         if (currentDrawFramebuffer != stateDrawFramebuffer ||
3106             currentReadFramebuffer != stateReadFramebuffer)
3107         {
3108             cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, stateDrawFramebuffer));
3109             currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
3110         }
3111     }
3112     else
3113     {
3114         if (currentDrawFramebuffer != stateDrawFramebuffer)
3115         {
3116             cap(CaptureBindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
3117                                        currentDrawFramebuffer));
3118             currentDrawFramebuffer = stateDrawFramebuffer;
3119         }
3120 
3121         if (currentReadFramebuffer != stateReadFramebuffer)
3122         {
3123             cap(CaptureBindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
3124                                        replayState.getReadFramebuffer()->id()));
3125             currentReadFramebuffer = stateReadFramebuffer;
3126         }
3127     }
3128 
3129     // Capture Program Pipelines
3130     const gl::ProgramPipelineManager *programPipelineManager =
3131         apiState.getProgramPipelineManagerForCapture();
3132 
3133     for (const auto &ppoIterator : *programPipelineManager)
3134     {
3135         gl::ProgramPipeline *pipeline = ppoIterator.second;
3136         gl::ProgramPipelineID id      = {ppoIterator.first};
3137         cap(CaptureGenProgramPipelines(replayState, true, 1, &id));
3138         MaybeCaptureUpdateResourceIDs(setupCalls);
3139 
3140         // PPOs can contain graphics and compute programs, so loop through all shader types rather
3141         // than just the linked ones since getLinkedShaderStages() will return either only graphics
3142         // or compute stages.
3143         for (gl::ShaderType shaderType : gl::AllShaderTypes())
3144         {
3145             gl::Program *program = pipeline->getShaderProgram(shaderType);
3146             if (!program)
3147             {
3148                 continue;
3149             }
3150             ASSERT(program->isLinked());
3151             GLbitfield gLbitfield = GetBitfieldFromShaderType(shaderType);
3152             cap(CaptureUseProgramStages(replayState, true, pipeline->id(), gLbitfield,
3153                                         program->id()));
3154         }
3155 
3156         gl::Program *program = pipeline->getActiveShaderProgram();
3157         if (program)
3158         {
3159             cap(CaptureActiveShaderProgram(replayState, true, id, program->id()));
3160         }
3161     }
3162 
3163     // For now we assume the installed program executable is the same as the current program.
3164     // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
3165     if (apiState.getProgram() && !context->isGLES1())
3166     {
3167         cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
3168         CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
3169     }
3170     else if (apiState.getProgramPipeline())
3171     {
3172         // glUseProgram() is called above to update the necessary uniform values for each program
3173         // that's being recreated. If there is no program currently bound, then we need to unbind
3174         // the last bound program so the PPO will be used instead:
3175         // 7.4 Program Pipeline Objects
3176         // If no current program object has been established by UseProgram, the program objects used
3177         // for each shader stage and for uniform updates are taken from the bound program pipeline
3178         // object, if any. If there is a current program object established by UseProgram, the bound
3179         // program pipeline object has no effect on rendering or uniform updates.
3180         cap(CaptureUseProgram(replayState, true, {0}));
3181         CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
3182         cap(CaptureBindProgramPipeline(replayState, true, apiState.getProgramPipeline()->id()));
3183     }
3184 
3185     // TODO(http://anglebug.com/3662): ES 3.x objects.
3186 
3187     // Create existing queries. Note that queries may be genned and not yet started. In that
3188     // case the queries will exist in the query map as nullptr entries.
3189     const gl::QueryMap &queryMap = context->getQueriesForCapture();
3190     for (gl::QueryMap::Iterator queryIter = queryMap.beginWithNull();
3191          queryIter != queryMap.endWithNull(); ++queryIter)
3192     {
3193         ASSERT(queryIter->first);
3194         gl::QueryID queryID = {queryIter->first};
3195 
3196         cap(CaptureGenQueries(replayState, true, 1, &queryID));
3197         MaybeCaptureUpdateResourceIDs(setupCalls);
3198 
3199         gl::Query *query = queryIter->second;
3200         if (query)
3201         {
3202             gl::QueryType queryType = query->getType();
3203 
3204             // Begin the query to generate the object
3205             cap(CaptureBeginQuery(replayState, true, queryType, queryID));
3206 
3207             // End the query if it was not active
3208             if (!IsQueryActive(apiState, queryID))
3209             {
3210                 cap(CaptureEndQuery(replayState, true, queryType));
3211             }
3212         }
3213     }
3214 
3215     // Transform Feedback
3216     const gl::TransformFeedbackMap &xfbMap = context->getTransformFeedbacksForCapture();
3217     for (const auto &xfbIter : xfbMap)
3218     {
3219         gl::TransformFeedbackID xfbID = {xfbIter.first};
3220 
3221         // Do not capture the default XFB object.
3222         if (xfbID.value == 0)
3223         {
3224             continue;
3225         }
3226 
3227         cap(CaptureGenTransformFeedbacks(replayState, true, 1, &xfbID));
3228         MaybeCaptureUpdateResourceIDs(setupCalls);
3229 
3230         gl::TransformFeedback *xfb = xfbIter.second;
3231         if (!xfb)
3232         {
3233             // The object was never created
3234             continue;
3235         }
3236 
3237         // Bind XFB to create the object
3238         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK, xfbID));
3239 
3240         // Bind the buffers associated with this XFB object
3241         for (size_t i = 0; i < xfb->getIndexedBufferCount(); ++i)
3242         {
3243             const gl::OffsetBindingPointer<gl::Buffer> &xfbBuffer = xfb->getIndexedBuffer(i);
3244 
3245             // Note: Buffers bound with BindBufferBase can be used with BindBuffer
3246             cap(CaptureBindBufferRange(replayState, true, gl::BufferBinding::TransformFeedback, 0,
3247                                        xfbBuffer.id(), xfbBuffer.getOffset(), xfbBuffer.getSize()));
3248         }
3249 
3250         if (xfb->isActive() || xfb->isPaused())
3251         {
3252             // We don't support active XFB in MEC yet
3253             UNIMPLEMENTED();
3254         }
3255     }
3256 
3257     // Bind the current XFB buffer after populating XFB objects
3258     gl::TransformFeedback *currentXFB = apiState.getCurrentTransformFeedback();
3259     if (currentXFB)
3260     {
3261         cap(CaptureBindTransformFeedback(replayState, true, GL_TRANSFORM_FEEDBACK,
3262                                          currentXFB->id()));
3263     }
3264 
3265     // Bind samplers
3266     const gl::SamplerBindingVector &samplerBindings = apiState.getSamplers();
3267     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(samplerBindings.size());
3268          ++bindingIndex)
3269     {
3270         gl::SamplerID samplerID = samplerBindings[bindingIndex].id();
3271         if (samplerID.value != 0)
3272         {
3273             cap(CaptureBindSampler(replayState, true, bindingIndex, samplerID));
3274         }
3275     }
3276 
3277     // Capture Image Texture bindings
3278     const std::vector<gl::ImageUnit> &imageUnits = apiState.getImageUnits();
3279     for (GLuint bindingIndex = 0; bindingIndex < static_cast<GLuint>(imageUnits.size());
3280          ++bindingIndex)
3281     {
3282         const gl::ImageUnit &imageUnit = imageUnits[bindingIndex];
3283 
3284         if (imageUnit.texture == 0)
3285         {
3286             continue;
3287         }
3288 
3289         cap(CaptureBindImageTexture(replayState, true, bindingIndex, imageUnit.texture.id(),
3290                                     imageUnit.level, imageUnit.layered, imageUnit.layer,
3291                                     imageUnit.access, imageUnit.format));
3292     }
3293 
3294     // Capture GL Context states.
3295     // TODO(http://anglebug.com/3662): Complete state capture.
3296     auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
3297         if (capValue)
3298         {
3299             cap(CaptureEnable(replayState, true, capEnum));
3300         }
3301         else
3302         {
3303             cap(CaptureDisable(replayState, true, capEnum));
3304         }
3305     };
3306 
3307     // Capture GLES1 context states.
3308     if (context->isGLES1())
3309     {
3310         const bool currentTextureState = apiState.getEnableFeature(GL_TEXTURE_2D);
3311         const bool defaultTextureState = replayState.getEnableFeature(GL_TEXTURE_2D);
3312         if (currentTextureState != defaultTextureState)
3313         {
3314             capCap(GL_TEXTURE_2D, currentTextureState);
3315         }
3316     }
3317 
3318     // Rasterizer state. Missing ES 3.x features.
3319     const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
3320     const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
3321     if (currentRasterState.cullFace != defaultRasterState.cullFace)
3322     {
3323         capCap(GL_CULL_FACE, currentRasterState.cullFace);
3324     }
3325 
3326     if (currentRasterState.cullMode != defaultRasterState.cullMode)
3327     {
3328         cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
3329     }
3330 
3331     if (currentRasterState.frontFace != defaultRasterState.frontFace)
3332     {
3333         cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
3334     }
3335 
3336     if (currentRasterState.polygonOffsetFill != defaultRasterState.polygonOffsetFill)
3337     {
3338         capCap(GL_POLYGON_OFFSET_FILL, currentRasterState.polygonOffsetFill);
3339     }
3340 
3341     if (currentRasterState.polygonOffsetFactor != defaultRasterState.polygonOffsetFactor ||
3342         currentRasterState.polygonOffsetUnits != defaultRasterState.polygonOffsetUnits)
3343     {
3344         cap(CapturePolygonOffset(replayState, true, currentRasterState.polygonOffsetFactor,
3345                                  currentRasterState.polygonOffsetUnits));
3346     }
3347 
3348     // pointDrawMode/multiSample are only used in the D3D back-end right now.
3349 
3350     if (currentRasterState.rasterizerDiscard != defaultRasterState.rasterizerDiscard)
3351     {
3352         capCap(GL_RASTERIZER_DISCARD, currentRasterState.rasterizerDiscard);
3353     }
3354 
3355     if (currentRasterState.dither != defaultRasterState.dither)
3356     {
3357         capCap(GL_DITHER, currentRasterState.dither);
3358     }
3359 
3360     // Depth/stencil state.
3361     const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
3362     const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
3363     if (defaultDSState.depthFunc != currentDSState.depthFunc)
3364     {
3365         cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
3366     }
3367 
3368     if (defaultDSState.depthMask != currentDSState.depthMask)
3369     {
3370         cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
3371     }
3372 
3373     if (defaultDSState.depthTest != currentDSState.depthTest)
3374     {
3375         capCap(GL_DEPTH_TEST, currentDSState.depthTest);
3376     }
3377 
3378     if (defaultDSState.stencilTest != currentDSState.stencilTest)
3379     {
3380         capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
3381     }
3382 
3383     if (currentDSState.stencilFunc == currentDSState.stencilBackFunc &&
3384         currentDSState.stencilMask == currentDSState.stencilBackMask)
3385     {
3386         // Front and back are equal
3387         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
3388             defaultDSState.stencilMask != currentDSState.stencilMask ||
3389             apiState.getStencilRef() != 0)
3390         {
3391             cap(CaptureStencilFunc(replayState, true, currentDSState.stencilFunc,
3392                                    apiState.getStencilRef(), currentDSState.stencilMask));
3393         }
3394     }
3395     else
3396     {
3397         // Front and back are separate
3398         if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
3399             defaultDSState.stencilMask != currentDSState.stencilMask ||
3400             apiState.getStencilRef() != 0)
3401         {
3402             cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
3403                                            apiState.getStencilRef(), currentDSState.stencilMask));
3404         }
3405 
3406         if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
3407             defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
3408             apiState.getStencilBackRef() != 0)
3409         {
3410             cap(CaptureStencilFuncSeparate(
3411                 replayState, true, GL_BACK, currentDSState.stencilBackFunc,
3412                 apiState.getStencilBackRef(), currentDSState.stencilBackMask));
3413         }
3414     }
3415 
3416     if (currentDSState.stencilFail == currentDSState.stencilBackFail &&
3417         currentDSState.stencilPassDepthFail == currentDSState.stencilBackPassDepthFail &&
3418         currentDSState.stencilPassDepthPass == currentDSState.stencilBackPassDepthPass)
3419     {
3420         // Front and back are equal
3421         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
3422             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
3423             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
3424         {
3425             cap(CaptureStencilOp(replayState, true, currentDSState.stencilFail,
3426                                  currentDSState.stencilPassDepthFail,
3427                                  currentDSState.stencilPassDepthPass));
3428         }
3429     }
3430     else
3431     {
3432         // Front and back are separate
3433         if (defaultDSState.stencilFail != currentDSState.stencilFail ||
3434             defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
3435             defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
3436         {
3437             cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
3438                                          currentDSState.stencilPassDepthFail,
3439                                          currentDSState.stencilPassDepthPass));
3440         }
3441 
3442         if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
3443             defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
3444             defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
3445         {
3446             cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
3447                                          currentDSState.stencilBackPassDepthFail,
3448                                          currentDSState.stencilBackPassDepthPass));
3449         }
3450     }
3451 
3452     if (currentDSState.stencilWritemask == currentDSState.stencilBackWritemask)
3453     {
3454         // Front and back are equal
3455         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
3456         {
3457             cap(CaptureStencilMask(replayState, true, currentDSState.stencilWritemask));
3458         }
3459     }
3460     else
3461     {
3462         // Front and back are separate
3463         if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
3464         {
3465             cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
3466                                            currentDSState.stencilWritemask));
3467         }
3468 
3469         if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
3470         {
3471             cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
3472                                            currentDSState.stencilBackWritemask));
3473         }
3474     }
3475 
3476     // Blend state.
3477     const gl::BlendState &defaultBlendState = replayState.getBlendState();
3478     const gl::BlendState &currentBlendState = apiState.getBlendState();
3479 
3480     if (currentBlendState.blend != defaultBlendState.blend)
3481     {
3482         capCap(GL_BLEND, currentBlendState.blend);
3483     }
3484 
3485     if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
3486         currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
3487         currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
3488         currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
3489     {
3490         if (currentBlendState.sourceBlendRGB == currentBlendState.sourceBlendAlpha &&
3491             currentBlendState.destBlendRGB == currentBlendState.destBlendAlpha)
3492         {
3493             // Color and alpha are equal
3494             cap(CaptureBlendFunc(replayState, true, currentBlendState.sourceBlendRGB,
3495                                  currentBlendState.destBlendRGB));
3496         }
3497         else
3498         {
3499             // Color and alpha are separate
3500             cap(CaptureBlendFuncSeparate(
3501                 replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
3502                 currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
3503         }
3504     }
3505 
3506     if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
3507         currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
3508     {
3509         cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
3510                                          currentBlendState.blendEquationAlpha));
3511     }
3512 
3513     if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
3514         currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
3515         currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
3516         currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
3517     {
3518         cap(CaptureColorMask(replayState, true,
3519                              gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
3520                              gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
3521                              gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
3522                              gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
3523     }
3524 
3525     const gl::ColorF &currentBlendColor = apiState.getBlendColor();
3526     if (currentBlendColor != gl::ColorF())
3527     {
3528         cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
3529                               currentBlendColor.blue, currentBlendColor.alpha));
3530     }
3531 
3532     // Pixel storage states.
3533     gl::PixelPackState &currentPackState = replayState.getPackState();
3534     if (currentPackState.alignment != apiState.getPackAlignment())
3535     {
3536         cap(CapturePixelStorei(replayState, true, GL_PACK_ALIGNMENT, apiState.getPackAlignment()));
3537         currentPackState.alignment = apiState.getPackAlignment();
3538     }
3539 
3540     if (currentPackState.rowLength != apiState.getPackRowLength())
3541     {
3542         cap(CapturePixelStorei(replayState, true, GL_PACK_ROW_LENGTH, apiState.getPackRowLength()));
3543         currentPackState.rowLength = apiState.getPackRowLength();
3544     }
3545 
3546     if (currentPackState.skipRows != apiState.getPackSkipRows())
3547     {
3548         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_ROWS, apiState.getPackSkipRows()));
3549         currentPackState.skipRows = apiState.getPackSkipRows();
3550     }
3551 
3552     if (currentPackState.skipPixels != apiState.getPackSkipPixels())
3553     {
3554         cap(CapturePixelStorei(replayState, true, GL_PACK_SKIP_PIXELS,
3555                                apiState.getPackSkipPixels()));
3556         currentPackState.skipPixels = apiState.getPackSkipPixels();
3557     }
3558 
3559     // We set unpack alignment above, no need to change it here
3560     ASSERT(currentUnpackState.alignment == 1);
3561     if (currentUnpackState.rowLength != apiState.getUnpackRowLength())
3562     {
3563         cap(CapturePixelStorei(replayState, true, GL_UNPACK_ROW_LENGTH,
3564                                apiState.getUnpackRowLength()));
3565         currentUnpackState.rowLength = apiState.getUnpackRowLength();
3566     }
3567 
3568     if (currentUnpackState.skipRows != apiState.getUnpackSkipRows())
3569     {
3570         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_ROWS,
3571                                apiState.getUnpackSkipRows()));
3572         currentUnpackState.skipRows = apiState.getUnpackSkipRows();
3573     }
3574 
3575     if (currentUnpackState.skipPixels != apiState.getUnpackSkipPixels())
3576     {
3577         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_PIXELS,
3578                                apiState.getUnpackSkipPixels()));
3579         currentUnpackState.skipPixels = apiState.getUnpackSkipPixels();
3580     }
3581 
3582     if (currentUnpackState.imageHeight != apiState.getUnpackImageHeight())
3583     {
3584         cap(CapturePixelStorei(replayState, true, GL_UNPACK_IMAGE_HEIGHT,
3585                                apiState.getUnpackImageHeight()));
3586         currentUnpackState.imageHeight = apiState.getUnpackImageHeight();
3587     }
3588 
3589     if (currentUnpackState.skipImages != apiState.getUnpackSkipImages())
3590     {
3591         cap(CapturePixelStorei(replayState, true, GL_UNPACK_SKIP_IMAGES,
3592                                apiState.getUnpackSkipImages()));
3593         currentUnpackState.skipImages = apiState.getUnpackSkipImages();
3594     }
3595 
3596     // Clear state. Missing ES 3.x features.
3597     // TODO(http://anglebug.com/3662): Complete state capture.
3598     const gl::ColorF &currentClearColor = apiState.getColorClearValue();
3599     if (currentClearColor != gl::ColorF())
3600     {
3601         cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
3602                               currentClearColor.blue, currentClearColor.alpha));
3603     }
3604 
3605     if (apiState.getDepthClearValue() != 1.0f)
3606     {
3607         cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
3608     }
3609 
3610     if (apiState.getStencilClearValue() != 0)
3611     {
3612         cap(CaptureClearStencil(replayState, true, apiState.getStencilClearValue()));
3613     }
3614 
3615     // Viewport / scissor / clipping planes.
3616     const gl::Rectangle &currentViewport = apiState.getViewport();
3617     if (currentViewport != gl::Rectangle())
3618     {
3619         cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
3620                             currentViewport.width, currentViewport.height));
3621     }
3622 
3623     if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
3624     {
3625         cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
3626     }
3627 
3628     if (apiState.isScissorTestEnabled())
3629     {
3630         capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
3631     }
3632 
3633     const gl::Rectangle &currentScissor = apiState.getScissor();
3634     if (currentScissor != gl::Rectangle())
3635     {
3636         cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
3637                            currentScissor.width, currentScissor.height));
3638     }
3639 
3640     // Allow the replayState object to be destroyed conveniently.
3641     replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
3642 }
3643 
SkipCall(EntryPoint entryPoint)3644 bool SkipCall(EntryPoint entryPoint)
3645 {
3646     switch (entryPoint)
3647     {
3648         case EntryPoint::GLDebugMessageCallback:
3649         case EntryPoint::GLDebugMessageCallbackKHR:
3650         case EntryPoint::GLDebugMessageControl:
3651         case EntryPoint::GLDebugMessageControlKHR:
3652         case EntryPoint::GLDebugMessageInsert:
3653         case EntryPoint::GLDebugMessageInsertKHR:
3654         case EntryPoint::GLGetDebugMessageLog:
3655         case EntryPoint::GLGetDebugMessageLogKHR:
3656         case EntryPoint::GLGetObjectLabelEXT:
3657         case EntryPoint::GLGetObjectLabelKHR:
3658         case EntryPoint::GLGetObjectPtrLabelKHR:
3659         case EntryPoint::GLGetPointervKHR:
3660         case EntryPoint::GLInsertEventMarkerEXT:
3661         case EntryPoint::GLLabelObjectEXT:
3662         case EntryPoint::GLObjectLabelKHR:
3663         case EntryPoint::GLObjectPtrLabelKHR:
3664         case EntryPoint::GLPopDebugGroupKHR:
3665         case EntryPoint::GLPopGroupMarkerEXT:
3666         case EntryPoint::GLPushDebugGroupKHR:
3667         case EntryPoint::GLPushGroupMarkerEXT:
3668             // Purposefully skip entry points from:
3669             // - KHR_debug
3670             // - EXT_debug_label
3671             // - EXT_debug_marker
3672             // There is no need to capture these for replaying a trace in our harness
3673             return true;
3674 
3675         case EntryPoint::GLGetActiveUniform:
3676         case EntryPoint::GLGetActiveUniformsiv:
3677             // Skip these calls because:
3678             // - We don't use the return values.
3679             // - Active uniform counts can vary between platforms due to cross stage optimizations
3680             //   and asking about uniforms above GL_ACTIVE_UNIFORMS triggers errors.
3681             return true;
3682 
3683         default:
3684             break;
3685     }
3686 
3687     return false;
3688 }
3689 
FindShaderProgramIDInCall(const CallCapture & call,gl::ShaderProgramID * idOut)3690 bool FindShaderProgramIDInCall(const CallCapture &call, gl::ShaderProgramID *idOut)
3691 {
3692     for (const ParamCapture &param : call.params.getParamCaptures())
3693     {
3694         if (param.type == ParamType::TShaderProgramID && param.name == "programPacked")
3695         {
3696             *idOut = param.value.ShaderProgramIDVal;
3697             return true;
3698         }
3699     }
3700 
3701     return false;
3702 }
3703 
GetAdjustedTextureCacheLevel(gl::TextureTarget target,GLint level)3704 GLint GetAdjustedTextureCacheLevel(gl::TextureTarget target, GLint level)
3705 {
3706     GLint adjustedLevel = level;
3707 
3708     // If target is a cube, we need to maintain 6 images per level
3709     if (IsCubeMapFaceTarget(target))
3710     {
3711         adjustedLevel *= 6;
3712         adjustedLevel += CubeMapTextureTargetToFaceIndex(target);
3713     }
3714 
3715     return adjustedLevel;
3716 }
3717 }  // namespace
3718 
ParamCapture()3719 ParamCapture::ParamCapture() : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup) {}
3720 
ParamCapture(const char * nameIn,ParamType typeIn)3721 ParamCapture::ParamCapture(const char *nameIn, ParamType typeIn)
3722     : name(nameIn), type(typeIn), enumGroup(gl::GLenumGroup::DefaultGroup)
3723 {}
3724 
3725 ParamCapture::~ParamCapture() = default;
3726 
ParamCapture(ParamCapture && other)3727 ParamCapture::ParamCapture(ParamCapture &&other)
3728     : type(ParamType::TGLenum), enumGroup(gl::GLenumGroup::DefaultGroup)
3729 {
3730     *this = std::move(other);
3731 }
3732 
operator =(ParamCapture && other)3733 ParamCapture &ParamCapture::operator=(ParamCapture &&other)
3734 {
3735     std::swap(name, other.name);
3736     std::swap(type, other.type);
3737     std::swap(value, other.value);
3738     std::swap(enumGroup, other.enumGroup);
3739     std::swap(data, other.data);
3740     std::swap(arrayClientPointerIndex, other.arrayClientPointerIndex);
3741     std::swap(readBufferSizeBytes, other.readBufferSizeBytes);
3742     std::swap(dataNElements, other.dataNElements);
3743     return *this;
3744 }
3745 
ParamBuffer()3746 ParamBuffer::ParamBuffer() {}
3747 
3748 ParamBuffer::~ParamBuffer() = default;
3749 
ParamBuffer(ParamBuffer && other)3750 ParamBuffer::ParamBuffer(ParamBuffer &&other)
3751 {
3752     *this = std::move(other);
3753 }
3754 
operator =(ParamBuffer && other)3755 ParamBuffer &ParamBuffer::operator=(ParamBuffer &&other)
3756 {
3757     std::swap(mParamCaptures, other.mParamCaptures);
3758     std::swap(mClientArrayDataParam, other.mClientArrayDataParam);
3759     std::swap(mReadBufferSize, other.mReadBufferSize);
3760     std::swap(mReturnValueCapture, other.mReturnValueCapture);
3761     std::swap(mMappedBufferID, other.mMappedBufferID);
3762     return *this;
3763 }
3764 
getParam(const char * paramName,ParamType paramType,int index)3765 ParamCapture &ParamBuffer::getParam(const char *paramName, ParamType paramType, int index)
3766 {
3767     ParamCapture &capture = mParamCaptures[index];
3768     ASSERT(capture.name == paramName);
3769     ASSERT(capture.type == paramType);
3770     return capture;
3771 }
3772 
getParam(const char * paramName,ParamType paramType,int index) const3773 const ParamCapture &ParamBuffer::getParam(const char *paramName,
3774                                           ParamType paramType,
3775                                           int index) const
3776 {
3777     return const_cast<ParamBuffer *>(this)->getParam(paramName, paramType, index);
3778 }
3779 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index)3780 ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
3781                                             const char *paramName2,
3782                                             ParamType paramType,
3783                                             int index)
3784 {
3785     ParamCapture &capture = mParamCaptures[index];
3786     ASSERT(capture.name == paramName1 || capture.name == paramName2);
3787     ASSERT(capture.type == paramType);
3788     return capture;
3789 }
3790 
getParamFlexName(const char * paramName1,const char * paramName2,ParamType paramType,int index) const3791 const ParamCapture &ParamBuffer::getParamFlexName(const char *paramName1,
3792                                                   const char *paramName2,
3793                                                   ParamType paramType,
3794                                                   int index) const
3795 {
3796     return const_cast<ParamBuffer *>(this)->getParamFlexName(paramName1, paramName2, paramType,
3797                                                              index);
3798 }
3799 
addParam(ParamCapture && param)3800 void ParamBuffer::addParam(ParamCapture &&param)
3801 {
3802     if (param.arrayClientPointerIndex != -1)
3803     {
3804         ASSERT(mClientArrayDataParam == -1);
3805         mClientArrayDataParam = static_cast<int>(mParamCaptures.size());
3806     }
3807 
3808     mReadBufferSize = std::max(param.readBufferSizeBytes, mReadBufferSize);
3809     mParamCaptures.emplace_back(std::move(param));
3810 }
3811 
addReturnValue(ParamCapture && returnValue)3812 void ParamBuffer::addReturnValue(ParamCapture &&returnValue)
3813 {
3814     mReturnValueCapture = std::move(returnValue);
3815 }
3816 
getClientArrayPointerParameter()3817 ParamCapture &ParamBuffer::getClientArrayPointerParameter()
3818 {
3819     ASSERT(hasClientArrayData());
3820     return mParamCaptures[mClientArrayDataParam];
3821 }
3822 
CallCapture(EntryPoint entryPointIn,ParamBuffer && paramsIn)3823 CallCapture::CallCapture(EntryPoint entryPointIn, ParamBuffer &&paramsIn)
3824     : entryPoint(entryPointIn), params(std::move(paramsIn))
3825 {}
3826 
CallCapture(const std::string & customFunctionNameIn,ParamBuffer && paramsIn)3827 CallCapture::CallCapture(const std::string &customFunctionNameIn, ParamBuffer &&paramsIn)
3828     : entryPoint(EntryPoint::GLInvalid),
3829       customFunctionName(customFunctionNameIn),
3830       params(std::move(paramsIn))
3831 {}
3832 
3833 CallCapture::~CallCapture() = default;
3834 
CallCapture(CallCapture && other)3835 CallCapture::CallCapture(CallCapture &&other)
3836 {
3837     *this = std::move(other);
3838 }
3839 
operator =(CallCapture && other)3840 CallCapture &CallCapture::operator=(CallCapture &&other)
3841 {
3842     std::swap(entryPoint, other.entryPoint);
3843     std::swap(customFunctionName, other.customFunctionName);
3844     std::swap(params, other.params);
3845     return *this;
3846 }
3847 
name() const3848 const char *CallCapture::name() const
3849 {
3850     if (entryPoint == EntryPoint::GLInvalid)
3851     {
3852         ASSERT(!customFunctionName.empty());
3853         return customFunctionName.c_str();
3854     }
3855 
3856     return angle::GetEntryPointName(entryPoint);
3857 }
3858 
ReplayContext(size_t readBufferSizebytes,const gl::AttribArray<size_t> & clientArraysSizebytes)3859 ReplayContext::ReplayContext(size_t readBufferSizebytes,
3860                              const gl::AttribArray<size_t> &clientArraysSizebytes)
3861 {
3862     mReadBuffer.resize(readBufferSizebytes);
3863 
3864     for (uint32_t i = 0; i < clientArraysSizebytes.size(); i++)
3865     {
3866         mClientArraysBuffer[i].resize(clientArraysSizebytes[i]);
3867     }
3868 }
~ReplayContext()3869 ReplayContext::~ReplayContext() {}
3870 
3871 FrameCapture::FrameCapture()  = default;
3872 FrameCapture::~FrameCapture() = default;
3873 
reset()3874 void FrameCapture::reset()
3875 {
3876     mSetupCalls.clear();
3877 }
3878 
FrameCaptureShared()3879 FrameCaptureShared::FrameCaptureShared()
3880     : mEnabled(true),
3881       mSerializeStateEnabled(false),
3882       mCompression(true),
3883       mClientVertexArrayMap{},
3884       mFrameIndex(1),
3885       mCaptureStartFrame(1),
3886       mCaptureEndFrame(10),
3887       mClientArraySizes{},
3888       mReadBufferSize(0),
3889       mHasResourceType{},
3890       mCaptureTrigger(0),
3891       mWindowSurfaceContextID({0})
3892 {
3893     reset();
3894 
3895     std::string enabledFromEnv =
3896         GetEnvironmentVarOrUnCachedAndroidProperty(kEnabledVarName, kAndroidCaptureEnabled);
3897     if (enabledFromEnv == "0")
3898     {
3899         mEnabled = false;
3900     }
3901 
3902     std::string pathFromEnv =
3903         GetEnvironmentVarOrUnCachedAndroidProperty(kOutDirectoryVarName, kAndroidOutDir);
3904     if (pathFromEnv.empty())
3905     {
3906         mOutDirectory = GetDefaultOutDirectory();
3907     }
3908     else
3909     {
3910         mOutDirectory = pathFromEnv;
3911     }
3912 
3913     // Ensure the capture path ends with a slash.
3914     if (mOutDirectory.back() != '\\' && mOutDirectory.back() != '/')
3915     {
3916         mOutDirectory += '/';
3917     }
3918 
3919     std::string startFromEnv =
3920         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameStartVarName, kAndroidFrameStart);
3921     if (!startFromEnv.empty())
3922     {
3923         mCaptureStartFrame = atoi(startFromEnv.c_str());
3924     }
3925 
3926     std::string endFromEnv =
3927         GetEnvironmentVarOrUnCachedAndroidProperty(kFrameEndVarName, kAndroidFrameEnd);
3928     if (!endFromEnv.empty())
3929     {
3930         mCaptureEndFrame = atoi(endFromEnv.c_str());
3931     }
3932 
3933     std::string captureTriggerFromEnv =
3934         GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureTriggerVarName, kAndroidCaptureTrigger);
3935     if (!captureTriggerFromEnv.empty())
3936     {
3937         mCaptureTrigger = atoi(captureTriggerFromEnv.c_str());
3938 
3939         // If the trigger has been populated, ignore the other frame range variables by setting them
3940         // to unreasonable values. This isn't perfect, but it is effective.
3941         mCaptureStartFrame = mCaptureEndFrame = std::numeric_limits<uint32_t>::max();
3942         INFO() << "Capture trigger detected, disabling capture start/end frame.";
3943     }
3944 
3945     std::string labelFromEnv =
3946         GetEnvironmentVarOrUnCachedAndroidProperty(kCaptureLabel, kAndroidCaptureLabel);
3947     if (!labelFromEnv.empty())
3948     {
3949         // Optional label to provide unique file names and namespaces
3950         mCaptureLabel = labelFromEnv;
3951     }
3952 
3953     std::string compressionFromEnv =
3954         GetEnvironmentVarOrUnCachedAndroidProperty(kCompression, kAndroidCompression);
3955     if (compressionFromEnv == "0")
3956     {
3957         mCompression = false;
3958     }
3959     std::string serializeStateEnabledFromEnv =
3960         angle::GetEnvironmentVar(kSerializeStateEnabledVarName);
3961     if (serializeStateEnabledFromEnv == "1")
3962     {
3963         mSerializeStateEnabled = true;
3964     }
3965 }
3966 
3967 FrameCaptureShared::~FrameCaptureShared() = default;
3968 
copyCompressedTextureData(const gl::Context * context,const CallCapture & call)3969 void FrameCaptureShared::copyCompressedTextureData(const gl::Context *context,
3970                                                    const CallCapture &call)
3971 {
3972     // For compressed textures, we need to copy the source data that was already captured into a new
3973     // cached texture entry for use during mid-execution capture, rather than reading it back with
3974     // ANGLE_get_image.
3975 
3976     GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
3977     GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
3978 
3979     // TODO(anglebug.com/6104): Type of incoming ID varies based on target type, but we're only
3980     // handling textures for now. If either of these asserts fire, then we need to add renderbuffer
3981     // support.
3982     ASSERT(srcTarget == GL_TEXTURE_2D || srcTarget == GL_TEXTURE_2D_ARRAY ||
3983            srcTarget == GL_TEXTURE_3D || srcTarget == GL_TEXTURE_CUBE_MAP);
3984     ASSERT(dstTarget == GL_TEXTURE_2D || dstTarget == GL_TEXTURE_2D_ARRAY ||
3985            dstTarget == GL_TEXTURE_3D || dstTarget == GL_TEXTURE_CUBE_MAP);
3986 
3987     gl::TextureID srcName =
3988         call.params.getParam("srcName", ParamType::TTextureID, 0).value.TextureIDVal;
3989     GLint srcLevel = call.params.getParam("srcLevel", ParamType::TGLint, 2).value.GLintVal;
3990     gl::TextureID dstName =
3991         call.params.getParam("dstName", ParamType::TTextureID, 6).value.TextureIDVal;
3992     GLint dstLevel = call.params.getParam("dstLevel", ParamType::TGLint, 8).value.GLintVal;
3993 
3994     // Look up the texture type
3995     gl::TextureTarget dstTargetPacked = gl::PackParam<gl::TextureTarget>(dstTarget);
3996     gl::TextureType dstTextureType    = gl::TextureTargetToType(dstTargetPacked);
3997 
3998     // Look up the currently bound texture
3999     gl::Texture *dstTexture = context->getState().getTargetTexture(dstTextureType);
4000     ASSERT(dstTexture);
4001 
4002     const gl::InternalFormat &dstFormat = *dstTexture->getFormat(dstTargetPacked, dstLevel).info;
4003 
4004     if (dstFormat.compressed)
4005     {
4006         context->getShareGroup()->getFrameCaptureShared()->copyCachedTextureLevel(
4007             context, srcName, srcLevel, dstName, dstLevel, call);
4008     }
4009 }
4010 
captureCompressedTextureData(const gl::Context * context,const CallCapture & call)4011 void FrameCaptureShared::captureCompressedTextureData(const gl::Context *context,
4012                                                       const CallCapture &call)
4013 {
4014     // For compressed textures, track a shadow copy of the data
4015     // for use during mid-execution capture, rather than reading it back
4016     // with ANGLE_get_image
4017 
4018     // Storing the compressed data is handled the same for all entry points,
4019     // they just have slightly different parameter locations
4020     int dataParamOffset    = -1;
4021     int xoffsetParamOffset = -1;
4022     int yoffsetParamOffset = -1;
4023     int zoffsetParamOffset = -1;
4024     int widthParamOffset   = -1;
4025     int heightParamOffset  = -1;
4026     int depthParamOffset   = -1;
4027     switch (call.entryPoint)
4028     {
4029         case EntryPoint::GLCompressedTexSubImage3D:
4030             xoffsetParamOffset = 2;
4031             yoffsetParamOffset = 3;
4032             zoffsetParamOffset = 4;
4033             widthParamOffset   = 5;
4034             heightParamOffset  = 6;
4035             depthParamOffset   = 7;
4036             dataParamOffset    = 10;
4037             break;
4038         case EntryPoint::GLCompressedTexImage3D:
4039             widthParamOffset  = 3;
4040             heightParamOffset = 4;
4041             depthParamOffset  = 5;
4042             dataParamOffset   = 8;
4043             break;
4044         case EntryPoint::GLCompressedTexSubImage2D:
4045             xoffsetParamOffset = 2;
4046             yoffsetParamOffset = 3;
4047             widthParamOffset   = 4;
4048             heightParamOffset  = 5;
4049             dataParamOffset    = 8;
4050             break;
4051         case EntryPoint::GLCompressedTexImage2D:
4052             widthParamOffset  = 3;
4053             heightParamOffset = 4;
4054             dataParamOffset   = 7;
4055             break;
4056         default:
4057             // There should be no other callers of this function
4058             ASSERT(0);
4059             break;
4060     }
4061 
4062     gl::Buffer *pixelUnpackBuffer =
4063         context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
4064 
4065     const uint8_t *data = static_cast<const uint8_t *>(
4066         call.params.getParam("data", ParamType::TvoidConstPointer, dataParamOffset)
4067             .value.voidConstPointerVal);
4068 
4069     GLsizei imageSize = call.params.getParam("imageSize", ParamType::TGLsizei, dataParamOffset - 1)
4070                             .value.GLsizeiVal;
4071 
4072     const uint8_t *pixelData = nullptr;
4073 
4074     if (pixelUnpackBuffer)
4075     {
4076         // If using pixel unpack buffer, map the buffer and track its data
4077         ASSERT(!pixelUnpackBuffer->isMapped());
4078         (void)pixelUnpackBuffer->mapRange(context, reinterpret_cast<GLintptr>(data), imageSize,
4079                                           GL_MAP_READ_BIT);
4080 
4081         pixelData = reinterpret_cast<const uint8_t *>(pixelUnpackBuffer->getMapPointer());
4082     }
4083     else
4084     {
4085         pixelData = data;
4086     }
4087 
4088     if (!pixelData)
4089     {
4090         // If no pointer was provided and we weren't able to map the buffer, there is no data to
4091         // capture
4092         return;
4093     }
4094 
4095     // Look up the texture type
4096     gl::TextureTarget targetPacked =
4097         call.params.getParam("targetPacked", ParamType::TTextureTarget, 0).value.TextureTargetVal;
4098     gl::TextureType textureType = gl::TextureTargetToType(targetPacked);
4099 
4100     // Create a copy of the incoming data
4101     std::vector<uint8_t> compressedData;
4102     compressedData.assign(pixelData, pixelData + imageSize);
4103 
4104     // Look up the currently bound texture
4105     gl::Texture *texture = context->getState().getTargetTexture(textureType);
4106     ASSERT(texture);
4107 
4108     // Record the data, indexed by textureID and level
4109     GLint level = call.params.getParam("level", ParamType::TGLint, 1).value.GLintVal;
4110     std::vector<uint8_t> &levelData =
4111         context->getShareGroup()->getFrameCaptureShared()->getCachedTextureLevelData(
4112             texture, targetPacked, level, call.entryPoint);
4113 
4114     // Unpack the various pixel rectangle parameters.
4115     ASSERT(widthParamOffset != -1);
4116     ASSERT(heightParamOffset != -1);
4117     GLsizei pixelWidth =
4118         call.params.getParam("width", ParamType::TGLsizei, widthParamOffset).value.GLsizeiVal;
4119     GLsizei pixelHeight =
4120         call.params.getParam("height", ParamType::TGLsizei, heightParamOffset).value.GLsizeiVal;
4121     GLsizei pixelDepth = 1;
4122     if (depthParamOffset != -1)
4123     {
4124         pixelDepth =
4125             call.params.getParam("depth", ParamType::TGLsizei, depthParamOffset).value.GLsizeiVal;
4126     }
4127 
4128     GLint xoffset = 0;
4129     GLint yoffset = 0;
4130     GLint zoffset = 0;
4131 
4132     if (xoffsetParamOffset != -1)
4133     {
4134         xoffset =
4135             call.params.getParam("xoffset", ParamType::TGLint, xoffsetParamOffset).value.GLintVal;
4136     }
4137 
4138     if (yoffsetParamOffset != -1)
4139     {
4140         yoffset =
4141             call.params.getParam("yoffset", ParamType::TGLint, yoffsetParamOffset).value.GLintVal;
4142     }
4143 
4144     if (zoffsetParamOffset != -1)
4145     {
4146         zoffset =
4147             call.params.getParam("zoffset", ParamType::TGLint, zoffsetParamOffset).value.GLintVal;
4148     }
4149 
4150     // Get the format of the texture for use with the compressed block size math.
4151     const gl::InternalFormat &format = *texture->getFormat(targetPacked, level).info;
4152 
4153     // Divide dimensions according to block size.
4154     const gl::Extents &levelExtents = texture->getExtents(targetPacked, level);
4155 
4156     // Scale down the width/height pixel offsets to reflect block size
4157     int blockWidth  = static_cast<int>(format.compressedBlockWidth);
4158     int blockHeight = static_cast<int>(format.compressedBlockHeight);
4159     ASSERT(format.compressedBlockDepth == 1);
4160 
4161     // Round the incoming width and height up to align with block size
4162     pixelWidth  = rx::roundUp(pixelWidth, blockWidth);
4163     pixelHeight = rx::roundUp(pixelHeight, blockHeight);
4164 
4165     // Scale the width, height, and offsets
4166     pixelWidth /= blockWidth;
4167     pixelHeight /= blockHeight;
4168     xoffset /= blockWidth;
4169     yoffset /= blockHeight;
4170 
4171     GLint pixelBytes = static_cast<GLint>(format.pixelBytes);
4172 
4173     // Also round the texture's width and height up to reflect block size
4174     int levelWidth  = rx::roundUp(levelExtents.width, blockWidth);
4175     int levelHeight = rx::roundUp(levelExtents.height, blockHeight);
4176 
4177     GLint pixelRowPitch   = pixelWidth * pixelBytes;
4178     GLint pixelDepthPitch = pixelRowPitch * pixelHeight;
4179     GLint levelRowPitch   = (levelWidth / blockWidth) * pixelBytes;
4180     GLint levelDepthPitch = (levelHeight / blockHeight) * levelRowPitch;
4181 
4182     for (GLint zindex = 0; zindex < pixelDepth; ++zindex)
4183     {
4184         GLint z = zindex + zoffset;
4185         for (GLint yindex = 0; yindex < pixelHeight; ++yindex)
4186         {
4187             GLint y           = yindex + yoffset;
4188             GLint pixelOffset = zindex * pixelDepthPitch + yindex * pixelRowPitch;
4189             GLint levelOffset = z * levelDepthPitch + y * levelRowPitch + xoffset * pixelBytes;
4190             ASSERT(static_cast<size_t>(levelOffset + pixelRowPitch) <= levelData.size());
4191             memcpy(&levelData[levelOffset], &pixelData[pixelOffset], pixelRowPitch);
4192         }
4193     }
4194 
4195     if (pixelUnpackBuffer)
4196     {
4197         GLboolean success;
4198         (void)pixelUnpackBuffer->unmap(context, &success);
4199         ASSERT(success);
4200     }
4201 }
4202 
trackBufferMapping(CallCapture * call,gl::BufferID id,GLintptr offset,GLsizeiptr length,bool writable)4203 void FrameCaptureShared::trackBufferMapping(CallCapture *call,
4204                                             gl::BufferID id,
4205                                             GLintptr offset,
4206                                             GLsizeiptr length,
4207                                             bool writable)
4208 {
4209     // Track that the buffer was mapped
4210     mResourceTracker.setBufferMapped(id);
4211 
4212     if (writable)
4213     {
4214         // If this buffer was mapped writable, we don't have any visibility into what
4215         // happens to it. Therefore, remember the details about it, and we'll read it back
4216         // on Unmap to repopulate it during replay.
4217         mBufferDataMap[id] = std::make_pair(offset, length);
4218 
4219         // Track that this buffer was potentially modified
4220         mResourceTracker.setBufferModified(id);
4221 
4222         // Track the bufferID that was just mapped for use when writing return value
4223         call->params.setMappedBufferID(id);
4224     }
4225 }
4226 
updateCopyImageSubData(CallCapture & call)4227 void FrameCaptureShared::updateCopyImageSubData(CallCapture &call)
4228 {
4229     // This call modifies srcName and dstName to no longer be object IDs (GLuint), but actual
4230     // packed types that can remapped using gTextureMap and gRenderbufferMap
4231 
4232     GLint srcName    = call.params.getParam("srcName", ParamType::TGLuint, 0).value.GLuintVal;
4233     GLenum srcTarget = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
4234     switch (srcTarget)
4235     {
4236         case GL_RENDERBUFFER:
4237         {
4238             // Convert the GLuint to RenderbufferID
4239             gl::RenderbufferID srcRenderbufferID = {static_cast<GLuint>(srcName)};
4240             call.params.setValueParamAtIndex("srcName", ParamType::TRenderbufferID,
4241                                              srcRenderbufferID, 0);
4242             break;
4243         }
4244         case GL_TEXTURE_2D:
4245         case GL_TEXTURE_2D_ARRAY:
4246         case GL_TEXTURE_3D:
4247         case GL_TEXTURE_CUBE_MAP:
4248         {
4249             // Convert the GLuint to TextureID
4250             gl::TextureID srcTextureID = {static_cast<GLuint>(srcName)};
4251             call.params.setValueParamAtIndex("srcName", ParamType::TTextureID, srcTextureID, 0);
4252             break;
4253         }
4254         default:
4255             ERR() << "Unhandled srcTarget = " << srcTarget;
4256             UNREACHABLE();
4257             break;
4258     }
4259 
4260     // Change dstName to the appropriate type based on dstTarget
4261     GLint dstName    = call.params.getParam("dstName", ParamType::TGLuint, 6).value.GLuintVal;
4262     GLenum dstTarget = call.params.getParam("dstTarget", ParamType::TGLenum, 7).value.GLenumVal;
4263     switch (dstTarget)
4264     {
4265         case GL_RENDERBUFFER:
4266         {
4267             // Convert the GLuint to RenderbufferID
4268             gl::RenderbufferID dstRenderbufferID = {static_cast<GLuint>(dstName)};
4269             call.params.setValueParamAtIndex("dstName", ParamType::TRenderbufferID,
4270                                              dstRenderbufferID, 6);
4271             break;
4272         }
4273         case GL_TEXTURE_2D:
4274         case GL_TEXTURE_2D_ARRAY:
4275         case GL_TEXTURE_3D:
4276         case GL_TEXTURE_CUBE_MAP:
4277         {
4278             // Convert the GLuint to TextureID
4279             gl::TextureID dstTextureID = {static_cast<GLuint>(dstName)};
4280             call.params.setValueParamAtIndex("dstName", ParamType::TTextureID, dstTextureID, 6);
4281             break;
4282         }
4283         default:
4284             ERR() << "Unhandled dstTarget = " << dstTarget;
4285             UNREACHABLE();
4286             break;
4287     }
4288 }
4289 
maybeOverrideEntryPoint(const gl::Context * context,CallCapture & call)4290 void FrameCaptureShared::maybeOverrideEntryPoint(const gl::Context *context, CallCapture &call)
4291 {
4292     switch (call.entryPoint)
4293     {
4294         case EntryPoint::GLEGLImageTargetTexture2DOES:
4295         {
4296             // We don't support reading EGLImages. Instead, just pull from a tiny null texture.
4297             // TODO (anglebug.com/4964): Read back the image data and populate the texture.
4298             std::vector<uint8_t> pixelData = {0, 0, 0, 0};
4299             call = CaptureTexSubImage2D(context->getState(), true, gl::TextureTarget::_2D, 0, 0, 0,
4300                                         1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data());
4301             break;
4302         }
4303         case EntryPoint::GLEGLImageTargetRenderbufferStorageOES:
4304         {
4305             UNIMPLEMENTED();
4306             break;
4307         }
4308         case EntryPoint::GLCopyImageSubData:
4309         case EntryPoint::GLCopyImageSubDataEXT:
4310         case EntryPoint::GLCopyImageSubDataOES:
4311         {
4312             // We must look at the src and dst target types to determine which remap table to use
4313             updateCopyImageSubData(call);
4314             break;
4315         }
4316         default:
4317             break;
4318     }
4319 }
4320 
maybeCaptureDrawArraysClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)4321 void FrameCaptureShared::maybeCaptureDrawArraysClientData(const gl::Context *context,
4322                                                           CallCapture &call,
4323                                                           size_t instanceCount)
4324 {
4325     if (!context->getStateCache().hasAnyActiveClientAttrib())
4326     {
4327         return;
4328     }
4329 
4330     // Get counts from paramBuffer.
4331     GLint firstVertex =
4332         call.params.getParamFlexName("first", "start", ParamType::TGLint, 1).value.GLintVal;
4333     GLsizei drawCount = call.params.getParam("count", ParamType::TGLsizei, 2).value.GLsizeiVal;
4334     captureClientArraySnapshot(context, firstVertex + drawCount, instanceCount);
4335 }
4336 
maybeCaptureDrawElementsClientData(const gl::Context * context,CallCapture & call,size_t instanceCount)4337 void FrameCaptureShared::maybeCaptureDrawElementsClientData(const gl::Context *context,
4338                                                             CallCapture &call,
4339                                                             size_t instanceCount)
4340 {
4341     if (!context->getStateCache().hasAnyActiveClientAttrib())
4342     {
4343         return;
4344     }
4345 
4346     // if the count is zero then the index evaluation is not valid and we wouldn't be drawing
4347     // anything anyway, so skip capturing
4348     GLsizei count = call.params.getParam("count", ParamType::TGLsizei, 1).value.GLsizeiVal;
4349     if (count == 0)
4350     {
4351         return;
4352     }
4353 
4354     gl::DrawElementsType drawElementsType =
4355         call.params.getParam("typePacked", ParamType::TDrawElementsType, 2)
4356             .value.DrawElementsTypeVal;
4357     const void *indices =
4358         call.params.getParam("indices", ParamType::TvoidConstPointer, 3).value.voidConstPointerVal;
4359 
4360     gl::IndexRange indexRange;
4361 
4362     bool restart = context->getState().isPrimitiveRestartEnabled();
4363 
4364     gl::Buffer *elementArrayBuffer = context->getState().getVertexArray()->getElementArrayBuffer();
4365     if (elementArrayBuffer)
4366     {
4367         size_t offset = reinterpret_cast<size_t>(indices);
4368         (void)elementArrayBuffer->getIndexRange(context, drawElementsType, offset, count, restart,
4369                                                 &indexRange);
4370     }
4371     else
4372     {
4373         ASSERT(indices);
4374         indexRange = gl::ComputeIndexRange(drawElementsType, indices, count, restart);
4375     }
4376 
4377     // index starts from 0
4378     captureClientArraySnapshot(context, indexRange.end + 1, instanceCount);
4379 }
4380 
maybeCapturePreCallUpdates(const gl::Context * context,CallCapture & call)4381 void FrameCaptureShared::maybeCapturePreCallUpdates(const gl::Context *context, CallCapture &call)
4382 {
4383     switch (call.entryPoint)
4384     {
4385         case EntryPoint::GLVertexAttribPointer:
4386         case EntryPoint::GLVertexPointer:
4387         case EntryPoint::GLColorPointer:
4388         case EntryPoint::GLTexCoordPointer:
4389         case EntryPoint::GLNormalPointer:
4390         case EntryPoint::GLPointSizePointerOES:
4391         {
4392             // Get array location
4393             GLuint index = 0;
4394             if (call.entryPoint == EntryPoint::GLVertexAttribPointer)
4395             {
4396                 index = call.params.getParam("index", ParamType::TGLuint, 0).value.GLuintVal;
4397             }
4398             else
4399             {
4400                 gl::ClientVertexArrayType type;
4401                 switch (call.entryPoint)
4402                 {
4403                     case EntryPoint::GLVertexPointer:
4404                         type = gl::ClientVertexArrayType::Vertex;
4405                         break;
4406                     case EntryPoint::GLColorPointer:
4407                         type = gl::ClientVertexArrayType::Color;
4408                         break;
4409                     case EntryPoint::GLTexCoordPointer:
4410                         type = gl::ClientVertexArrayType::TextureCoord;
4411                         break;
4412                     case EntryPoint::GLNormalPointer:
4413                         type = gl::ClientVertexArrayType::Normal;
4414                         break;
4415                     case EntryPoint::GLPointSizePointerOES:
4416                         type = gl::ClientVertexArrayType::PointSize;
4417                         break;
4418                     default:
4419                         UNREACHABLE();
4420                         type = gl::ClientVertexArrayType::InvalidEnum;
4421                 }
4422                 index = gl::GLES1Renderer::VertexArrayIndex(type, context->getState().gles1());
4423             }
4424 
4425             if (call.params.hasClientArrayData())
4426             {
4427                 mClientVertexArrayMap[index] = static_cast<int>(mFrameCalls.size());
4428             }
4429             else
4430             {
4431                 mClientVertexArrayMap[index] = -1;
4432             }
4433             break;
4434         }
4435 
4436         case EntryPoint::GLDeleteBuffers:
4437         {
4438             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
4439             const gl::BufferID *bufferIDs =
4440                 call.params.getParam("buffersPacked", ParamType::TBufferIDConstPointer, 1)
4441                     .value.BufferIDConstPointerVal;
4442             FrameCaptureShared *frameCaptureShared =
4443                 context->getShareGroup()->getFrameCaptureShared();
4444             ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4445             for (GLsizei i = 0; i < count; i++)
4446             {
4447                 // For each buffer being deleted, check our backup of data and remove it
4448                 const auto &bufferDataInfo = mBufferDataMap.find(bufferIDs[i]);
4449                 if (bufferDataInfo != mBufferDataMap.end())
4450                 {
4451                     mBufferDataMap.erase(bufferDataInfo);
4452                 }
4453                 // If we're capturing, track what buffers have been deleted
4454                 if (frameCaptureShared->isCaptureActive())
4455                 {
4456                     resourceTracker.setDeletedBuffer(bufferIDs[i]);
4457                 }
4458             }
4459             break;
4460         }
4461 
4462         case EntryPoint::GLGenBuffers:
4463         {
4464             GLsizei count = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
4465             const gl::BufferID *bufferIDs =
4466                 call.params.getParam("buffersPacked", ParamType::TBufferIDPointer, 1)
4467                     .value.BufferIDPointerVal;
4468             FrameCaptureShared *frameCaptureShared =
4469                 context->getShareGroup()->getFrameCaptureShared();
4470             ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4471             for (GLsizei i = 0; i < count; i++)
4472             {
4473                 // If we're capturing, track what new buffers have been genned
4474                 if (frameCaptureShared->isCaptureActive())
4475                 {
4476                     resourceTracker.setGennedBuffer(bufferIDs[i]);
4477                 }
4478             }
4479             break;
4480         }
4481 
4482         case EntryPoint::GLDeleteSync:
4483         {
4484             GLsync sync = call.params.getParam("sync", ParamType::TGLsync, 0).value.GLsyncVal;
4485             FrameCaptureShared *frameCaptureShared =
4486                 context->getShareGroup()->getFrameCaptureShared();
4487             ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4488             // If we're capturing, track which fence sync has been deleted
4489             if (frameCaptureShared->isCaptureActive())
4490             {
4491                 resourceTracker.setDeletedFenceSync(sync);
4492             }
4493             break;
4494         }
4495 
4496         case EntryPoint::GLDrawArrays:
4497         {
4498             maybeCaptureDrawArraysClientData(context, call, 1);
4499             break;
4500         }
4501 
4502         case EntryPoint::GLDrawArraysInstanced:
4503         case EntryPoint::GLDrawArraysInstancedANGLE:
4504         case EntryPoint::GLDrawArraysInstancedEXT:
4505         {
4506             GLsizei instancecount =
4507                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 3)
4508                     .value.GLsizeiVal;
4509             maybeCaptureDrawArraysClientData(context, call, instancecount);
4510             break;
4511         }
4512 
4513         case EntryPoint::GLDrawElements:
4514         {
4515             maybeCaptureDrawElementsClientData(context, call, 1);
4516             break;
4517         }
4518 
4519         case EntryPoint::GLDrawElementsInstanced:
4520         case EntryPoint::GLDrawElementsInstancedANGLE:
4521         case EntryPoint::GLDrawElementsInstancedEXT:
4522         {
4523             GLsizei instancecount =
4524                 call.params.getParamFlexName("instancecount", "primcount", ParamType::TGLsizei, 4)
4525                     .value.GLsizeiVal;
4526             maybeCaptureDrawElementsClientData(context, call, instancecount);
4527             break;
4528         }
4529 
4530         case EntryPoint::GLCreateShaderProgramv:
4531         {
4532             // Refresh the cached shader sources.
4533             // The command CreateShaderProgramv() creates a stand-alone program from an array of
4534             // null-terminated source code strings for a single shader type, so we need update the
4535             // Shader and Program sources, similar to GLCompileShader + GLLinkProgram handling.
4536             gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
4537             const ParamCapture &paramCapture =
4538                 call.params.getParam("typePacked", ParamType::TShaderType, 0);
4539             gl::ShaderType shaderType = paramCapture.value.ShaderTypeVal;
4540             gl::Program *program      = context->getProgramResolveLink(programID);
4541             ASSERT(program);
4542             const gl::Shader *shader = program->getAttachedShader(shaderType);
4543             ASSERT(shader);
4544             FrameCaptureShared *frameCaptureShared =
4545                 context->getShareGroup()->getFrameCaptureShared();
4546             frameCaptureShared->setShaderSource(shader->getHandle(), shader->getSourceString());
4547             frameCaptureShared->setProgramSources(programID, GetAttachedProgramSources(program));
4548 
4549             if (isCaptureActive())
4550             {
4551                 mResourceTracker.setCreatedProgram(programID);
4552             }
4553             break;
4554         }
4555 
4556         case EntryPoint::GLCreateProgram:
4557         {
4558             // If we're capturing, track which programs have been created
4559             if (isCaptureActive())
4560             {
4561                 gl::ShaderProgramID programID = {call.params.getReturnValue().value.GLuintVal};
4562                 mResourceTracker.setCreatedProgram(programID);
4563             }
4564             break;
4565         }
4566 
4567         case EntryPoint::GLDeleteProgram:
4568         {
4569             // If we're capturing, track which programs have been deleted
4570             if (isCaptureActive())
4571             {
4572                 const ParamCapture &param =
4573                     call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
4574 
4575                 mResourceTracker.setDeletedProgram(param.value.ShaderProgramIDVal);
4576             }
4577             break;
4578         }
4579 
4580         case EntryPoint::GLCompileShader:
4581         {
4582             // Refresh the cached shader sources.
4583             gl::ShaderProgramID shaderID =
4584                 call.params.getParam("shaderPacked", ParamType::TShaderProgramID, 0)
4585                     .value.ShaderProgramIDVal;
4586             const gl::Shader *shader = context->getShader(shaderID);
4587             context->getShareGroup()->getFrameCaptureShared()->setShaderSource(
4588                 shaderID, shader->getSourceString());
4589             break;
4590         }
4591 
4592         case EntryPoint::GLLinkProgram:
4593         {
4594             // Refresh the cached program sources.
4595             gl::ShaderProgramID programID =
4596                 call.params.getParam("programPacked", ParamType::TShaderProgramID, 0)
4597                     .value.ShaderProgramIDVal;
4598             const gl::Program *program = context->getProgramResolveLink(programID);
4599             context->getShareGroup()->getFrameCaptureShared()->setProgramSources(
4600                 programID, GetAttachedProgramSources(program));
4601             break;
4602         }
4603 
4604         case EntryPoint::GLCompressedTexImage1D:
4605         case EntryPoint::GLCompressedTexSubImage1D:
4606         {
4607             UNIMPLEMENTED();
4608             break;
4609         }
4610 
4611         case EntryPoint::GLCompressedTexImage2D:
4612         case EntryPoint::GLCompressedTexImage3D:
4613         case EntryPoint::GLCompressedTexSubImage2D:
4614         case EntryPoint::GLCompressedTexSubImage3D:
4615         {
4616             captureCompressedTextureData(context, call);
4617             break;
4618         }
4619 
4620         case EntryPoint::GLCopyImageSubData:
4621         case EntryPoint::GLCopyImageSubDataEXT:
4622         case EntryPoint::GLCopyImageSubDataOES:
4623         {
4624             // glCopyImageSubData supports copying compressed and uncompressed texture formats.
4625             copyCompressedTextureData(context, call);
4626             break;
4627         }
4628 
4629         case EntryPoint::GLDeleteTextures:
4630         {
4631             // Free any TextureLevelDataMap entries being tracked for this texture
4632             // This is to cover the scenario where a texture has been created, its
4633             // levels cached, then texture deleted and recreated, receiving the same ID
4634 
4635             // Look up how many textures are being deleted
4636             GLsizei n = call.params.getParam("n", ParamType::TGLsizei, 0).value.GLsizeiVal;
4637 
4638             // Look up the pointer to list of textures
4639             const gl::TextureID *textureIDs =
4640                 call.params.getParam("texturesPacked", ParamType::TTextureIDConstPointer, 1)
4641                     .value.TextureIDConstPointerVal;
4642 
4643             // For each texture listed for deletion
4644             for (int32_t i = 0; i < n; ++i)
4645             {
4646                 // Look it up in the cache, and delete it if found
4647                 context->getShareGroup()->getFrameCaptureShared()->deleteCachedTextureLevelData(
4648                     textureIDs[i]);
4649             }
4650             break;
4651         }
4652 
4653         case EntryPoint::GLMapBuffer:
4654         case EntryPoint::GLMapBufferOES:
4655         {
4656             gl::BufferBinding target =
4657                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4658                     .value.BufferBindingVal;
4659 
4660             GLbitfield access =
4661                 call.params.getParam("access", ParamType::TGLenum, 1).value.GLenumVal;
4662 
4663             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4664 
4665             GLintptr offset   = 0;
4666             GLsizeiptr length = static_cast<GLsizeiptr>(buffer->getSize());
4667 
4668             bool writable =
4669                 access == GL_WRITE_ONLY_OES || access == GL_WRITE_ONLY || access == GL_READ_WRITE;
4670 
4671             FrameCaptureShared *frameCaptureShared =
4672                 context->getShareGroup()->getFrameCaptureShared();
4673             frameCaptureShared->trackBufferMapping(&call, buffer->id(), offset, length, writable);
4674             break;
4675         }
4676 
4677         case EntryPoint::GLUnmapNamedBuffer:
4678         {
4679             UNIMPLEMENTED();
4680             break;
4681         }
4682 
4683         case EntryPoint::GLMapBufferRange:
4684         case EntryPoint::GLMapBufferRangeEXT:
4685         {
4686             GLintptr offset =
4687                 call.params.getParam("offset", ParamType::TGLintptr, 1).value.GLintptrVal;
4688             GLsizeiptr length =
4689                 call.params.getParam("length", ParamType::TGLsizeiptr, 2).value.GLsizeiptrVal;
4690             GLbitfield access =
4691                 call.params.getParam("access", ParamType::TGLbitfield, 3).value.GLbitfieldVal;
4692 
4693             gl::BufferBinding target =
4694                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4695                     .value.BufferBindingVal;
4696             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4697 
4698             FrameCaptureShared *frameCaptureShared =
4699                 context->getShareGroup()->getFrameCaptureShared();
4700             frameCaptureShared->trackBufferMapping(&call, buffer->id(), offset, length,
4701                                                    access & GL_MAP_WRITE_BIT);
4702             break;
4703         }
4704 
4705         case EntryPoint::GLUnmapBuffer:
4706         case EntryPoint::GLUnmapBufferOES:
4707         {
4708             // See if we need to capture the buffer contents
4709             captureMappedBufferSnapshot(context, call);
4710 
4711             // Track that the buffer was unmapped, for use during state reset
4712             ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4713             gl::BufferBinding target =
4714                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4715                     .value.BufferBindingVal;
4716             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4717             resourceTracker.setBufferUnmapped(buffer->id());
4718             break;
4719         }
4720 
4721         case EntryPoint::GLBufferData:
4722         case EntryPoint::GLBufferSubData:
4723         {
4724             gl::BufferBinding target =
4725                 call.params.getParam("targetPacked", ParamType::TBufferBinding, 0)
4726                     .value.BufferBindingVal;
4727 
4728             gl::Buffer *buffer = context->getState().getTargetBuffer(target);
4729 
4730             // Track that this buffer's contents have been modified
4731             ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4732             resourceTracker.setBufferModified(buffer->id());
4733 
4734             // BufferData is equivalent to UnmapBuffer, for what we're tracking.
4735             // From the ES 3.1 spec in BufferData section:
4736             //     If any portion of the buffer object is mapped in the current context or any
4737             //     context current to another thread, it is as though UnmapBuffer (see section
4738             //     6.3.1) is executed in each such context prior to deleting the existing data
4739             //     store.
4740             // Track that the buffer was unmapped, for use during state reset
4741             resourceTracker.setBufferUnmapped(buffer->id());
4742 
4743             break;
4744         }
4745         default:
4746             break;
4747     }
4748 
4749     updateReadBufferSize(call.params.getReadBufferSize());
4750 
4751     gl::ShaderProgramID shaderProgramID;
4752     if (FindShaderProgramIDInCall(call, &shaderProgramID))
4753     {
4754         ResourceTracker &resourceTracker = context->getFrameCaptureSharedResourceTracker();
4755         resourceTracker.onShaderProgramAccess(shaderProgramID);
4756     }
4757 }
4758 
captureCall(const gl::Context * context,CallCapture && call,bool isCallValid)4759 void FrameCaptureShared::captureCall(const gl::Context *context,
4760                                      CallCapture &&call,
4761                                      bool isCallValid)
4762 {
4763     if (SkipCall(call.entryPoint))
4764     {
4765         return;
4766     }
4767 
4768     maybeOverrideEntryPoint(context, call);
4769 
4770     maybeCapturePreCallUpdates(context, call);
4771 
4772     if (isCallValid)
4773     {
4774         mFrameCalls.emplace_back(std::move(call));
4775     }
4776     else
4777     {
4778         INFO() << "FrameCapture: Not capturing invalid call to "
4779                << GetEntryPointName(call.entryPoint);
4780     }
4781 
4782     maybeCapturePostCallUpdates(context);
4783 }
4784 
maybeCapturePostCallUpdates(const gl::Context * context)4785 void FrameCaptureShared::maybeCapturePostCallUpdates(const gl::Context *context)
4786 {
4787     // Process resource ID updates.
4788     MaybeCaptureUpdateResourceIDs(&mFrameCalls);
4789 
4790     const CallCapture &lastCall = mFrameCalls.back();
4791     switch (lastCall.entryPoint)
4792     {
4793         case EntryPoint::GLCreateShaderProgramv:
4794         {
4795             gl::ShaderProgramID programId;
4796             programId.value            = lastCall.params.getReturnValue().value.GLuintVal;
4797             const gl::Program *program = context->getProgramResolveLink(programId);
4798             CaptureUpdateUniformLocations(program, &mFrameCalls);
4799             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
4800             break;
4801         }
4802         case EntryPoint::GLLinkProgram:
4803         {
4804             const ParamCapture &param =
4805                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
4806             const gl::Program *program =
4807                 context->getProgramResolveLink(param.value.ShaderProgramIDVal);
4808             CaptureUpdateUniformLocations(program, &mFrameCalls);
4809             CaptureUpdateUniformBlockIndexes(program, &mFrameCalls);
4810             break;
4811         }
4812         case EntryPoint::GLUseProgram:
4813             CaptureUpdateCurrentProgram(lastCall, &mFrameCalls);
4814             break;
4815         case EntryPoint::GLDeleteProgram:
4816         {
4817             const ParamCapture &param =
4818                 lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
4819             CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
4820             break;
4821         }
4822         default:
4823             break;
4824     }
4825 }
4826 
captureClientArraySnapshot(const gl::Context * context,size_t vertexCount,size_t instanceCount)4827 void FrameCaptureShared::captureClientArraySnapshot(const gl::Context *context,
4828                                                     size_t vertexCount,
4829                                                     size_t instanceCount)
4830 {
4831     const gl::VertexArray *vao = context->getState().getVertexArray();
4832 
4833     // Capture client array data.
4834     for (size_t attribIndex : context->getStateCache().getActiveClientAttribsMask())
4835     {
4836         const gl::VertexAttribute &attrib = vao->getVertexAttribute(attribIndex);
4837         const gl::VertexBinding &binding  = vao->getVertexBinding(attrib.bindingIndex);
4838 
4839         int callIndex = mClientVertexArrayMap[attribIndex];
4840 
4841         if (callIndex != -1)
4842         {
4843             size_t count = vertexCount;
4844 
4845             if (binding.getDivisor() > 0)
4846             {
4847                 count = rx::UnsignedCeilDivide(static_cast<uint32_t>(instanceCount),
4848                                                binding.getDivisor());
4849             }
4850 
4851             // The last capture element doesn't take up the full stride.
4852             size_t bytesToCapture = (count - 1) * binding.getStride() + attrib.format->pixelBytes;
4853 
4854             CallCapture &call   = mFrameCalls[callIndex];
4855             ParamCapture &param = call.params.getClientArrayPointerParameter();
4856             ASSERT(param.type == ParamType::TvoidConstPointer);
4857 
4858             ParamBuffer updateParamBuffer;
4859             updateParamBuffer.addValueParam<GLint>("arrayIndex", ParamType::TGLint,
4860                                                    static_cast<uint32_t>(attribIndex));
4861 
4862             ParamCapture updateMemory("pointer", ParamType::TvoidConstPointer);
4863             CaptureMemory(param.value.voidConstPointerVal, bytesToCapture, &updateMemory);
4864             updateParamBuffer.addParam(std::move(updateMemory));
4865 
4866             updateParamBuffer.addValueParam<GLuint64>("size", ParamType::TGLuint64, bytesToCapture);
4867 
4868             mFrameCalls.emplace_back("UpdateClientArrayPointer", std::move(updateParamBuffer));
4869 
4870             mClientArraySizes[attribIndex] =
4871                 std::max(mClientArraySizes[attribIndex], bytesToCapture);
4872         }
4873     }
4874 }
4875 
captureMappedBufferSnapshot(const gl::Context * context,const CallCapture & call)4876 void FrameCaptureShared::captureMappedBufferSnapshot(const gl::Context *context,
4877                                                      const CallCapture &call)
4878 {
4879     // If the buffer was mapped writable, we need to restore its data, since we have no visibility
4880     // into what the client did to the buffer while mapped
4881     // This sequence will result in replay calls like this:
4882     //   ...
4883     //   gMappedBufferData[gBufferMap[42]] = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, 65536,
4884     //                                                        GL_MAP_WRITE_BIT);
4885     //   ...
4886     //   UpdateClientBufferData(42, &gBinaryData[164631024], 65536);
4887     //   glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
4888     //   ...
4889 
4890     // Re-map the buffer, using the info we tracked about the buffer
4891     gl::BufferBinding target =
4892         call.params.getParam("targetPacked", ParamType::TBufferBinding, 0).value.BufferBindingVal;
4893 
4894     FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
4895     gl::Buffer *buffer                     = context->getState().getTargetBuffer(target);
4896     if (!frameCaptureShared->hasBufferData(buffer->id()))
4897     {
4898         // This buffer was not marked writable, so we did not back it up
4899         return;
4900     }
4901 
4902     std::pair<GLintptr, GLsizeiptr> bufferDataOffsetAndLength =
4903         frameCaptureShared->getBufferDataOffsetAndLength(buffer->id());
4904     GLintptr offset   = bufferDataOffsetAndLength.first;
4905     GLsizeiptr length = bufferDataOffsetAndLength.second;
4906 
4907     // Map the buffer so we can copy its contents out
4908     ASSERT(!buffer->isMapped());
4909     angle::Result result = buffer->mapRange(context, offset, length, GL_MAP_READ_BIT);
4910     if (result != angle::Result::Continue)
4911     {
4912         ERR() << "Failed to mapRange of buffer" << std::endl;
4913     }
4914     const uint8_t *data = reinterpret_cast<const uint8_t *>(buffer->getMapPointer());
4915 
4916     // Create the parameters to our helper for use during replay
4917     ParamBuffer dataParamBuffer;
4918 
4919     // Pass in the target buffer ID
4920     dataParamBuffer.addValueParam("dest", ParamType::TGLuint, buffer->id().value);
4921 
4922     // Capture the current buffer data with a binary param
4923     ParamCapture captureData("source", ParamType::TvoidConstPointer);
4924     CaptureMemory(data, length, &captureData);
4925     dataParamBuffer.addParam(std::move(captureData));
4926 
4927     // Also track its size for use with memcpy
4928     dataParamBuffer.addValueParam<GLsizeiptr>("size", ParamType::TGLsizeiptr, length);
4929 
4930     // Call the helper that populates the buffer with captured data
4931     mFrameCalls.emplace_back("UpdateClientBufferData", std::move(dataParamBuffer));
4932 
4933     // Unmap the buffer and move on
4934     GLboolean dontCare;
4935     (void)buffer->unmap(context, &dontCare);
4936 }
4937 
checkForCaptureTrigger()4938 void FrameCaptureShared::checkForCaptureTrigger()
4939 {
4940     // If the capture trigger has not been set, move on
4941     if (mCaptureTrigger == 0)
4942     {
4943         return;
4944     }
4945 
4946     // Otherwise, poll the value for a change
4947     std::string captureTriggerStr = GetCaptureTrigger();
4948     if (captureTriggerStr.empty())
4949     {
4950         return;
4951     }
4952 
4953     // If the value has changed, use the original value as the frame count
4954     // TODO (anglebug.com/4949): Improve capture at unknown frame time. It is good to
4955     // avoid polling if the feature is not enabled, but not entirely intuitive to set
4956     // a value to zero when you want to trigger it.
4957     uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
4958     if (captureTrigger != mCaptureTrigger)
4959     {
4960         // Start mid-execution capture for the next frame
4961         mCaptureStartFrame = mFrameIndex + 1;
4962 
4963         // Use the original trigger value as the frame count
4964         mCaptureEndFrame = mCaptureStartFrame + (mCaptureTrigger - 1);
4965 
4966         INFO() << "Capture triggered after frame " << mFrameIndex << " for " << mCaptureTrigger
4967                << " frames";
4968 
4969         // Stop polling
4970         mCaptureTrigger = 0;
4971     }
4972 }
4973 
setupSharedAndAuxReplay(const gl::Context * context,bool isMidExecutionCapture)4974 void FrameCaptureShared::setupSharedAndAuxReplay(const gl::Context *context,
4975                                                  bool isMidExecutionCapture)
4976 {
4977     // Make sure all pending work for every Context in the share group has completed so all data
4978     // (buffers, textures, etc.) has been updated and no resources are in use.
4979     egl::ShareGroup *shareGroup            = context->getShareGroup();
4980     const egl::ContextSet *shareContextSet = shareGroup->getContexts();
4981     for (gl::Context *shareContext : *shareContextSet)
4982     {
4983         shareContext->finish();
4984     }
4985 
4986     clearSetupCalls();
4987     if (isMidExecutionCapture)
4988     {
4989         CaptureSharedContextMidExecutionSetup(context, &mSetupCalls, &mResourceTracker);
4990     }
4991 
4992     WriteSharedContextCppReplay(mCompression, mOutDirectory, mCaptureLabel, 1, 1, mSetupCalls,
4993                                 &mResourceTracker, &mBinaryData, mSerializeStateEnabled, *this);
4994 
4995     for (const gl::Context *shareContext : *shareContextSet)
4996     {
4997         FrameCapture *frameCapture = shareContext->getFrameCapture();
4998         frameCapture->clearSetupCalls();
4999 
5000         if (isMidExecutionCapture)
5001         {
5002             CaptureMidExecutionSetup(shareContext, &frameCapture->getSetupCalls(),
5003                                      &mResourceTracker);
5004         }
5005 
5006         if (!frameCapture->getSetupCalls().empty() && shareContext->id() != context->id())
5007         {
5008             // The presentation context's setup functions will be written later as part of the
5009             // WriteWindowSurfaceContextCppReplay() output.
5010             WriteAuxiliaryContextCppSetupReplay(mCompression, mOutDirectory, shareContext,
5011                                                 mCaptureLabel, 1, frameCapture->getSetupCalls(),
5012                                                 &mBinaryData, mSerializeStateEnabled, *this);
5013         }
5014     }
5015 }
5016 
onEndFrame(const gl::Context * context)5017 void FrameCaptureShared::onEndFrame(const gl::Context *context)
5018 {
5019     if (!enabled() || mFrameIndex > mCaptureEndFrame)
5020     {
5021         setCaptureInactive();
5022         return;
5023     }
5024 
5025     FrameCapture *frameCapture = context->getFrameCapture();
5026 
5027     // Count resource IDs. This is also done on every frame. It could probably be done by
5028     // checking the GL state instead of the calls.
5029     for (const CallCapture &call : mFrameCalls)
5030     {
5031         for (const ParamCapture &param : call.params.getParamCaptures())
5032         {
5033             ResourceIDType idType = GetResourceIDTypeFromParamType(param.type);
5034             if (idType != ResourceIDType::InvalidEnum)
5035             {
5036                 mHasResourceType.set(idType);
5037             }
5038         }
5039     }
5040 
5041     // On Android, we can trigger a capture during the run
5042     checkForCaptureTrigger();
5043     // Done after checkForCaptureTrigger(), since that can modify mCaptureStartFrame.
5044     if (mFrameIndex >= mCaptureStartFrame)
5045     {
5046         setCaptureActive();
5047         // Assume that the context performing the swap is the "main" context.
5048         mWindowSurfaceContextID = context->id();
5049     }
5050     else
5051     {
5052         reset();
5053         mFrameIndex++;
5054 
5055         // When performing a mid-execution capture, setup the replay before capturing calls for the
5056         // first frame.
5057         if (mFrameIndex == mCaptureStartFrame)
5058         {
5059             setupSharedAndAuxReplay(context, true);
5060         }
5061 
5062         // Not capturing yet, so return.
5063         return;
5064     }
5065 
5066     if (mIsFirstFrame)
5067     {
5068         mCaptureStartFrame = mFrameIndex;
5069 
5070         // When *not* performing a mid-execution capture, setup the replay with the first frame.
5071         if (mCaptureStartFrame == 1)
5072         {
5073             setupSharedAndAuxReplay(context, false);
5074         }
5075     }
5076 
5077     if (!mFrameCalls.empty())
5078     {
5079         mActiveFrameIndices.push_back(getReplayFrameIndex());
5080     }
5081 
5082     // Note that we currently capture before the start frame to collect shader and program sources.
5083     // For simplicity, it's currently a requirement that the same context is used to perform the
5084     // swap every frame.
5085     ASSERT(mWindowSurfaceContextID == context->id());
5086 
5087     // Make sure all pending work for every Context in the share group has completed so all data
5088     // (buffers, textures, etc.) has been updated and no resources are in use.
5089     egl::ShareGroup *shareGroup            = context->getShareGroup();
5090     const egl::ContextSet *shareContextSet = shareGroup->getContexts();
5091     for (gl::Context *shareContext : *shareContextSet)
5092     {
5093         shareContext->finish();
5094     }
5095 
5096     WriteWindowSurfaceContextCppReplay(mCompression, mOutDirectory, context, mCaptureLabel,
5097                                        getReplayFrameIndex(), getFrameCount(), mFrameCalls,
5098                                        frameCapture->getSetupCalls(), &mResourceTracker,
5099                                        &mBinaryData, mSerializeStateEnabled, *this);
5100 
5101     if (mFrameIndex == mCaptureEndFrame)
5102     {
5103         // Save the index files after the last frame.
5104         writeCppReplayIndexFiles(context, false);
5105         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
5106         mBinaryData.clear();
5107         mWroteIndexFile = true;
5108     }
5109 
5110     reset();
5111     mFrameIndex++;
5112     mIsFirstFrame = false;
5113 }
5114 
onDestroyContext(const gl::Context * context)5115 void FrameCaptureShared::onDestroyContext(const gl::Context *context)
5116 {
5117     if (!mEnabled)
5118     {
5119         return;
5120     }
5121     if (!mWroteIndexFile && mFrameIndex > mCaptureStartFrame)
5122     {
5123         // If context is destroyed before end frame is reached and at least
5124         // 1 frame has been recorded, then write the index files.
5125         // It doesnt make sense to write the index files when no frame has been recorded
5126         mFrameIndex -= 1;
5127         mCaptureEndFrame = mFrameIndex;
5128         writeCppReplayIndexFiles(context, true);
5129         SaveBinaryData(mCompression, mOutDirectory, kSharedContextId, mCaptureLabel, mBinaryData);
5130         mBinaryData.clear();
5131         mWroteIndexFile = true;
5132     }
5133 }
5134 
onMakeCurrent(const gl::Context * context,const egl::Surface * drawSurface)5135 void FrameCaptureShared::onMakeCurrent(const gl::Context *context, const egl::Surface *drawSurface)
5136 {
5137     if (!drawSurface)
5138     {
5139         return;
5140     }
5141 
5142     // Track the width and height of the draw surface as provided to makeCurrent
5143     mDrawSurfaceDimensions[context->id()] =
5144         gl::Extents(drawSurface->getWidth(), drawSurface->getHeight(), 1);
5145 }
5146 
5147 DataCounters::DataCounters() = default;
5148 
5149 DataCounters::~DataCounters() = default;
5150 
getAndIncrement(EntryPoint entryPoint,const std::string & paramName)5151 int DataCounters::getAndIncrement(EntryPoint entryPoint, const std::string &paramName)
5152 {
5153     Counter counterKey = {entryPoint, paramName};
5154     return mData[counterKey]++;
5155 }
5156 
5157 DataTracker::DataTracker() = default;
5158 
5159 DataTracker::~DataTracker() = default;
5160 
5161 StringCounters::StringCounters() = default;
5162 
5163 StringCounters::~StringCounters() = default;
5164 
getStringCounter(std::vector<std::string> & strings)5165 int StringCounters::getStringCounter(std::vector<std::string> &strings)
5166 {
5167     const auto &id = mStringCounterMap.find(strings);
5168     if (id == mStringCounterMap.end())
5169     {
5170         return kStringsNotFound;
5171     }
5172     else
5173     {
5174         return mStringCounterMap[strings];
5175     }
5176 }
5177 
setStringCounter(std::vector<std::string> & strings,int & counter)5178 void StringCounters::setStringCounter(std::vector<std::string> &strings, int &counter)
5179 {
5180     ASSERT(counter >= 0);
5181     mStringCounterMap[strings] = counter;
5182 }
5183 
5184 ResourceTracker::ResourceTracker() = default;
5185 
5186 ResourceTracker::~ResourceTracker() = default;
5187 
setDeletedBuffer(gl::BufferID id)5188 void ResourceTracker::setDeletedBuffer(gl::BufferID id)
5189 {
5190     if (id.value == 0)
5191     {
5192         // Ignore buffer ID 0
5193         return;
5194     }
5195 
5196     if (mNewBuffers.find(id) != mNewBuffers.end())
5197     {
5198         // This is a buffer genned after MEC was initialized, just clear it, since there will be no
5199         // actions required for it to return to starting state.
5200         mNewBuffers.erase(id);
5201         return;
5202     }
5203 
5204     if (mStartingBuffers.find(id) != mStartingBuffers.end())
5205     {
5206         // The app is deleting a buffer we started with, we need to regen on loop
5207         mBuffersToRegen.insert(id);
5208         mBuffersToRestore.insert(id);
5209     }
5210 
5211     // If none of the above is true, the app is deleting a buffer that was never genned.
5212     // This is allowed by the spec for DeleteBuffers:
5213     //    Unused names in buffers are silently ignored, as is the value zero.
5214 }
5215 
setDeletedFenceSync(GLsync sync)5216 void ResourceTracker::setDeletedFenceSync(GLsync sync)
5217 {
5218     ASSERT(sync != nullptr);
5219     if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
5220     {
5221         // This is a fence sync created after MEC was initialized. Ignore it.
5222         return;
5223     }
5224 
5225     // In this case, the app is deleting a fence sync we started with, we need to regen on loop.
5226     mFenceSyncsToRegen.insert(sync);
5227 }
5228 
setCreatedProgram(gl::ShaderProgramID id)5229 void ResourceTracker::setCreatedProgram(gl::ShaderProgramID id)
5230 {
5231     if (mStartingPrograms.find(id) == mStartingPrograms.end())
5232     {
5233         // This is a program created after MEC was initialized, track it
5234         mNewPrograms.insert(id);
5235         return;
5236     }
5237 }
5238 
setDeletedProgram(gl::ShaderProgramID id)5239 void ResourceTracker::setDeletedProgram(gl::ShaderProgramID id)
5240 {
5241     if (id.value == 0)
5242     {
5243         // Ignore program ID 0
5244         return;
5245     }
5246 
5247     if (mNewPrograms.find(id) != mNewPrograms.end())
5248     {
5249         // This is a program created after MEC was initialized, just clear it, since there will be
5250         // no actions required for it to return to starting state.
5251         mNewPrograms.erase(id);
5252         return;
5253     }
5254 
5255     // Ensure this program was in our starting set
5256     // It's possible this could fire if the app deletes programs that were never generated
5257     ASSERT(mStartingPrograms.empty() || (mStartingPrograms.find(id) != mStartingPrograms.end()));
5258 
5259     // In this case, the app is deleting a program we started with, we need to regen on loop
5260     mProgramsToRegen.insert(id);
5261 }
5262 
setGennedBuffer(gl::BufferID id)5263 void ResourceTracker::setGennedBuffer(gl::BufferID id)
5264 {
5265     if (mStartingBuffers.find(id) == mStartingBuffers.end())
5266     {
5267         // This is a buffer genned after MEC was initialized, track it
5268         mNewBuffers.insert(id);
5269         return;
5270     }
5271 }
5272 
setBufferModified(gl::BufferID id)5273 void ResourceTracker::setBufferModified(gl::BufferID id)
5274 {
5275     // If this was a starting buffer, we need to track it for restore
5276     if (mStartingBuffers.find(id) != mStartingBuffers.end())
5277     {
5278         mBuffersToRestore.insert(id);
5279     }
5280 }
5281 
setBufferMapped(gl::BufferID id)5282 void ResourceTracker::setBufferMapped(gl::BufferID id)
5283 {
5284     // If this was a starting buffer, we may need to restore it to original state during Reset
5285     if (mStartingBuffers.find(id) != mStartingBuffers.end())
5286     {
5287         // Track that its current state is mapped (true)
5288         mStartingBuffersMappedCurrent[id] = true;
5289     }
5290 }
5291 
setBufferUnmapped(gl::BufferID id)5292 void ResourceTracker::setBufferUnmapped(gl::BufferID id)
5293 {
5294     // If this was a starting buffer, we may need to restore it to original state during Reset
5295     if (mStartingBuffers.find(id) != mStartingBuffers.end())
5296     {
5297         // Track that its current state is unmapped (false)
5298         mStartingBuffersMappedCurrent[id] = false;
5299     }
5300 }
5301 
onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)5302 void ResourceTracker::onShaderProgramAccess(gl::ShaderProgramID shaderProgramID)
5303 {
5304     mMaxShaderPrograms = std::max(mMaxShaderPrograms, shaderProgramID.value + 1);
5305 }
5306 
isCapturing() const5307 bool FrameCaptureShared::isCapturing() const
5308 {
5309     // Currently we will always do a capture up until the last frame. In the future we could improve
5310     // mid execution capture by only capturing between the start and end frames. The only necessary
5311     // reason we need to capture before the start is for attached program and shader sources.
5312     return mEnabled && mFrameIndex <= mCaptureEndFrame;
5313 }
5314 
getFrameCount() const5315 uint32_t FrameCaptureShared::getFrameCount() const
5316 {
5317     return mCaptureEndFrame - mCaptureStartFrame + 1;
5318 }
5319 
getReplayFrameIndex() const5320 uint32_t FrameCaptureShared::getReplayFrameIndex() const
5321 {
5322     return mFrameIndex - mCaptureStartFrame + 1;
5323 }
5324 
replay(gl::Context * context)5325 void FrameCaptureShared::replay(gl::Context *context)
5326 {
5327     ReplayContext replayContext(mReadBufferSize, mClientArraySizes);
5328     for (const CallCapture &call : mFrameCalls)
5329     {
5330         INFO() << "frame index: " << mFrameIndex << " " << call.name();
5331 
5332         if (call.entryPoint == EntryPoint::GLInvalid)
5333         {
5334             if (call.customFunctionName == "UpdateClientArrayPointer")
5335             {
5336                 GLint arrayIndex =
5337                     call.params.getParam("arrayIndex", ParamType::TGLint, 0).value.GLintVal;
5338                 ASSERT(arrayIndex < gl::MAX_VERTEX_ATTRIBS);
5339 
5340                 const ParamCapture &pointerParam =
5341                     call.params.getParam("pointer", ParamType::TvoidConstPointer, 1);
5342                 ASSERT(pointerParam.data.size() == 1);
5343                 const void *pointer = pointerParam.data[0].data();
5344 
5345                 size_t size = static_cast<size_t>(
5346                     call.params.getParam("size", ParamType::TGLuint64, 2).value.GLuint64Val);
5347 
5348                 std::vector<uint8_t> &curClientArrayBuffer =
5349                     replayContext.getClientArraysBuffer()[arrayIndex];
5350                 ASSERT(curClientArrayBuffer.size() >= size);
5351                 memcpy(curClientArrayBuffer.data(), pointer, size);
5352             }
5353             continue;
5354         }
5355 
5356         ReplayCall(context, &replayContext, call);
5357     }
5358 }
5359 
writeCppReplayIndexFiles(const gl::Context * context,bool writeResetContextCall)5360 void FrameCaptureShared::writeCppReplayIndexFiles(const gl::Context *context,
5361                                                   bool writeResetContextCall)
5362 {
5363     const gl::ContextID contextId       = context->id();
5364     const egl::Config *config           = context->getConfig();
5365     const egl::AttributeMap &attributes = context->getDisplay()->getAttributeMap();
5366 
5367     unsigned frameCount = getFrameCount();
5368 
5369     std::stringstream header;
5370     std::stringstream source;
5371 
5372     header << "#pragma once\n";
5373     header << "\n";
5374     header << "#include <EGL/egl.h>\n";
5375     header << "#include <cstdint>\n";
5376     header << "\n";
5377 
5378     if (!mCaptureLabel.empty())
5379     {
5380         header << "namespace " << mCaptureLabel << "\n";
5381         header << "{\n";
5382     }
5383     header << "// Begin Trace Metadata\n";
5384     header << "#define ANGLE_REPLAY_VERSION";
5385     if (!mCaptureLabel.empty())
5386     {
5387         std::string captureLabelUpper = mCaptureLabel;
5388         angle::ToUpper(&captureLabelUpper);
5389         header << "_" << captureLabelUpper;
5390     }
5391     header << " " << ANGLE_REVISION << "\n";
5392     header << "constexpr uint32_t kReplayContextClientMajorVersion = "
5393            << context->getClientMajorVersion() << ";\n";
5394     header << "constexpr uint32_t kReplayContextClientMinorVersion = "
5395            << context->getClientMinorVersion() << ";\n";
5396     header << "constexpr EGLint kReplayPlatformType = "
5397            << attributes.getAsInt(EGL_PLATFORM_ANGLE_TYPE_ANGLE) << ";\n";
5398     header << "constexpr EGLint kReplayDeviceType = "
5399            << attributes.getAsInt(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE) << ";\n";
5400     header << "constexpr uint32_t kReplayFrameStart = 1;\n";
5401     header << "constexpr uint32_t kReplayFrameEnd = " << frameCount << ";\n";
5402     header << "constexpr EGLint kReplayDrawSurfaceWidth = "
5403            << mDrawSurfaceDimensions.at(contextId).width << ";\n";
5404     header << "constexpr EGLint kReplayDrawSurfaceHeight = "
5405            << mDrawSurfaceDimensions.at(contextId).height << ";\n";
5406     header << "constexpr EGLint kDefaultFramebufferRedBits = "
5407            << (config ? std::to_string(config->redSize) : "EGL_DONT_CARE") << ";\n";
5408     header << "constexpr EGLint kDefaultFramebufferGreenBits = "
5409            << (config ? std::to_string(config->greenSize) : "EGL_DONT_CARE") << ";\n";
5410     header << "constexpr EGLint kDefaultFramebufferBlueBits = "
5411            << (config ? std::to_string(config->blueSize) : "EGL_DONT_CARE") << ";\n";
5412     header << "constexpr EGLint kDefaultFramebufferAlphaBits = "
5413            << (config ? std::to_string(config->alphaSize) : "EGL_DONT_CARE") << ";\n";
5414     header << "constexpr EGLint kDefaultFramebufferDepthBits = "
5415            << (config ? std::to_string(config->depthSize) : "EGL_DONT_CARE") << ";\n";
5416     header << "constexpr EGLint kDefaultFramebufferStencilBits = "
5417            << (config ? std::to_string(config->stencilSize) : "EGL_DONT_CARE") << ";\n";
5418     header << "constexpr bool kIsBinaryDataCompressed = " << (mCompression ? "true" : "false")
5419            << ";\n";
5420     header << "constexpr bool kAreClientArraysEnabled = "
5421            << (context->getState().areClientArraysEnabled() ? "true" : "false") << ";\n";
5422     header << "constexpr bool kbindGeneratesResources = "
5423            << (context->getState().isBindGeneratesResourceEnabled() ? "true" : "false") << ";\n";
5424     header << "constexpr bool kWebGLCompatibility = "
5425            << (context->getState().getExtensions().webglCompatibility ? "true" : "false") << ";\n";
5426     header << "constexpr bool kRobustResourceInit = "
5427            << (context->getState().isRobustResourceInitEnabled() ? "true" : "false") << ";\n";
5428 
5429     header << "// End Trace Metadata\n";
5430     header << "\n";
5431     for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5432     {
5433         header << "void " << FmtReplayFunction(contextId, frameIndex) << ";\n";
5434     }
5435     header << "\n";
5436     if (mSerializeStateEnabled)
5437     {
5438         for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5439         {
5440             header << "const char *" << FmtGetSerializedContextStateFunction(contextId, frameIndex)
5441                    << ";\n";
5442         }
5443         header << "\n";
5444     }
5445 
5446     header << "void InitReplay();\n";
5447 
5448     source << "#include \"" << FmtCapturePrefix(contextId, mCaptureLabel) << ".h\"\n";
5449     source << "#include \"trace_fixture.h\"\n";
5450     source << "#include \"angle_trace_gl.h\"\n";
5451     source << "\n";
5452 
5453     if (!mCaptureLabel.empty())
5454     {
5455         source << "using namespace " << mCaptureLabel << ";\n";
5456         source << "\n";
5457     }
5458 
5459     source << "void " << mCaptureLabel << "::InitReplay()\n";
5460     source << "{\n";
5461     WriteInitReplayCall(mCompression, source, kSharedContextId, mCaptureLabel,
5462                         MaxClientArraySize(mClientArraySizes), mReadBufferSize);
5463     source << "}\n";
5464 
5465     source << "extern \"C\" {\n";
5466     source << "void ReplayFrame(uint32_t frameIndex)\n";
5467     source << "{\n";
5468     source << "    switch (frameIndex)\n";
5469     source << "    {\n";
5470     for (uint32_t frameIndex : mActiveFrameIndices)
5471     {
5472         source << "        case " << frameIndex << ":\n";
5473         source << "            " << FmtReplayFunction(contextId, frameIndex) << ";\n";
5474         source << "            break;\n";
5475     }
5476     source << "        default:\n";
5477     source << "            break;\n";
5478     source << "    }\n";
5479     source << "}\n";
5480     source << "\n";
5481 
5482     if (writeResetContextCall)
5483     {
5484         source << "void ResetReplay()\n";
5485         source << "{\n";
5486         source << "    // Reset context is empty because context is destroyed before end "
5487                   "frame is reached\n";
5488         source << "}\n";
5489         source << "\n";
5490     }
5491 
5492     if (mSerializeStateEnabled)
5493     {
5494         source << "const char *GetSerializedContextState(uint32_t frameIndex)\n";
5495         source << "{\n";
5496         source << "    switch (frameIndex)\n";
5497         source << "    {\n";
5498         for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5499         {
5500             source << "        case " << frameIndex << ":\n";
5501             source << "            return "
5502                    << FmtGetSerializedContextStateFunction(contextId, frameIndex) << ";\n";
5503         }
5504         source << "        default:\n";
5505         source << "            return \"\";\n";
5506         source << "    }\n";
5507         source << "}\n";
5508         source << "\n";
5509     }
5510 
5511     source << "}  // extern \"C\"\n";
5512 
5513     if (!mCaptureLabel.empty())
5514     {
5515         header << "} // namespace " << mCaptureLabel << "\n";
5516     }
5517 
5518     {
5519         std::string headerContents = header.str();
5520 
5521         std::stringstream headerPathStream;
5522         headerPathStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel) << ".h";
5523         std::string headerPath = headerPathStream.str();
5524 
5525         SaveFileHelper saveHeader(headerPath);
5526         saveHeader << headerContents;
5527     }
5528 
5529     {
5530         std::string sourceContents = source.str();
5531 
5532         std::stringstream sourcePathStream;
5533         sourcePathStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel) << ".cpp";
5534         std::string sourcePath = sourcePathStream.str();
5535 
5536         SaveFileHelper saveSource(sourcePath);
5537         saveSource << sourceContents;
5538     }
5539 
5540     {
5541         std::stringstream indexPathStream;
5542         indexPathStream << mOutDirectory << FmtCapturePrefix(contextId, mCaptureLabel)
5543                         << "_files.txt";
5544         std::string indexPath = indexPathStream.str();
5545 
5546         SaveFileHelper saveIndex(indexPath);
5547         for (uint32_t frameIndex = 1; frameIndex <= frameCount; ++frameIndex)
5548         {
5549             saveIndex << GetCaptureFileName(contextId, mCaptureLabel, frameIndex, ".cpp") << "\n";
5550         }
5551 
5552         egl::ShareGroup *shareGroup      = context->getShareGroup();
5553         egl::ContextSet *shareContextSet = shareGroup->getContexts();
5554         for (gl::Context *shareContext : *shareContextSet)
5555         {
5556             if (shareContext->id() == contextId)
5557             {
5558                 // We already listed all of the "main" context's files, so skip it here.
5559                 continue;
5560             }
5561             saveIndex << GetCaptureFileName(shareContext->id(), mCaptureLabel, 1, ".cpp") << "\n";
5562         }
5563         saveIndex << GetCaptureFileName(kSharedContextId, mCaptureLabel, 1, ".cpp") << "\n";
5564     }
5565 }
5566 
reset()5567 void FrameCaptureShared::reset()
5568 {
5569     mFrameCalls.clear();
5570     mClientVertexArrayMap.fill(-1);
5571 
5572     // Do not reset replay-specific settings like the maximum read buffer size, client array sizes,
5573     // or the 'has seen' type map. We could refine this into per-frame and per-capture maximums if
5574     // necessary.
5575 }
5576 
getShaderSource(gl::ShaderProgramID id) const5577 const std::string &FrameCaptureShared::getShaderSource(gl::ShaderProgramID id) const
5578 {
5579     const auto &foundSources = mCachedShaderSource.find(id);
5580     ASSERT(foundSources != mCachedShaderSource.end());
5581     return foundSources->second;
5582 }
5583 
setShaderSource(gl::ShaderProgramID id,std::string source)5584 void FrameCaptureShared::setShaderSource(gl::ShaderProgramID id, std::string source)
5585 {
5586     mCachedShaderSource[id] = source;
5587 }
5588 
getProgramSources(gl::ShaderProgramID id) const5589 const ProgramSources &FrameCaptureShared::getProgramSources(gl::ShaderProgramID id) const
5590 {
5591     const auto &foundSources = mCachedProgramSources.find(id);
5592     ASSERT(foundSources != mCachedProgramSources.end());
5593     return foundSources->second;
5594 }
5595 
setProgramSources(gl::ShaderProgramID id,ProgramSources sources)5596 void FrameCaptureShared::setProgramSources(gl::ShaderProgramID id, ProgramSources sources)
5597 {
5598     mCachedProgramSources[id] = sources;
5599 }
5600 
retrieveCachedTextureLevel(gl::TextureID id,gl::TextureTarget target,GLint level)5601 const std::vector<uint8_t> &FrameCaptureShared::retrieveCachedTextureLevel(gl::TextureID id,
5602                                                                            gl::TextureTarget target,
5603                                                                            GLint level)
5604 {
5605     // Look up the data for the requested texture
5606     const auto &foundTextureLevels = mCachedTextureLevelData.find(id);
5607     ASSERT(foundTextureLevels != mCachedTextureLevelData.end());
5608 
5609     GLint adjustedLevel = GetAdjustedTextureCacheLevel(target, level);
5610 
5611     const auto &foundTextureLevel = foundTextureLevels->second.find(adjustedLevel);
5612     ASSERT(foundTextureLevel != foundTextureLevels->second.end());
5613     const std::vector<uint8_t> &capturedTextureLevel = foundTextureLevel->second;
5614 
5615     return capturedTextureLevel;
5616 }
5617 
copyCachedTextureLevel(const gl::Context * context,gl::TextureID srcID,GLint srcLevel,gl::TextureID dstID,GLint dstLevel,const CallCapture & call)5618 void FrameCaptureShared::copyCachedTextureLevel(const gl::Context *context,
5619                                                 gl::TextureID srcID,
5620                                                 GLint srcLevel,
5621                                                 gl::TextureID dstID,
5622                                                 GLint dstLevel,
5623                                                 const CallCapture &call)
5624 {
5625     // TODO(http://anglebug.com/5604): Add support for partial level copies.
5626     ASSERT(call.params.getParam("srcX", ParamType::TGLint, 3).value.GLintVal == 0);
5627     ASSERT(call.params.getParam("srcY", ParamType::TGLint, 4).value.GLintVal == 0);
5628     ASSERT(call.params.getParam("srcZ", ParamType::TGLint, 5).value.GLintVal == 0);
5629     ASSERT(call.params.getParam("dstX", ParamType::TGLint, 9).value.GLintVal == 0);
5630     ASSERT(call.params.getParam("dstY", ParamType::TGLint, 10).value.GLintVal == 0);
5631     ASSERT(call.params.getParam("dstZ", ParamType::TGLint, 11).value.GLintVal == 0);
5632     GLenum srcTarget  = call.params.getParam("srcTarget", ParamType::TGLenum, 1).value.GLenumVal;
5633     GLsizei srcWidth  = call.params.getParam("srcWidth", ParamType::TGLsizei, 12).value.GLsizeiVal;
5634     GLsizei srcHeight = call.params.getParam("srcHeight", ParamType::TGLsizei, 13).value.GLsizeiVal;
5635     GLsizei srcDepth  = call.params.getParam("srcDepth", ParamType::TGLsizei, 14).value.GLsizeiVal;
5636     gl::Texture *srcTexture           = context->getTexture({srcID});
5637     gl::TextureTarget srcTargetPacked = gl::PackParam<gl::TextureTarget>(srcTarget);
5638     const gl::Extents &srcExtents     = srcTexture->getExtents(srcTargetPacked, srcLevel);
5639     ASSERT(srcExtents.width == srcWidth && srcExtents.height == srcHeight &&
5640            srcExtents.depth == srcDepth);
5641 
5642     // Look up the data for the source texture
5643     const auto &foundSrcTextureLevels = mCachedTextureLevelData.find(srcID);
5644     ASSERT(foundSrcTextureLevels != mCachedTextureLevelData.end());
5645 
5646     // For that texture, look up the data for the given level
5647     const auto &foundSrcTextureLevel = foundSrcTextureLevels->second.find(srcLevel);
5648     ASSERT(foundSrcTextureLevel != foundSrcTextureLevels->second.end());
5649     const std::vector<uint8_t> &srcTextureLevel = foundSrcTextureLevel->second;
5650 
5651     auto foundDstTextureLevels = mCachedTextureLevelData.find(dstID);
5652     if (foundDstTextureLevels == mCachedTextureLevelData.end())
5653     {
5654         // Initialize the texture ID data.
5655         auto emplaceResult = mCachedTextureLevelData.emplace(dstID, TextureLevels());
5656         ASSERT(emplaceResult.second);
5657         foundDstTextureLevels = emplaceResult.first;
5658     }
5659 
5660     TextureLevels &foundDstLevels         = foundDstTextureLevels->second;
5661     TextureLevels::iterator foundDstLevel = foundDstLevels.find(dstLevel);
5662     if (foundDstLevel != foundDstLevels.end())
5663     {
5664         // If we have a cache for this level, remove it since we're recreating it.
5665         foundDstLevels.erase(dstLevel);
5666     }
5667 
5668     // Initialize destination texture data and copy the source into it.
5669     std::vector<uint8_t> dstTextureLevel = srcTextureLevel;
5670     auto emplaceResult = foundDstLevels.emplace(dstLevel, std::move(dstTextureLevel));
5671     ASSERT(emplaceResult.second);
5672 }
5673 
getCachedTextureLevelData(gl::Texture * texture,gl::TextureTarget target,GLint textureLevel,EntryPoint entryPoint)5674 std::vector<uint8_t> &FrameCaptureShared::getCachedTextureLevelData(gl::Texture *texture,
5675                                                                     gl::TextureTarget target,
5676                                                                     GLint textureLevel,
5677                                                                     EntryPoint entryPoint)
5678 {
5679     auto foundTextureLevels = mCachedTextureLevelData.find(texture->id());
5680     if (foundTextureLevels == mCachedTextureLevelData.end())
5681     {
5682         // Initialize the texture ID data.
5683         auto emplaceResult = mCachedTextureLevelData.emplace(texture->id(), TextureLevels());
5684         ASSERT(emplaceResult.second);
5685         foundTextureLevels = emplaceResult.first;
5686     }
5687 
5688     // For this texture, look up the adjusted level, which may not match 1:1 due to cubes
5689     GLint adjustedLevel = GetAdjustedTextureCacheLevel(target, textureLevel);
5690 
5691     TextureLevels &foundLevels         = foundTextureLevels->second;
5692     TextureLevels::iterator foundLevel = foundLevels.find(adjustedLevel);
5693     if (foundLevel != foundLevels.end())
5694     {
5695         if (entryPoint == EntryPoint::GLCompressedTexImage2D ||
5696             entryPoint == EntryPoint::GLCompressedTexImage3D)
5697         {
5698             // Delete the cached entry in case the caller is respecifying the level.
5699             foundLevels.erase(adjustedLevel);
5700         }
5701         else
5702         {
5703             ASSERT(entryPoint == EntryPoint::GLCompressedTexSubImage2D ||
5704                    entryPoint == EntryPoint::GLCompressedTexSubImage3D);
5705 
5706             // If we have a cache for this level, return it now
5707             return foundLevel->second;
5708         }
5709     }
5710 
5711     // Otherwise, create an appropriately sized cache for this level
5712 
5713     // Get the format of the texture for use with the compressed block size math.
5714     const gl::InternalFormat &format = *texture->getFormat(target, textureLevel).info;
5715 
5716     // Divide dimensions according to block size.
5717     const gl::Extents &levelExtents = texture->getExtents(target, textureLevel);
5718 
5719     // Calculate the size needed to store the compressed level
5720     GLuint sizeInBytes;
5721     bool result = format.computeCompressedImageSize(levelExtents, &sizeInBytes);
5722     ASSERT(result);
5723 
5724     // Initialize texture rectangle data. Default init to zero for stability.
5725     std::vector<uint8_t> newPixelData(sizeInBytes, 0);
5726     auto emplaceResult = foundLevels.emplace(adjustedLevel, std::move(newPixelData));
5727     ASSERT(emplaceResult.second);
5728 
5729     // Using the level entry we just created, return the location (a byte vector) where compressed
5730     // texture level data should be stored
5731     return emplaceResult.first->second;
5732 }
5733 
deleteCachedTextureLevelData(gl::TextureID id)5734 void FrameCaptureShared::deleteCachedTextureLevelData(gl::TextureID id)
5735 {
5736     const auto &foundTextureLevels = mCachedTextureLevelData.find(id);
5737     if (foundTextureLevels != mCachedTextureLevelData.end())
5738     {
5739         // Delete all texture levels at once
5740         mCachedTextureLevelData.erase(foundTextureLevels);
5741     }
5742 }
5743 
CaptureMemory(const void * source,size_t size,ParamCapture * paramCapture)5744 void CaptureMemory(const void *source, size_t size, ParamCapture *paramCapture)
5745 {
5746     std::vector<uint8_t> data(size);
5747     memcpy(data.data(), source, size);
5748     paramCapture->data.emplace_back(std::move(data));
5749 }
5750 
CaptureString(const GLchar * str,ParamCapture * paramCapture)5751 void CaptureString(const GLchar *str, ParamCapture *paramCapture)
5752 {
5753     // include the '\0' suffix
5754     CaptureMemory(str, strlen(str) + 1, paramCapture);
5755 }
5756 
CaptureStringLimit(const GLchar * str,uint32_t limit,ParamCapture * paramCapture)5757 void CaptureStringLimit(const GLchar *str, uint32_t limit, ParamCapture *paramCapture)
5758 {
5759     // Write the incoming string up to limit, including null terminator
5760     size_t length = strlen(str) + 1;
5761 
5762     if (length > limit)
5763     {
5764         // If too many characters, resize the string to fit in the limit
5765         std::string newStr = str;
5766         newStr.resize(limit - 1);
5767         CaptureString(newStr.c_str(), paramCapture);
5768     }
5769     else
5770     {
5771         CaptureMemory(str, length, paramCapture);
5772     }
5773 }
5774 
CaptureVertexPointerGLES1(const gl::State & glState,gl::ClientVertexArrayType type,const void * pointer,ParamCapture * paramCapture)5775 void CaptureVertexPointerGLES1(const gl::State &glState,
5776                                gl::ClientVertexArrayType type,
5777                                const void *pointer,
5778                                ParamCapture *paramCapture)
5779 {
5780     paramCapture->value.voidConstPointerVal = pointer;
5781     if (!glState.getTargetBuffer(gl::BufferBinding::Array))
5782     {
5783         paramCapture->arrayClientPointerIndex =
5784             gl::GLES1Renderer::VertexArrayIndex(type, glState.gles1());
5785     }
5786 }
5787 
GetProgramForCapture(const gl::State & glState,gl::ShaderProgramID handle)5788 gl::Program *GetProgramForCapture(const gl::State &glState, gl::ShaderProgramID handle)
5789 {
5790     gl::Program *program = glState.getShaderProgramManagerForCapture().getProgram(handle);
5791     return program;
5792 }
5793 
CaptureGetActiveUniformBlockivParameters(const gl::State & glState,gl::ShaderProgramID handle,gl::UniformBlockIndex uniformBlockIndex,GLenum pname,ParamCapture * paramCapture)5794 void CaptureGetActiveUniformBlockivParameters(const gl::State &glState,
5795                                               gl::ShaderProgramID handle,
5796                                               gl::UniformBlockIndex uniformBlockIndex,
5797                                               GLenum pname,
5798                                               ParamCapture *paramCapture)
5799 {
5800     int numParams = 1;
5801 
5802     // From the OpenGL ES 3.0 spec:
5803     // If pname is UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, then a list of the
5804     // active uniform indices for the uniform block identified by uniformBlockIndex is
5805     // returned. The number of elements that will be written to params is the value of
5806     // UNIFORM_BLOCK_ACTIVE_UNIFORMS for uniformBlockIndex
5807     if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES)
5808     {
5809         gl::Program *program = GetProgramForCapture(glState, handle);
5810         if (program)
5811         {
5812             gl::QueryActiveUniformBlockiv(program, uniformBlockIndex,
5813                                           GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &numParams);
5814         }
5815     }
5816 
5817     paramCapture->readBufferSizeBytes = sizeof(GLint) * numParams;
5818 }
5819 
CaptureGetParameter(const gl::State & glState,GLenum pname,size_t typeSize,ParamCapture * paramCapture)5820 void CaptureGetParameter(const gl::State &glState,
5821                          GLenum pname,
5822                          size_t typeSize,
5823                          ParamCapture *paramCapture)
5824 {
5825     // kMaxReportedCapabilities is the biggest array we'll need to hold data from glGet calls.
5826     // This value needs to be updated if any new extensions are introduced that would allow for
5827     // more compressed texture formats. The current value is taken from:
5828     // http://opengles.gpuinfo.org/displaycapability.php?name=GL_NUM_COMPRESSED_TEXTURE_FORMATS&esversion=2
5829     constexpr unsigned int kMaxReportedCapabilities = 69;
5830     paramCapture->readBufferSizeBytes               = typeSize * kMaxReportedCapabilities;
5831 }
5832 
CaptureGenHandlesImpl(GLsizei n,GLuint * handles,ParamCapture * paramCapture)5833 void CaptureGenHandlesImpl(GLsizei n, GLuint *handles, ParamCapture *paramCapture)
5834 {
5835     paramCapture->readBufferSizeBytes = sizeof(GLuint) * n;
5836     CaptureMemory(handles, paramCapture->readBufferSizeBytes, paramCapture);
5837 }
5838 
CaptureShaderStrings(GLsizei count,const GLchar * const * strings,const GLint * length,ParamCapture * paramCapture)5839 void CaptureShaderStrings(GLsizei count,
5840                           const GLchar *const *strings,
5841                           const GLint *length,
5842                           ParamCapture *paramCapture)
5843 {
5844     for (GLsizei index = 0; index < count; ++index)
5845     {
5846         size_t len = ((length && length[index] >= 0) ? length[index] : strlen(strings[index]));
5847         // includes the '\0' suffix
5848         std::vector<uint8_t> data(len + 1, 0);
5849         memcpy(data.data(), strings[index], len);
5850         paramCapture->data.emplace_back(std::move(data));
5851     }
5852 }
5853 
5854 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLboolean value)5855 void WriteParamValueReplay<ParamType::TGLboolean>(std::ostream &os,
5856                                                   const CallCapture &call,
5857                                                   GLboolean value)
5858 {
5859     switch (value)
5860     {
5861         case GL_TRUE:
5862             os << "GL_TRUE";
5863             break;
5864         case GL_FALSE:
5865             os << "GL_FALSE";
5866             break;
5867         default:
5868             os << "0x" << std::hex << std::uppercase << GLint(value);
5869     }
5870 }
5871 
5872 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const void * value)5873 void WriteParamValueReplay<ParamType::TvoidConstPointer>(std::ostream &os,
5874                                                          const CallCapture &call,
5875                                                          const void *value)
5876 {
5877     if (value == 0)
5878     {
5879         os << "nullptr";
5880     }
5881     else
5882     {
5883         os << "reinterpret_cast<const void *>("
5884            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
5885     }
5886 }
5887 
5888 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLfloat * value)5889 void WriteParamValueReplay<ParamType::TGLfloatConstPointer>(std::ostream &os,
5890                                                             const CallCapture &call,
5891                                                             const GLfloat *value)
5892 {
5893     if (value == 0)
5894     {
5895         os << "nullptr";
5896     }
5897     else
5898     {
5899         os << "reinterpret_cast<const GLfloat *>("
5900            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
5901     }
5902 }
5903 
5904 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,const GLuint * value)5905 void WriteParamValueReplay<ParamType::TGLuintConstPointer>(std::ostream &os,
5906                                                            const CallCapture &call,
5907                                                            const GLuint *value)
5908 {
5909     if (value == 0)
5910     {
5911         os << "nullptr";
5912     }
5913     else
5914     {
5915         os << "reinterpret_cast<const GLuint *>("
5916            << static_cast<int>(reinterpret_cast<uintptr_t>(value)) << ")";
5917     }
5918 }
5919 
5920 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROCKHR value)5921 void WriteParamValueReplay<ParamType::TGLDEBUGPROCKHR>(std::ostream &os,
5922                                                        const CallCapture &call,
5923                                                        GLDEBUGPROCKHR value)
5924 {}
5925 
5926 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLDEBUGPROC value)5927 void WriteParamValueReplay<ParamType::TGLDEBUGPROC>(std::ostream &os,
5928                                                     const CallCapture &call,
5929                                                     GLDEBUGPROC value)
5930 {}
5931 
5932 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::BufferID value)5933 void WriteParamValueReplay<ParamType::TBufferID>(std::ostream &os,
5934                                                  const CallCapture &call,
5935                                                  gl::BufferID value)
5936 {
5937     os << "gBufferMap[" << value.value << "]";
5938 }
5939 
5940 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FenceNVID value)5941 void WriteParamValueReplay<ParamType::TFenceNVID>(std::ostream &os,
5942                                                   const CallCapture &call,
5943                                                   gl::FenceNVID value)
5944 {
5945     os << "gFenceNVMap[" << value.value << "]";
5946 }
5947 
5948 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::FramebufferID value)5949 void WriteParamValueReplay<ParamType::TFramebufferID>(std::ostream &os,
5950                                                       const CallCapture &call,
5951                                                       gl::FramebufferID value)
5952 {
5953     os << "gFramebufferMap[" << value.value << "]";
5954 }
5955 
5956 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::MemoryObjectID value)5957 void WriteParamValueReplay<ParamType::TMemoryObjectID>(std::ostream &os,
5958                                                        const CallCapture &call,
5959                                                        gl::MemoryObjectID value)
5960 {
5961     os << "gMemoryObjectMap[" << value.value << "]";
5962 }
5963 
5964 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ProgramPipelineID value)5965 void WriteParamValueReplay<ParamType::TProgramPipelineID>(std::ostream &os,
5966                                                           const CallCapture &call,
5967                                                           gl::ProgramPipelineID value)
5968 {
5969     os << "gProgramPipelineMap[" << value.value << "]";
5970 }
5971 
5972 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::QueryID value)5973 void WriteParamValueReplay<ParamType::TQueryID>(std::ostream &os,
5974                                                 const CallCapture &call,
5975                                                 gl::QueryID value)
5976 {
5977     os << "gQueryMap[" << value.value << "]";
5978 }
5979 
5980 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::RenderbufferID value)5981 void WriteParamValueReplay<ParamType::TRenderbufferID>(std::ostream &os,
5982                                                        const CallCapture &call,
5983                                                        gl::RenderbufferID value)
5984 {
5985     os << "gRenderbufferMap[" << value.value << "]";
5986 }
5987 
5988 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SamplerID value)5989 void WriteParamValueReplay<ParamType::TSamplerID>(std::ostream &os,
5990                                                   const CallCapture &call,
5991                                                   gl::SamplerID value)
5992 {
5993     os << "gSamplerMap[" << value.value << "]";
5994 }
5995 
5996 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::SemaphoreID value)5997 void WriteParamValueReplay<ParamType::TSemaphoreID>(std::ostream &os,
5998                                                     const CallCapture &call,
5999                                                     gl::SemaphoreID value)
6000 {
6001     os << "gSemaphoreMap[" << value.value << "]";
6002 }
6003 
6004 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::ShaderProgramID value)6005 void WriteParamValueReplay<ParamType::TShaderProgramID>(std::ostream &os,
6006                                                         const CallCapture &call,
6007                                                         gl::ShaderProgramID value)
6008 {
6009     os << "gShaderProgramMap[" << value.value << "]";
6010 }
6011 
6012 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLsync value)6013 void WriteParamValueReplay<ParamType::TGLsync>(std::ostream &os,
6014                                                const CallCapture &call,
6015                                                GLsync value)
6016 {
6017     os << "gSyncMap[" << SyncIndexValue(value) << "]";
6018 }
6019 
6020 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TextureID value)6021 void WriteParamValueReplay<ParamType::TTextureID>(std::ostream &os,
6022                                                   const CallCapture &call,
6023                                                   gl::TextureID value)
6024 {
6025     os << "gTextureMap[" << value.value << "]";
6026 }
6027 
6028 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::TransformFeedbackID value)6029 void WriteParamValueReplay<ParamType::TTransformFeedbackID>(std::ostream &os,
6030                                                             const CallCapture &call,
6031                                                             gl::TransformFeedbackID value)
6032 {
6033     os << "gTransformFeedbackMap[" << value.value << "]";
6034 }
6035 
6036 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::VertexArrayID value)6037 void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
6038                                                       const CallCapture &call,
6039                                                       gl::VertexArrayID value)
6040 {
6041     os << "gVertexArrayMap[" << value.value << "]";
6042 }
6043 
6044 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformLocation value)6045 void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
6046                                                         const CallCapture &call,
6047                                                         gl::UniformLocation value)
6048 {
6049     if (value.value == -1)
6050     {
6051         os << "-1";
6052         return;
6053     }
6054 
6055     os << "gUniformLocations[";
6056 
6057     // Find the program from the call parameters.
6058     gl::ShaderProgramID programID;
6059     if (FindShaderProgramIDInCall(call, &programID))
6060     {
6061         os << "gShaderProgramMap[" << programID.value << "]";
6062     }
6063     else
6064     {
6065         os << "gCurrentProgram";
6066     }
6067 
6068     os << "][" << value.value << "]";
6069 }
6070 
6071 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,gl::UniformBlockIndex value)6072 void WriteParamValueReplay<ParamType::TUniformBlockIndex>(std::ostream &os,
6073                                                           const CallCapture &call,
6074                                                           gl::UniformBlockIndex value)
6075 {
6076     // Find the program from the call parameters.
6077     gl::ShaderProgramID programID;
6078     bool foundProgram = FindShaderProgramIDInCall(call, &programID);
6079     ASSERT(foundProgram);
6080 
6081     os << "gUniformBlockIndexes[gShaderProgramMap[" << programID.value << "]][" << value.value
6082        << "]";
6083 }
6084 
6085 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLeglImageOES value)6086 void WriteParamValueReplay<ParamType::TGLeglImageOES>(std::ostream &os,
6087                                                       const CallCapture &call,
6088                                                       GLeglImageOES value)
6089 {
6090     uint64_t pointerValue = reinterpret_cast<uint64_t>(value);
6091     os << "reinterpret_cast<EGLImageKHR>(" << pointerValue << "ul)";
6092 }
6093 
6094 template <>
WriteParamValueReplay(std::ostream & os,const CallCapture & call,GLubyte value)6095 void WriteParamValueReplay<ParamType::TGLubyte>(std::ostream &os,
6096                                                 const CallCapture &call,
6097                                                 GLubyte value)
6098 {
6099     const int v = value;
6100     os << v;
6101 }
6102 
6103 }  // namespace angle
6104