| /* |
| * 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| 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(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| |
| // 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(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); |
| |
| // 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 |