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
// 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
// texture in the specified texture target.

View File

@ -462,24 +462,37 @@ status_t GLConsumer::bindTextureImageLocked() {
}
status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
mCurrentCrop);
mCurrentCrop);
if (err != NO_ERROR) {
ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
mEglDisplay, mCurrentTexture);
return UNKNOWN_ERROR;
}
mCurrentTextureImage->bindToTextureTarget(mTexTarget);
while ((error = glGetError()) != GL_NO_ERROR) {
ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
return UNKNOWN_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);
return UNKNOWN_ERROR;
}
}
// Wait for the new buffer to be ready.
return doGLFenceWaitLocked();
}
status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
@ -1056,12 +1069,13 @@ GLConsumer::EglImage::~EglImage() {
}
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.
bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
bool displayInvalid = mEglDisplay != eglDisplay;
bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
if (haveImage && (displayInvalid || cropInvalid)) {
if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
ALOGE("createIfNeeded: eglDestroyImageKHR failed");
}

View File

@ -386,4 +386,59 @@ TEST_F(SurfaceTextureMultiContextGLTest,
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