Add an optional parameter (ANGLE_CAPTURE_LABEL) to
ANGLE frame capture that tags files and functions
uniquely, allowing multiple frame captures to be
replayed by a test harness.

Example:

  ANGLE_CAPTURE_LABEL=foo

Results in filenames like this:

  foo_capture_context1.cpp
  foo_capture_context1.h
  foo_capture_context1_files.txt
  foo_capture_context1_frame000.angledata
  foo_capture_context1_frame000.cpp
  foo_capture_context1_frame001.angledata
  foo_capture_context1_frame001.cpp
  ...

Functions wrapped in namespaces like this:

  namespace foo
  {
      void ReplayContext1Frame0();
      void ReplayContext1Frame1();
  }

For use like this:

  foo::SetupContext1Replay();
  for (...)
  {
      foo::ReplayContext1Frame(i);
  }

Bug: angleproject:3630
Change-Id: Ibe27dc4d40a36606ee40678a9e4d43b5a4baf976
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1949603
Commit-Queue: Cody Northrop <cnorthrop@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Cody Northrop 2019-12-03 15:54:41 -07:00 коммит произвёл Commit Bot
Родитель 554b453c95
Коммит 1d77542f56
3 изменённых файлов: 126 добавлений и 23 удалений

Просмотреть файл

