am 53cf2020: Merge changes I37fd43b5,I91eb29db,I0491ce35 into ics-mr1

* commit '53cf20202a3848a6c61b5229814268180a3d2f16':
  SurfaceTexture: fix a couple tests
  EGL: default to swap interval 1
  SurfaceTexture: clean up some tests
This commit is contained in:
Jamie Gennis 2011-11-21 15:56:11 -08:00 committed by Android Git Automerger
commit f59fa92c30
4 changed files with 322 additions and 244 deletions

View File

@ -202,6 +202,10 @@ public:
// getCurrentScalingMode returns the scaling mode of the current buffer
uint32_t getCurrentScalingMode() const;
// isSynchronousMode returns whether the SurfaceTexture is currently in
// synchronous mode.
bool isSynchronousMode() const;
// abandon frees all the buffers and puts the SurfaceTexture into the
// 'abandoned' state. Once put in this state the SurfaceTexture can never
// leave it. When in the 'abandoned' state, all methods of the

View File

@ -1005,6 +1005,11 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const {
return mCurrentScalingMode;
}
bool SurfaceTexture::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mSynchronousMode;
}
int SurfaceTexture::query(int what, int* outValue)
{
Mutex::Autolock lock(mMutex);

View File

@ -396,7 +396,8 @@ protected:
1.0f, 1.0f,
};
glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0,
triangleVertices);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
glEnableVertexAttribArray(mPositionHandle);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
@ -410,13 +411,17 @@ protected:
// XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
// they're setting the defautls for that target, but when hacking things
// to use GL_TEXTURE_2D they are needed to achieve the same behavior.
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
GLfloat texMatrix[16];
@ -640,8 +645,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
for (int i = 0; i < 5; i++) {
const android_native_rect_t& crop(crops[i]);
SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left,
crop.top, crop.right, crop.bottom).string());
SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }",
crop.left, crop.top, crop.right, crop.bottom).string());
ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
@ -650,13 +655,15 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
buf->getNativeBuffer()));
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
buf->unlock();
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
buf->getNativeBuffer()));
mST->updateTexImage();
@ -708,7 +715,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
class ProducerThread : public Thread {
public:
ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels):
ProducerThread(const sp<ANativeWindow>& anw,
const TestPixel* testPixels):
mANW(anw),
mTestPixels(testPixels) {
}
@ -940,82 +948,6 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
}
TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
mST->setDefaultBufferSize(texWidth, texHeight);
// Do the producer side of things
EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClearColor(0.6, 0.6, 0.6, 0.6);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(4, 4, 4, 4);
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(24, 48, 4, 4);
glClearColor(0.0, 1.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(37, 17, 4, 4);
glClearColor(0.0, 0.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mEglDisplay, stcEglSurface);
// Do the consumer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glDisable(GL_SCISSOR_TEST);
mST->updateTexImage();
// We must wait until updateTexImage has been called to destroy the
// EGLSurface because we're in synchronous mode.
eglDestroySurface(mEglDisplay, stcEglSurface);
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255));
EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255));
EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255));
EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
}
TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
class ProducerThread : public Thread {
public:
@ -1093,13 +1025,284 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
}
TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
int texHeight = 16;
ANativeWindowBuffer* anb;
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
// make sure it works with small textures
mST->setDefaultBufferSize(16, texHeight);
EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
EXPECT_EQ(16, anb->width);
EXPECT_EQ(texHeight, anb->height);
EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it works with GL_MAX_TEXTURE_SIZE
mST->setDefaultBufferSize(maxTextureSize, texHeight);
EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
EXPECT_EQ(maxTextureSize, anb->width);
EXPECT_EQ(texHeight, anb->height);
EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it fails with GL_MAX_TEXTURE_SIZE+1
mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
EXPECT_EQ(maxTextureSize+1, anb->width);
EXPECT_EQ(texHeight, anb->height);
EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
ASSERT_NE(NO_ERROR, mST->updateTexImage());
}
/*
* This test is for testing GL -> GL texture streaming via SurfaceTexture. It
* contains functionality to create a producer thread that will perform GL
* rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
* Additionally it supports interlocking the producer and consumer threads so
* that a specific sequence of calls can be deterministically created by the
* test.
* This test fixture is for testing GL -> GL texture streaming. It creates an
* EGLSurface and an EGLContext for the image producer to use.
*/
class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
protected:
SurfaceTextureGLToGLTest():
mProducerEglSurface(EGL_NO_SURFACE),
mProducerEglContext(EGL_NO_CONTEXT) {
}
virtual void SetUp() {
SurfaceTextureGLTest::SetUp();
EGLConfig myConfig = {0};
EGLint numConfigs = 0;
EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
1, &numConfigs));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
EGL_NO_CONTEXT, getContextAttribs());
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
}
virtual void TearDown() {
if (mProducerEglContext != EGL_NO_CONTEXT) {
eglDestroyContext(mEglDisplay, mProducerEglContext);
}
if (mProducerEglSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEglDisplay, mProducerEglSurface);
}
SurfaceTextureGLTest::TearDown();
}
EGLSurface mProducerEglSurface;
EGLContext mProducerEglContext;
};
TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
mST->setDefaultBufferSize(texWidth, texHeight);
// Do the producer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// This is needed to ensure we pick up a buffer of the correct size.
eglSwapBuffers(mEglDisplay, mProducerEglSurface);
glClearColor(0.6, 0.6, 0.6, 0.6);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(4, 4, 4, 4);
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(24, 48, 4, 4);
glClearColor(0.0, 1.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(37, 17, 4, 4);
glClearColor(0.0, 0.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mEglDisplay, mProducerEglSurface);
// Do the consumer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glDisable(GL_SCISSOR_TEST);
mST->updateTexImage(); // Skip the first frame, which was empty
mST->updateTexImage();
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, texWidth, texHeight);
drawTexture();
EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255));
EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255));
EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255));
EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
sp<GraphicBuffer> buffers[3];
// This test requires async mode to run on a single thread.
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
for (int i = 0; i < 3; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mEglDisplay, mProducerEglSurface);
// Consume a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mST->updateTexImage();
buffers[i] = mST->getCurrentBuffer();
}
// Destroy the GL texture object to release its ref on buffers[2].
GLuint texID = TEX_ID;
glDeleteTextures(1, &texID);
// Destroy the EGLSurface
EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Release the ref that the SurfaceTexture has on buffers[2].
mST->abandon();
EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[1]->getStrongCount());
// Depending on how lazily the GL driver dequeues buffers, we may end up
// with either two or three total buffers. If there are three, make sure
// the last one was properly down-ref'd.
if (buffers[2] != buffers[0]) {
EXPECT_EQ(1, buffers[2]->getStrongCount());
}
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
sp<GraphicBuffer> buffers[3];
// This test requires async mode to run on a single thread.
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
for (int i = 0; i < 3; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Consume a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
buffers[i] = mST->getCurrentBuffer();
}
// Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
// on buffers[2].
mST->abandon();
// Destroy the GL texture object to release its ref on buffers[2].
GLuint texID = TEX_ID;
glDeleteTextures(1, &texID);
// Destroy the EGLSurface.
EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[1]->getStrongCount());
// Depending on how lazily the GL driver dequeues buffers, we may end up
// with either two or three total buffers. If there are three, make sure
// the last one was properly down-ref'd.
if (buffers[2] != buffers[0]) {
EXPECT_EQ(1, buffers[2]->getStrongCount());
}
}
TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
// This test requires 3 buffers to run on a single thread.
mST->setBufferCountServer(3);
ASSERT_TRUE(mST->isSynchronousMode());
for (int i = 0; i < 10; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Consume a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
}
ASSERT_TRUE(mST->isSynchronousMode());
}
/*
* This test fixture is for testing GL -> GL texture streaming from one thread
* to another. It contains functionality to create a producer thread that will
* perform GL rendering to an ANativeWindow that feeds frames to a
* SurfaceTexture. Additionally it supports interlocking the producer and
* consumer threads so that a specific sequence of calls can be
* deterministically created by the test.
*
* The intended usage is as follows:
*
@ -1122,7 +1325,7 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
* }
*
*/
class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
protected:
// ProducerThread is an abstract base class to simplify the creation of
@ -1223,30 +1426,8 @@ protected:
Condition mFrameFinishCondition;
};
SurfaceTextureGLToGLTest():
mProducerEglSurface(EGL_NO_SURFACE),
mProducerEglContext(EGL_NO_CONTEXT) {
}
virtual void SetUp() {
SurfaceTextureGLTest::SetUp();
EGLConfig myConfig = {0};
EGLint numConfigs = 0;
EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
1, &numConfigs));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
EGL_NO_CONTEXT, getContextAttribs());
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
SurfaceTextureGLToGLTest::SetUp();
mFC = new FrameCondition();
mST->setFrameAvailableListener(mFC);
}
@ -1255,15 +1436,9 @@ protected:
if (mProducerThread != NULL) {
mProducerThread->requestExitAndWait();
}
if (mProducerEglContext != EGL_NO_CONTEXT) {
eglDestroyContext(mEglDisplay, mProducerEglContext);
}
if (mProducerEglSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEglDisplay, mProducerEglSurface);
}
mProducerThread.clear();
mFC.clear();
SurfaceTextureGLTest::TearDown();
SurfaceTextureGLToGLTest::TearDown();
}
void runProducerThread(const sp<ProducerThread> producerThread) {
@ -1274,13 +1449,12 @@ protected:
producerThread->run();
}
EGLSurface mProducerEglSurface;
EGLContext mProducerEglContext;
sp<ProducerThread> mProducerThread;
sp<FrameCondition> mFC;
};
TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) {
TEST_F(SurfaceTextureGLThreadToGLTest,
UpdateTexImageBeforeFrameFinishedCompletes) {
class PT : public ProducerThread {
virtual void render() {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@ -1298,7 +1472,8 @@ TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) {
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) {
TEST_F(SurfaceTextureGLThreadToGLTest,
UpdateTexImageAfterFrameFinishedCompletes) {
class PT : public ProducerThread {
virtual void render() {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@ -1316,7 +1491,8 @@ TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) {
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
TEST_F(SurfaceTextureGLThreadToGLTest,
RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@ -1344,7 +1520,8 @@ TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedComple
}
}
TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
TEST_F(SurfaceTextureGLThreadToGLTest,
RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@ -1373,7 +1550,8 @@ TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedComplet
}
// XXX: This test is disabled because it is currently hanging on some devices.
TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
TEST_F(SurfaceTextureGLThreadToGLTest,
DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
enum { NUM_ITERATIONS = 64 };
class PT : public ProducerThread {
@ -1438,118 +1616,4 @@ TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalled
}
}
TEST_F(SurfaceTextureGLTest, EglDestroySurfaceUnrefsBuffers) {
EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
sp<GraphicBuffer> buffers[3];
for (int i = 0; i < 3; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(mEglDisplay, stcEglSurface);
// Consume a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mST->updateTexImage();
buffers[i] = mST->getCurrentBuffer();
}
// Destroy the GL texture object to release its ref on buffers[2].
GLuint texID = TEX_ID;
glDeleteTextures(1, &texID);
// Destroy the EGLSurface
EXPECT_TRUE(eglDestroySurface(mEglDisplay, stcEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Release the ref that the SurfaceTexture has on buffers[2].
mST->abandon();
EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[1]->getStrongCount());
EXPECT_EQ(1, buffers[2]->getStrongCount());
}
TEST_F(SurfaceTextureGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
sp<GraphicBuffer> buffers[3];
for (int i = 0; i < 3; i++) {
// Produce a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_TRUE(eglSwapBuffers(mEglDisplay, stcEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
// Consume a frame
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
buffers[i] = mST->getCurrentBuffer();
}
// Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
// on buffers[2].
mST->abandon();
// Destroy the GL texture object to release its ref on buffers[2].
GLuint texID = TEX_ID;
glDeleteTextures(1, &texID);
// Destroy the EGLSurface.
EXPECT_TRUE(eglDestroySurface(mEglDisplay, stcEglSurface));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
EXPECT_EQ(1, buffers[0]->getStrongCount());
EXPECT_EQ(1, buffers[1]->getStrongCount());
EXPECT_EQ(1, buffers[2]->getStrongCount());
}
TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
int texHeight = 16;
ANativeWindowBuffer* anb;
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
// make sure it works with small textures
mST->setDefaultBufferSize(16, texHeight);
EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
EXPECT_EQ(16, anb->width);
EXPECT_EQ(texHeight, anb->height);
EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it works with GL_MAX_TEXTURE_SIZE
mST->setDefaultBufferSize(maxTextureSize, texHeight);
EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
EXPECT_EQ(maxTextureSize, anb->width);
EXPECT_EQ(texHeight, anb->height);
EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it fails with GL_MAX_TEXTURE_SIZE+1
mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
EXPECT_EQ(maxTextureSize+1, anb->width);
EXPECT_EQ(texHeight, anb->height);
EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
ASSERT_NE(NO_ERROR, mST->updateTexImage());
}
} // namespace android

View File

@ -370,6 +370,11 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
}
}
// the EGL spec requires that a new EGLSurface default to swap interval
// 1, so explicitly set that on the window here.
ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
anw->setSwapInterval(anw, 1);
EGLSurface surface = cnx->egl.eglCreateWindowSurface(
iDpy, iConfig, window, attrib_list);
if (surface != EGL_NO_SURFACE) {