• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 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 // frame_capture_test_utils:
7 //   Helper functions for capture and replay of traces.
8 //
9 
10 #include "frame_capture_test_utils.h"
11 
12 #include "common/frame_capture_utils.h"
13 #include "common/string_utils.h"
14 
15 #include <rapidjson/document.h>
16 #include <rapidjson/istreamwrapper.h>
17 #include <fstream>
18 
19 namespace angle
20 {
21 namespace
22 {
LoadJSONFromFile(const std::string & fileName,rapidjson::Document * doc)23 bool LoadJSONFromFile(const std::string &fileName, rapidjson::Document *doc)
24 {
25     std::ifstream ifs(fileName);
26     if (!ifs.is_open())
27     {
28         return false;
29     }
30 
31     rapidjson::IStreamWrapper inWrapper(ifs);
32     doc->ParseStream(inWrapper);
33     return !doc->HasParseError();
34 }
35 }  // namespace
36 
LoadTraceNamesFromJSON(const std::string jsonFilePath,std::vector<std::string> * namesOut)37 bool LoadTraceNamesFromJSON(const std::string jsonFilePath, std::vector<std::string> *namesOut)
38 {
39     rapidjson::Document doc;
40     if (!LoadJSONFromFile(jsonFilePath, &doc))
41     {
42         return false;
43     }
44 
45     if (!doc.IsObject() || !doc.HasMember("traces") || !doc["traces"].IsArray())
46     {
47         return false;
48     }
49 
50     // Read trace json into a list of trace names.
51     std::vector<std::string> traces;
52 
53     rapidjson::Document::Array traceArray = doc["traces"].GetArray();
54     for (rapidjson::SizeType arrayIndex = 0; arrayIndex < traceArray.Size(); ++arrayIndex)
55     {
56         const rapidjson::Document::ValueType &arrayElement = traceArray[arrayIndex];
57 
58         if (!arrayElement.IsString())
59         {
60             return false;
61         }
62 
63         std::vector<std::string> traceAndVersion;
64         angle::SplitStringAlongWhitespace(arrayElement.GetString(), &traceAndVersion);
65         traces.push_back(traceAndVersion[0]);
66     }
67 
68     *namesOut = std::move(traces);
69     return true;
70 }
71 
LoadTraceInfoFromJSON(const std::string & traceName,const std::string & traceJsonPath,TraceInfo * traceInfoOut)72 bool LoadTraceInfoFromJSON(const std::string &traceName,
73                            const std::string &traceJsonPath,
74                            TraceInfo *traceInfoOut)
75 {
76     rapidjson::Document doc;
77     if (!LoadJSONFromFile(traceJsonPath, &doc))
78     {
79         return false;
80     }
81 
82     if (!doc.IsObject() || !doc.HasMember("TraceMetadata"))
83     {
84         return false;
85     }
86 
87     const rapidjson::Document::Object &meta = doc["TraceMetadata"].GetObj();
88 
89     strncpy(traceInfoOut->name, traceName.c_str(), kTraceInfoMaxNameLen);
90     traceInfoOut->contextClientMajorVersion = meta["ContextClientMajorVersion"].GetInt();
91     traceInfoOut->contextClientMinorVersion = meta["ContextClientMinorVersion"].GetInt();
92     traceInfoOut->frameEnd                  = meta["FrameEnd"].GetInt();
93     traceInfoOut->frameStart                = meta["FrameStart"].GetInt();
94     traceInfoOut->drawSurfaceHeight         = meta["DrawSurfaceHeight"].GetInt();
95     traceInfoOut->drawSurfaceWidth          = meta["DrawSurfaceWidth"].GetInt();
96 
97     angle::HexStringToUInt(meta["DrawSurfaceColorSpace"].GetString(),
98                            &traceInfoOut->drawSurfaceColorSpace);
99     angle::HexStringToUInt(meta["DisplayPlatformType"].GetString(),
100                            &traceInfoOut->displayPlatformType);
101     angle::HexStringToUInt(meta["DisplayDeviceType"].GetString(), &traceInfoOut->displayDeviceType);
102 
103     traceInfoOut->configRedBits     = meta["ConfigRedBits"].GetInt();
104     traceInfoOut->configGreenBits   = meta["ConfigGreenBits"].GetInt();
105     traceInfoOut->configBlueBits    = meta["ConfigBlueBits"].GetInt();
106     traceInfoOut->configAlphaBits   = meta["ConfigAlphaBits"].GetInt();
107     traceInfoOut->configDepthBits   = meta["ConfigDepthBits"].GetInt();
108     traceInfoOut->configStencilBits = meta["ConfigStencilBits"].GetInt();
109 
110     traceInfoOut->isBinaryDataCompressed = meta["IsBinaryDataCompressed"].GetBool();
111     traceInfoOut->areClientArraysEnabled = meta["AreClientArraysEnabled"].GetBool();
112     traceInfoOut->isBindGeneratesResourcesEnabled =
113         meta["IsBindGeneratesResourcesEnabled"].GetBool();
114     traceInfoOut->isWebGLCompatibilityEnabled = meta["IsWebGLCompatibilityEnabled"].GetBool();
115     traceInfoOut->isRobustResourceInitEnabled = meta["IsRobustResourceInitEnabled"].GetBool();
116     traceInfoOut->windowSurfaceContextId      = doc["WindowSurfaceContextID"].GetInt();
117 
118     if (doc.HasMember("RequiredExtensions"))
119     {
120         const rapidjson::Value &requiredExtensions = doc["RequiredExtensions"];
121         if (!requiredExtensions.IsArray())
122         {
123             return false;
124         }
125         for (rapidjson::SizeType i = 0; i < requiredExtensions.Size(); i++)
126         {
127             std::string ext = std::string(requiredExtensions[i].GetString());
128             traceInfoOut->requiredExtensions.push_back(ext);
129         }
130     }
131 
132     if (meta.HasMember("KeyFrames"))
133     {
134         const rapidjson::Value &keyFrames = meta["KeyFrames"];
135         if (!keyFrames.IsArray())
136         {
137             return false;
138         }
139         for (rapidjson::SizeType i = 0; i < keyFrames.Size(); i++)
140         {
141             int frame = keyFrames[i].GetInt();
142             traceInfoOut->keyFrames.push_back(frame);
143         }
144     }
145 
146     const rapidjson::Document::Array &traceFiles = doc["TraceFiles"].GetArray();
147     for (const rapidjson::Value &value : traceFiles)
148     {
149         traceInfoOut->traceFiles.push_back(value.GetString());
150     }
151 
152     traceInfoOut->initialized = true;
153     return true;
154 }
155 
TraceLibrary(const std::string & traceName,const TraceInfo & traceInfo)156 TraceLibrary::TraceLibrary(const std::string &traceName, const TraceInfo &traceInfo)
157 {
158     std::stringstream libNameStr;
159     SearchType searchType = SearchType::ModuleDir;
160 
161 #if defined(ANGLE_TRACE_EXTERNAL_BINARIES)
162     // This means we are using the binary build of traces on Android, which are
163     // not bundled in the APK, but located in the app's home directory.
164     searchType = SearchType::SystemDir;
165     libNameStr << "/data/user/0/com.android.angle.test/angle_traces/";
166 #endif  // defined(ANGLE_TRACE_EXTERNAL_BINARIES)
167 #if !defined(ANGLE_PLATFORM_WINDOWS)
168     libNameStr << "lib";
169 #endif  // !defined(ANGLE_PLATFORM_WINDOWS)
170     libNameStr << traceName;
171 #if defined(ANGLE_PLATFORM_ANDROID) && defined(COMPONENT_BUILD)
172     // Added to shared library names in Android component builds in
173     // https://chromium.googlesource.com/chromium/src/+/9bacc8c4868cc802f69e1e858eea6757217a508f/build/toolchain/toolchain.gni#56
174     libNameStr << ".cr";
175 #endif  // defined(ANGLE_PLATFORM_ANDROID) && defined(COMPONENT_BUILD)
176     std::string libName = libNameStr.str();
177     std::string loadError;
178     mTraceLibrary.reset(OpenSharedLibraryAndGetError(libName.c_str(), searchType, &loadError));
179     if (mTraceLibrary->getNative() == nullptr)
180     {
181         FATAL() << "Failed to load trace library (" << libName << "): " << loadError;
182     }
183 
184     callFunc<SetupEntryPoints>("SetupEntryPoints", static_cast<angle::TraceCallbacks *>(this),
185                                &mTraceFunctions);
186     mTraceFunctions->SetTraceInfo(traceInfo);
187     mTraceInfo = traceInfo;
188 }
189 
LoadBinaryData(const char * fileName)190 uint8_t *TraceLibrary::LoadBinaryData(const char *fileName)
191 {
192     std::ostringstream pathBuffer;
193     pathBuffer << mBinaryDataDir << "/" << fileName;
194     FILE *fp = fopen(pathBuffer.str().c_str(), "rb");
195     if (fp == 0)
196     {
197         fprintf(stderr, "Error loading binary data file: %s\n", fileName);
198         exit(1);
199     }
200     fseek(fp, 0, SEEK_END);
201     long size = ftell(fp);
202     fseek(fp, 0, SEEK_SET);
203     if (mTraceInfo.isBinaryDataCompressed)
204     {
205         if (!strstr(fileName, ".gz"))
206         {
207             fprintf(stderr, "Filename does not end in .gz");
208             exit(1);
209         }
210 
211         std::vector<uint8_t> compressedData(size);
212         (void)fread(compressedData.data(), 1, size, fp);
213 
214         uint32_t uncompressedSize =
215             zlib_internal::GetGzipUncompressedSize(compressedData.data(), compressedData.size());
216 
217         mBinaryData.resize(uncompressedSize + 1);  // +1 to make sure .data() is valid
218         uLong destLen = uncompressedSize;
219         int zResult =
220             zlib_internal::GzipUncompressHelper(mBinaryData.data(), &destLen, compressedData.data(),
221                                                 static_cast<uLong>(compressedData.size()));
222 
223         if (zResult != Z_OK)
224         {
225             std::cerr << "Failure to decompressed binary data: " << zResult << "\n";
226             exit(1);
227         }
228     }
229     else
230     {
231         if (!strstr(fileName, ".angledata"))
232         {
233             fprintf(stderr, "Filename does not end in .angledata");
234             exit(1);
235         }
236         mBinaryData.resize(size + 1);
237         (void)fread(mBinaryData.data(), 1, size, fp);
238     }
239     fclose(fp);
240 
241     return mBinaryData.data();
242 }
243 
244 }  // namespace angle
245