1062 lines
29 KiB
C++
1062 lines
29 KiB
C++
//
|
|
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// trace_interpreter.cpp:
|
|
// Parser and interpreter for the C-based replays.
|
|
//
|
|
|
|
#include "trace_interpreter.h"
|
|
|
|
#include "anglebase/no_destructor.h"
|
|
#include "common/gl_enum_utils.h"
|
|
#include "common/string_utils.h"
|
|
#include "trace_fixture.h"
|
|
|
|
#define USE_SYSTEM_ZLIB
|
|
#include "compression_utils_portable.h"
|
|
|
|
namespace angle
|
|
{
|
|
namespace
|
|
{
|
|
bool ShouldParseFile(const std::string &file)
|
|
{
|
|
return EndsWith(file, ".c") || EndsWith(file, ".cpp");
|
|
}
|
|
|
|
void ReplayTraceFunction(const TraceFunction &func, const TraceFunctionMap &customFunctions)
|
|
{
|
|
for (const CallCapture &call : func)
|
|
{
|
|
ReplayTraceFunctionCall(call, customFunctions);
|
|
}
|
|
}
|
|
|
|
class Parser : angle::NonCopyable
|
|
{
|
|
public:
|
|
Parser(const std::string &stream,
|
|
TraceFunctionMap &functionsIn,
|
|
TraceStringMap &stringsIn,
|
|
bool verboseLogging)
|
|
: mStream(stream),
|
|
mFunctions(functionsIn),
|
|
mStrings(stringsIn),
|
|
mIndex(0),
|
|
mVerboseLogging(verboseLogging)
|
|
{}
|
|
|
|
void parse()
|
|
{
|
|
while (mIndex < mStream.size())
|
|
{
|
|
if (peek() == '#' || peek() == '/')
|
|
{
|
|
skipLine();
|
|
}
|
|
else if (peek() == 'v')
|
|
{
|
|
ASSERT(check("void "));
|
|
readFunction();
|
|
}
|
|
else if (peek() == 'c')
|
|
{
|
|
ASSERT(check("const "));
|
|
readMultilineString();
|
|
}
|
|
else
|
|
{
|
|
printf("Unexpected character: '%c'\n", peek());
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
ANGLE_INLINE char peek() const { return mStream[mIndex]; }
|
|
|
|
ANGLE_INLINE char look(size_t ahead) const { return mStream[mIndex + ahead]; }
|
|
|
|
ANGLE_INLINE void advance() { mIndex++; }
|
|
|
|
ANGLE_INLINE void advanceTo(char delim)
|
|
{
|
|
while (peek() != delim)
|
|
{
|
|
advance();
|
|
}
|
|
}
|
|
|
|
bool check(const char *forString) const
|
|
{
|
|
return mStream.substr(mIndex, strlen(forString)) == forString;
|
|
}
|
|
|
|
void skipLine()
|
|
{
|
|
advanceTo('\n');
|
|
skipWhitespace();
|
|
}
|
|
|
|
void skipWhitespace()
|
|
{
|
|
while (isspace(peek()))
|
|
{
|
|
advance();
|
|
}
|
|
}
|
|
|
|
void skipNonWhitespace()
|
|
{
|
|
while (!isspace(peek()))
|
|
{
|
|
advance();
|
|
}
|
|
}
|
|
|
|
// In our simplified trace C, every line that begins with a } either ends a function or a
|
|
// string. All lines inside the function begin with whitespace. So to find the end of the
|
|
// function we just need to scan for a line beginning with }.
|
|
void skipFunction()
|
|
{
|
|
while (peek() != '}')
|
|
{
|
|
advanceTo('\n');
|
|
advance();
|
|
}
|
|
advance();
|
|
skipWhitespace();
|
|
}
|
|
|
|
void readStringAppend(std::string *stringOut, char delim)
|
|
{
|
|
while (peek() != delim)
|
|
{
|
|
if (peek() == '\\')
|
|
{
|
|
advance();
|
|
switch (peek())
|
|
{
|
|
case 'n':
|
|
*stringOut += '\n';
|
|
break;
|
|
case '\"':
|
|
*stringOut += '\"';
|
|
break;
|
|
case '\\':
|
|
*stringOut += '\\';
|
|
break;
|
|
default:
|
|
printf("Unrecognized escape character: \\%c\n", peek());
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*stringOut += peek();
|
|
}
|
|
advance();
|
|
}
|
|
}
|
|
|
|
void readToken(Token &token, char delim)
|
|
{
|
|
size_t startIndex = mIndex;
|
|
advanceTo(delim);
|
|
size_t tokenSize = mIndex - startIndex;
|
|
ASSERT(tokenSize < kMaxTokenSize);
|
|
memcpy(token, &mStream[startIndex], tokenSize);
|
|
token[mIndex - startIndex] = 0;
|
|
}
|
|
|
|
void skipCast()
|
|
{
|
|
if (peek() == '(')
|
|
{
|
|
advanceTo(')');
|
|
advance();
|
|
}
|
|
}
|
|
|
|
void skipComments()
|
|
{
|
|
while (peek() == '/')
|
|
{
|
|
skipLine();
|
|
}
|
|
}
|
|
|
|
void readFunction()
|
|
{
|
|
std::string funcName;
|
|
TraceFunction func;
|
|
|
|
// Skip past the "void" return value.
|
|
skipNonWhitespace();
|
|
advance();
|
|
readStringAppend(&funcName, '(');
|
|
if (mVerboseLogging)
|
|
{
|
|
printf("function: %s\n", funcName.c_str());
|
|
}
|
|
|
|
// Skip this function because of the switch statements.
|
|
if (funcName == "ReplayFrame")
|
|
{
|
|
skipFunction();
|
|
return;
|
|
}
|
|
|
|
skipLine();
|
|
ASSERT(peek() == '{');
|
|
skipLine();
|
|
while (peek() != '}')
|
|
{
|
|
skipComments();
|
|
|
|
Token nameToken;
|
|
readToken(nameToken, '(');
|
|
advance();
|
|
ParamBuffer params;
|
|
Token paramTokens[kMaxParameters];
|
|
size_t numParams = 0;
|
|
skipCast();
|
|
size_t tokenStart = mIndex;
|
|
while (peek() != ';')
|
|
{
|
|
// Skip casts.
|
|
if (peek() == ',' || (peek() == ')' && mIndex != tokenStart))
|
|
{
|
|
ASSERT(numParams < kMaxParameters);
|
|
size_t tokenSize = mIndex - tokenStart;
|
|
ASSERT(tokenSize < kMaxTokenSize);
|
|
Token &token = paramTokens[numParams++];
|
|
|
|
memcpy(token, &mStream[tokenStart], tokenSize);
|
|
token[tokenSize] = 0;
|
|
advance();
|
|
skipWhitespace();
|
|
skipCast();
|
|
tokenStart = mIndex;
|
|
}
|
|
else
|
|
{
|
|
advance();
|
|
}
|
|
}
|
|
|
|
// Turn on if you want more spam.
|
|
// if (mVerboseLogging)
|
|
//{
|
|
// printf("call: %s(", nameToken);
|
|
// for (size_t paramIndex = 0; paramIndex < numParams; ++paramIndex)
|
|
// {
|
|
// if (paramIndex > 0)
|
|
// {
|
|
// printf(", ");
|
|
// }
|
|
// printf("%s", paramTokens[paramIndex]);
|
|
// }
|
|
// printf(")\n");
|
|
//}
|
|
|
|
// We pass in the strings for specific use with C string array parameters.
|
|
CallCapture call = ParseCallCapture(nameToken, numParams, paramTokens, mStrings);
|
|
func.push_back(std::move(call));
|
|
skipLine();
|
|
}
|
|
skipLine();
|
|
|
|
addFunction(funcName, func);
|
|
}
|
|
|
|
void readMultilineString()
|
|
{
|
|
std::string name;
|
|
TraceString traceStr;
|
|
|
|
while (peek() != 'g')
|
|
{
|
|
advance();
|
|
}
|
|
ASSERT(check("glShaderSource") || check("glTransformFeedbackVaryings"));
|
|
|
|
readStringAppend(&name, '[');
|
|
if (mVerboseLogging)
|
|
{
|
|
printf("string: %s\n", name.c_str());
|
|
}
|
|
skipLine();
|
|
std::string str;
|
|
while (peek() != '}')
|
|
{
|
|
advance();
|
|
readStringAppend(&str, '\"');
|
|
advance();
|
|
if (peek() == ',')
|
|
{
|
|
traceStr.strings.push_back(std::move(str));
|
|
}
|
|
skipLine();
|
|
}
|
|
skipLine();
|
|
|
|
for (const std::string &cppstr : traceStr.strings)
|
|
{
|
|
traceStr.pointers.push_back(cppstr.c_str());
|
|
}
|
|
|
|
mStrings[name] = std::move(traceStr);
|
|
}
|
|
|
|
void addFunction(const std::string &funcName, TraceFunction &func)
|
|
{
|
|
// Run initialize immediately so we can load the binary data.
|
|
if (funcName == "InitReplay")
|
|
{
|
|
ReplayTraceFunction(func, {});
|
|
func.clear();
|
|
}
|
|
mFunctions[funcName] = std::move(func);
|
|
}
|
|
|
|
const std::string &mStream;
|
|
TraceFunctionMap &mFunctions;
|
|
TraceStringMap &mStrings;
|
|
size_t mIndex;
|
|
bool mVerboseLogging = false;
|
|
};
|
|
|
|
void PackResourceID(ParamBuffer ¶ms, const Token &token)
|
|
{
|
|
ASSERT(token[0] == 'g');
|
|
const char *start = strrchr(token, '[');
|
|
ASSERT(start != nullptr && EndsWith(token, "]"));
|
|
uint32_t value = static_cast<uint32_t>(atoi(start + 1));
|
|
if (BeginsWith(token, "gShaderProgramMap"))
|
|
{
|
|
gl::ShaderProgramID id = {value};
|
|
params.addUnnamedParam(ParamType::TShaderProgramID, id);
|
|
}
|
|
else if (BeginsWith(token, "gBufferMap"))
|
|
{
|
|
gl::BufferID id = {value};
|
|
params.addUnnamedParam(ParamType::TBufferID, id);
|
|
}
|
|
else if (BeginsWith(token, "gTextureMap"))
|
|
{
|
|
gl::TextureID id = {value};
|
|
params.addUnnamedParam(ParamType::TTextureID, id);
|
|
}
|
|
else if (BeginsWith(token, "gRenderbufferMap"))
|
|
{
|
|
gl::RenderbufferID id = {value};
|
|
params.addUnnamedParam(ParamType::TRenderbufferID, id);
|
|
}
|
|
else if (BeginsWith(token, "gFramebufferMap"))
|
|
{
|
|
gl::FramebufferID id = {value};
|
|
params.addUnnamedParam(ParamType::TFramebufferID, id);
|
|
}
|
|
else if (BeginsWith(token, "gSyncMap"))
|
|
{
|
|
gl::SyncID id = {value};
|
|
params.addUnnamedParam(ParamType::TSyncID, id);
|
|
}
|
|
else if (BeginsWith(token, "gTransformFeedbackMap"))
|
|
{
|
|
gl::TransformFeedbackID id = {value};
|
|
params.addUnnamedParam(ParamType::TTransformFeedbackID, id);
|
|
}
|
|
else if (BeginsWith(token, "gVertexArrayMap"))
|
|
{
|
|
gl::VertexArrayID id = {value};
|
|
params.addUnnamedParam(ParamType::TVertexArrayID, id);
|
|
}
|
|
else if (BeginsWith(token, "gQueryMap"))
|
|
{
|
|
gl::QueryID id = {value};
|
|
params.addUnnamedParam(ParamType::TQueryID, id);
|
|
}
|
|
else if (BeginsWith(token, "gSamplerMap"))
|
|
{
|
|
gl::SamplerID id = {value};
|
|
params.addUnnamedParam(ParamType::TSamplerID, id);
|
|
}
|
|
else
|
|
{
|
|
printf("Unknown resource map: %s\n", token);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
template <typename IntT>
|
|
void PackIntParameter(ParamBuffer ¶ms, ParamType paramType, const Token &token)
|
|
{
|
|
IntT value;
|
|
|
|
if (token[0] == 'G')
|
|
{
|
|
ASSERT(BeginsWith(token, "GL_"));
|
|
if (strchr(token, '|') == 0)
|
|
{
|
|
value = static_cast<IntT>(gl::StringToGLenum(token));
|
|
}
|
|
else
|
|
{
|
|
value = static_cast<IntT>(gl::StringToGLbitfield(token));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!isdigit(token[0]) && !(token[0] == '-' && isdigit(token[1])))
|
|
{
|
|
printf("Expected number, got %s\n", token);
|
|
UNREACHABLE();
|
|
}
|
|
if (token[0] == '0' && token[1] == 'x')
|
|
{
|
|
value = static_cast<IntT>(strtol(token, nullptr, 16));
|
|
}
|
|
else
|
|
{
|
|
value = static_cast<IntT>(atoi(token));
|
|
}
|
|
}
|
|
|
|
params.addUnnamedParam(paramType, value);
|
|
}
|
|
|
|
uint32_t GetStringArrayOffset(const Token &token, const char *prefixString)
|
|
{
|
|
const char *offsetString = &token[strlen(prefixString)];
|
|
return atoi(offsetString);
|
|
}
|
|
|
|
template <typename PointerT>
|
|
void PackMemPointer(ParamBuffer ¶ms, ParamType paramType, uint32_t offset, uint8_t *mem)
|
|
{
|
|
ASSERT(gBinaryData);
|
|
params.addUnnamedParam(paramType, reinterpret_cast<PointerT>(&mem[offset]));
|
|
}
|
|
|
|
template <typename T>
|
|
void PackMutablePointerParameter(ParamBuffer ¶ms, ParamType paramType, const Token &token)
|
|
{
|
|
if (token[0] == '0' && token[1] == 0)
|
|
{
|
|
params.addUnnamedParam(paramType, reinterpret_cast<T *>(0));
|
|
}
|
|
else if (token[0] == '&')
|
|
{
|
|
ASSERT(BeginsWith(token, "&gReadBuffer[") && EndsWith(token, "]"));
|
|
uint32_t offset = GetStringArrayOffset(token, "&gReadBuffer[");
|
|
PackMemPointer<T *>(params, paramType, offset, gReadBuffer);
|
|
}
|
|
else if (token[0] == 'g')
|
|
{
|
|
ASSERT(strcmp(token, "gReadBuffer") == 0);
|
|
params.addUnnamedParam(paramType, reinterpret_cast<T *>(gReadBuffer));
|
|
}
|
|
else
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void PackConstPointerParameter(ParamBuffer ¶ms, ParamType paramType, const Token &token)
|
|
{
|
|
// Handle nullptr, the literal "0".
|
|
if (token[0] == '0' && token[1] == 0)
|
|
{
|
|
params.addUnnamedParam(paramType, reinterpret_cast<const T *>(0));
|
|
}
|
|
else if (token[0] == '&')
|
|
{
|
|
ASSERT(BeginsWith(token, "&gBinaryData[") && EndsWith(token, "]"));
|
|
uint32_t offset = GetStringArrayOffset(token, "&gReadBuffer[");
|
|
PackMemPointer<const T *>(params, paramType, offset, gBinaryData);
|
|
}
|
|
else if (token[0] == 'g')
|
|
{
|
|
if (strcmp(token, "gResourceIDBuffer") == 0)
|
|
{
|
|
params.addUnnamedParam(paramType, reinterpret_cast<const T *>(gResourceIDBuffer));
|
|
}
|
|
else if (BeginsWith(token, "gClientArrays"))
|
|
{
|
|
uint32_t offset = GetStringArrayOffset(token, "gClientArrays[");
|
|
params.addUnnamedParam(paramType, reinterpret_cast<const T *>(gClientArrays[offset]));
|
|
}
|
|
else
|
|
{
|
|
printf("Unexpected token: %s\n", token);
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(isdigit(token[0]));
|
|
uint32_t offset = atoi(token);
|
|
params.addUnnamedParam(paramType,
|
|
reinterpret_cast<const T *>(static_cast<uintptr_t>(offset)));
|
|
}
|
|
}
|
|
|
|
class TraceInterpreter : angle::NonCopyable
|
|
{
|
|
public:
|
|
TraceInterpreter() = default;
|
|
~TraceInterpreter() = default;
|
|
|
|
void replayFrame(uint32_t frameIndex);
|
|
void setupReplay();
|
|
void resetReplay();
|
|
const char *getSerializedContextState(uint32_t frameIndex);
|
|
|
|
private:
|
|
void runTraceFunction(const char *name) const;
|
|
void parseTraceUncompressed();
|
|
void parseTraceGz();
|
|
|
|
TraceFunctionMap mTraceFunctions;
|
|
TraceStringMap mTraceStrings;
|
|
bool mVerboseLogging = true;
|
|
};
|
|
|
|
void TraceInterpreter::replayFrame(uint32_t frameIndex)
|
|
{
|
|
char funcName[kMaxTokenSize];
|
|
snprintf(funcName, kMaxTokenSize, "ReplayFrame%u", frameIndex);
|
|
runTraceFunction(funcName);
|
|
}
|
|
|
|
void TraceInterpreter::parseTraceUncompressed()
|
|
{
|
|
for (const std::string &file : gTraceFiles)
|
|
{
|
|
if (!ShouldParseFile(file))
|
|
{
|
|
if (mVerboseLogging)
|
|
{
|
|
printf("Skipping function parsing for %s.\n", file.c_str());
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (mVerboseLogging)
|
|
{
|
|
printf("Parsing functions from %s\n", file.c_str());
|
|
}
|
|
std::stringstream pathStream;
|
|
pathStream << gBinaryDataDir << GetPathSeparator() << file;
|
|
std::string path = pathStream.str();
|
|
|
|
std::string fileData;
|
|
if (!ReadFileToString(path, &fileData))
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
Parser parser(fileData, mTraceFunctions, mTraceStrings, mVerboseLogging);
|
|
parser.parse();
|
|
}
|
|
}
|
|
|
|
void TraceInterpreter::parseTraceGz()
|
|
{
|
|
if (mVerboseLogging)
|
|
{
|
|
printf("Parsing functions from %s\n", gTraceGzPath.c_str());
|
|
}
|
|
|
|
FILE *fp = fopen(gTraceGzPath.c_str(), "rb");
|
|
if (fp == 0)
|
|
{
|
|
printf("Error loading trace (gz) from: %s\n", gTraceGzPath.c_str());
|
|
exit(1);
|
|
}
|
|
|
|
fseek(fp, 0, SEEK_END);
|
|
long size = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
std::vector<uint8_t> compressedData(size);
|
|
(void)fread(compressedData.data(), 1, size, fp);
|
|
|
|
uint32_t uncompressedSize =
|
|
zlib_internal::GetGzipUncompressedSize(compressedData.data(), compressedData.size());
|
|
|
|
std::string uncompressedData(uncompressedSize, 0);
|
|
uLong destLen = uncompressedSize;
|
|
int zResult = zlib_internal::GzipUncompressHelper((uint8_t *)uncompressedData.data(), &destLen,
|
|
compressedData.data(),
|
|
static_cast<uLong>(compressedData.size()));
|
|
|
|
if (zResult != Z_OK)
|
|
{
|
|
printf("Failure to decompress gz trace: %s\n", gTraceGzPath.c_str());
|
|
exit(1);
|
|
}
|
|
|
|
Parser parser(uncompressedData, mTraceFunctions, mTraceStrings, mVerboseLogging);
|
|
parser.parse();
|
|
}
|
|
|
|
void TraceInterpreter::setupReplay()
|
|
{
|
|
if (!gTraceGzPath.empty())
|
|
{
|
|
parseTraceGz();
|
|
}
|
|
else
|
|
{
|
|
parseTraceUncompressed();
|
|
}
|
|
|
|
if (mTraceFunctions.count("SetupReplay") == 0)
|
|
{
|
|
printf("Did not find a SetupReplay function to run among %zu parsed functions.\n",
|
|
mTraceFunctions.size());
|
|
exit(1);
|
|
}
|
|
|
|
runTraceFunction("SetupReplay");
|
|
}
|
|
|
|
void TraceInterpreter::resetReplay()
|
|
{
|
|
runTraceFunction("ResetReplay");
|
|
}
|
|
|
|
const char *TraceInterpreter::getSerializedContextState(uint32_t frameIndex)
|
|
{
|
|
// TODO: Necessary for complete self-testing. http://anglebug.com/7779
|
|
UNREACHABLE();
|
|
return nullptr;
|
|
}
|
|
|
|
void TraceInterpreter::runTraceFunction(const char *name) const
|
|
{
|
|
auto iter = mTraceFunctions.find(name);
|
|
if (iter == mTraceFunctions.end())
|
|
{
|
|
printf("Cannot find function: %s\n", name);
|
|
UNREACHABLE();
|
|
}
|
|
const TraceFunction &func = iter->second;
|
|
ReplayTraceFunction(func, mTraceFunctions);
|
|
}
|
|
|
|
TraceInterpreter &GetInterpreter()
|
|
{
|
|
static angle::base::NoDestructor<std::unique_ptr<TraceInterpreter>> sTraceInterpreter(
|
|
new TraceInterpreter());
|
|
return *sTraceInterpreter.get()->get();
|
|
}
|
|
} // anonymous namespace
|
|
|
|
template <>
|
|
void PackParameter<uint32_t>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
if (token[0] == 'g')
|
|
{
|
|
PackResourceID(params, token);
|
|
}
|
|
else
|
|
{
|
|
PackIntParameter<uint32_t>(params, ParamType::TGLuint, token);
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<int32_t>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
if (BeginsWith(token, "gUniformLocations"))
|
|
{
|
|
const char *start = strrchr(token, '[');
|
|
ASSERT(start != nullptr && EndsWith(token, "]"));
|
|
int32_t value = atoi(start + 1);
|
|
gl::UniformLocation loc = {value};
|
|
params.addUnnamedParam(ParamType::TUniformLocation, loc);
|
|
}
|
|
else
|
|
{
|
|
PackIntParameter<int32_t>(params, ParamType::TGLint, token);
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<void *>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
void *value = 0;
|
|
params.addUnnamedParam(ParamType::TvoidPointer, value);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const int32_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackConstPointerParameter<int32_t>(params, ParamType::TGLintConstPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<void **>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<int32_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackMutablePointerParameter<int32_t>(params, ParamType::TGLintPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<uint64_t>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
params.addUnnamedParam(ParamType::TGLuint64,
|
|
static_cast<GLuint64>(std::strtoull(token, nullptr, 10)));
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<int64_t>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
params.addUnnamedParam(ParamType::TGLint64,
|
|
static_cast<GLint64>(std::strtoll(token, nullptr, 10)));
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const int64_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<int64_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<uint64_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const char *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
if (token[0] == '"')
|
|
{
|
|
ASSERT(EndsWith(token, "\""));
|
|
|
|
ParamCapture param(params.getNextParamName(), ParamType::TGLcharConstPointer);
|
|
std::vector<uint8_t> data(&token[1], &token[strlen(token) - 1]);
|
|
data.push_back(0);
|
|
param.data.push_back(std::move(data));
|
|
param.value.GLcharConstPointerVal = reinterpret_cast<const char *>(param.data[0].data());
|
|
params.addParam(std::move(param));
|
|
}
|
|
else
|
|
{
|
|
PackConstPointerParameter<char>(params, ParamType::TGLcharConstPointer, token);
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const void *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackConstPointerParameter<void>(params, ParamType::TvoidConstPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<uint32_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackMutablePointerParameter<uint32_t>(params, ParamType::TGLuintPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const uint32_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackConstPointerParameter<uint32_t>(params, ParamType::TGLuintConstPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<float>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
params.addUnnamedParam(ParamType::TGLfloat, std::stof(token));
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<uint8_t>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
PackIntParameter<uint8_t>(params, ParamType::TGLubyte, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<float *>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
PackMutablePointerParameter<float>(params, ParamType::TGLfloatPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const float *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackConstPointerParameter<float>(params, ParamType::TGLfloatConstPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<GLsync>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
PackResourceID(params, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const char *const *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
// Find the string that corresponds to "token". Currently we only support string arrays.
|
|
auto iter = strings.find(token);
|
|
if (iter == strings.end())
|
|
{
|
|
printf("Could not find string: %s\n", token);
|
|
UNREACHABLE();
|
|
}
|
|
const TraceString &traceStr = iter->second;
|
|
params.addUnnamedParam(ParamType::TGLcharConstPointerPointer, traceStr.pointers.data());
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const char **>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<GLDEBUGPROCKHR>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<EGLDEBUGPROCKHR>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const struct AHardwareBuffer *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<EGLSetBlobFuncANDROID>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<EGLGetBlobFuncANDROID>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<int16_t>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
PackIntParameter<int16_t>(params, ParamType::TGLshort, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const int16_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackConstPointerParameter<int16_t>(params, ParamType::TGLshortConstPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<char *>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<unsigned char *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackMutablePointerParameter<GLubyte>(params, ParamType::TGLubytePointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const void *const *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<const uint64_t *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
#if defined(ANGLE_PLATFORM_WINDOWS)
|
|
template <>
|
|
void PackParameter<EGLNativeDisplayType>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
#endif // defined(ANGLE_PLATFORM_WINDOWS)
|
|
|
|
#if defined(ANGLE_PLATFORM_WINDOWS) || defined(ANGLE_PLATFORM_ANDROID)
|
|
template <>
|
|
void PackParameter<EGLNativeWindowType>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<EGLNativePixmapType>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
UNREACHABLE();
|
|
}
|
|
#endif // defined(ANGLE_PLATFORM_WINDOWS) || defined(ANGLE_PLATFORM_ANDROID)
|
|
|
|
#if defined(ANGLE_PLATFORM_APPLE) || !defined(ANGLE_IS_64_BIT_CPU)
|
|
template <>
|
|
void PackParameter<const long *>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackConstPointerParameter<int64_t>(params, ParamType::TGLuint64ConstPointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<long *>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
PackMutablePointerParameter<int64_t>(params, ParamType::TGLint64Pointer, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<long>(ParamBuffer ¶ms, const Token &token, const TraceStringMap &strings)
|
|
{
|
|
PackIntParameter<int64_t>(params, ParamType::TGLint64, token);
|
|
}
|
|
|
|
template <>
|
|
void PackParameter<unsigned long>(ParamBuffer ¶ms,
|
|
const Token &token,
|
|
const TraceStringMap &strings)
|
|
{
|
|
PackIntParameter<uint64_t>(params, ParamType::TGLuint64, token);
|
|
}
|
|
#endif // defined(ANGLE_PLATFORM_APPLE) || !defined(ANGLE_IS_64_BIT_CPU)
|
|
|
|
GLuint GetResourceIDMapValue(ResourceIDType resourceIDType, GLuint key)
|
|
{
|
|
switch (resourceIDType)
|
|
{
|
|
case ResourceIDType::Buffer:
|
|
return gBufferMap[key];
|
|
case ResourceIDType::FenceNV:
|
|
return gFenceNVMap[key];
|
|
case ResourceIDType::Framebuffer:
|
|
return gFramebufferMap[key];
|
|
case ResourceIDType::ProgramPipeline:
|
|
return gProgramPipelineMap[key];
|
|
case ResourceIDType::Query:
|
|
return gQueryMap[key];
|
|
case ResourceIDType::Renderbuffer:
|
|
return gRenderbufferMap[key];
|
|
case ResourceIDType::Sampler:
|
|
return gSamplerMap[key];
|
|
case ResourceIDType::Semaphore:
|
|
return gSemaphoreMap[key];
|
|
case ResourceIDType::ShaderProgram:
|
|
return gShaderProgramMap[key];
|
|
case ResourceIDType::Texture:
|
|
return gTextureMap[key];
|
|
case ResourceIDType::TransformFeedback:
|
|
return gTransformFeedbackMap[key];
|
|
case ResourceIDType::VertexArray:
|
|
return gVertexArrayMap[key];
|
|
default:
|
|
printf("Incompatible resource ID type: %d\n", static_cast<int>(resourceIDType));
|
|
UNREACHABLE();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
} // namespace angle
|
|
|
|
extern "C" {
|
|
void SetupReplay()
|
|
{
|
|
angle::GetInterpreter().setupReplay();
|
|
}
|
|
|
|
void ReplayFrame(uint32_t frameIndex)
|
|
{
|
|
angle::GetInterpreter().replayFrame(frameIndex);
|
|
}
|
|
|
|
void ResetReplay()
|
|
{
|
|
angle::GetInterpreter().resetReplay();
|
|
}
|
|
|
|
const char *GetSerializedContextState(uint32_t frameIndex)
|
|
{
|
|
return angle::GetInterpreter().getSerializedContextState(frameIndex);
|
|
}
|
|
} // extern "C"
|