Commit 9b4fd545 by Tim Van Patten Committed by Commit Bot

Capture/Replay: Reset GL Fence Sync objects

Asphalt 9 uses GL Fence Sync objects during rendering, which results in Fence Sync objects being created during setup and deleted while replaying frames. When the replay is restarted, the Fence Sync objects that were created during setup and deleted during the replay need to be recreated during the reset phase. Bug: angleproject:5883 Bug: angleproject:4599 Change-Id: I118f2b7208c4d512ab646b10f52b3a0936895089 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2838237 Commit-Queue: Tim Van Patten <timvp@google.com> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 9acfccbd
......@@ -931,6 +931,37 @@ void MaybeResetResources(std::stringstream &out,
}
}
void MaybeResetFenceSyncObjects(std::stringstream &out,
DataTracker *dataTracker,
std::stringstream &header,
ResourceTracker *resourceTracker,
std::vector<uint8_t> *binaryData)
{
FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
// If any of our starting fence sync objects were deleted during the run, recreate them
FenceSyncSet &fenceSyncsToRegen = resourceTracker->getFenceSyncsToRegen();
for (const GLsync sync : fenceSyncsToRegen)
{
// Emit their regen calls
for (CallCapture &call : fenceSyncRegenCalls[sync])
{
out << " ";
WriteCppReplayForCall(call, dataTracker, out, header, binaryData);
out << ";\n";
}
}
}
void MaybeResetOpaqueTypeObjects(std::stringstream &out,
DataTracker *dataTracker,
std::stringstream &header,
ResourceTracker *resourceTracker,
std::vector<uint8_t> *binaryData)
{
MaybeResetFenceSyncObjects(out, dataTracker, header, resourceTracker, binaryData);
}
void WriteCppReplayFunctionWithParts(const gl::Context *context,
ReplayFunc replayFunc,
DataTracker *dataTracker,
......@@ -1058,8 +1089,11 @@ void WriteCppReplay(bool compression,
resourceTracker, binaryData);
}
out << restoreCallStream.str();
// Reset opaque type objects that don't have IDs, so are not ResourceIDTypes.
MaybeResetOpaqueTypeObjects(restoreCallStream, &dataTracker, header, resourceTracker,
binaryData);
out << restoreCallStream.str();
out << "}\n";
}
......@@ -2104,6 +2138,18 @@ void CaptureBufferResetCalls(const gl::State &replayState,
CaptureUnmapBuffer(replayState, true, gl::BufferBinding::Array, GL_TRUE));
}
void CaptureFenceSyncResetCalls(const gl::State &replayState,
ResourceTracker *resourceTracker,
GLsync syncID,
const gl::Sync *sync)
{
// Track calls to regenerate a given fence sync
FenceSyncCalls &fenceSyncRegenCalls = resourceTracker->getFenceSyncRegenCalls();
Capture(&fenceSyncRegenCalls[syncID],
CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
MaybeCaptureUpdateResourceIDs(&fenceSyncRegenCalls[syncID]);
}
void CaptureBufferBindingResetCalls(const gl::State &replayState,
ResourceTracker *resourceTracker,
gl::BufferBinding binding,
......@@ -3073,6 +3119,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
continue;
}
cap(CaptureFenceSync(replayState, true, sync->getCondition(), sync->getFlags(), syncID));
CaptureFenceSyncResetCalls(replayState, resourceTracker, syncID, sync);
resourceTracker->getStartingFenceSyncs().insert(syncID);
}
// Capture Image Texture bindings
......@@ -4047,7 +4095,7 @@ void FrameCapture::maybeCapturePreCallUpdates(const gl::Context *context, CallCa
mBufferDataMap.erase(bufferDataInfo);
}
// If we're capturing, track what buffers have been deleted
if (mFrameIndex >= mCaptureStartFrame)
if (isCaptureActive())
{
mResourceTracker.setDeletedBuffer(bufferIDs[i]);
}
......@@ -4064,7 +4112,7 @@ void FrameCapture::maybeCapturePreCallUpdates(const gl::Context *context, CallCa
for (GLsizei i = 0; i < count; i++)
{
// If we're capturing, track what new buffers have been genned
if (mFrameIndex >= mCaptureStartFrame)
if (isCaptureActive())
{
mResourceTracker.setGennedBuffer(bufferIDs[i]);
}
......@@ -4072,6 +4120,17 @@ void FrameCapture::maybeCapturePreCallUpdates(const gl::Context *context, CallCa
break;
}
case EntryPoint::GLDeleteSync:
{
GLsync sync = call.params.getParam("sync", ParamType::TGLsync, 0).value.GLsyncVal;
// If we're capturing, track which fence sync has been deleted
if (isCaptureActive())
{
mResourceTracker.setDeletedFenceSync(sync);
}
break;
}
case EntryPoint::GLDrawArrays:
{
maybeCaptureDrawArraysClientData(context, call, 1);
......@@ -4506,11 +4565,17 @@ void FrameCapture::checkForCaptureTrigger()
void FrameCapture::onEndFrame(const gl::Context *context)
{
if (mFrameIndex > mCaptureEndFrame)
{
setCaptureInactive();
return;
}
// On Android, we can trigger a capture during the run
checkForCaptureTrigger();
// Note that we currently capture before the start frame to collect shader and program sources.
if (!mFrameCalls.empty() && mFrameIndex >= mCaptureStartFrame)
if (!mFrameCalls.empty() && isCaptureActive())
{
if (mIsFirstFrame)
{
......@@ -4555,6 +4620,8 @@ void FrameCapture::onEndFrame(const gl::Context *context)
if (enabled() && mFrameIndex == mCaptureStartFrame)
{
setCaptureActive();
mSetupCalls.clear();
CaptureMidExecutionSetup(context, &mSetupCalls, &mResourceTracker, this);
}
......@@ -4661,6 +4728,19 @@ void ResourceTracker::setDeletedBuffer(gl::BufferID id)
mBuffersToRestore.insert(id);
}
void ResourceTracker::setDeletedFenceSync(GLsync sync)
{
ASSERT(sync != nullptr);
if (mStartingFenceSyncs.find(sync) == mStartingFenceSyncs.end())
{
// This is a fence sync created after MEC was initialized. Ignore it.
return;
}
// In this case, the app is deleting a fence sync we started with, we need to regen on loop.
mFenceSyncsToRegen.insert(sync);
}
void ResourceTracker::setGennedBuffer(gl::BufferID id)
{
if (mStartingBuffers.find(id) == mStartingBuffers.end())
......
......@@ -213,6 +213,9 @@ using BufferCalls = std::map<gl::BufferID, std::vector<CallCapture>>;
// true means mapped, false means unmapped
using BufferMapStatusMap = std::map<gl::BufferID, bool>;
using FenceSyncSet = std::set<GLsync>;
using FenceSyncCalls = std::map<GLsync, std::vector<CallCapture>>;
// Helper to track resource changes during the capture
class ResourceTracker final : angle::NonCopyable
{
......@@ -258,6 +261,11 @@ class ResourceTracker final : angle::NonCopyable
void onShaderProgramAccess(gl::ShaderProgramID shaderProgramID);
uint32_t getMaxShaderPrograms() const { return mMaxShaderPrograms; }
FenceSyncSet &getStartingFenceSyncs() { return mStartingFenceSyncs; }
FenceSyncCalls &getFenceSyncRegenCalls() { return mFenceSyncRegenCalls; }
FenceSyncSet &getFenceSyncsToRegen() { return mFenceSyncsToRegen; }
void setDeletedFenceSync(GLsync sync);
private:
// Buffer regen calls will delete and gen a buffer
BufferCalls mBufferRegenCalls;
......@@ -287,6 +295,14 @@ class ResourceTracker final : angle::NonCopyable
// Maximum accessed shader program ID.
uint32_t mMaxShaderPrograms = 0;
// Fence sync objects created during MEC setup
FenceSyncSet mStartingFenceSyncs;
// Fence sync regen calls will create a fence sync objects
FenceSyncCalls mFenceSyncRegenCalls;
// Fence syncs to regen are a list of starting fence sync objects that were deleted and need to
// be regen'ed.
FenceSyncSet mFenceSyncsToRegen;
};
// Used by the CPP replay to filter out unnecessary code.
......@@ -361,6 +377,10 @@ class FrameCapture final : angle::NonCopyable
ReplayContext *replayContext,
const CallCapture &call);
void setCaptureActive() { mCaptureActive = true; }
void setCaptureInactive() { mCaptureActive = false; }
bool isCaptureActive() { return mCaptureActive; }
std::vector<CallCapture> mSetupCalls;
std::vector<CallCapture> mFrameCalls;
......@@ -391,6 +411,8 @@ class FrameCapture final : angle::NonCopyable
// Initialize it to the number of frames you want to capture, and then clear the value to 0 when
// you reach the content you want to capture. Currently only available on Android.
uint32_t mCaptureTrigger;
bool mCaptureActive = false;
};
// Shared class for any items that need to be tracked by FrameCapture across shared contexts
......
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