2d14a0ed4f
If a display is terminated and then initialized, we can't detect this using the display itself (it has the same value), but all EglImages still become invalid for the display. This patch detects this during image binding and forces creation of a new EglImage. Bug: 10430249 Change-Id: I75101c50962f21263dca3ec6e241a2e5a3c23dad
445 lines
15 KiB
C++
445 lines
15 KiB
C++
/*
|
|
* 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
|