| /* | 
 |  * Copyright 2013 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #define LOG_TAG "SurfaceTextureMultiContextGL_test" | 
 | //#define LOG_NDEBUG 0 | 
 |  | 
 | #include "SurfaceTextureMultiContextGL.h" | 
 |  | 
 | #include "FillBuffer.h" | 
 |  | 
 | #include <GLES/glext.h> | 
 |  | 
 | namespace android { | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Attempt to latch the texture on the secondary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(EGL_SUCCESS, eglGetError()); | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Check that the GL texture was deleted. | 
 |     EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, | 
 |         DetachFromContextSucceedsAfterProducerDisconnect) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Check that the GL texture was deleted. | 
 |     EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Attempt to detach from the primary context. | 
 |     mST->abandon(); | 
 |     ASSERT_EQ(NO_INIT, mST->detachFromContext()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attempt to detach from the primary context again. | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Make there be no current display. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, | 
 |             EGL_NO_CONTEXT)); | 
 |     ASSERT_EQ(EGL_SUCCESS, eglGetError()); | 
 |  | 
 |     // Attempt to detach from the primary context. | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Make current context be incorrect. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(EGL_SUCCESS, eglGetError()); | 
 |  | 
 |     // Attempt to detach from the primary context. | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attempt to latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the secondary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); | 
 |  | 
 |     // Verify that the texture object was created and bound. | 
 |     GLint texBinding = -1; | 
 |     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); | 
 |     EXPECT_EQ(SECOND_TEX_ID, texBinding); | 
 |  | 
 |     // Try to use the texture from the secondary context. | 
 |     glClearColor(0.2, 0.2, 0.2, 0.2); | 
 |     glClear(GL_COLOR_BUFFER_BIT); | 
 |     glViewport(0, 0, 1, 1); | 
 |     mSecondTextureRenderer->drawTexture(); | 
 |     ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35)); | 
 |     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, | 
 |         AttachToContextSucceedsAfterProducerDisconnect) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the secondary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); | 
 |  | 
 |     // Verify that the texture object was created and bound. | 
 |     GLint texBinding = -1; | 
 |     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); | 
 |     EXPECT_EQ(SECOND_TEX_ID, texBinding); | 
 |  | 
 |     // Try to use the texture from the secondary context. | 
 |     glClearColor(0.2, 0.2, 0.2, 0.2); | 
 |     glClear(GL_COLOR_BUFFER_BIT); | 
 |     glViewport(0, 0, 1, 1); | 
 |     mSecondTextureRenderer->drawTexture(); | 
 |     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); | 
 |     ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, | 
 |         AttachToContextSucceedsBeforeUpdateTexImage) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Detach from the primary context. | 
 |     native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU); | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the secondary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); | 
 |  | 
 |     // Verify that the texture object was created and bound. | 
 |     GLint texBinding = -1; | 
 |     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); | 
 |     EXPECT_EQ(SECOND_TEX_ID, texBinding); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Try to use the texture from the secondary context. | 
 |     glClearColor(0.2, 0.2, 0.2, 0.2); | 
 |     glClear(GL_COLOR_BUFFER_BIT); | 
 |     glViewport(0, 0, 1, 1); | 
 |     mSecondTextureRenderer->drawTexture(); | 
 |     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); | 
 |     ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attempt to attach to the secondary context. | 
 |     mST->abandon(); | 
 |  | 
 |     // Attempt to attach to the primary context. | 
 |     ASSERT_EQ(NO_INIT, mST->attachToContext(SECOND_TEX_ID)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Attempt to attach to the primary context. | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, | 
 |         AttachToContextFailsWhenAttachedBeforeUpdateTexImage) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Attempt to attach to the primary context. | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Make there be no current display. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, | 
 |             EGL_NO_CONTEXT)); | 
 |     ASSERT_EQ(EGL_SUCCESS, eglGetError()); | 
 |  | 
 |     // Attempt to attach with no context current. | 
 |     ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Latch the texture contents on the primary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the secondary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); | 
 |  | 
 |     // Detach from the secondary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the tertiary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mThirdEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID)); | 
 |  | 
 |     // Verify that the texture object was created and bound. | 
 |     GLint texBinding = -1; | 
 |     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); | 
 |     EXPECT_EQ(THIRD_TEX_ID, texBinding); | 
 |  | 
 |     // Try to use the texture from the tertiary context. | 
 |     glClearColor(0.2, 0.2, 0.2, 0.2); | 
 |     glClear(GL_COLOR_BUFFER_BIT); | 
 |     glViewport(0, 0, 1, 1); | 
 |     mThirdTextureRenderer->drawTexture(); | 
 |     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); | 
 |     ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, | 
 |         AttachToContextSucceedsTwiceBeforeUpdateTexImage) { | 
 |     ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW)); | 
 |  | 
 |     // Detach from the primary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the secondary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); | 
 |  | 
 |     // Detach from the secondary context. | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |  | 
 |     // Attach to the tertiary context. | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mThirdEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID)); | 
 |  | 
 |     // Verify that the texture object was created and bound. | 
 |     GLint texBinding = -1; | 
 |     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding); | 
 |     EXPECT_EQ(THIRD_TEX_ID, texBinding); | 
 |  | 
 |     // Latch the texture contents on the tertiary context. | 
 |     mFW->waitForFrame(); | 
 |     ASSERT_EQ(OK, mST->updateTexImage()); | 
 |  | 
 |     // Try to use the texture from the tertiary context. | 
 |     glClearColor(0.2, 0.2, 0.2, 0.2); | 
 |     glClear(GL_COLOR_BUFFER_BIT); | 
 |     glViewport(0, 0, 1, 1); | 
 |     mThirdTextureRenderer->drawTexture(); | 
 |     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); | 
 |     ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35)); | 
 | } | 
 |  | 
 | TEST_F(SurfaceTextureMultiContextGLTest, | 
 |         UpdateTexImageSucceedsForBufferConsumedBeforeDetach) { | 
 |     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 and attach to the secondary context | 
 |     ASSERT_EQ(OK, mST->detachFromContext()); | 
 |     ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, | 
 |             mSecondEglContext)); | 
 |     ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID)); | 
 |  | 
 |     // Consume final frame on secondary context | 
 |     mFW->waitForFrame(); | 
 |     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 |