mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-01 05:48:11 +03:00
Defines the interface between the test suite (or an other TraceLibrary class user) and trace libraries. TraceFunctions defines entry points for calls suite->trace, such as SetupReplay() or SetBinaryDataDir(). TraceCallbacks defines entry points for calls trace->suite, for example for loading .angledata.gz files. These are set up via the exported SetupEntryPoints() call. Functions like SetupReplay etc no longer need to be exported from the trace library. TraceInfo (parsed representation of the trace json) is moved to trace_interface as is. This is convenient for further changes to the fixture that will allow to easily move some of the captured parameters to json. This also moves Decompress functionality (and memory ownership) to test suite entirely, which avoids Decompress/Delete callbacks - the trace just calls LoadBinaryData via TraceCallbacks and TraceLibrary releases the memory either on FinishReplay or in its destructor. This should also take care of the memory leak described in https://crrev.com/c/3858185 Bug: b/286072760 Change-Id: Ibc6f6f64156ad805b1917c8fc41a3b0d2c0d6375 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4594445 Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com> Commit-Queue: Roman Lavrov <romanl@google.com> Reviewed-by: Cody Northrop <cnorthrop@google.com>
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 : gTraceInfo.traceFiles)
|
|
{
|
|
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"
|