• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2022 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 // trace_interpreter.cpp:
7 //   Parser and interpreter for the C-based replays.
8 //
9 
10 #include "trace_interpreter.h"
11 
12 #include "anglebase/no_destructor.h"
13 #include "common/gl_enum_utils.h"
14 #include "common/string_utils.h"
15 #include "trace_fixture.h"
16 
17 #define USE_SYSTEM_ZLIB
18 #include "compression_utils_portable.h"
19 
20 namespace angle
21 {
22 namespace
23 {
ShouldParseFile(const std::string & file)24 bool ShouldParseFile(const std::string &file)
25 {
26     return EndsWith(file, ".c") || EndsWith(file, ".cpp");
27 }
28 
ReplayTraceFunction(const TraceFunction & func,const TraceFunctionMap & customFunctions)29 void ReplayTraceFunction(const TraceFunction &func, const TraceFunctionMap &customFunctions)
30 {
31     for (const CallCapture &call : func)
32     {
33         ReplayTraceFunctionCall(call, customFunctions);
34     }
35 }
36 
37 class Parser : angle::NonCopyable
38 {
39   public:
Parser(const std::string & stream,TraceFunctionMap & functionsIn,TraceStringMap & stringsIn,bool verboseLogging)40     Parser(const std::string &stream,
41            TraceFunctionMap &functionsIn,
42            TraceStringMap &stringsIn,
43            bool verboseLogging)
44         : mStream(stream),
45           mFunctions(functionsIn),
46           mStrings(stringsIn),
47           mIndex(0),
48           mVerboseLogging(verboseLogging)
49     {}
50 
parse()51     void parse()
52     {
53         while (mIndex < mStream.size())
54         {
55             if (peek() == '#' || peek() == '/')
56             {
57                 skipLine();
58             }
59             else if (peek() == 'v')
60             {
61                 ASSERT(check("void "));
62                 readFunction();
63             }
64             else if (peek() == 'c')
65             {
66                 ASSERT(check("const "));
67                 readMultilineString();
68             }
69             else
70             {
71                 printf("Unexpected character: '%c'\n", peek());
72                 UNREACHABLE();
73             }
74         }
75     }
76 
77   private:
peek() const78     ANGLE_INLINE char peek() const { return mStream[mIndex]; }
79 
look(size_t ahead) const80     ANGLE_INLINE char look(size_t ahead) const { return mStream[mIndex + ahead]; }
81 
advance()82     ANGLE_INLINE void advance() { mIndex++; }
83 
advanceTo(char delim)84     ANGLE_INLINE void advanceTo(char delim)
85     {
86         while (peek() != delim)
87         {
88             advance();
89         }
90     }
91 
check(const char * forString) const92     bool check(const char *forString) const
93     {
94         return mStream.substr(mIndex, strlen(forString)) == forString;
95     }
96 
skipLine()97     void skipLine()
98     {
99         advanceTo('\n');
100         skipWhitespace();
101     }
102 
skipWhitespace()103     void skipWhitespace()
104     {
105         while (isspace(peek()))
106         {
107             advance();
108         }
109     }
110 
skipNonWhitespace()111     void skipNonWhitespace()
112     {
113         while (!isspace(peek()))
114         {
115             advance();
116         }
117     }
118 
119     // In our simplified trace C, every line that begins with a } either ends a function or a
120     // string. All lines inside the function begin with whitespace. So to find the end of the
121     // function we just need to scan for a line beginning with }.
skipFunction()122     void skipFunction()
123     {
124         while (peek() != '}')
125         {
126             advanceTo('\n');
127             advance();
128         }
129         advance();
130         skipWhitespace();
131     }
132 
readStringAppend(std::string * stringOut,char delim)133     void readStringAppend(std::string *stringOut, char delim)
134     {
135         while (peek() != delim)
136         {
137             if (peek() == '\\')
138             {
139                 advance();
140                 switch (peek())
141                 {
142                     case 'n':
143                         *stringOut += '\n';
144                         break;
145                     case '\"':
146                         *stringOut += '\"';
147                         break;
148                     case '\\':
149                         *stringOut += '\\';
150                         break;
151                     default:
152                         printf("Unrecognized escape character: \\%c\n", peek());
153                         UNREACHABLE();
154                         break;
155                 }
156             }
157             else
158             {
159                 *stringOut += peek();
160             }
161             advance();
162         }
163     }
164 
readToken(Token & token,char delim)165     void readToken(Token &token, char delim)
166     {
167         size_t startIndex = mIndex;
168         advanceTo(delim);
169         size_t tokenSize = mIndex - startIndex;
170         ASSERT(tokenSize < kMaxTokenSize);
171         memcpy(token, &mStream[startIndex], tokenSize);
172         token[mIndex - startIndex] = 0;
173     }
174 
skipCast()175     void skipCast()
176     {
177         if (peek() == '(')
178         {
179             advanceTo(')');
180             advance();
181         }
182     }
183 
skipComments()184     void skipComments()
185     {
186         while (peek() == '/')
187         {
188             skipLine();
189         }
190     }
191 
readFunction()192     void readFunction()
193     {
194         std::string funcName;
195         TraceFunction func;
196 
197         // Skip past the "void" return value.
198         skipNonWhitespace();
199         advance();
200         readStringAppend(&funcName, '(');
201         if (mVerboseLogging)
202         {
203             printf("function: %s\n", funcName.c_str());
204         }
205 
206         // Skip this function because of the switch statements.
207         if (funcName == "ReplayFrame")
208         {
209             skipFunction();
210             return;
211         }
212 
213         skipLine();
214         ASSERT(peek() == '{');
215         skipLine();
216         while (peek() != '}')
217         {
218             skipComments();
219 
220             Token nameToken;
221             readToken(nameToken, '(');
222             advance();
223             ParamBuffer params;
224             Token paramTokens[kMaxParameters];
225             size_t numParams = 0;
226             skipCast();
227             size_t tokenStart = mIndex;
228             while (peek() != ';')
229             {
230                 // Skip casts.
231                 if (peek() == ',' || (peek() == ')' && mIndex != tokenStart))
232                 {
233                     ASSERT(numParams < kMaxParameters);
234                     size_t tokenSize = mIndex - tokenStart;
235                     ASSERT(tokenSize < kMaxTokenSize);
236                     Token &token = paramTokens[numParams++];
237 
238                     memcpy(token, &mStream[tokenStart], tokenSize);
239                     token[tokenSize] = 0;
240                     advance();
241                     skipWhitespace();
242                     skipCast();
243                     tokenStart = mIndex;
244                 }
245                 else
246                 {
247                     advance();
248                 }
249             }
250 
251             // Turn on if you want more spam.
252             // if (mVerboseLogging)
253             //{
254             //    printf("call: %s(", nameToken);
255             //    for (size_t paramIndex = 0; paramIndex < numParams; ++paramIndex)
256             //    {
257             //        if (paramIndex > 0)
258             //        {
259             //            printf(", ");
260             //        }
261             //        printf("%s", paramTokens[paramIndex]);
262             //    }
263             //    printf(")\n");
264             //}
265 
266             // We pass in the strings for specific use with C string array parameters.
267             CallCapture call = ParseCallCapture(nameToken, numParams, paramTokens, mStrings);
268             func.push_back(std::move(call));
269             skipLine();
270         }
271         skipLine();
272 
273         addFunction(funcName, func);
274     }
275 
readMultilineString()276     void readMultilineString()
277     {
278         std::string name;
279         TraceString traceStr;
280 
281         while (peek() != 'g')
282         {
283             advance();
284         }
285         ASSERT(check("glShaderSource") || check("glTransformFeedbackVaryings"));
286 
287         readStringAppend(&name, '[');
288         if (mVerboseLogging)
289         {
290             printf("string: %s\n", name.c_str());
291         }
292         skipLine();
293         std::string str;
294         while (peek() != '}')
295         {
296             advance();
297             readStringAppend(&str, '\"');
298             advance();
299             if (peek() == ',')
300             {
301                 traceStr.strings.push_back(std::move(str));
302             }
303             skipLine();
304         }
305         skipLine();
306 
307         for (const std::string &cppstr : traceStr.strings)
308         {
309             traceStr.pointers.push_back(cppstr.c_str());
310         }
311 
312         mStrings[name] = std::move(traceStr);
313     }
314 
addFunction(const std::string & funcName,TraceFunction & func)315     void addFunction(const std::string &funcName, TraceFunction &func)
316     {
317         // Run initialize immediately so we can load the binary data.
318         if (funcName == "InitReplay")
319         {
320             ReplayTraceFunction(func, {});
321             func.clear();
322         }
323         mFunctions[funcName] = std::move(func);
324     }
325 
326     const std::string &mStream;
327     TraceFunctionMap &mFunctions;
328     TraceStringMap &mStrings;
329     size_t mIndex;
330     bool mVerboseLogging = false;
331 };
332 
PackResourceID(ParamBuffer & params,const Token & token)333 void PackResourceID(ParamBuffer &params, const Token &token)
334 {
335     ASSERT(token[0] == 'g');
336     const char *start = strrchr(token, '[');
337     ASSERT(start != nullptr && EndsWith(token, "]"));
338     uint32_t value = static_cast<uint32_t>(atoi(start + 1));
339     if (BeginsWith(token, "gShaderProgramMap"))
340     {
341         gl::ShaderProgramID id = {value};
342         params.addUnnamedParam(ParamType::TShaderProgramID, id);
343     }
344     else if (BeginsWith(token, "gBufferMap"))
345     {
346         gl::BufferID id = {value};
347         params.addUnnamedParam(ParamType::TBufferID, id);
348     }
349     else if (BeginsWith(token, "gTextureMap"))
350     {
351         gl::TextureID id = {value};
352         params.addUnnamedParam(ParamType::TTextureID, id);
353     }
354     else if (BeginsWith(token, "gRenderbufferMap"))
355     {
356         gl::RenderbufferID id = {value};
357         params.addUnnamedParam(ParamType::TRenderbufferID, id);
358     }
359     else if (BeginsWith(token, "gFramebufferMap"))
360     {
361         gl::FramebufferID id = {value};
362         params.addUnnamedParam(ParamType::TFramebufferID, id);
363     }
364     else if (BeginsWith(token, "gSyncMap"))
365     {
366         gl::SyncID id = {value};
367         params.addUnnamedParam(ParamType::TSyncID, id);
368     }
369     else if (BeginsWith(token, "gTransformFeedbackMap"))
370     {
371         gl::TransformFeedbackID id = {value};
372         params.addUnnamedParam(ParamType::TTransformFeedbackID, id);
373     }
374     else if (BeginsWith(token, "gVertexArrayMap"))
375     {
376         gl::VertexArrayID id = {value};
377         params.addUnnamedParam(ParamType::TVertexArrayID, id);
378     }
379     else if (BeginsWith(token, "gQueryMap"))
380     {
381         gl::QueryID id = {value};
382         params.addUnnamedParam(ParamType::TQueryID, id);
383     }
384     else if (BeginsWith(token, "gSamplerMap"))
385     {
386         gl::SamplerID id = {value};
387         params.addUnnamedParam(ParamType::TSamplerID, id);
388     }
389     else
390     {
391         printf("Unknown resource map: %s\n", token);
392         UNREACHABLE();
393     }
394 }
395 
396 template <typename IntT>
PackIntParameter(ParamBuffer & params,ParamType paramType,const Token & token)397 void PackIntParameter(ParamBuffer &params, ParamType paramType, const Token &token)
398 {
399     IntT value;
400 
401     if (token[0] == 'G')
402     {
403         ASSERT(BeginsWith(token, "GL_"));
404         if (strchr(token, '|') == 0)
405         {
406             value = static_cast<IntT>(gl::StringToGLenum(token));
407         }
408         else
409         {
410             value = static_cast<IntT>(gl::StringToGLbitfield(token));
411         }
412     }
413     else
414     {
415         if (!isdigit(token[0]) && !(token[0] == '-' && isdigit(token[1])))
416         {
417             printf("Expected number, got %s\n", token);
418             UNREACHABLE();
419         }
420         if (token[0] == '0' && token[1] == 'x')
421         {
422             value = static_cast<IntT>(strtol(token, nullptr, 16));
423         }
424         else
425         {
426             value = static_cast<IntT>(atoi(token));
427         }
428     }
429 
430     params.addUnnamedParam(paramType, value);
431 }
432 
GetStringArrayOffset(const Token & token,const char * prefixString)433 uint32_t GetStringArrayOffset(const Token &token, const char *prefixString)
434 {
435     const char *offsetString = &token[strlen(prefixString)];
436     return atoi(offsetString);
437 }
438 
439 template <typename PointerT>
PackMemPointer(ParamBuffer & params,ParamType paramType,uint32_t offset,uint8_t * mem)440 void PackMemPointer(ParamBuffer &params, ParamType paramType, uint32_t offset, uint8_t *mem)
441 {
442     ASSERT(gBinaryData);
443     params.addUnnamedParam(paramType, reinterpret_cast<PointerT>(&mem[offset]));
444 }
445 
446 template <typename T>
PackMutablePointerParameter(ParamBuffer & params,ParamType paramType,const Token & token)447 void PackMutablePointerParameter(ParamBuffer &params, ParamType paramType, const Token &token)
448 {
449     if (token[0] == '0' && token[1] == 0)
450     {
451         params.addUnnamedParam(paramType, reinterpret_cast<T *>(0));
452     }
453     else if (token[0] == '&')
454     {
455         ASSERT(BeginsWith(token, "&gReadBuffer[") && EndsWith(token, "]"));
456         uint32_t offset = GetStringArrayOffset(token, "&gReadBuffer[");
457         PackMemPointer<T *>(params, paramType, offset, gReadBuffer);
458     }
459     else if (token[0] == 'g')
460     {
461         ASSERT(strcmp(token, "gReadBuffer") == 0);
462         params.addUnnamedParam(paramType, reinterpret_cast<T *>(gReadBuffer));
463     }
464     else
465     {
466         UNREACHABLE();
467     }
468 }
469 
470 template <typename T>
PackConstPointerParameter(ParamBuffer & params,ParamType paramType,const Token & token)471 void PackConstPointerParameter(ParamBuffer &params, ParamType paramType, const Token &token)
472 {
473     // Handle nullptr, the literal "0".
474     if (token[0] == '0' && token[1] == 0)
475     {
476         params.addUnnamedParam(paramType, reinterpret_cast<const T *>(0));
477     }
478     else if (token[0] == '&')
479     {
480         ASSERT(BeginsWith(token, "&gBinaryData[") && EndsWith(token, "]"));
481         uint32_t offset = GetStringArrayOffset(token, "&gReadBuffer[");
482         PackMemPointer<const T *>(params, paramType, offset, gBinaryData);
483     }
484     else if (token[0] == 'g')
485     {
486         if (strcmp(token, "gResourceIDBuffer") == 0)
487         {
488             params.addUnnamedParam(paramType, reinterpret_cast<const T *>(gResourceIDBuffer));
489         }
490         else if (BeginsWith(token, "gClientArrays"))
491         {
492             uint32_t offset = GetStringArrayOffset(token, "gClientArrays[");
493             params.addUnnamedParam(paramType, reinterpret_cast<const T *>(gClientArrays[offset]));
494         }
495         else
496         {
497             printf("Unexpected token: %s\n", token);
498             UNREACHABLE();
499         }
500     }
501     else
502     {
503         ASSERT(isdigit(token[0]));
504         uint32_t offset = atoi(token);
505         params.addUnnamedParam(paramType,
506                                reinterpret_cast<const T *>(static_cast<uintptr_t>(offset)));
507     }
508 }
509 
510 class TraceInterpreter : angle::NonCopyable
511 {
512   public:
513     TraceInterpreter()  = default;
514     ~TraceInterpreter() = default;
515 
516     void replayFrame(uint32_t frameIndex);
517     void setupReplay();
518     void resetReplay();
519     void setupFirstFrame();
520     const char *getSerializedContextState(uint32_t frameIndex);
521 
522   private:
523     void runTraceFunction(const char *name) const;
524     void parseTraceUncompressed();
525     void parseTraceGz();
526 
527     TraceFunctionMap mTraceFunctions;
528     TraceStringMap mTraceStrings;
529     bool mVerboseLogging = true;
530 };
531 
replayFrame(uint32_t frameIndex)532 void TraceInterpreter::replayFrame(uint32_t frameIndex)
533 {
534     char funcName[kMaxTokenSize];
535     snprintf(funcName, kMaxTokenSize, "ReplayFrame%u", frameIndex);
536     runTraceFunction(funcName);
537 }
538 
parseTraceUncompressed()539 void TraceInterpreter::parseTraceUncompressed()
540 {
541     for (const std::string &file : gTraceInfo.traceFiles)
542     {
543         if (!ShouldParseFile(file))
544         {
545             if (mVerboseLogging)
546             {
547                 printf("Skipping function parsing for %s.\n", file.c_str());
548             }
549             continue;
550         }
551 
552         if (mVerboseLogging)
553         {
554             printf("Parsing functions from %s\n", file.c_str());
555         }
556         std::stringstream pathStream;
557         pathStream << gBinaryDataDir << GetPathSeparator() << file;
558         std::string path = pathStream.str();
559 
560         std::string fileData;
561         if (!ReadFileToString(path, &fileData))
562         {
563             UNREACHABLE();
564         }
565 
566         Parser parser(fileData, mTraceFunctions, mTraceStrings, mVerboseLogging);
567         parser.parse();
568     }
569 }
570 
parseTraceGz()571 void TraceInterpreter::parseTraceGz()
572 {
573     if (mVerboseLogging)
574     {
575         printf("Parsing functions from %s\n", gTraceGzPath.c_str());
576     }
577 
578     FILE *fp = fopen(gTraceGzPath.c_str(), "rb");
579     if (fp == 0)
580     {
581         printf("Error loading trace (gz) from: %s\n", gTraceGzPath.c_str());
582         exit(1);
583     }
584 
585     fseek(fp, 0, SEEK_END);
586     long size = ftell(fp);
587     fseek(fp, 0, SEEK_SET);
588 
589     std::vector<uint8_t> compressedData(size);
590     (void)fread(compressedData.data(), 1, size, fp);
591 
592     uint32_t uncompressedSize =
593         zlib_internal::GetGzipUncompressedSize(compressedData.data(), compressedData.size());
594 
595     std::string uncompressedData(uncompressedSize, 0);
596     uLong destLen = uncompressedSize;
597     int zResult = zlib_internal::GzipUncompressHelper((uint8_t *)uncompressedData.data(), &destLen,
598                                                       compressedData.data(),
599                                                       static_cast<uLong>(compressedData.size()));
600 
601     if (zResult != Z_OK)
602     {
603         printf("Failure to decompress gz trace: %s\n", gTraceGzPath.c_str());
604         exit(1);
605     }
606 
607     Parser parser(uncompressedData, mTraceFunctions, mTraceStrings, mVerboseLogging);
608     parser.parse();
609 }
610 
setupReplay()611 void TraceInterpreter::setupReplay()
612 {
613     if (!gTraceGzPath.empty())
614     {
615         parseTraceGz();
616     }
617     else
618     {
619         parseTraceUncompressed();
620     }
621 
622     if (mTraceFunctions.count("SetupReplay") == 0)
623     {
624         printf("Did not find a SetupReplay function to run among %zu parsed functions.\n",
625                mTraceFunctions.size());
626         exit(1);
627     }
628 
629     runTraceFunction("SetupReplay");
630 }
631 
resetReplay()632 void TraceInterpreter::resetReplay()
633 {
634     runTraceFunction("ResetReplay");
635 }
636 
setupFirstFrame()637 void TraceInterpreter::setupFirstFrame()
638 {
639     runTraceFunction("SetupFirstFrame");
640 }
641 
getSerializedContextState(uint32_t frameIndex)642 const char *TraceInterpreter::getSerializedContextState(uint32_t frameIndex)
643 {
644     // TODO: Necessary for complete self-testing. http://anglebug.com/42266250
645     UNREACHABLE();
646     return nullptr;
647 }
648 
runTraceFunction(const char * name) const649 void TraceInterpreter::runTraceFunction(const char *name) const
650 {
651     auto iter = mTraceFunctions.find(name);
652     if (iter == mTraceFunctions.end())
653     {
654         printf("Cannot find function: %s\n", name);
655         UNREACHABLE();
656     }
657     const TraceFunction &func = iter->second;
658     ReplayTraceFunction(func, mTraceFunctions);
659 }
660 
GetInterpreter()661 TraceInterpreter &GetInterpreter()
662 {
663     static angle::base::NoDestructor<std::unique_ptr<TraceInterpreter>> sTraceInterpreter(
664         new TraceInterpreter());
665     return *sTraceInterpreter.get()->get();
666 }
667 }  // anonymous namespace
668 
669 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)670 void PackParameter<uint32_t>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
671 {
672     if (token[0] == 'g')
673     {
674         PackResourceID(params, token);
675     }
676     else
677     {
678         PackIntParameter<uint32_t>(params, ParamType::TGLuint, token);
679     }
680 }
681 
682 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)683 void PackParameter<int32_t>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
684 {
685     if (BeginsWith(token, "gUniformLocations"))
686     {
687         const char *start = strrchr(token, '[');
688         ASSERT(start != nullptr && EndsWith(token, "]"));
689         int32_t value           = atoi(start + 1);
690         gl::UniformLocation loc = {value};
691         params.addUnnamedParam(ParamType::TUniformLocation, loc);
692     }
693     else
694     {
695         PackIntParameter<int32_t>(params, ParamType::TGLint, token);
696     }
697 }
698 
699 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)700 void PackParameter<void *>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
701 {
702     void *value = 0;
703     params.addUnnamedParam(ParamType::TvoidPointer, value);
704 }
705 
706 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)707 void PackParameter<const int32_t *>(ParamBuffer &params,
708                                     const Token &token,
709                                     const TraceStringMap &strings)
710 {
711     PackConstPointerParameter<int32_t>(params, ParamType::TGLintConstPointer, token);
712 }
713 
714 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)715 void PackParameter<void **>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
716 {
717     UNREACHABLE();
718 }
719 
720 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)721 void PackParameter<int32_t *>(ParamBuffer &params,
722                               const Token &token,
723                               const TraceStringMap &strings)
724 {
725     PackMutablePointerParameter<int32_t>(params, ParamType::TGLintPointer, token);
726 }
727 
728 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)729 void PackParameter<uint64_t>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
730 {
731     params.addUnnamedParam(ParamType::TGLuint64,
732                            static_cast<GLuint64>(std::strtoull(token, nullptr, 10)));
733 }
734 
735 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)736 void PackParameter<int64_t>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
737 {
738     params.addUnnamedParam(ParamType::TGLint64,
739                            static_cast<GLint64>(std::strtoll(token, nullptr, 10)));
740 }
741 
742 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)743 void PackParameter<const int64_t *>(ParamBuffer &params,
744                                     const Token &token,
745                                     const TraceStringMap &strings)
746 {
747     UNREACHABLE();
748 }
749 
750 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)751 void PackParameter<int64_t *>(ParamBuffer &params,
752                               const Token &token,
753                               const TraceStringMap &strings)
754 {
755     UNREACHABLE();
756 }
757 
758 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)759 void PackParameter<uint64_t *>(ParamBuffer &params,
760                                const Token &token,
761                                const TraceStringMap &strings)
762 {
763     UNREACHABLE();
764 }
765 
766 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)767 void PackParameter<const char *>(ParamBuffer &params,
768                                  const Token &token,
769                                  const TraceStringMap &strings)
770 {
771     if (token[0] == '"')
772     {
773         ASSERT(EndsWith(token, "\""));
774 
775         ParamCapture param(params.getNextParamName(), ParamType::TGLcharConstPointer);
776         std::vector<uint8_t> data(&token[1], &token[strlen(token) - 1]);
777         data.push_back(0);
778         param.data.push_back(std::move(data));
779         param.value.GLcharConstPointerVal = reinterpret_cast<const char *>(param.data[0].data());
780         params.addParam(std::move(param));
781     }
782     else
783     {
784         PackConstPointerParameter<char>(params, ParamType::TGLcharConstPointer, token);
785     }
786 }
787 
788 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)789 void PackParameter<const void *>(ParamBuffer &params,
790                                  const Token &token,
791                                  const TraceStringMap &strings)
792 {
793     PackConstPointerParameter<void>(params, ParamType::TvoidConstPointer, token);
794 }
795 
796 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)797 void PackParameter<uint32_t *>(ParamBuffer &params,
798                                const Token &token,
799                                const TraceStringMap &strings)
800 {
801     PackMutablePointerParameter<uint32_t>(params, ParamType::TGLuintPointer, token);
802 }
803 
804 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)805 void PackParameter<const uint32_t *>(ParamBuffer &params,
806                                      const Token &token,
807                                      const TraceStringMap &strings)
808 {
809     PackConstPointerParameter<uint32_t>(params, ParamType::TGLuintConstPointer, token);
810 }
811 
812 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)813 void PackParameter<float>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
814 {
815     params.addUnnamedParam(ParamType::TGLfloat, std::stof(token));
816 }
817 
818 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)819 void PackParameter<uint8_t>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
820 {
821     PackIntParameter<uint8_t>(params, ParamType::TGLubyte, token);
822 }
823 
824 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)825 void PackParameter<float *>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
826 {
827     PackMutablePointerParameter<float>(params, ParamType::TGLfloatPointer, token);
828 }
829 
830 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)831 void PackParameter<const float *>(ParamBuffer &params,
832                                   const Token &token,
833                                   const TraceStringMap &strings)
834 {
835     PackConstPointerParameter<float>(params, ParamType::TGLfloatConstPointer, token);
836 }
837 
838 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)839 void PackParameter<GLsync>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
840 {
841     PackResourceID(params, token);
842 }
843 
844 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)845 void PackParameter<const char *const *>(ParamBuffer &params,
846                                         const Token &token,
847                                         const TraceStringMap &strings)
848 {
849     // Find the string that corresponds to "token". Currently we only support string arrays.
850     auto iter = strings.find(token);
851     if (iter == strings.end())
852     {
853         printf("Could not find string: %s\n", token);
854         UNREACHABLE();
855     }
856     const TraceString &traceStr = iter->second;
857     params.addUnnamedParam(ParamType::TGLcharConstPointerPointer, traceStr.pointers.data());
858 }
859 
860 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)861 void PackParameter<const char **>(ParamBuffer &params,
862                                   const Token &token,
863                                   const TraceStringMap &strings)
864 {
865     UNREACHABLE();
866 }
867 
868 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)869 void PackParameter<GLDEBUGPROCKHR>(ParamBuffer &params,
870                                    const Token &token,
871                                    const TraceStringMap &strings)
872 {
873     UNREACHABLE();
874 }
875 
876 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)877 void PackParameter<EGLDEBUGPROCKHR>(ParamBuffer &params,
878                                     const Token &token,
879                                     const TraceStringMap &strings)
880 {
881     UNREACHABLE();
882 }
883 
884 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)885 void PackParameter<const struct AHardwareBuffer *>(ParamBuffer &params,
886                                                    const Token &token,
887                                                    const TraceStringMap &strings)
888 {
889     UNREACHABLE();
890 }
891 
892 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)893 void PackParameter<EGLSetBlobFuncANDROID>(ParamBuffer &params,
894                                           const Token &token,
895                                           const TraceStringMap &strings)
896 {
897     UNREACHABLE();
898 }
899 
900 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)901 void PackParameter<EGLGetBlobFuncANDROID>(ParamBuffer &params,
902                                           const Token &token,
903                                           const TraceStringMap &strings)
904 {
905     UNREACHABLE();
906 }
907 
908 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)909 void PackParameter<int16_t>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
910 {
911     PackIntParameter<int16_t>(params, ParamType::TGLshort, token);
912 }
913 
914 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)915 void PackParameter<const int16_t *>(ParamBuffer &params,
916                                     const Token &token,
917                                     const TraceStringMap &strings)
918 {
919     PackConstPointerParameter<int16_t>(params, ParamType::TGLshortConstPointer, token);
920 }
921 
922 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)923 void PackParameter<char *>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
924 {
925     UNREACHABLE();
926 }
927 
928 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)929 void PackParameter<unsigned char *>(ParamBuffer &params,
930                                     const Token &token,
931                                     const TraceStringMap &strings)
932 {
933     PackMutablePointerParameter<GLubyte>(params, ParamType::TGLubytePointer, token);
934 }
935 
936 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)937 void PackParameter<const void *const *>(ParamBuffer &params,
938                                         const Token &token,
939                                         const TraceStringMap &strings)
940 {
941     UNREACHABLE();
942 }
943 
944 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)945 void PackParameter<const uint64_t *>(ParamBuffer &params,
946                                      const Token &token,
947                                      const TraceStringMap &strings)
948 {
949     UNREACHABLE();
950 }
951 
952 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)953 void PackParameter<GLGETBLOBPROCANGLE>(ParamBuffer &params,
954                                        const Token &token,
955                                        const TraceStringMap &strings)
956 {
957     UNREACHABLE();
958 }
959 
960 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)961 void PackParameter<GLSETBLOBPROCANGLE>(ParamBuffer &params,
962                                        const Token &token,
963                                        const TraceStringMap &strings)
964 {
965     UNREACHABLE();
966 }
967 
968 #if defined(ANGLE_PLATFORM_WINDOWS)
969 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)970 void PackParameter<EGLNativeDisplayType>(ParamBuffer &params,
971                                          const Token &token,
972                                          const TraceStringMap &strings)
973 {
974     UNREACHABLE();
975 }
976 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
977 
978 #if defined(ANGLE_PLATFORM_WINDOWS) || defined(ANGLE_PLATFORM_ANDROID)
979 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)980 void PackParameter<EGLNativeWindowType>(ParamBuffer &params,
981                                         const Token &token,
982                                         const TraceStringMap &strings)
983 {
984     UNREACHABLE();
985 }
986 
987 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)988 void PackParameter<EGLNativePixmapType>(ParamBuffer &params,
989                                         const Token &token,
990                                         const TraceStringMap &strings)
991 {
992     UNREACHABLE();
993 }
994 #endif  // defined(ANGLE_PLATFORM_WINDOWS) || defined(ANGLE_PLATFORM_ANDROID)
995 
996 #if defined(ANGLE_PLATFORM_APPLE) || !defined(ANGLE_IS_64_BIT_CPU)
997 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)998 void PackParameter<const long *>(ParamBuffer &params,
999                                  const Token &token,
1000                                  const TraceStringMap &strings)
1001 {
1002     PackConstPointerParameter<int64_t>(params, ParamType::TGLuint64ConstPointer, token);
1003 }
1004 
1005 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)1006 void PackParameter<long *>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
1007 {
1008     PackMutablePointerParameter<int64_t>(params, ParamType::TGLint64Pointer, token);
1009 }
1010 
1011 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)1012 void PackParameter<long>(ParamBuffer &params, const Token &token, const TraceStringMap &strings)
1013 {
1014     PackIntParameter<int64_t>(params, ParamType::TGLint64, token);
1015 }
1016 
1017 template <>
PackParameter(ParamBuffer & params,const Token & token,const TraceStringMap & strings)1018 void PackParameter<unsigned long>(ParamBuffer &params,
1019                                   const Token &token,
1020                                   const TraceStringMap &strings)
1021 {
1022     PackIntParameter<uint64_t>(params, ParamType::TGLuint64, token);
1023 }
1024 #endif  // defined(ANGLE_PLATFORM_APPLE) || !defined(ANGLE_IS_64_BIT_CPU)
1025 
GetResourceIDMapValue(ResourceIDType resourceIDType,GLuint key)1026 GLuint GetResourceIDMapValue(ResourceIDType resourceIDType, GLuint key)
1027 {
1028     switch (resourceIDType)
1029     {
1030         case ResourceIDType::Buffer:
1031             return gBufferMap[key];
1032         case ResourceIDType::FenceNV:
1033             return gFenceNVMap[key];
1034         case ResourceIDType::Framebuffer:
1035             return gFramebufferMap[key];
1036         case ResourceIDType::ProgramPipeline:
1037             return gProgramPipelineMap[key];
1038         case ResourceIDType::Query:
1039             return gQueryMap[key];
1040         case ResourceIDType::Renderbuffer:
1041             return gRenderbufferMap[key];
1042         case ResourceIDType::Sampler:
1043             return gSamplerMap[key];
1044         case ResourceIDType::Semaphore:
1045             return gSemaphoreMap[key];
1046         case ResourceIDType::ShaderProgram:
1047             return gShaderProgramMap[key];
1048         case ResourceIDType::Texture:
1049             return gTextureMap[key];
1050         case ResourceIDType::TransformFeedback:
1051             return gTransformFeedbackMap[key];
1052         case ResourceIDType::VertexArray:
1053             return gVertexArrayMap[key];
1054         default:
1055             printf("Incompatible resource ID type: %d\n", static_cast<int>(resourceIDType));
1056             UNREACHABLE();
1057             return 0;
1058     }
1059 }
1060 
1061 }  // namespace angle
1062 
1063 extern "C" {
SetupReplay()1064 void SetupReplay()
1065 {
1066     angle::GetInterpreter().setupReplay();
1067 }
1068 
ReplayFrame(uint32_t frameIndex)1069 void ReplayFrame(uint32_t frameIndex)
1070 {
1071     angle::GetInterpreter().replayFrame(frameIndex);
1072 }
1073 
ResetReplay()1074 void ResetReplay()
1075 {
1076     angle::GetInterpreter().resetReplay();
1077 }
1078 
GetSerializedContextState(uint32_t frameIndex)1079 const char *GetSerializedContextState(uint32_t frameIndex)
1080 {
1081     return angle::GetInterpreter().getSerializedContextState(frameIndex);
1082 }
1083 }  // extern "C"
1084