Loading include/gui/GLConsumer.h +3 −1 Original line number Diff line number Diff line Loading @@ -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. Loading libs/gui/GLConsumer.cpp +23 −9 Original line number Diff line number Diff line Loading @@ -463,23 +463,36 @@ status_t GLConsumer::bindTextureImageLocked() { status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, 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) { // 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) { Loading Loading @@ -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"); } Loading libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp +55 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
include/gui/GLConsumer.h +3 −1 Original line number Diff line number Diff line Loading @@ -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. Loading
libs/gui/GLConsumer.cpp +23 −9 Original line number Diff line number Diff line Loading @@ -463,23 +463,36 @@ status_t GLConsumer::bindTextureImageLocked() { status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, 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) { // 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) { Loading Loading @@ -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"); } Loading
libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp +55 −0 Original line number Diff line number Diff line Loading @@ -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