Skip to content

Commit

Permalink
Traces: --offscreen syncs on N-2 frame GPU completion
Browse files Browse the repository at this point in the history
This avoids the issue described on the bug where an app's assumption
about double buffering can create a race.

This prevents the replay from getting too far ahead rendering to
offscreen framebuffers.

Also correct mOffscreenFramebuffers to use mTotalFrameCount as the use
of mOffscreenFrameCount appears accidental.

Bug: angleproject:370089935
Change-Id: I30f438eb66201fe77d61710cbe6e90d47e839dd8
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5895974
Reviewed-by: Cody Northrop <[email protected]>
Reviewed-by: Charlie Lao <[email protected]>
Commit-Queue: Roman Lavrov <[email protected]>
  • Loading branch information
romanl-g authored and Angle LUCI CQ committed Sep 30, 2024
1 parent 7c81171 commit 03b5ea3
Showing 1 changed file with 21 additions and 3 deletions.
24 changes: 21 additions & 3 deletions src/tests/perf_tests/TracePerfTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,12 @@ class TracePerfTest : public ANGLERenderTest
std::vector<TimeSample> mTimeline;

bool mUseTimestampQueries = false;
// Note: more than 2 offscreen buffers can cause races, surface is double buffered so real-world
// apps can rely on (now broken) assumptions about GPU completion of a previous frame
static constexpr int mMaxOffscreenBufferCount = 2;
std::array<GLuint, mMaxOffscreenBufferCount> mOffscreenFramebuffers = {0, 0};
std::array<GLuint, mMaxOffscreenBufferCount> mOffscreenTextures = {0, 0};
std::array<GLsync, mMaxOffscreenBufferCount> mOffscreenSyncs = {0, 0};
GLuint mOffscreenDepthStencil = 0;
int mWindowWidth = 0;
int mWindowHeight = 0;
Expand Down Expand Up @@ -2102,6 +2105,19 @@ void TracePerfTest::drawBenchmark()
// ping pong between them for each frame.
glBindFramebuffer(GL_FRAMEBUFFER,
mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);

GLsync sync = mOffscreenSyncs[mTotalFrameCount % mMaxOffscreenBufferCount];
if (sync)
{
constexpr GLuint64 kTimeout = 2'000'000'000; // 2 seconds
GLenum result = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, kTimeout);
if (result != GL_CONDITION_SATISFIED && result != GL_ALREADY_SIGNALED)
{
failTest(std::string("glClientWaitSync unexpected result: ") +
std::to_string(result));
}
glDeleteSync(sync);
}
}

char frameName[32];
Expand Down Expand Up @@ -2130,9 +2146,8 @@ void TracePerfTest::drawBenchmark()
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &currentReadFBO);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(
GL_READ_FRAMEBUFFER,
mOffscreenFramebuffers[mOffscreenFrameCount % mMaxOffscreenBufferCount]);
glBindFramebuffer(GL_READ_FRAMEBUFFER,
mOffscreenFramebuffers[mTotalFrameCount % mMaxOffscreenBufferCount]);

uint32_t frameX = (mOffscreenFrameCount % kFramesPerXY) % kFramesPerX;
uint32_t frameY = (mOffscreenFrameCount % kFramesPerXY) / kFramesPerX;
Expand All @@ -2147,6 +2162,9 @@ void TracePerfTest::drawBenchmark()
glDisable(GL_SCISSOR_TEST);
}

mOffscreenSyncs[mTotalFrameCount % mMaxOffscreenBufferCount] =
glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

glBlitFramebuffer(0, 0, mWindowWidth, mWindowHeight, windowX, windowY,
windowX + kOffscreenFrameWidth, windowY + kOffscreenFrameHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
Expand Down

0 comments on commit 03b5ea3

Please sign in to comment.