@ -41,6 +41,36 @@ Some simple environment variables control frame capture:
* `ANGLE_CAPTURE_FRAME_END=<n>`:
* By default ANGLE will capture the first ten frames. This variable can override the default.
* Example: `ANGLE_CAPTURE_FRAME_END=4`. Default is `10`.
* `ANGLE_CAPTURE_LABEL=<label>`:
* When specified, files and functions will be labeled uniquely.
* Example: `ANGLE_CAPTURE_LABEL=foo`
* Results in filenames like this:
```
foo_capture_context1.cpp
foo_capture_context1.h
foo_capture_context1_files.txt
foo_capture_context1_frame000.angledata
foo_capture_context1_frame000.cpp
foo_capture_context1_frame001.angledata
foo_capture_context1_frame001.cpp
...
```
* Functions wrapped in namespaces like this:
```
namespace foo
{
void ReplayContext1Frame0();
void ReplayContext1Frame1();
}
```
* For use like this:
```
foo::SetupContext1Replay();
for (...)
{
foo::ReplayContext1Frame(i);
}
```
A good way to test out the capture is to use environment variables in conjunction with the sample
template. For example:
@ -105,6 +135,7 @@ as the GLES driver for your application.
$ adb shell setprop debug.angle.capture.enabled 0
$ adb shell setprop debug.angle.capture.out_dir foo
$ adb shell setprop debug.angle.capture.frame_start 0
$ adb shell setprop debug.angle.capture.label bar
```
3. Run the application, then pull the files to the capture_replay directory

Просмотреть файл

@ -40,6 +40,7 @@ constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
#if defined(ANGLE_PLATFORM_ANDROID)
@ -47,6 +48,7 @@ constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
constexpr char kAndroidOutDir[] = "debug.angle.capture.out_dir";
constexpr char kAndroidFrameStart[] = "debug.angle.capture.frame_start";
constexpr char kAndroidFrameEnd[] = "debug.angle.capture.frame_end";
constexpr char kAndroidCaptureLabel[] = "debug.angle.capture.label";
constexpr int kStreamSize = 64;
@ -102,6 +104,13 @@ void PrimeAndroidEnvironmentVariables()
INFO() << "Frame capture read " << frameEnd << " from " << kAndroidFrameEnd;
setenv(kFrameEndVarName, frameEnd.c_str(), 1);
}
std::string captureLabel = AndroidGetEnvFromProp(kAndroidCaptureLabel);
if (!captureLabel.empty())
{
INFO() << "Capture label read " << captureLabel << " from " << kAndroidCaptureLabel;
setenv(kCaptureLabel, captureLabel.c_str(), 1);
}
}
#endif
@ -148,13 +157,24 @@ std::string GetDefaultOutDirectory()
struct FmtCapturePrefix
{
FmtCapturePrefix(int contextIdIn) : contextId(contextIdIn) {}
FmtCapturePrefix(int contextIdIn, const std::string &captureLabelIn)
: contextId(contextIdIn), captureLabel(captureLabelIn)
{}
int contextId;
const std::string &captureLabel;
};
std::ostream &operator<<(std::ostream &os, const FmtCapturePrefix &fmt)
{
os << "angle_capture_context" << fmt.contextId;
if (fmt.captureLabel.empty())
{
os << "angle";
}
else
{
os << fmt.captureLabel;
}
os << "_capture_context" << fmt.contextId;
return os;
}
@ -173,20 +193,24 @@ std::ostream &operator<<(std::ostream &os, const FmtReplayFunction &fmt)
return os;
}
std::string GetCaptureFileName(int contextId, uint32_t frameIndex, const char *suffix)
std::string GetCaptureFileName(int contextId,
const std::string &captureLabel,
uint32_t frameIndex,
const char *suffix)
{
std::stringstream fnameStream;
fnameStream << FmtCapturePrefix(contextId) << "_frame" << std::setfill('0') << std::setw(3)
<< frameIndex << suffix;
fnameStream << FmtCapturePrefix(contextId, captureLabel) << "_frame" << std::setfill('0')
<< std::setw(3) << frameIndex << suffix;
return fnameStream.str();
}
std::string GetCaptureFilePath(const std::string &outDir,
int contextId,
const std::string &captureLabel,
uint32_t frameIndex,
const char *suffix)
{
return outDir + GetCaptureFileName(contextId, frameIndex, suffix);
return outDir + GetCaptureFileName(contextId, captureLabel, frameIndex, suffix);
}
void WriteParamStaticVarName(const CallCapture &call,
@ -515,16 +539,19 @@ struct SaveFileHelper
void SaveBinaryData(const std::string &outDir,
std::ostream &out,
int contextId,
const std::string &captureLabel,
uint32_t frameIndex,
const char *suffix,
const std::vector<uint8_t> &binaryData)
{
std::string binaryDataFileName = GetCaptureFileName(contextId, frameIndex, suffix);
std::string binaryDataFileName =
GetCaptureFileName(contextId, captureLabel, frameIndex, suffix);
out << " LoadBinaryData(\"" << binaryDataFileName << "\", "
<< static_cast<int>(binaryData.size()) << ");\n";
std::string dataFilepath = GetCaptureFilePath(outDir, contextId, frameIndex, suffix);
std::string dataFilepath =
GetCaptureFilePath(outDir, contextId, captureLabel, frameIndex, suffix);
SaveFileHelper saveData(dataFilepath, std::ios::binary);
saveData.ofs.write(reinterpret_cast<const char *>(binaryData.data()), binaryData.size());
@ -532,6 +559,7 @@ void SaveBinaryData(const std::string &outDir,
void WriteCppReplay(const std::string &outDir,
int contextId,
const std::string &captureLabel,
uint32_t frameIndex,
const std::vector<CallCapture> &frameCalls,
const std::vector<CallCapture> &setupCalls)
@ -541,12 +569,18 @@ void WriteCppReplay(const std::string &outDir,
std::stringstream out;
std::stringstream header;
header << "#include \"" << FmtCapturePrefix(contextId) << ".h\"\n";
header << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
header << "";
header << "\n";
header << "namespace\n";
header << "{\n";
if (!captureLabel.empty())
{
out << "namespace " << captureLabel << "\n";
out << "{\n";
}
if (frameIndex == 0 || !setupCalls.empty())
{
out << "void SetupContext" << Str(contextId) << "Replay()\n";
@ -564,7 +598,8 @@ void WriteCppReplay(const std::string &outDir,
if (!setupBinaryData.empty())
{
SaveBinaryData(outDir, out, contextId, frameIndex, ".setup.angledata", setupBinaryData);
SaveBinaryData(outDir, out, contextId, captureLabel, frameIndex, ".setup.angledata",
setupBinaryData);
}
out << setupCallStream.str();
@ -588,19 +623,25 @@ void WriteCppReplay(const std::string &outDir,
if (!binaryData.empty())
{
SaveBinaryData(outDir, out, contextId, frameIndex, ".angledata", binaryData);
SaveBinaryData(outDir, out, contextId, captureLabel, frameIndex, ".angledata", binaryData);
}
out << callStream.str();
out << "}\n";
if (!captureLabel.empty())
{
out << "} // namespace " << captureLabel << "\n";
}
header << "} // namespace\n";
{
std::string outString = out.str();
std::string headerString = header.str();
std::string cppFilePath = GetCaptureFilePath(outDir, contextId, frameIndex, ".cpp");
std::string cppFilePath =
GetCaptureFilePath(outDir, contextId, captureLabel, frameIndex, ".cpp");
SaveFileHelper saveCpp(cppFilePath);
saveCpp << headerString << "\n" << outString;
@ -609,6 +650,7 @@ void WriteCppReplay(const std::string &outDir,
void WriteCppReplayIndexFiles(const std::string &outDir,
int contextId,
const std::string &captureLabel,
uint32_t frameStart,
uint32_t frameEnd,
size_t readBufferSize,
@ -631,6 +673,13 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
header << "\n";
header << "// Replay functions\n";
header << "\n";
header << "using ResourceMap = std::unordered_map<GLuint, GLuint>;\n";
header << "\n";
if (!captureLabel.empty())
{
header << "namespace " << captureLabel << "\n";
header << "{\n";
}
header << "constexpr uint32_t kReplayFrameStart = " << frameStart << ";\n";
header << "constexpr uint32_t kReplayFrameEnd = " << frameEnd << ";\n";
header << "\n";
@ -647,11 +696,9 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
header << "\n";
header << "// Global state\n";
header << "\n";
header << "using ResourceMap = std::unordered_map<GLuint, GLuint>;\n";
header << "\n";
header << "extern uint8_t *gBinaryData;\n";
source << "#include \"" << FmtCapturePrefix(contextId) << ".h\"\n";
source << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
source << "\n";
source << "namespace\n";
source << "{\n";
@ -659,13 +706,22 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
"readBufferOffset)\n";
source << "{\n";
source << " GLuint returnedID;\n";
source << " memcpy(&returnedID, &gReadBuffer[readBufferOffset], sizeof(GLuint));\n";
std::string captureNamespace = !captureLabel.empty() ? captureLabel + "::" : "";
source << " memcpy(&returnedID, &" << captureNamespace
<< "gReadBuffer[readBufferOffset], sizeof(GLuint));\n ";
source << " (*resourceMap)[id] = returnedID;\n";
source << "}\n";
source << "\n";
source << "const char *gBinaryDataDir = \".\";\n";
source << "} // namespace\n";
source << "\n";
if (!captureLabel.empty())
{
source << "namespace " << captureLabel << "\n";
source << "{\n";
}
source << "uint8_t *gBinaryData = nullptr;\n";
if (readBufferSize > 0)
@ -754,11 +810,17 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
source << "}\n";
}
if (!captureLabel.empty())
{
header << "} // namespace " << captureLabel << "\n";
source << "} // namespace " << captureLabel << "\n";
}
{
std::string headerContents = header.str();
std::stringstream headerPathStream;
headerPathStream << outDir << FmtCapturePrefix(contextId) << ".h";
headerPathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << ".h";
std::string headerPath = headerPathStream.str();
SaveFileHelper saveHeader(headerPath);
@ -769,7 +831,7 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
std::string sourceContents = source.str();
std::stringstream sourcePathStream;
sourcePathStream << outDir << FmtCapturePrefix(contextId) << ".cpp";
sourcePathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << ".cpp";
std::string sourcePath = sourcePathStream.str();
SaveFileHelper saveSource(sourcePath);
@ -778,13 +840,13 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
{
std::stringstream indexPathStream;
indexPathStream << outDir << FmtCapturePrefix(contextId) << "_files.txt";
indexPathStream << outDir << FmtCapturePrefix(contextId, captureLabel) << "_files.txt";
std::string indexPath = indexPathStream.str();
SaveFileHelper saveIndex(indexPath);
for (uint32_t frameIndex = frameStart; frameIndex <= frameEnd; ++frameIndex)
{
saveIndex << GetCaptureFileName(contextId, frameIndex, ".cpp") << "\n";
saveIndex << GetCaptureFileName(contextId, captureLabel, frameIndex, ".cpp") << "\n";
}
}
}
@ -1865,6 +1927,13 @@ FrameCapture::FrameCapture()
{
mFrameEnd = atoi(endFromEnv.c_str());
}
std::string labelFromEnv = angle::GetEnvironmentVar(kCaptureLabel);
if (!labelFromEnv.empty())
{
// Optional label to provide unique file names and namespaces
mCaptureLabel = labelFromEnv;
}
}
FrameCapture::~FrameCapture() = default;
@ -2032,13 +2101,15 @@ void FrameCapture::onEndFrame(const gl::Context *context)
// Note that we currently capture before the start frame to collect shader and program sources.
if (!mFrameCalls.empty() && mFrameIndex >= mFrameStart)
{
WriteCppReplay(mOutDirectory, context->id(), mFrameIndex, mFrameCalls, mSetupCalls);
WriteCppReplay(mOutDirectory, context->id(), mCaptureLabel, mFrameIndex, mFrameCalls,
mSetupCalls);
// Save the index files after the last frame.
if (mFrameIndex == mFrameEnd)
{
WriteCppReplayIndexFiles(mOutDirectory, context->id(), mFrameStart, mFrameEnd,
mReadBufferSize, mClientArraySizes, mHasResourceType);
WriteCppReplayIndexFiles(mOutDirectory, context->id(), mCaptureLabel, mFrameStart,
mFrameEnd, mReadBufferSize, mClientArraySizes,
mHasResourceType);
}
}

Просмотреть файл

@ -201,6 +201,7 @@ class FrameCapture final : angle::NonCopyable
bool mEnabled;
std::string mOutDirectory;
std::string mCaptureLabel;
gl::AttribArray<int> mClientVertexArrayMap;
uint32_t mFrameIndex;
uint32_t mFrameStart;