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:
commit
f59fa92c30
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user