libgui: add BQ consumer buffer free notifications
This change adds a new callback for BufferQueue consumers to be notified
when the BufferQueue frees some or all of its buffers. This is needed
to retain SurfaceTexture behavior where all buffers would be freed when
the producer disconnects. This change also modifies the
SurfaceTextureGLToGLTest.EglDestroySurfaceUnrefsBuffers test to catch
when the buffers are not freed.
The implementation is a little complicated because it needs to avoid
circular sp<> references across what will be a binder interface (so wp<>
can't be used directly). It also needs to avoid the possibility of
locking the BufferQueue and consumer (e.g. SurfaceTexture) mutexes in
the wrong order.
This change also includes a few additional fixes and test cleanups.
Change-Id: I27b77d0af15cb4b135f4b63573f634f5f0da2182
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 8c6defe..71cf577 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -47,6 +47,11 @@
}
virtual void SetUp() {
+ const ::testing::TestInfo* const testInfo =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
+ testInfo->name());
+
mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
@@ -148,6 +153,11 @@
eglTerminate(mEglDisplay);
}
ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ const ::testing::TestInfo* const testInfo =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("End test: %s.%s", testInfo->test_case_name(),
+ testInfo->name());
}
virtual EGLint const* getConfigAttribs() {
@@ -1188,7 +1198,10 @@
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
- sp<GraphicBuffer> buffers[3];
+ sp<GraphicBuffer> buffers[2];
+
+ sp<FrameWaiter> fw(new FrameWaiter);
+ mST->setFrameAvailableListener(fw);
// This test requires async mode to run on a single thread.
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -1197,7 +1210,7 @@
EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < 2; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
@@ -1209,6 +1222,7 @@
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ fw->waitForFrame();
mST->updateTexImage();
buffers[i] = mST->getCurrentBuffer();
}
@@ -1220,24 +1234,23 @@
// Destroy the EGLSurface
EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mProducerEglSurface = EGL_NO_SURFACE;
- // Release the ref that the SurfaceTexture has on buffers[2].
- mST->abandon();
-
+ // This test should have the only reference to buffer 0.
EXPECT_EQ(1, buffers[0]->getStrongCount());
- EXPECT_EQ(1, buffers[1]->getStrongCount());
- // Depending on how lazily the GL driver dequeues buffers, we may end up
- // with either two or three total buffers. If there are three, make sure
- // the last one was properly down-ref'd.
- if (buffers[2] != buffers[0]) {
- EXPECT_EQ(1, buffers[2]->getStrongCount());
- }
+ // The SurfaceTexture should hold a single reference to buffer 1 in its
+ // mCurrentBuffer member. All of the references in the slots should have
+ // been released.
+ EXPECT_EQ(2, buffers[1]->getStrongCount());
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
sp<GraphicBuffer> buffers[3];
+ sp<FrameWaiter> fw(new FrameWaiter);
+ mST->setFrameAvailableListener(fw);
+
// This test requires async mode to run on a single thread.
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
@@ -1258,6 +1271,7 @@
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ fw->waitForFrame();
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
buffers[i] = mST->getCurrentBuffer();
}
@@ -1273,6 +1287,7 @@
// Destroy the EGLSurface.
EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mProducerEglSurface = EGL_NO_SURFACE;
EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[1]->getStrongCount());