Merge "Fix some policy-base routing issues." into ics-mr1
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 27d863d..15c2bab 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -202,6 +202,10 @@
// 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
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 57f9e15..971a1b8 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -40,6 +40,7 @@
protected:
SurfaceTextureClient();
+ virtual ~SurfaceTextureClient();
void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
private:
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index ee54bf4..beb23f6 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -441,6 +441,11 @@
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
}
+ if (mCurrentTexture == buf) {
+ // The current texture no longer references the buffer in this slot
+ // since we just allocated a new buffer.
+ mCurrentTexture = INVALID_BUFFER_SLOT;
+ }
returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
}
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
@@ -641,8 +646,9 @@
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("disconnect: SurfaceTexture has been abandoned!");
- return NO_INIT;
+ // it is not really an error to disconnect after the surface
+ // has been abandoned, it should just be a no-op.
+ return NO_ERROR;
}
int err = NO_ERROR;
@@ -1004,6 +1010,11 @@
return mCurrentScalingMode;
}
+bool SurfaceTexture::isSynchronousMode() const {
+ Mutex::Autolock lock(mMutex);
+ return mSynchronousMode;
+}
+
int SurfaceTexture::query(int what, int* outValue)
{
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 98fa171..48070d6 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -36,6 +36,12 @@
SurfaceTextureClient::init();
}
+SurfaceTextureClient::~SurfaceTextureClient() {
+ if (mConnectedToCpu) {
+ SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU);
+ }
+}
+
void SurfaceTextureClient::init() {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = hook_setSwapInterval;
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 93ebfb9..6d1b951 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -396,7 +396,8 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* }
*
*/
-class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
protected:
// ProducerThread is an abstract base class to simplify the creation of
@@ -1223,30 +1426,8 @@
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 @@
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 @@
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 @@
// 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 @@
// 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, RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
+TEST_F(SurfaceTextureGLThreadToGLTest,
+ RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@@ -1373,7 +1550,8 @@
}
// 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(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
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 5855b63..9c1a10e 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -44,10 +44,17 @@
LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
+ LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
+endif
+
+ifneq ($(MAX_EGL_CACHE_SIZE),)
+ LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
+endif
+
include $(BUILD_SHARED_LIBRARY)
installed_libEGL := $(LOCAL_INSTALLED_MODULE)
-
# OpenGL drivers config file
ifneq ($(BOARD_EGL_CFG),)
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 2237eb6..a63d5b0 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -370,6 +370,11 @@
}
}
+ // 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) {
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 13a4929..c4a7466 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -25,10 +25,18 @@
#include <sys/types.h>
#include <unistd.h>
+#ifndef MAX_EGL_CACHE_ENTRY_SIZE
+#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024);
+#endif
+
+#ifndef MAX_EGL_CACHE_SIZE
+#define MAX_EGL_CACHE_SIZE (64 * 1024);
+#endif
+
// Cache size limits.
static const size_t maxKeySize = 1024;
-static const size_t maxValueSize = 4096;
-static const size_t maxTotalSize = 64 * 1024;
+static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE;
+static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
// Cache file header
static const char* cacheFileMagic = "EGL$";
@@ -85,7 +93,7 @@
bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
bool atEnd = (bcExtLen+1) < extsLen &&
!strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
- bool inMiddle = strstr(" " BC_EXT_STR " ", exts);
+ bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
if (equal || atStart || atEnd || inMiddle) {
PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
eglSetBlobCacheFuncsANDROID =
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 862b48d..31119f9 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -220,15 +220,19 @@
if (end) {
// length of the extension string
const size_t len = end - start;
- // NOTE: we could avoid the copy if we had strnstr.
- const String8 ext(start, len);
- // now go through all implementations and look for this extension
- for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
- // if we find it, add this extension string to our list
- // (and don't forget the space)
- const char* match = strstr(disp[i].queryString.extensions, ext.string());
- if (match && (match[len] == ' ' || match[len] == 0)) {
- mExtensionString.append(start, len+1);
+ if (len) {
+ // NOTE: we could avoid the copy if we had strnstr.
+ const String8 ext(start, len);
+ // now go through all implementations and look for this extension
+ for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+ if (disp[i].queryString.extensions) {
+ // if we find it, add this extension string to our list
+ // (and don't forget the space)
+ const char* match = strstr(disp[i].queryString.extensions, ext.string());
+ if (match && (match[len] == ' ' || match[len] == 0)) {
+ mExtensionString.append(start, len+1);
+ }
+ }
}
}
// process the next extension string, and skip the space.
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
index c5e34cd..0c5fa04 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
@@ -124,6 +124,10 @@
public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE;
public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF;
public static final int GL_BGRA = 0x80E1;
+ public static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
+ public static final int GL_SAMPLER_EXTERNAL_OES = 0x8D66;
+ public static final int GL_TEXTURE_BINDING_EXTERNAL_OES = 0x8D67;
+ public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 0x8D68;
native private static void _nativeClassInit();
static {
@@ -135,4 +139,4 @@
private static final int GL_FLOAT = GLES10.GL_FLOAT;
private static final int GL_SHORT = GLES10.GL_SHORT;
- private static Buffer _matrixIndexPointerOES;
\ No newline at end of file
+ private static Buffer _matrixIndexPointerOES;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 53502dbc..61a8358 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -30,10 +30,6 @@
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
endif
-ifneq (,$(findstring $(TARGET_DEVICE),tuna toro maguro))
- LOCAL_CFLAGS += -DREFRESH_RATE=59
-endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \