Commit 14a2983f by Jamie Madill Committed by Commit Bot

Trace/Replay: Add uniform locations map.

This portability feature allows a single T-Rex capture done on Vulkan to work seamlessly on the ANGLE GL back-end and the WGL-loaded NVIDIA OpenGL driver. Previously the uniform locations would not be consistent between ANGLE and a native driver. And incompatiblities would trigger error messages between ANGLE back-ends. Will allow us to compare ANGLE performance vs the native driver using a capture. Example captured calls: glLinkProgram(gShaderProgramMap[3]); UpdateUniformLocation(gShaderProgramMap[3], "s_texture", 0); Bug: angleproject:4411 Change-Id: I5ddc76d75e15a9291b351e2aab94af4881f6ef47 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2068121 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com>
parent aa09ca69
...@@ -738,15 +738,27 @@ void WriteCppReplayIndexFiles(const std::string &outDir, ...@@ -738,15 +738,27 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
header << "#include <limits>\n"; header << "#include <limits>\n";
header << "#include <unordered_map>\n"; header << "#include <unordered_map>\n";
header << "\n"; header << "\n";
header << "// Replay functions\n";
header << "\n";
header << "using ResourceMap = std::unordered_map<GLuint, GLuint>;\n";
header << "\n";
if (!captureLabel.empty()) if (!captureLabel.empty())
{ {
header << "namespace " << captureLabel << "\n"; header << "namespace " << captureLabel << "\n";
header << "{\n"; header << "{\n";
} }
header << "// Replay functions\n";
header << "\n";
header << "// Maps from <captured Program ID, captured location> to run-time location.\n";
header
<< "using LocationsMap = std::unordered_map<GLuint, std::unordered_map<GLint, GLint>>;\n";
header << "extern LocationsMap gUniformLocations;\n";
header << "extern GLuint gCurrentProgram;\n";
header << "void UpdateUniformLocation(GLuint program, const char *name, GLint location);\n";
header << "void DeleteUniformLocations(GLuint program);\n";
header << "void UpdateCurrentProgram(GLuint program);\n";
header << "\n";
header << "// Maps from captured Resource ID to run-time Resource ID.\n";
header << "using ResourceMap = std::unordered_map<GLuint, GLuint>;\n";
header << "\n";
header << "\n";
header << "constexpr uint32_t kReplayFrameStart = " << frameStart << ";\n"; header << "constexpr uint32_t kReplayFrameStart = " << frameStart << ";\n";
header << "constexpr uint32_t kReplayFrameEnd = " << frameEnd << ";\n"; header << "constexpr uint32_t kReplayFrameEnd = " << frameEnd << ";\n";
header << "\n"; header << "\n";
...@@ -768,6 +780,13 @@ void WriteCppReplayIndexFiles(const std::string &outDir, ...@@ -768,6 +780,13 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
source << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n"; source << "#include \"" << FmtCapturePrefix(contextId, captureLabel) << ".h\"\n";
source << "\n"; source << "\n";
if (!captureLabel.empty())
{
source << "namespace " << captureLabel << "\n";
source << "{\n";
}
source << "namespace\n"; source << "namespace\n";
source << "{\n"; source << "{\n";
source << "void UpdateResourceMap(ResourceMap *resourceMap, GLuint id, GLsizei " source << "void UpdateResourceMap(ResourceMap *resourceMap, GLuint id, GLsizei "
...@@ -783,12 +802,22 @@ void WriteCppReplayIndexFiles(const std::string &outDir, ...@@ -783,12 +802,22 @@ void WriteCppReplayIndexFiles(const std::string &outDir,
source << "const char *gBinaryDataDir = \".\";\n"; source << "const char *gBinaryDataDir = \".\";\n";
source << "} // namespace\n"; source << "} // namespace\n";
source << "\n"; source << "\n";
source << "LocationsMap gUniformLocations;\n";
if (!captureLabel.empty()) source << "GLuint gCurrentProgram = 0;\n";
{ source << "\n";
source << "namespace " << captureLabel << "\n"; source << "void UpdateUniformLocation(GLuint program, const char *name, GLint location)\n";
source << "{\n"; source << "{\n";
} source << " gUniformLocations[program][location] = glGetUniformLocation(program, name);\n";
source << "}\n";
source << "void DeleteUniformLocations(GLuint program)\n";
source << "{\n";
source << " gUniformLocations.erase(program);\n";
source << "}\n";
source << "void UpdateCurrentProgram(GLuint program)\n";
source << "{\n";
source << " gCurrentProgram = program;\n";
source << "}\n";
source << "\n";
source << "uint8_t *gBinaryData = nullptr;\n"; source << "uint8_t *gBinaryData = nullptr;\n";
source << "void* gMappedBufferData = nullptr;\n"; source << "void* gMappedBufferData = nullptr;\n";
...@@ -967,6 +996,56 @@ void CaptureUpdateResourceIDs(const CallCapture &call, ...@@ -967,6 +996,56 @@ void CaptureUpdateResourceIDs(const CallCapture &call,
} }
} }
void CaptureUpdateUniformLocations(const gl::Program *program, std::vector<CallCapture> *callsOut)
{
const std::vector<gl::LinkedUniform> &uniforms = program->getState().getUniforms();
const std::vector<gl::VariableLocation> &locations = program->getUniformLocations();
for (GLint location = 0; location < static_cast<GLint>(locations.size()); ++location)
{
const gl::VariableLocation &locationVar = locations[location];
const gl::LinkedUniform &uniform = uniforms[locationVar.index];
ParamBuffer params;
params.addValueParam("program", ParamType::TShaderProgramID, program->id());
std::string name = uniform.name;
if (uniform.isArray())
{
if (locationVar.arrayIndex > 0)
{
// Non-sequential array uniform locations are not currently handled.
// In practice array locations shouldn't ever be non-sequential.
ASSERT(uniform.location == -1 ||
location == uniform.location + static_cast<int>(locationVar.arrayIndex));
continue;
}
if (uniform.isArrayOfArrays())
{
UNIMPLEMENTED();
}
name = gl::StripLastArrayIndex(name);
}
ParamCapture nameParam("name", ParamType::TGLcharConstPointer);
CaptureString(name.c_str(), &nameParam);
params.addParam(std::move(nameParam));
params.addValueParam("location", ParamType::TGLint, location);
callsOut->emplace_back("UpdateUniformLocation", std::move(params));
}
}
void CaptureDeleteUniformLocations(gl::ShaderProgramID program, std::vector<CallCapture> *callsOut)
{
ParamBuffer params;
params.addValueParam("program", ParamType::TShaderProgramID, program);
callsOut->emplace_back("DeleteUniformLocations", std::move(params));
}
void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut) void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
{ {
const CallCapture &call = callsOut->back(); const CallCapture &call = callsOut->back();
...@@ -1076,6 +1155,18 @@ void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut) ...@@ -1076,6 +1155,18 @@ void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
} }
} }
void CaptureUpdateCurrentProgram(const CallCapture &call, std::vector<CallCapture> *callsOut)
{
const ParamCapture &param =
call.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
gl::ShaderProgramID programID = param.value.ShaderProgramIDVal;
ParamBuffer paramBuffer;
paramBuffer.addValueParam("program", ParamType::TShaderProgramID, programID);
callsOut->emplace_back("UpdateCurrentProgram", std::move(paramBuffer));
}
bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue) bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
{ {
if (currentValue.Type != gl::VertexAttribType::Float) if (currentValue.Type != gl::VertexAttribType::Float)
...@@ -1598,8 +1689,8 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1598,8 +1689,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
gl::ShaderProgramID tempShaderID = {1}; gl::ShaderProgramID tempShaderID = {1};
for (const auto &programIter : programs) for (const auto &programIter : programs)
{ {
gl::ShaderProgramID id = {programIter.first}; gl::ShaderProgramID id = {programIter.first};
gl::Program *program = programIter.second; const gl::Program *program = programIter.second;
// Get last compiled shader source. // Get last compiled shader source.
const auto &foundSources = cachedProgramSources.find(id); const auto &foundSources = cachedProgramSources.find(id);
...@@ -1629,6 +1720,7 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1629,6 +1720,7 @@ void CaptureMidExecutionSetup(const gl::Context *context,
} }
cap(CaptureLinkProgram(replayState, true, id)); cap(CaptureLinkProgram(replayState, true, id));
CaptureUpdateUniformLocations(program, setupCalls);
} }
// Handle shaders. // Handle shaders.
...@@ -1671,6 +1763,7 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1671,6 +1763,7 @@ void CaptureMidExecutionSetup(const gl::Context *context,
if (apiState.getProgram()) if (apiState.getProgram())
{ {
cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id())); cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
CaptureUpdateCurrentProgram(setupCalls->back(), setupCalls);
} }
// TODO(http://anglebug.com/3662): ES 3.x objects. // TODO(http://anglebug.com/3662): ES 3.x objects.
...@@ -2374,8 +2467,39 @@ void FrameCapture::captureCall(const gl::Context *context, CallCapture &&call) ...@@ -2374,8 +2467,39 @@ void FrameCapture::captureCall(const gl::Context *context, CallCapture &&call)
mReadBufferSize = std::max(mReadBufferSize, call.params.getReadBufferSize()); mReadBufferSize = std::max(mReadBufferSize, call.params.getReadBufferSize());
mFrameCalls.emplace_back(std::move(call)); mFrameCalls.emplace_back(std::move(call));
maybeCapturePostCallUpdates(context);
}
void FrameCapture::maybeCapturePostCallUpdates(const gl::Context *context)
{
// Process resource ID updates. // Process resource ID updates.
MaybeCaptureUpdateResourceIDs(&mFrameCalls); MaybeCaptureUpdateResourceIDs(&mFrameCalls);
const CallCapture &lastCall = mFrameCalls.back();
switch (lastCall.entryPoint)
{
case gl::EntryPoint::LinkProgram:
{
const ParamCapture &param =
lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
const gl::Program *program =
context->getProgramResolveLink(param.value.ShaderProgramIDVal);
CaptureUpdateUniformLocations(program, &mFrameCalls);
break;
}
case gl::EntryPoint::UseProgram:
CaptureUpdateCurrentProgram(lastCall, &mFrameCalls);
break;
case gl::EntryPoint::DeleteProgram:
{
const ParamCapture &param =
lastCall.params.getParam("programPacked", ParamType::TShaderProgramID, 0);
CaptureDeleteUniformLocations(param.value.ShaderProgramIDVal, &mFrameCalls);
break;
}
default:
break;
}
} }
void FrameCapture::captureClientArraySnapshot(const gl::Context *context, void FrameCapture::captureClientArraySnapshot(const gl::Context *context,
...@@ -2783,12 +2907,44 @@ void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os, ...@@ -2783,12 +2907,44 @@ void WriteParamValueReplay<ParamType::TVertexArrayID>(std::ostream &os,
os << "gVertexArrayMap[" << value.value << "]"; os << "gVertexArrayMap[" << value.value << "]";
} }
bool FindShaderProgramIDInCall(const CallCapture &call, gl::ShaderProgramID *idOut)
{
for (const ParamCapture &param : call.params.getParamCaptures())
{
if (param.type == ParamType::TShaderProgramID && param.name == "programPacked")
{
*idOut = param.value.ShaderProgramIDVal;
return true;
}
}
return false;
}
template <> template <>
void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os, void WriteParamValueReplay<ParamType::TUniformLocation>(std::ostream &os,
const CallCapture &call, const CallCapture &call,
gl::UniformLocation value) gl::UniformLocation value)
{ {
// TODO(jmadill): Uniform locations map. http://anglebug.com/4411 if (value.value == -1)
os << value.value; {
os << "-1";
return;
}
os << "gUniformLocations[";
// Find the program from the call parameters.
gl::ShaderProgramID programID;
if (FindShaderProgramIDInCall(call, &programID))
{
os << "gShaderProgramMap[" << programID.value << "]";
}
else
{
os << "gCurrentProgram";
}
os << "][" << value.value << "]";
} }
} // namespace angle } // namespace angle
...@@ -208,6 +208,7 @@ class FrameCapture final : angle::NonCopyable ...@@ -208,6 +208,7 @@ class FrameCapture final : angle::NonCopyable
void reset(); void reset();
void maybeCaptureClientData(const gl::Context *context, const CallCapture &call); void maybeCaptureClientData(const gl::Context *context, const CallCapture &call);
void maybeCapturePostCallUpdates(const gl::Context *context);
static void ReplayCall(gl::Context *context, static void ReplayCall(gl::Context *context,
ReplayContext *replayContext, ReplayContext *replayContext,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment