Merge "GLConsumer: Fix eglTerminate/eglInit edge case." into lmp-dev

This commit is contained in:
Eric Penner 2014-08-27 18:07:04 +00:00 committed by Android (Google) Code Review
commit 5c4a156659
3 changed files with 81 additions and 10 deletions

View File

@ -287,7 +287,9 @@ private:
// createIfNeeded creates an EGLImage if required (we haven't created // createIfNeeded creates an EGLImage if required (we haven't created
// one yet, or the EGLDisplay or crop-rect has changed). // one yet, or the EGLDisplay or crop-rect has changed).
status_t createIfNeeded(EGLDisplay display, const Rect& cropRect); status_t createIfNeeded(EGLDisplay display,
const Rect& cropRect,
bool forceCreate = false);
// This calls glEGLImageTargetTexture2DOES to bind the image to the // This calls glEGLImageTargetTexture2DOES to bind the image to the
// texture in the specified texture target. // texture in the specified texture target.

View File

@ -463,23 +463,36 @@ status_t GLConsumer::bindTextureImageLocked() {
status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
mCurrentCrop); mCurrentCrop);
if (err != NO_ERROR) { if (err != NO_ERROR) {
ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d", ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
mEglDisplay, mCurrentTexture); mEglDisplay, mCurrentTexture);
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
mCurrentTextureImage->bindToTextureTarget(mTexTarget); mCurrentTextureImage->bindToTextureTarget(mTexTarget);
while ((error = glGetError()) != GL_NO_ERROR) { // In the rare case that the display is terminated and then initialized
// again, we can't detect that the display changed (it didn't), but the
// image is invalid. In this case, repeat the exact same steps while
// forcing the creation of a new image.
if ((error = glGetError()) != GL_NO_ERROR) {
glBindTexture(mTexTarget, mTexName);
status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
mCurrentCrop,
true);
if (err != NO_ERROR) {
ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
mEglDisplay, mCurrentTexture);
return UNKNOWN_ERROR;
}
mCurrentTextureImage->bindToTextureTarget(mTexTarget);
if ((error = glGetError()) != GL_NO_ERROR) {
ST_LOGE("bindTextureImage: error binding external image: %#04x", error); ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
}
// Wait for the new buffer to be ready. // Wait for the new buffer to be ready.
return doGLFenceWaitLocked(); return doGLFenceWaitLocked();
} }
status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) { status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
@ -1056,12 +1069,13 @@ GLConsumer::EglImage::~EglImage() {
} }
status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
const Rect& cropRect) { const Rect& cropRect,
bool forceCreation) {
// If there's an image and it's no longer valid, destroy it. // If there's an image and it's no longer valid, destroy it.
bool haveImage = mEglImage != EGL_NO_IMAGE_KHR; bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
bool displayInvalid = mEglDisplay != eglDisplay; bool displayInvalid = mEglDisplay != eglDisplay;
bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect; bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
if (haveImage && (displayInvalid || cropInvalid)) { if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
ALOGE("createIfNeeded: eglDestroyImageKHR failed"); ALOGE("createIfNeeded: eglDestroyImageKHR failed");
} }

View File

@ -386,4 +386,59 @@ TEST_F(SurfaceTextureMultiContextGLTest,
ASSERT_EQ(OK, mST->updateTexImage()); ASSERT_EQ(OK, mST->updateTexImage());
} }
TEST_F(SurfaceTextureMultiContextGLTest,
AttachAfterDisplayTerminatedSucceeds) {
ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
// produce two frames and consume them both on the primary context
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
mFW->waitForFrame();
ASSERT_EQ(OK, mST->updateTexImage());
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
mFW->waitForFrame();
ASSERT_EQ(OK, mST->updateTexImage());
// produce one more frame
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
// Detach from the primary context.
ASSERT_EQ(OK, mST->releaseTexImage());
ASSERT_EQ(OK, mST->detachFromContext());
// Terminate and then initialize the display. All contexts, surfaces
// and images are invalid at this point.
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
EGLint majorVersion = 0;
EGLint minorVersion = 0;
EXPECT_TRUE(eglTerminate(display));
EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// The surface is invalid so create it again.
EGLint pbufferAttribs[] = {
EGL_WIDTH, 64,
EGL_HEIGHT, 64,
EGL_NONE };
mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
pbufferAttribs);
// The second context is invalid so create it again.
mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig,
EGL_NO_CONTEXT, getContextAttribs());
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext);
ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mSecondEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Now attach to and consume final frame on secondary context.
ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
mFW->waitForFrame();
ASSERT_EQ(OK, mST->updateTexImage());
}
} // namespace android } // namespace android