blob: 3a5917f5796ebaf3c73346b74c4c5d5152ac1313 [file] [log] [blame]
Jamie Gennisd99c0882011-03-10 16:24:46 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jamie Gennis2640bfd2011-07-14 17:11:47 -070017#define LOG_TAG "SurfaceTexture_test"
Jamie Gennis5451d152011-06-08 09:40:45 -070018//#define LOG_NDEBUG 0
19
Jamie Gennisd99c0882011-03-10 16:24:46 -080020#include <gtest/gtest.h>
21#include <gui/SurfaceTexture.h>
22#include <gui/SurfaceTextureClient.h>
23#include <ui/GraphicBuffer.h>
24#include <utils/String8.h>
Jamie Gennis5451d152011-06-08 09:40:45 -070025#include <utils/threads.h>
Jamie Gennisd99c0882011-03-10 16:24:46 -080026
Mathias Agopian90ac7992012-02-25 18:48:35 -080027#include <gui/ISurfaceComposer.h>
28#include <gui/Surface.h>
29#include <gui/SurfaceComposerClient.h>
Jamie Gennisd99c0882011-03-10 16:24:46 -080030
31#include <EGL/egl.h>
32#include <EGL/eglext.h>
33#include <GLES2/gl2.h>
34#include <GLES2/gl2ext.h>
35
36#include <ui/FramebufferNativeWindow.h>
37
38namespace android {
39
40class GLTest : public ::testing::Test {
41protected:
42
43 GLTest():
44 mEglDisplay(EGL_NO_DISPLAY),
45 mEglSurface(EGL_NO_SURFACE),
46 mEglContext(EGL_NO_CONTEXT) {
47 }
48
49 virtual void SetUp() {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -070050 const ::testing::TestInfo* const testInfo =
51 ::testing::UnitTest::GetInstance()->current_test_info();
52 ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
53 testInfo->name());
54
Jamie Gennisd99c0882011-03-10 16:24:46 -080055 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
56 ASSERT_EQ(EGL_SUCCESS, eglGetError());
57 ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
58
59 EGLint majorVersion;
60 EGLint minorVersion;
61 EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
62 ASSERT_EQ(EGL_SUCCESS, eglGetError());
63 RecordProperty("EglVersionMajor", majorVersion);
64 RecordProperty("EglVersionMajor", minorVersion);
65
Jamie Gennisd99c0882011-03-10 16:24:46 -080066 EGLint numConfigs = 0;
Jamie Gennis1876d132011-03-17 16:32:52 -070067 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
Jamie Gennisd99c0882011-03-10 16:24:46 -080068 1, &numConfigs));
69 ASSERT_EQ(EGL_SUCCESS, eglGetError());
70
71 char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
72 if (displaySecsEnv != NULL) {
73 mDisplaySecs = atoi(displaySecsEnv);
74 if (mDisplaySecs < 0) {
75 mDisplaySecs = 0;
76 }
77 } else {
78 mDisplaySecs = 0;
79 }
80
81 if (mDisplaySecs > 0) {
82 mComposerClient = new SurfaceComposerClient;
83 ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
84
Jamie Gennisfc850122011-04-25 16:40:05 -070085 mSurfaceControl = mComposerClient->createSurface(
Jamie Gennisd99c0882011-03-10 16:24:46 -080086 String8("Test Surface"), 0,
87 getSurfaceWidth(), getSurfaceHeight(),
88 PIXEL_FORMAT_RGB_888, 0);
89
90 ASSERT_TRUE(mSurfaceControl != NULL);
91 ASSERT_TRUE(mSurfaceControl->isValid());
92
Mathias Agopian698c0872011-06-28 19:09:31 -070093 SurfaceComposerClient::openGlobalTransaction();
Jamie Gennis5dd0c4f2011-06-13 19:06:52 -070094 ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
Jamie Gennisd99c0882011-03-10 16:24:46 -080095 ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
Mathias Agopian698c0872011-06-28 19:09:31 -070096 SurfaceComposerClient::closeGlobalTransaction();
Jamie Gennisd99c0882011-03-10 16:24:46 -080097
98 sp<ANativeWindow> window = mSurfaceControl->getSurface();
Jamie Gennis1876d132011-03-17 16:32:52 -070099 mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800100 window.get(), NULL);
101 } else {
102 EGLint pbufferAttribs[] = {
103 EGL_WIDTH, getSurfaceWidth(),
104 EGL_HEIGHT, getSurfaceHeight(),
105 EGL_NONE };
106
Jamie Gennis1876d132011-03-17 16:32:52 -0700107 mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800108 pbufferAttribs);
109 }
110 ASSERT_EQ(EGL_SUCCESS, eglGetError());
111 ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
112
Jamie Gennis1876d132011-03-17 16:32:52 -0700113 mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800114 getContextAttribs());
115 ASSERT_EQ(EGL_SUCCESS, eglGetError());
116 ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
117
118 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
119 mEglContext));
120 ASSERT_EQ(EGL_SUCCESS, eglGetError());
121
122 EGLint w, h;
123 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
124 ASSERT_EQ(EGL_SUCCESS, eglGetError());
125 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
126 ASSERT_EQ(EGL_SUCCESS, eglGetError());
127 RecordProperty("EglSurfaceWidth", w);
128 RecordProperty("EglSurfaceHeight", h);
129
130 glViewport(0, 0, w, h);
131 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
132 }
133
134 virtual void TearDown() {
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700135 // Display the result
Jamie Gennisd99c0882011-03-10 16:24:46 -0800136 if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
137 eglSwapBuffers(mEglDisplay, mEglSurface);
138 sleep(mDisplaySecs);
139 }
140
141 if (mComposerClient != NULL) {
142 mComposerClient->dispose();
143 }
144 if (mEglContext != EGL_NO_CONTEXT) {
145 eglDestroyContext(mEglDisplay, mEglContext);
146 }
147 if (mEglSurface != EGL_NO_SURFACE) {
148 eglDestroySurface(mEglDisplay, mEglSurface);
149 }
150 if (mEglDisplay != EGL_NO_DISPLAY) {
151 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
152 EGL_NO_CONTEXT);
153 eglTerminate(mEglDisplay);
154 }
155 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -0700156
157 const ::testing::TestInfo* const testInfo =
158 ::testing::UnitTest::GetInstance()->current_test_info();
159 ALOGV("End test: %s.%s", testInfo->test_case_name(),
160 testInfo->name());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800161 }
162
163 virtual EGLint const* getConfigAttribs() {
164 static EGLint sDefaultConfigAttribs[] = {
165 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
166 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
167 EGL_RED_SIZE, 8,
168 EGL_GREEN_SIZE, 8,
169 EGL_BLUE_SIZE, 8,
170 EGL_ALPHA_SIZE, 8,
171 EGL_DEPTH_SIZE, 16,
172 EGL_STENCIL_SIZE, 8,
173 EGL_NONE };
174
175 return sDefaultConfigAttribs;
176 }
177
178 virtual EGLint const* getContextAttribs() {
179 static EGLint sDefaultContextAttribs[] = {
180 EGL_CONTEXT_CLIENT_VERSION, 2,
181 EGL_NONE };
182
183 return sDefaultContextAttribs;
184 }
185
186 virtual EGLint getSurfaceWidth() {
Jamie Gennisc8c51522011-06-15 14:24:38 -0700187 return 512;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800188 }
189
190 virtual EGLint getSurfaceHeight() {
Jamie Gennisc8c51522011-06-15 14:24:38 -0700191 return 512;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800192 }
193
Jamie Gennisd99c0882011-03-10 16:24:46 -0800194 ::testing::AssertionResult checkPixel(int x, int y, int r,
Jamie Gennis824efa72011-06-13 13:41:01 -0700195 int g, int b, int a, int tolerance=2) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800196 GLubyte pixel[4];
197 String8 msg;
198 glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
199 GLenum err = glGetError();
200 if (err != GL_NO_ERROR) {
201 msg += String8::format("error reading pixel: %#x", err);
202 while ((err = glGetError()) != GL_NO_ERROR) {
203 msg += String8::format(", %#x", err);
204 }
205 fprintf(stderr, "pixel check failure: %s\n", msg.string());
206 return ::testing::AssertionFailure(
207 ::testing::Message(msg.string()));
208 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700209 if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800210 msg += String8::format("r(%d isn't %d)", pixel[0], r);
211 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700212 if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800213 if (!msg.isEmpty()) {
214 msg += " ";
215 }
216 msg += String8::format("g(%d isn't %d)", pixel[1], g);
217 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700218 if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800219 if (!msg.isEmpty()) {
220 msg += " ";
221 }
222 msg += String8::format("b(%d isn't %d)", pixel[2], b);
223 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700224 if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800225 if (!msg.isEmpty()) {
226 msg += " ";
227 }
228 msg += String8::format("a(%d isn't %d)", pixel[3], a);
229 }
230 if (!msg.isEmpty()) {
231 fprintf(stderr, "pixel check failure: %s\n", msg.string());
232 return ::testing::AssertionFailure(
233 ::testing::Message(msg.string()));
234 } else {
235 return ::testing::AssertionSuccess();
236 }
237 }
238
239 int mDisplaySecs;
240 sp<SurfaceComposerClient> mComposerClient;
241 sp<SurfaceControl> mSurfaceControl;
242
243 EGLDisplay mEglDisplay;
244 EGLSurface mEglSurface;
245 EGLContext mEglContext;
Jamie Gennis1876d132011-03-17 16:32:52 -0700246 EGLConfig mGlConfig;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800247};
248
Jamie Gennis74bed552012-03-28 19:05:54 -0700249static void loadShader(GLenum shaderType, const char* pSource,
250 GLuint* outShader) {
251 GLuint shader = glCreateShader(shaderType);
252 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
253 if (shader) {
254 glShaderSource(shader, 1, &pSource, NULL);
255 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
256 glCompileShader(shader);
257 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
258 GLint compiled = 0;
259 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
260 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
261 if (!compiled) {
262 GLint infoLen = 0;
263 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
264 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
265 if (infoLen) {
266 char* buf = (char*) malloc(infoLen);
267 if (buf) {
268 glGetShaderInfoLog(shader, infoLen, NULL, buf);
269 printf("Shader compile log:\n%s\n", buf);
270 free(buf);
271 FAIL();
272 }
273 } else {
274 char* buf = (char*) malloc(0x1000);
275 if (buf) {
276 glGetShaderInfoLog(shader, 0x1000, NULL, buf);
277 printf("Shader compile log:\n%s\n", buf);
278 free(buf);
279 FAIL();
280 }
281 }
282 glDeleteShader(shader);
283 shader = 0;
284 }
285 }
286 ASSERT_TRUE(shader != 0);
287 *outShader = shader;
288}
289
290static void createProgram(const char* pVertexSource,
291 const char* pFragmentSource, GLuint* outPgm) {
292 GLuint vertexShader, fragmentShader;
293 {
294 SCOPED_TRACE("compiling vertex shader");
295 ASSERT_NO_FATAL_FAILURE(loadShader(GL_VERTEX_SHADER, pVertexSource,
296 &vertexShader));
297 }
298 {
299 SCOPED_TRACE("compiling fragment shader");
300 ASSERT_NO_FATAL_FAILURE(loadShader(GL_FRAGMENT_SHADER, pFragmentSource,
301 &fragmentShader));
302 }
303
304 GLuint program = glCreateProgram();
305 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
306 if (program) {
307 glAttachShader(program, vertexShader);
308 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
309 glAttachShader(program, fragmentShader);
310 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
311 glLinkProgram(program);
312 GLint linkStatus = GL_FALSE;
313 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
314 if (linkStatus != GL_TRUE) {
315 GLint bufLength = 0;
316 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
317 if (bufLength) {
318 char* buf = (char*) malloc(bufLength);
319 if (buf) {
320 glGetProgramInfoLog(program, bufLength, NULL, buf);
321 printf("Program link log:\n%s\n", buf);
322 free(buf);
323 FAIL();
324 }
325 }
326 glDeleteProgram(program);
327 program = 0;
328 }
329 }
330 glDeleteShader(vertexShader);
331 glDeleteShader(fragmentShader);
332 ASSERT_TRUE(program != 0);
333 *outPgm = program;
334}
335
336static int abs(int value) {
337 return value > 0 ? value : -value;
338}
339
340
Jamie Gennisd99c0882011-03-10 16:24:46 -0800341// XXX: Code above this point should live elsewhere
342
343class SurfaceTextureGLTest : public GLTest {
344protected:
Jamie Gennis79e31252011-10-19 15:19:19 -0700345 enum { TEX_ID = 123 };
Jamie Gennisd99c0882011-03-10 16:24:46 -0800346
347 virtual void SetUp() {
348 GLTest::SetUp();
349 mST = new SurfaceTexture(TEX_ID);
350 mSTC = new SurfaceTextureClient(mST);
351 mANW = mSTC;
Jamie Gennis74bed552012-03-28 19:05:54 -0700352 mTextureRenderer = new TextureRenderer(TEX_ID, mST);
353 ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800354 }
355
Jamie Gennis2640bfd2011-07-14 17:11:47 -0700356 virtual void TearDown() {
357 mANW.clear();
358 mSTC.clear();
359 mST.clear();
360 GLTest::TearDown();
361 }
362
Jamie Gennisd99c0882011-03-10 16:24:46 -0800363 void drawTexture() {
Jamie Gennis74bed552012-03-28 19:05:54 -0700364 mTextureRenderer->drawTexture();
Jamie Gennisd99c0882011-03-10 16:24:46 -0800365 }
366
Jamie Gennis74bed552012-03-28 19:05:54 -0700367 class TextureRenderer: public RefBase {
368 public:
369 TextureRenderer(GLuint texName, const sp<SurfaceTexture>& st):
370 mTexName(texName),
371 mST(st) {
372 }
373
374 void SetUp() {
375 const char vsrc[] =
376 "attribute vec4 vPosition;\n"
377 "varying vec2 texCoords;\n"
378 "uniform mat4 texMatrix;\n"
379 "void main() {\n"
380 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
381 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
382 " gl_Position = vPosition;\n"
383 "}\n";
384
385 const char fsrc[] =
386 "#extension GL_OES_EGL_image_external : require\n"
387 "precision mediump float;\n"
388 "uniform samplerExternalOES texSampler;\n"
389 "varying vec2 texCoords;\n"
390 "void main() {\n"
391 " gl_FragColor = texture2D(texSampler, texCoords);\n"
392 "}\n";
393
394 {
395 SCOPED_TRACE("creating shader program");
396 ASSERT_NO_FATAL_FAILURE(createProgram(vsrc, fsrc, &mPgm));
397 }
398
399 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
400 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
401 ASSERT_NE(-1, mPositionHandle);
402 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
403 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
404 ASSERT_NE(-1, mTexSamplerHandle);
405 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
406 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
407 ASSERT_NE(-1, mTexMatrixHandle);
408 }
409
410 // drawTexture draws the SurfaceTexture over the entire GL viewport.
411 void drawTexture() {
412 const GLfloat triangleVertices[] = {
413 -1.0f, 1.0f,
414 -1.0f, -1.0f,
415 1.0f, -1.0f,
416 1.0f, 1.0f,
417 };
418
419 glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0,
420 triangleVertices);
421 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
422 glEnableVertexAttribArray(mPositionHandle);
423 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
424
425 glUseProgram(mPgm);
426 glUniform1i(mTexSamplerHandle, 0);
427 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
428 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
429 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
430
431 // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
432 // they're setting the defautls for that target, but when hacking
433 // things to use GL_TEXTURE_2D they are needed to achieve the same
434 // behavior.
435 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
436 GL_LINEAR);
437 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
438 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
439 GL_LINEAR);
440 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
441 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
442 GL_CLAMP_TO_EDGE);
443 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
444 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
445 GL_CLAMP_TO_EDGE);
446 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
447
448 GLfloat texMatrix[16];
449 mST->getTransformMatrix(texMatrix);
450 glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
451
452 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
453 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
454 }
455
456 GLuint mTexName;
457 sp<SurfaceTexture> mST;
458 GLuint mPgm;
459 GLint mPositionHandle;
460 GLint mTexSamplerHandle;
461 GLint mTexMatrixHandle;
462 };
463
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700464 class FrameWaiter : public SurfaceTexture::FrameAvailableListener {
465 public:
466 FrameWaiter():
467 mPendingFrames(0) {
468 }
469
470 void waitForFrame() {
471 Mutex::Autolock lock(mMutex);
472 while (mPendingFrames == 0) {
473 mCondition.wait(mMutex);
474 }
475 mPendingFrames--;
476 }
477
478 virtual void onFrameAvailable() {
479 Mutex::Autolock lock(mMutex);
480 mPendingFrames++;
481 mCondition.signal();
482 }
483
484 int mPendingFrames;
485 Mutex mMutex;
486 Condition mCondition;
487 };
488
Daniel Lam9abe1eb2012-03-26 20:37:15 -0700489 // Note that SurfaceTexture will lose the notifications
490 // onBuffersReleased and onFrameAvailable as there is currently
491 // no way to forward the events. This DisconnectWaiter will not let the
492 // disconnect finish until finishDisconnect() is called. It will
493 // also block until a disconnect is called
494 class DisconnectWaiter : public BufferQueue::ConsumerListener {
495 public:
496 DisconnectWaiter () :
497 mWaitForDisconnect(false),
498 mPendingFrames(0) {
499 }
500
501 void waitForFrame() {
502 Mutex::Autolock lock(mMutex);
503 while (mPendingFrames == 0) {
504 mFrameCondition.wait(mMutex);
505 }
506 mPendingFrames--;
507 }
508
509 virtual void onFrameAvailable() {
510 Mutex::Autolock lock(mMutex);
511 mPendingFrames++;
512 mFrameCondition.signal();
513 }
514
515 virtual void onBuffersReleased() {
516 Mutex::Autolock lock(mMutex);
517 while (!mWaitForDisconnect) {
518 mDisconnectCondition.wait(mMutex);
519 }
520 }
521
522 void finishDisconnect() {
523 Mutex::Autolock lock(mMutex);
524 mWaitForDisconnect = true;
525 mDisconnectCondition.signal();
526 }
527
528 private:
529 Mutex mMutex;
530
531 bool mWaitForDisconnect;
532 Condition mDisconnectCondition;
533
534 int mPendingFrames;
535 Condition mFrameCondition;
536 };
537
Jamie Gennisd99c0882011-03-10 16:24:46 -0800538 sp<SurfaceTexture> mST;
539 sp<SurfaceTextureClient> mSTC;
540 sp<ANativeWindow> mANW;
Jamie Gennis74bed552012-03-28 19:05:54 -0700541 sp<TextureRenderer> mTextureRenderer;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800542};
543
544// Fill a YV12 buffer with a multi-colored checkerboard pattern
545void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
546 const int blockWidth = w > 16 ? w / 16 : 1;
547 const int blockHeight = h > 16 ? h / 16 : 1;
548 const int yuvTexOffsetY = 0;
549 int yuvTexStrideY = stride;
550 int yuvTexOffsetV = yuvTexStrideY * h;
551 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
552 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
553 int yuvTexStrideU = yuvTexStrideV;
554 for (int x = 0; x < w; x++) {
555 for (int y = 0; y < h; y++) {
556 int parityX = (x / blockWidth) & 1;
557 int parityY = (y / blockHeight) & 1;
558 unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
559 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
560 if (x < w / 2 && y < h / 2) {
561 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
562 if (x * 2 < w / 2 && y * 2 < h / 2) {
563 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
564 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
565 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
566 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
567 intensity;
568 }
569 }
570 }
571 }
572}
573
574// Fill a YV12 buffer with red outside a given rectangle and green inside it.
575void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
576 const android_native_rect_t& rect) {
577 const int yuvTexOffsetY = 0;
578 int yuvTexStrideY = stride;
579 int yuvTexOffsetV = yuvTexStrideY * h;
580 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
581 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
582 int yuvTexStrideU = yuvTexStrideV;
583 for (int x = 0; x < w; x++) {
584 for (int y = 0; y < h; y++) {
585 bool inside = rect.left <= x && x < rect.right &&
586 rect.top <= y && y < rect.bottom;
587 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
588 if (x < w / 2 && y < h / 2) {
589 bool inside = rect.left <= 2*x && 2*x < rect.right &&
590 rect.top <= 2*y && 2*y < rect.bottom;
591 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
592 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
593 inside ? 16 : 255;
594 }
595 }
596 }
597}
598
Jamie Gennis1876d132011-03-17 16:32:52 -0700599void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
600 const size_t PIXEL_SIZE = 4;
601 for (int x = 0; x < w; x++) {
602 for (int y = 0; y < h; y++) {
603 off_t offset = (y * stride + x) * PIXEL_SIZE;
604 for (int c = 0; c < 4; c++) {
605 int parityX = (x / (1 << (c+2))) & 1;
606 int parityY = (y / (1 << (c+2))) & 1;
607 buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
608 }
609 }
610 }
611}
612
Jamie Gennisfe27e2f2011-11-11 18:05:11 -0800613void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
614 uint8_t g, uint8_t b, uint8_t a) {
615 const size_t PIXEL_SIZE = 4;
616 for (int y = 0; y < h; y++) {
617 for (int x = 0; x < h; x++) {
618 off_t offset = (y * stride + x) * PIXEL_SIZE;
619 buf[offset + 0] = r;
620 buf[offset + 1] = g;
621 buf[offset + 2] = b;
622 buf[offset + 3] = a;
623 }
624 }
625}
626
Jamie Gennisce561372012-03-19 18:33:05 -0700627// Produce a single RGBA8 frame by filling a buffer with a checkerboard pattern
628// using the CPU. This assumes that the ANativeWindow is already configured to
629// allow this to be done (e.g. the format is set to RGBA8).
630//
631// Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE().
632void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) {
633 android_native_buffer_t* anb;
634 ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &anb));
635 ASSERT_TRUE(anb != NULL);
636
637 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
638 ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf->getNativeBuffer()));
639
640 uint8_t* img = NULL;
641 ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
642 (void**)(&img)));
643 fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
644 ASSERT_EQ(NO_ERROR, buf->unlock());
645 ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer()));
646}
647
Jamie Gennisd99c0882011-03-10 16:24:46 -0800648TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700649 const int texWidth = 64;
650 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800651
652 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700653 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800654 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
655 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
656
Iliyan Malchev697526b2011-05-01 11:33:26 -0700657 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800658 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
659 ASSERT_TRUE(anb != NULL);
660
661 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
662 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
663
664 // Fill the buffer with the a checkerboard pattern
665 uint8_t* img = NULL;
666 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700667 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800668 buf->unlock();
669 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
670
671 mST->updateTexImage();
672
673 glClearColor(0.2, 0.2, 0.2, 0.2);
674 glClear(GL_COLOR_BUFFER_BIT);
675
Jamie Gennisc8c51522011-06-15 14:24:38 -0700676 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800677 drawTexture();
678
679 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
680 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700681 EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255));
682 EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800683
Jamie Gennisc8c51522011-06-15 14:24:38 -0700684 EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
685 EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
686 EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800687 EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700688 EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800689 EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
690 EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
691}
692
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700693TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700694 const int texWidth = 64;
695 const int texHeight = 64;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800696
697 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700698 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800699 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
700 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
701
Iliyan Malchev697526b2011-05-01 11:33:26 -0700702 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800703 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
704 ASSERT_TRUE(anb != NULL);
705
706 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
707 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
708
709 // Fill the buffer with the a checkerboard pattern
710 uint8_t* img = NULL;
711 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700712 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800713 buf->unlock();
714 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
715
716 mST->updateTexImage();
717
718 glClearColor(0.2, 0.2, 0.2, 0.2);
719 glClear(GL_COLOR_BUFFER_BIT);
720
Jamie Gennisc8c51522011-06-15 14:24:38 -0700721 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800722 drawTexture();
723
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700724 EXPECT_TRUE(checkPixel( 0, 0, 0, 133, 0, 255));
725 EXPECT_TRUE(checkPixel(63, 0, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800726 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
727 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
728
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700729 EXPECT_TRUE(checkPixel(22, 19, 100, 255, 74, 255));
730 EXPECT_TRUE(checkPixel(45, 11, 100, 255, 74, 255));
731 EXPECT_TRUE(checkPixel(52, 12, 155, 0, 181, 255));
732 EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
733 EXPECT_TRUE(checkPixel(31, 54, 0, 71, 117, 255));
734 EXPECT_TRUE(checkPixel(29, 28, 0, 133, 0, 255));
735 EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800736}
737
738TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700739 const int texWidth = 64;
740 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800741
742 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700743 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800744 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
745 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
746
747 android_native_rect_t crops[] = {
748 {4, 6, 22, 36},
749 {0, 6, 22, 36},
750 {4, 0, 22, 36},
Jamie Gennis1876d132011-03-17 16:32:52 -0700751 {4, 6, texWidth, 36},
752 {4, 6, 22, texHeight},
Jamie Gennisd99c0882011-03-10 16:24:46 -0800753 };
754
755 for (int i = 0; i < 5; i++) {
756 const android_native_rect_t& crop(crops[i]);
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800757 SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }",
758 crop.left, crop.top, crop.right, crop.bottom).string());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800759
760 ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
761
Iliyan Malchev697526b2011-05-01 11:33:26 -0700762 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800763 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
764 ASSERT_TRUE(anb != NULL);
765
766 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800767 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
768 buf->getNativeBuffer()));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800769
770 uint8_t* img = NULL;
771 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700772 fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800773 buf->unlock();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800774 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
775 buf->getNativeBuffer()));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800776
777 mST->updateTexImage();
778
779 glClearColor(0.2, 0.2, 0.2, 0.2);
780 glClear(GL_COLOR_BUFFER_BIT);
781
Jamie Gennisc8c51522011-06-15 14:24:38 -0700782 glViewport(0, 0, 64, 64);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800783 drawTexture();
784
785 EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
786 EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255));
787 EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255));
788 EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255));
789
790 EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255));
791 EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255));
792 EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255));
793 EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255));
794 EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255));
795 EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255));
796 EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255));
797 }
798}
799
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700800// This test is intended to catch synchronization bugs between the CPU-written
801// and GPU-read buffers.
802TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
803 enum { texWidth = 16 };
804 enum { texHeight = 16 };
805 enum { numFrames = 1024 };
806
807 ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
808 ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
809 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
810 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
811 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
812 GRALLOC_USAGE_SW_WRITE_OFTEN));
813
814 struct TestPixel {
815 int x;
816 int y;
817 };
818 const TestPixel testPixels[] = {
819 { 4, 11 },
820 { 12, 14 },
821 { 7, 2 },
822 };
823 enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])};
824
825 class ProducerThread : public Thread {
826 public:
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800827 ProducerThread(const sp<ANativeWindow>& anw,
828 const TestPixel* testPixels):
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700829 mANW(anw),
830 mTestPixels(testPixels) {
831 }
832
833 virtual ~ProducerThread() {
834 }
835
836 virtual bool threadLoop() {
837 for (int i = 0; i < numFrames; i++) {
838 ANativeWindowBuffer* anb;
839 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
840 return false;
841 }
842 if (anb == NULL) {
843 return false;
844 }
845
846 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
847 if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
848 != NO_ERROR) {
849 return false;
850 }
851
852 const int yuvTexOffsetY = 0;
853 int stride = buf->getStride();
854 int yuvTexStrideY = stride;
855 int yuvTexOffsetV = yuvTexStrideY * texHeight;
856 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
857 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
858 int yuvTexStrideU = yuvTexStrideV;
859
860 uint8_t* img = NULL;
861 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
862
863 // Gray out all the test pixels first, so we're more likely to
864 // see a failure if GL is still texturing from the buffer we
865 // just dequeued.
866 for (int j = 0; j < numTestPixels; j++) {
867 int x = mTestPixels[j].x;
868 int y = mTestPixels[j].y;
869 uint8_t value = 128;
870 img[y*stride + x] = value;
871 }
872
873 // Fill the buffer with gray.
874 for (int y = 0; y < texHeight; y++) {
875 for (int x = 0; x < texWidth; x++) {
876 img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128;
877 img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128;
878 img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128;
879 }
880 }
881
882 // Set the test pixels to either white or black.
883 for (int j = 0; j < numTestPixels; j++) {
884 int x = mTestPixels[j].x;
885 int y = mTestPixels[j].y;
886 uint8_t value = 0;
887 if (j == (i % numTestPixels)) {
888 value = 255;
889 }
890 img[y*stride + x] = value;
891 }
892
893 buf->unlock();
894 if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
895 != NO_ERROR) {
896 return false;
897 }
898 }
899 return false;
900 }
901
902 sp<ANativeWindow> mANW;
903 const TestPixel* mTestPixels;
904 };
905
906 sp<FrameWaiter> fw(new FrameWaiter);
907 mST->setFrameAvailableListener(fw);
908
909 sp<Thread> pt(new ProducerThread(mANW, testPixels));
910 pt->run();
911
912 glViewport(0, 0, texWidth, texHeight);
913
914 glClearColor(0.2, 0.2, 0.2, 0.2);
915 glClear(GL_COLOR_BUFFER_BIT);
916
917 // We wait for the first two frames up front so that the producer will be
918 // likely to dequeue the buffer that's currently being textured from.
919 fw->waitForFrame();
920 fw->waitForFrame();
921
922 for (int i = 0; i < numFrames; i++) {
923 SCOPED_TRACE(String8::format("frame %d", i).string());
924
925 // We must wait for each frame to come in because if we ever do an
926 // updateTexImage call that doesn't consume a newly available buffer
927 // then the producer and consumer will get out of sync, which will cause
928 // a deadlock.
929 if (i > 1) {
930 fw->waitForFrame();
931 }
932 mST->updateTexImage();
933 drawTexture();
934
935 for (int j = 0; j < numTestPixels; j++) {
936 int x = testPixels[j].x;
937 int y = testPixels[j].y;
938 uint8_t value = 0;
939 if (j == (i % numTestPixels)) {
940 // We must y-invert the texture coords
941 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
942 } else {
943 // We must y-invert the texture coords
944 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255));
945 }
946 }
947 }
948
949 pt->requestExitAndWait();
950}
951
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700952TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700953 const int texWidth = 64;
954 const int texHeight = 66;
955
956 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
957 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
958 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
959 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
960
Jamie Gennisce561372012-03-19 18:33:05 -0700961 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
Jamie Gennis1876d132011-03-17 16:32:52 -0700962
963 mST->updateTexImage();
964
965 glClearColor(0.2, 0.2, 0.2, 0.2);
966 glClear(GL_COLOR_BUFFER_BIT);
967
Jamie Gennisc8c51522011-06-15 14:24:38 -0700968 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700969 drawTexture();
970
971 EXPECT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
972 EXPECT_TRUE(checkPixel(63, 0, 231, 231, 231, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700973 EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
974 EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700975
976 EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700977 EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700978 EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700979 EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
980 EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700981 EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700982 EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700983 EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231));
984 EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35));
985 EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700986 EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700987 EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
988 EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700989 EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700990 EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700991 EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
992}
993
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700994TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700995 const int texWidth = 64;
996 const int texHeight = 64;
997
998 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
999 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
1000 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
1001 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
1002
Jamie Gennisce561372012-03-19 18:33:05 -07001003 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
Jamie Gennis1876d132011-03-17 16:32:52 -07001004
1005 mST->updateTexImage();
1006
1007 glClearColor(0.2, 0.2, 0.2, 0.2);
1008 glClear(GL_COLOR_BUFFER_BIT);
1009
Jamie Gennisc8c51522011-06-15 14:24:38 -07001010 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -07001011 drawTexture();
1012
1013 EXPECT_TRUE(checkPixel( 0, 0, 231, 231, 231, 231));
1014 EXPECT_TRUE(checkPixel(63, 0, 35, 35, 35, 35));
1015 EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
1016 EXPECT_TRUE(checkPixel( 0, 63, 35, 35, 35, 35));
1017
1018 EXPECT_TRUE(checkPixel(12, 46, 231, 231, 231, 35));
1019 EXPECT_TRUE(checkPixel(16, 1, 231, 231, 35, 231));
1020 EXPECT_TRUE(checkPixel(21, 12, 231, 35, 35, 231));
1021 EXPECT_TRUE(checkPixel(26, 51, 231, 35, 231, 35));
1022 EXPECT_TRUE(checkPixel( 5, 32, 35, 231, 231, 35));
1023 EXPECT_TRUE(checkPixel(13, 8, 35, 231, 231, 231));
1024 EXPECT_TRUE(checkPixel(46, 3, 35, 35, 231, 35));
1025 EXPECT_TRUE(checkPixel(30, 33, 35, 35, 35, 35));
1026 EXPECT_TRUE(checkPixel( 6, 52, 231, 231, 35, 35));
1027 EXPECT_TRUE(checkPixel(55, 33, 35, 231, 35, 231));
1028 EXPECT_TRUE(checkPixel(16, 29, 35, 35, 231, 231));
1029 EXPECT_TRUE(checkPixel( 1, 30, 35, 35, 35, 231));
1030 EXPECT_TRUE(checkPixel(41, 37, 35, 35, 231, 231));
1031 EXPECT_TRUE(checkPixel(46, 29, 231, 231, 35, 35));
1032 EXPECT_TRUE(checkPixel(15, 25, 35, 231, 35, 231));
1033 EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
1034}
1035
Daniel Lam9abe1eb2012-03-26 20:37:15 -07001036// Tests if SurfaceTexture and BufferQueue are robust enough
1037// to handle a special case where updateTexImage is called
1038// in the middle of disconnect. This ordering is enforced
1039// by blocking in the disconnect callback.
1040TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
1041
1042 class ProducerThread : public Thread {
1043 public:
1044 ProducerThread(const sp<ANativeWindow>& anw):
1045 mANW(anw) {
1046 }
1047
1048 virtual ~ProducerThread() {
1049 }
1050
1051 virtual bool threadLoop() {
1052 ANativeWindowBuffer* anb;
1053
1054 native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL);
1055
1056 for (int numFrames =0 ; numFrames < 2; numFrames ++) {
1057
1058 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
1059 return false;
1060 }
1061 if (anb == NULL) {
1062 return false;
1063 }
1064 if (mANW->queueBuffer(mANW.get(), anb)
1065 != NO_ERROR) {
1066 return false;
1067 }
1068 }
1069
1070 native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL);
1071
1072 return false;
1073 }
1074
1075 private:
1076 sp<ANativeWindow> mANW;
1077 };
1078
1079 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1080
1081 sp<DisconnectWaiter> dw(new DisconnectWaiter());
1082 mST->getBufferQueue()->consumerConnect(dw);
1083
1084
1085 sp<Thread> pt(new ProducerThread(mANW));
1086 pt->run();
1087
1088 // eat a frame so SurfaceTexture will own an at least one slot
1089 dw->waitForFrame();
1090 EXPECT_EQ(OK,mST->updateTexImage());
1091
1092 dw->waitForFrame();
1093 // Could fail here as SurfaceTexture thinks it still owns the slot
1094 // but bufferQueue has released all slots
1095 EXPECT_EQ(OK,mST->updateTexImage());
1096
1097 dw->finishDisconnect();
1098}
1099
1100
1101// This test ensures that the SurfaceTexture clears the mCurrentTexture
1102// when it is disconnected and reconnected. Otherwise it will
1103// attempt to release a buffer that it does not owned
1104TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
1105 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1106
1107 native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL);
1108
1109 ANativeWindowBuffer *anb;
1110
1111 EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
1112 EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
1113
1114 EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
1115 EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
1116
1117 EXPECT_EQ(OK,mST->updateTexImage());
1118 EXPECT_EQ(OK,mST->updateTexImage());
1119
1120 native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL);
1121 native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL);
1122
1123 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1124
1125 EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
1126 EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
1127
1128 // Will fail here if mCurrentTexture is not cleared properly
1129 EXPECT_EQ(OK,mST->updateTexImage());
1130}
1131
Jamie Gennis7b305ff2011-07-19 12:08:33 -07001132TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
1133 class ProducerThread : public Thread {
1134 public:
1135 ProducerThread(const sp<ANativeWindow>& anw):
1136 mANW(anw),
1137 mDequeueError(NO_ERROR) {
1138 }
1139
1140 virtual ~ProducerThread() {
1141 }
1142
1143 virtual bool threadLoop() {
1144 Mutex::Autolock lock(mMutex);
1145 ANativeWindowBuffer* anb;
1146
1147 // Frame 1
1148 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
1149 return false;
1150 }
1151 if (anb == NULL) {
1152 return false;
1153 }
1154 if (mANW->queueBuffer(mANW.get(), anb)
1155 != NO_ERROR) {
1156 return false;
1157 }
1158
1159 // Frame 2
1160 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
1161 return false;
1162 }
1163 if (anb == NULL) {
1164 return false;
1165 }
1166 if (mANW->queueBuffer(mANW.get(), anb)
1167 != NO_ERROR) {
1168 return false;
1169 }
1170
1171 // Frame 3 - error expected
1172 mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
1173 return false;
1174 }
1175
1176 status_t getDequeueError() {
1177 Mutex::Autolock lock(mMutex);
1178 return mDequeueError;
1179 }
1180
1181 private:
1182 sp<ANativeWindow> mANW;
1183 status_t mDequeueError;
1184 Mutex mMutex;
1185 };
1186
1187 sp<FrameWaiter> fw(new FrameWaiter);
1188 mST->setFrameAvailableListener(fw);
1189 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1190 ASSERT_EQ(OK, mST->setBufferCountServer(2));
1191
1192 sp<Thread> pt(new ProducerThread(mANW));
1193 pt->run();
1194
1195 fw->waitForFrame();
1196 fw->waitForFrame();
1197
1198 // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
1199 // block waiting for a buffer to become available.
1200 usleep(100000);
1201
1202 mST->abandon();
1203
1204 pt->requestExitAndWait();
1205 ASSERT_EQ(NO_INIT,
1206 reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
1207}
1208
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001209TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
1210 int texHeight = 16;
1211 ANativeWindowBuffer* anb;
1212
1213 GLint maxTextureSize;
1214 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1215
1216 // make sure it works with small textures
1217 mST->setDefaultBufferSize(16, texHeight);
1218 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1219 EXPECT_EQ(16, anb->width);
1220 EXPECT_EQ(texHeight, anb->height);
1221 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1222 EXPECT_EQ(NO_ERROR, mST->updateTexImage());
1223
1224 // make sure it works with GL_MAX_TEXTURE_SIZE
1225 mST->setDefaultBufferSize(maxTextureSize, texHeight);
1226 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1227 EXPECT_EQ(maxTextureSize, anb->width);
1228 EXPECT_EQ(texHeight, anb->height);
1229 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1230 EXPECT_EQ(NO_ERROR, mST->updateTexImage());
1231
1232 // make sure it fails with GL_MAX_TEXTURE_SIZE+1
1233 mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
1234 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1235 EXPECT_EQ(maxTextureSize+1, anb->width);
1236 EXPECT_EQ(texHeight, anb->height);
1237 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1238 ASSERT_NE(NO_ERROR, mST->updateTexImage());
1239}
1240
Jamie Gennis5451d152011-06-08 09:40:45 -07001241/*
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001242 * This test fixture is for testing GL -> GL texture streaming. It creates an
1243 * EGLSurface and an EGLContext for the image producer to use.
1244 */
1245class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
1246protected:
1247 SurfaceTextureGLToGLTest():
1248 mProducerEglSurface(EGL_NO_SURFACE),
1249 mProducerEglContext(EGL_NO_CONTEXT) {
1250 }
1251
1252 virtual void SetUp() {
1253 SurfaceTextureGLTest::SetUp();
1254
Jamie Gennisce561372012-03-19 18:33:05 -07001255 mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001256 mANW.get(), NULL);
1257 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1258 ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
1259
Jamie Gennisce561372012-03-19 18:33:05 -07001260 mProducerEglContext = eglCreateContext(mEglDisplay, mGlConfig,
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001261 EGL_NO_CONTEXT, getContextAttribs());
1262 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1263 ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
1264 }
1265
1266 virtual void TearDown() {
1267 if (mProducerEglContext != EGL_NO_CONTEXT) {
1268 eglDestroyContext(mEglDisplay, mProducerEglContext);
1269 }
1270 if (mProducerEglSurface != EGL_NO_SURFACE) {
1271 eglDestroySurface(mEglDisplay, mProducerEglSurface);
1272 }
1273 SurfaceTextureGLTest::TearDown();
1274 }
1275
1276 EGLSurface mProducerEglSurface;
1277 EGLContext mProducerEglContext;
1278};
1279
1280TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
1281 const int texWidth = 64;
1282 const int texHeight = 64;
1283
1284 mST->setDefaultBufferSize(texWidth, texHeight);
1285
1286 // Do the producer side of things
1287 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1288 mProducerEglSurface, mProducerEglContext));
1289 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1290
1291 // This is needed to ensure we pick up a buffer of the correct size.
1292 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1293
1294 glClearColor(0.6, 0.6, 0.6, 0.6);
1295 glClear(GL_COLOR_BUFFER_BIT);
1296
1297 glEnable(GL_SCISSOR_TEST);
1298 glScissor(4, 4, 4, 4);
1299 glClearColor(1.0, 0.0, 0.0, 1.0);
1300 glClear(GL_COLOR_BUFFER_BIT);
1301
1302 glScissor(24, 48, 4, 4);
1303 glClearColor(0.0, 1.0, 0.0, 1.0);
1304 glClear(GL_COLOR_BUFFER_BIT);
1305
1306 glScissor(37, 17, 4, 4);
1307 glClearColor(0.0, 0.0, 1.0, 1.0);
1308 glClear(GL_COLOR_BUFFER_BIT);
1309
1310 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1311
1312 // Do the consumer side of things
1313 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1314 mEglContext));
1315 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1316
1317 glDisable(GL_SCISSOR_TEST);
1318
1319 mST->updateTexImage(); // Skip the first frame, which was empty
1320 mST->updateTexImage();
1321
1322 glClearColor(0.2, 0.2, 0.2, 0.2);
1323 glClear(GL_COLOR_BUFFER_BIT);
1324
1325 glViewport(0, 0, texWidth, texHeight);
1326 drawTexture();
1327
1328 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
1329 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
1330 EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
1331 EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
1332
1333 EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255));
1334 EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255));
1335 EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255));
1336 EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
1337 EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
1338 EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153));
1339 EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153));
1340 EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
1341 EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
1342 EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
1343 EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
1344 EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
1345 EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
1346 EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
1347 EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
1348 EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
1349}
1350
1351TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001352 sp<GraphicBuffer> buffers[2];
1353
1354 sp<FrameWaiter> fw(new FrameWaiter);
1355 mST->setFrameAvailableListener(fw);
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001356
Jamie Gennise3603d72011-11-19 21:20:17 -08001357 // This test requires async mode to run on a single thread.
1358 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1359 mProducerEglSurface, mProducerEglContext));
1360 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1361 EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
1362 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1363
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001364 for (int i = 0; i < 2; i++) {
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001365 // Produce a frame
1366 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1367 mProducerEglSurface, mProducerEglContext));
1368 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1369 glClear(GL_COLOR_BUFFER_BIT);
1370 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1371
1372 // Consume a frame
1373 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1374 mEglContext));
1375 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001376 fw->waitForFrame();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001377 mST->updateTexImage();
1378 buffers[i] = mST->getCurrentBuffer();
1379 }
1380
1381 // Destroy the GL texture object to release its ref on buffers[2].
1382 GLuint texID = TEX_ID;
1383 glDeleteTextures(1, &texID);
1384
1385 // Destroy the EGLSurface
1386 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
1387 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001388 mProducerEglSurface = EGL_NO_SURFACE;
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001389
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001390 // This test should have the only reference to buffer 0.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001391 EXPECT_EQ(1, buffers[0]->getStrongCount());
Jamie Gennise3603d72011-11-19 21:20:17 -08001392
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001393 // The SurfaceTexture should hold a single reference to buffer 1 in its
1394 // mCurrentBuffer member. All of the references in the slots should have
1395 // been released.
1396 EXPECT_EQ(2, buffers[1]->getStrongCount());
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001397}
1398
1399TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
1400 sp<GraphicBuffer> buffers[3];
1401
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001402 sp<FrameWaiter> fw(new FrameWaiter);
1403 mST->setFrameAvailableListener(fw);
1404
Jamie Gennise3603d72011-11-19 21:20:17 -08001405 // This test requires async mode to run on a single thread.
1406 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1407 mProducerEglSurface, mProducerEglContext));
1408 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1409 EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
1410 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1411
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001412 for (int i = 0; i < 3; i++) {
1413 // Produce a frame
1414 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1415 mProducerEglSurface, mProducerEglContext));
1416 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1417 glClear(GL_COLOR_BUFFER_BIT);
1418 EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
1419 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1420
1421 // Consume a frame
1422 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1423 mEglContext));
1424 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001425 fw->waitForFrame();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001426 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1427 buffers[i] = mST->getCurrentBuffer();
1428 }
1429
1430 // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
1431 // on buffers[2].
1432 mST->abandon();
1433
1434 // Destroy the GL texture object to release its ref on buffers[2].
1435 GLuint texID = TEX_ID;
1436 glDeleteTextures(1, &texID);
1437
1438 // Destroy the EGLSurface.
1439 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
1440 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001441 mProducerEglSurface = EGL_NO_SURFACE;
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001442
1443 EXPECT_EQ(1, buffers[0]->getStrongCount());
1444 EXPECT_EQ(1, buffers[1]->getStrongCount());
Jamie Gennise3603d72011-11-19 21:20:17 -08001445
1446 // Depending on how lazily the GL driver dequeues buffers, we may end up
1447 // with either two or three total buffers. If there are three, make sure
1448 // the last one was properly down-ref'd.
1449 if (buffers[2] != buffers[0]) {
1450 EXPECT_EQ(1, buffers[2]->getStrongCount());
1451 }
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001452}
1453
Jamie Gennis59769462011-11-19 18:04:43 -08001454TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
1455 // This test requires 3 buffers to run on a single thread.
1456 mST->setBufferCountServer(3);
1457
1458 ASSERT_TRUE(mST->isSynchronousMode());
1459
1460 for (int i = 0; i < 10; i++) {
1461 // Produce a frame
1462 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1463 mProducerEglSurface, mProducerEglContext));
1464 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1465 glClear(GL_COLOR_BUFFER_BIT);
1466 EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
1467 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1468
1469 // Consume a frame
1470 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1471 mEglContext));
1472 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1473 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1474 }
1475
1476 ASSERT_TRUE(mST->isSynchronousMode());
1477}
1478
Jamie Gennisc2c38022012-04-11 17:20:03 -07001479TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) {
1480 enum { texWidth = 64 };
1481 enum { texHeight = 64 };
1482
1483 // Set the user buffer size.
1484 native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
1485
1486 // Do the producer side of things
1487 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1488 mProducerEglSurface, mProducerEglContext));
1489 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1490
1491 // This is needed to ensure we pick up a buffer of the correct size.
1492 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1493
1494 glClearColor(0.6, 0.6, 0.6, 0.6);
1495 glClear(GL_COLOR_BUFFER_BIT);
1496
1497 glEnable(GL_SCISSOR_TEST);
1498 glScissor(4, 4, 1, 1);
1499 glClearColor(1.0, 0.0, 0.0, 1.0);
1500 glClear(GL_COLOR_BUFFER_BIT);
1501
1502 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1503
1504 // Do the consumer side of things
1505 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1506 mEglContext));
1507 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1508
1509 glDisable(GL_SCISSOR_TEST);
1510
1511 mST->updateTexImage(); // Skip the first frame, which was empty
1512 mST->updateTexImage();
1513
1514 glClearColor(0.2, 0.2, 0.2, 0.2);
1515 glClear(GL_COLOR_BUFFER_BIT);
1516
1517 glViewport(0, 0, texWidth, texHeight);
1518 drawTexture();
1519
1520 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
1521 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
1522 EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
1523 EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
1524
1525 EXPECT_TRUE(checkPixel( 4, 4, 255, 0, 0, 255));
1526 EXPECT_TRUE(checkPixel( 5, 5, 153, 153, 153, 153));
1527 EXPECT_TRUE(checkPixel( 3, 3, 153, 153, 153, 153));
1528 EXPECT_TRUE(checkPixel(45, 52, 153, 153, 153, 153));
1529 EXPECT_TRUE(checkPixel(12, 36, 153, 153, 153, 153));
1530}
1531
1532TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedUserSizedGLFilledBuffer) {
1533 enum { texWidth = 64 };
1534 enum { texHeight = 16 };
1535
1536 // Set the transform hint.
1537 mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
1538
1539 // Set the user buffer size.
1540 native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
1541
1542 // Do the producer side of things
1543 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1544 mProducerEglSurface, mProducerEglContext));
1545 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1546
1547 // This is needed to ensure we pick up a buffer of the correct size and the
1548 // new rotation hint.
1549 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1550
1551 glClearColor(0.6, 0.6, 0.6, 0.6);
1552 glClear(GL_COLOR_BUFFER_BIT);
1553
1554 glEnable(GL_SCISSOR_TEST);
1555 glScissor(24, 4, 1, 1);
1556 glClearColor(1.0, 0.0, 0.0, 1.0);
1557 glClear(GL_COLOR_BUFFER_BIT);
1558
1559 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1560
1561 // Do the consumer side of things
1562 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1563 mEglContext));
1564 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1565
1566 glDisable(GL_SCISSOR_TEST);
1567
1568 mST->updateTexImage(); // Skip the first frame, which was empty
1569 mST->updateTexImage();
1570
1571 glClearColor(0.2, 0.2, 0.2, 0.2);
1572 glClear(GL_COLOR_BUFFER_BIT);
1573
1574 glViewport(0, 0, texWidth, texHeight);
1575 drawTexture();
1576
1577 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
1578 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
1579 EXPECT_TRUE(checkPixel(63, 15, 153, 153, 153, 153));
1580 EXPECT_TRUE(checkPixel( 0, 15, 153, 153, 153, 153));
1581
1582 EXPECT_TRUE(checkPixel(24, 4, 255, 0, 0, 255));
1583 EXPECT_TRUE(checkPixel(25, 5, 153, 153, 153, 153));
1584 EXPECT_TRUE(checkPixel(23, 3, 153, 153, 153, 153));
1585 EXPECT_TRUE(checkPixel(45, 13, 153, 153, 153, 153));
1586 EXPECT_TRUE(checkPixel(12, 8, 153, 153, 153, 153));
1587}
1588
1589TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) {
1590 enum { texWidth = 64 };
1591 enum { texHeight = 16 };
1592
1593 // Set the transform hint.
1594 mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
1595
1596 // Set the default buffer size.
1597 mST->setDefaultBufferSize(texWidth, texHeight);
1598
1599 // Do the producer side of things
1600 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1601 mProducerEglSurface, mProducerEglContext));
1602 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1603
1604 // This is needed to ensure we pick up a buffer of the correct size and the
1605 // new rotation hint.
1606 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1607
1608 glClearColor(0.6, 0.6, 0.6, 0.6);
1609 glClear(GL_COLOR_BUFFER_BIT);
1610
1611 glEnable(GL_SCISSOR_TEST);
1612 glScissor(24, 4, 1, 1);
1613 glClearColor(1.0, 0.0, 0.0, 1.0);
1614 glClear(GL_COLOR_BUFFER_BIT);
1615
1616 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1617
1618 // Do the consumer side of things
1619 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1620 mEglContext));
1621 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1622
1623 glDisable(GL_SCISSOR_TEST);
1624
1625 mST->updateTexImage(); // Skip the first frame, which was empty
1626 mST->updateTexImage();
1627
1628 glClearColor(0.2, 0.2, 0.2, 0.2);
1629 glClear(GL_COLOR_BUFFER_BIT);
1630
1631 glViewport(0, 0, texWidth, texHeight);
1632 drawTexture();
1633
1634 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
1635 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
1636 EXPECT_TRUE(checkPixel(63, 15, 153, 153, 153, 153));
1637 EXPECT_TRUE(checkPixel( 0, 15, 153, 153, 153, 153));
1638
1639 EXPECT_TRUE(checkPixel(24, 4, 255, 0, 0, 255));
1640 EXPECT_TRUE(checkPixel(25, 5, 153, 153, 153, 153));
1641 EXPECT_TRUE(checkPixel(23, 3, 153, 153, 153, 153));
1642 EXPECT_TRUE(checkPixel(45, 13, 153, 153, 153, 153));
1643 EXPECT_TRUE(checkPixel(12, 8, 153, 153, 153, 153));
1644}
1645
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001646/*
1647 * This test fixture is for testing GL -> GL texture streaming from one thread
1648 * to another. It contains functionality to create a producer thread that will
1649 * perform GL rendering to an ANativeWindow that feeds frames to a
1650 * SurfaceTexture. Additionally it supports interlocking the producer and
1651 * consumer threads so that a specific sequence of calls can be
1652 * deterministically created by the test.
Jamie Gennis5451d152011-06-08 09:40:45 -07001653 *
1654 * The intended usage is as follows:
1655 *
1656 * TEST_F(...) {
1657 * class PT : public ProducerThread {
1658 * virtual void render() {
1659 * ...
1660 * swapBuffers();
1661 * }
1662 * };
1663 *
1664 * runProducerThread(new PT());
1665 *
1666 * // The order of these calls will vary from test to test and may include
1667 * // multiple frames and additional operations (e.g. GL rendering from the
1668 * // texture).
1669 * fc->waitForFrame();
1670 * mST->updateTexImage();
1671 * fc->finishFrame();
1672 * }
1673 *
1674 */
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001675class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
Jamie Gennis5451d152011-06-08 09:40:45 -07001676protected:
1677
1678 // ProducerThread is an abstract base class to simplify the creation of
1679 // OpenGL ES frame producer threads.
1680 class ProducerThread : public Thread {
1681 public:
1682 virtual ~ProducerThread() {
1683 }
1684
1685 void setEglObjects(EGLDisplay producerEglDisplay,
1686 EGLSurface producerEglSurface,
1687 EGLContext producerEglContext) {
1688 mProducerEglDisplay = producerEglDisplay;
1689 mProducerEglSurface = producerEglSurface;
1690 mProducerEglContext = producerEglContext;
1691 }
1692
1693 virtual bool threadLoop() {
1694 eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
1695 mProducerEglSurface, mProducerEglContext);
1696 render();
1697 eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
1698 EGL_NO_CONTEXT);
1699 return false;
1700 }
1701
1702 protected:
1703 virtual void render() = 0;
1704
1705 void swapBuffers() {
1706 eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
1707 }
1708
1709 EGLDisplay mProducerEglDisplay;
1710 EGLSurface mProducerEglSurface;
1711 EGLContext mProducerEglContext;
1712 };
1713
1714 // FrameCondition is a utility class for interlocking between the producer
1715 // and consumer threads. The FrameCondition object should be created and
1716 // destroyed in the consumer thread only. The consumer thread should set
1717 // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
1718 // and should call both waitForFrame and finishFrame once for each expected
1719 // frame.
1720 //
1721 // This interlocking relies on the fact that onFrameAvailable gets called
1722 // synchronously from SurfaceTexture::queueBuffer.
1723 class FrameCondition : public SurfaceTexture::FrameAvailableListener {
1724 public:
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001725 FrameCondition():
1726 mFrameAvailable(false),
1727 mFrameFinished(false) {
1728 }
1729
Jamie Gennis5451d152011-06-08 09:40:45 -07001730 // waitForFrame waits for the next frame to arrive. This should be
1731 // called from the consumer thread once for every frame expected by the
1732 // test.
1733 void waitForFrame() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001734 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001735 ALOGV("+waitForFrame");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001736 while (!mFrameAvailable) {
1737 mFrameAvailableCondition.wait(mMutex);
1738 }
1739 mFrameAvailable = false;
Steve Block6807e592011-10-20 11:56:00 +01001740 ALOGV("-waitForFrame");
Jamie Gennis5451d152011-06-08 09:40:45 -07001741 }
1742
1743 // Allow the producer to return from its swapBuffers call and continue
1744 // on to produce the next frame. This should be called by the consumer
1745 // thread once for every frame expected by the test.
1746 void finishFrame() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001747 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001748 ALOGV("+finishFrame");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001749 mFrameFinished = true;
Jamie Gennis5451d152011-06-08 09:40:45 -07001750 mFrameFinishCondition.signal();
Steve Block6807e592011-10-20 11:56:00 +01001751 ALOGV("-finishFrame");
Jamie Gennis5451d152011-06-08 09:40:45 -07001752 }
1753
1754 // This should be called by SurfaceTexture on the producer thread.
1755 virtual void onFrameAvailable() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001756 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001757 ALOGV("+onFrameAvailable");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001758 mFrameAvailable = true;
Jamie Gennis5451d152011-06-08 09:40:45 -07001759 mFrameAvailableCondition.signal();
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001760 while (!mFrameFinished) {
1761 mFrameFinishCondition.wait(mMutex);
1762 }
1763 mFrameFinished = false;
Steve Block6807e592011-10-20 11:56:00 +01001764 ALOGV("-onFrameAvailable");
Jamie Gennis5451d152011-06-08 09:40:45 -07001765 }
1766
1767 protected:
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001768 bool mFrameAvailable;
1769 bool mFrameFinished;
1770
Jamie Gennis5451d152011-06-08 09:40:45 -07001771 Mutex mMutex;
1772 Condition mFrameAvailableCondition;
1773 Condition mFrameFinishCondition;
1774 };
1775
Jamie Gennis5451d152011-06-08 09:40:45 -07001776 virtual void SetUp() {
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001777 SurfaceTextureGLToGLTest::SetUp();
Jamie Gennis5451d152011-06-08 09:40:45 -07001778 mFC = new FrameCondition();
1779 mST->setFrameAvailableListener(mFC);
1780 }
1781
1782 virtual void TearDown() {
1783 if (mProducerThread != NULL) {
1784 mProducerThread->requestExitAndWait();
1785 }
Jamie Gennis5451d152011-06-08 09:40:45 -07001786 mProducerThread.clear();
1787 mFC.clear();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001788 SurfaceTextureGLToGLTest::TearDown();
Jamie Gennis5451d152011-06-08 09:40:45 -07001789 }
1790
1791 void runProducerThread(const sp<ProducerThread> producerThread) {
1792 ASSERT_TRUE(mProducerThread == NULL);
1793 mProducerThread = producerThread;
1794 producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
1795 mProducerEglContext);
1796 producerThread->run();
1797 }
1798
Jamie Gennis5451d152011-06-08 09:40:45 -07001799 sp<ProducerThread> mProducerThread;
1800 sp<FrameCondition> mFC;
1801};
1802
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001803TEST_F(SurfaceTextureGLThreadToGLTest,
1804 UpdateTexImageBeforeFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001805 class PT : public ProducerThread {
1806 virtual void render() {
1807 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1808 glClear(GL_COLOR_BUFFER_BIT);
1809 swapBuffers();
1810 }
1811 };
1812
1813 runProducerThread(new PT());
1814
1815 mFC->waitForFrame();
1816 mST->updateTexImage();
1817 mFC->finishFrame();
1818
1819 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
Jamie Gennisd99c0882011-03-10 16:24:46 -08001820}
Jamie Gennis5451d152011-06-08 09:40:45 -07001821
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001822TEST_F(SurfaceTextureGLThreadToGLTest,
1823 UpdateTexImageAfterFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001824 class PT : public ProducerThread {
1825 virtual void render() {
1826 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1827 glClear(GL_COLOR_BUFFER_BIT);
1828 swapBuffers();
1829 }
1830 };
1831
1832 runProducerThread(new PT());
1833
1834 mFC->waitForFrame();
1835 mFC->finishFrame();
1836 mST->updateTexImage();
1837
1838 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1839}
1840
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001841TEST_F(SurfaceTextureGLThreadToGLTest,
1842 RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001843 enum { NUM_ITERATIONS = 1024 };
1844
1845 class PT : public ProducerThread {
1846 virtual void render() {
1847 for (int i = 0; i < NUM_ITERATIONS; i++) {
1848 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1849 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001850 ALOGV("+swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001851 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001852 ALOGV("-swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001853 }
1854 }
1855 };
1856
1857 runProducerThread(new PT());
1858
1859 for (int i = 0; i < NUM_ITERATIONS; i++) {
1860 mFC->waitForFrame();
Steve Block6807e592011-10-20 11:56:00 +01001861 ALOGV("+updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001862 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001863 ALOGV("-updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001864 mFC->finishFrame();
1865
1866 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1867 }
1868}
1869
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001870TEST_F(SurfaceTextureGLThreadToGLTest,
1871 RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001872 enum { NUM_ITERATIONS = 1024 };
1873
1874 class PT : public ProducerThread {
1875 virtual void render() {
1876 for (int i = 0; i < NUM_ITERATIONS; i++) {
1877 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1878 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001879 ALOGV("+swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001880 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001881 ALOGV("-swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001882 }
1883 }
1884 };
1885
1886 runProducerThread(new PT());
1887
1888 for (int i = 0; i < NUM_ITERATIONS; i++) {
1889 mFC->waitForFrame();
1890 mFC->finishFrame();
Steve Block6807e592011-10-20 11:56:00 +01001891 ALOGV("+updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001892 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001893 ALOGV("-updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001894
1895 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1896 }
1897}
1898
Jamie Gennis6e502192011-07-21 14:31:31 -07001899// XXX: This test is disabled because it is currently hanging on some devices.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001900TEST_F(SurfaceTextureGLThreadToGLTest,
1901 DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
Jamie Gennis6e502192011-07-21 14:31:31 -07001902 enum { NUM_ITERATIONS = 64 };
1903
1904 class PT : public ProducerThread {
1905 virtual void render() {
1906 for (int i = 0; i < NUM_ITERATIONS; i++) {
1907 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1908 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001909 ALOGV("+swapBuffers");
Jamie Gennis6e502192011-07-21 14:31:31 -07001910 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001911 ALOGV("-swapBuffers");
Jamie Gennis6e502192011-07-21 14:31:31 -07001912 }
1913 }
1914 };
1915
1916 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1917 ASSERT_EQ(OK, mST->setBufferCountServer(2));
1918
1919 runProducerThread(new PT());
1920
1921 // Allow three frames to be rendered and queued before starting the
1922 // rendering in this thread. For the latter two frames we don't call
1923 // updateTexImage so the next dequeue from the producer thread will block
1924 // waiting for a frame to become available.
1925 mFC->waitForFrame();
1926 mFC->finishFrame();
1927
1928 // We must call updateTexImage to consume the first frame so that the
1929 // SurfaceTexture is able to reduce the buffer count to 2. This is because
1930 // the GL driver may dequeue a buffer when the EGLSurface is created, and
1931 // that happens before we call setBufferCountServer. It's possible that the
1932 // driver does not dequeue a buffer at EGLSurface creation time, so we
1933 // cannot rely on this to cause the second dequeueBuffer call to block.
1934 mST->updateTexImage();
1935
1936 mFC->waitForFrame();
1937 mFC->finishFrame();
1938 mFC->waitForFrame();
1939 mFC->finishFrame();
1940
1941 // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
1942 // block waiting for a buffer to become available.
1943 usleep(100000);
1944
1945 // Render and present a number of images. This thread should not be blocked
1946 // by the fact that the producer thread is blocking in dequeue.
1947 for (int i = 0; i < NUM_ITERATIONS; i++) {
1948 glClear(GL_COLOR_BUFFER_BIT);
1949 eglSwapBuffers(mEglDisplay, mEglSurface);
1950 }
1951
1952 // Consume the two pending buffers to unblock the producer thread.
1953 mST->updateTexImage();
1954 mST->updateTexImage();
1955
1956 // Consume the remaining buffers from the producer thread.
1957 for (int i = 0; i < NUM_ITERATIONS-3; i++) {
1958 mFC->waitForFrame();
1959 mFC->finishFrame();
Steve Block6807e592011-10-20 11:56:00 +01001960 ALOGV("+updateTexImage");
Jamie Gennis6e502192011-07-21 14:31:31 -07001961 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001962 ALOGV("-updateTexImage");
Jamie Gennis6e502192011-07-21 14:31:31 -07001963 }
1964}
1965
Jamie Gennisfe27e2f2011-11-11 18:05:11 -08001966class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
1967protected:
1968
1969 virtual void SetUp() {
1970 SurfaceTextureGLTest::SetUp();
1971
1972 glGenFramebuffers(1, &mFbo);
1973 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1974
1975 glGenTextures(1, &mFboTex);
1976 glBindTexture(GL_TEXTURE_2D, mFboTex);
1977 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
1978 getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1979 glBindTexture(GL_TEXTURE_2D, 0);
1980 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1981
1982 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1983 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1984 GL_TEXTURE_2D, mFboTex, 0);
1985 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1986 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1987 }
1988
1989 virtual void TearDown() {
1990 SurfaceTextureGLTest::TearDown();
1991
1992 glDeleteTextures(1, &mFboTex);
1993 glDeleteFramebuffers(1, &mFbo);
1994 }
1995
1996 GLuint mFbo;
1997 GLuint mFboTex;
1998};
1999
2000// This test is intended to verify that proper synchronization is done when
2001// rendering into an FBO.
2002TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
2003 const int texWidth = 64;
2004 const int texHeight = 64;
2005
2006 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
2007 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
2008 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
2009 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
2010
2011 android_native_buffer_t* anb;
2012 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
2013 ASSERT_TRUE(anb != NULL);
2014
2015 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
2016 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
2017
2018 // Fill the buffer with green
2019 uint8_t* img = NULL;
2020 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
2021 fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
2022 0, 255);
2023 buf->unlock();
2024 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
2025
2026 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
2027
2028 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
2029 drawTexture();
2030 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2031
2032 for (int i = 0; i < 4; i++) {
2033 SCOPED_TRACE(String8::format("frame %d", i).string());
2034
2035 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
2036 ASSERT_TRUE(anb != NULL);
2037
2038 buf = new GraphicBuffer(anb, false);
2039 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
2040 buf->getNativeBuffer()));
2041
2042 // Fill the buffer with red
2043 ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
2044 (void**)(&img)));
2045 fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0,
2046 0, 255);
2047 ASSERT_EQ(NO_ERROR, buf->unlock());
2048 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
2049 buf->getNativeBuffer()));
2050
2051 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
2052
2053 drawTexture();
2054
2055 EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
2056 }
2057
2058 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
2059
2060 EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
2061}
2062
Jamie Gennisce561372012-03-19 18:33:05 -07002063class SurfaceTextureMultiContextGLTest : public SurfaceTextureGLTest {
2064protected:
Jamie Gennis74bed552012-03-28 19:05:54 -07002065 enum { SECOND_TEX_ID = 123 };
2066 enum { THIRD_TEX_ID = 456 };
2067
Jamie Gennisce561372012-03-19 18:33:05 -07002068 SurfaceTextureMultiContextGLTest():
2069 mSecondEglContext(EGL_NO_CONTEXT) {
2070 }
2071
2072 virtual void SetUp() {
2073 SurfaceTextureGLTest::SetUp();
2074
Jamie Gennis74bed552012-03-28 19:05:54 -07002075 // Set up the secondary context and texture renderer.
Jamie Gennisce561372012-03-19 18:33:05 -07002076 mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig,
2077 EGL_NO_CONTEXT, getContextAttribs());
2078 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2079 ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext);
Jamie Gennis74bed552012-03-28 19:05:54 -07002080
2081 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2082 mSecondEglContext));
2083 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2084 mSecondTextureRenderer = new TextureRenderer(SECOND_TEX_ID, mST);
2085 ASSERT_NO_FATAL_FAILURE(mSecondTextureRenderer->SetUp());
2086
2087 // Set up the tertiary context and texture renderer.
2088 mThirdEglContext = eglCreateContext(mEglDisplay, mGlConfig,
2089 EGL_NO_CONTEXT, getContextAttribs());
2090 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2091 ASSERT_NE(EGL_NO_CONTEXT, mThirdEglContext);
2092
2093 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2094 mThirdEglContext));
2095 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2096 mThirdTextureRenderer = new TextureRenderer(THIRD_TEX_ID, mST);
2097 ASSERT_NO_FATAL_FAILURE(mThirdTextureRenderer->SetUp());
2098
2099 // Switch back to the primary context to start the tests.
2100 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2101 mEglContext));
Jamie Gennisce561372012-03-19 18:33:05 -07002102 }
2103
2104 virtual void TearDown() {
Jamie Gennis74bed552012-03-28 19:05:54 -07002105 if (mThirdEglContext != EGL_NO_CONTEXT) {
2106 eglDestroyContext(mEglDisplay, mThirdEglContext);
2107 }
Jamie Gennisce561372012-03-19 18:33:05 -07002108 if (mSecondEglContext != EGL_NO_CONTEXT) {
2109 eglDestroyContext(mEglDisplay, mSecondEglContext);
2110 }
2111 SurfaceTextureGLTest::TearDown();
2112 }
2113
2114 EGLContext mSecondEglContext;
Jamie Gennis74bed552012-03-28 19:05:54 -07002115 sp<TextureRenderer> mSecondTextureRenderer;
2116
2117 EGLContext mThirdEglContext;
2118 sp<TextureRenderer> mThirdTextureRenderer;
Jamie Gennisce561372012-03-19 18:33:05 -07002119};
2120
2121TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) {
2122 sp<FrameWaiter> fw(new FrameWaiter);
2123 mST->setFrameAvailableListener(fw);
2124
2125 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2126
2127 // Latch the texture contents on the primary context.
Jamie Gennis74bed552012-03-28 19:05:54 -07002128 fw->waitForFrame();
2129 ASSERT_EQ(OK, mST->updateTexImage());
Jamie Gennisce561372012-03-19 18:33:05 -07002130
2131 // Attempt to latch the texture on the secondary context.
Jamie Gennis74bed552012-03-28 19:05:54 -07002132 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
Jamie Gennisce561372012-03-19 18:33:05 -07002133 mSecondEglContext));
2134 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennis74bed552012-03-28 19:05:54 -07002135 ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage());
2136}
2137
2138TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextSucceeds) {
2139 sp<FrameWaiter> fw(new FrameWaiter);
2140 mST->setFrameAvailableListener(fw);
2141
2142 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2143
2144 // Latch the texture contents on the primary context.
2145 fw->waitForFrame();
2146 ASSERT_EQ(OK, mST->updateTexImage());
2147
2148 // Detach from the primary context.
2149 ASSERT_EQ(OK, mST->detachFromContext());
2150
2151 // Check that the GL texture was deleted.
2152 EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID));
2153}
2154
2155TEST_F(SurfaceTextureMultiContextGLTest,
2156 DetachFromContextSucceedsAfterProducerDisconnect) {
2157 sp<FrameWaiter> fw(new FrameWaiter);
2158 mST->setFrameAvailableListener(fw);
2159
2160 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2161
2162 // Latch the texture contents on the primary context.
2163 fw->waitForFrame();
2164 ASSERT_EQ(OK, mST->updateTexImage());
2165
2166 // Detach from the primary context.
2167 native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
2168 ASSERT_EQ(OK, mST->detachFromContext());
2169
2170 // Check that the GL texture was deleted.
2171 EXPECT_EQ(GL_FALSE, glIsTexture(TEX_ID));
2172}
2173
2174TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenAbandoned) {
2175 sp<FrameWaiter> fw(new FrameWaiter);
2176 mST->setFrameAvailableListener(fw);
2177
2178 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2179
2180 // Latch the texture contents on the primary context.
2181 fw->waitForFrame();
2182 ASSERT_EQ(OK, mST->updateTexImage());
2183
2184 // Attempt to detach from the primary context.
2185 mST->abandon();
2186 ASSERT_EQ(NO_INIT, mST->detachFromContext());
2187}
2188
2189TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWhenDetached) {
2190 sp<FrameWaiter> fw(new FrameWaiter);
2191 mST->setFrameAvailableListener(fw);
2192
2193 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2194
2195 // Latch the texture contents on the primary context.
2196 fw->waitForFrame();
2197 ASSERT_EQ(OK, mST->updateTexImage());
2198
2199 // Detach from the primary context.
2200 ASSERT_EQ(OK, mST->detachFromContext());
2201
2202 // Attempt to detach from the primary context again.
2203 ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext());
2204}
2205
2206TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoDisplay) {
2207 sp<FrameWaiter> fw(new FrameWaiter);
2208 mST->setFrameAvailableListener(fw);
2209
2210 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2211
2212 // Latch the texture contents on the primary context.
2213 fw->waitForFrame();
2214 ASSERT_EQ(OK, mST->updateTexImage());
2215
2216 // Make there be no current display.
2217 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
2218 EGL_NO_CONTEXT));
2219 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2220
2221 // Attempt to detach from the primary context.
2222 ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext());
2223}
2224
2225TEST_F(SurfaceTextureMultiContextGLTest, DetachFromContextFailsWithNoContext) {
2226 sp<FrameWaiter> fw(new FrameWaiter);
2227 mST->setFrameAvailableListener(fw);
2228
2229 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2230
2231 // Latch the texture contents on the primary context.
2232 fw->waitForFrame();
2233 ASSERT_EQ(OK, mST->updateTexImage());
2234
2235 // Make current context be incorrect.
2236 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2237 mSecondEglContext));
2238 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2239
2240 // Attempt to detach from the primary context.
2241 ASSERT_EQ(INVALID_OPERATION, mST->detachFromContext());
2242}
2243
2244TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageFailsWhenDetached) {
2245 sp<FrameWaiter> fw(new FrameWaiter);
2246 mST->setFrameAvailableListener(fw);
2247
2248 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2249
2250 // Detach from the primary context.
2251 ASSERT_EQ(OK, mST->detachFromContext());
2252
2253 // Attempt to latch the texture contents on the primary context.
2254 fw->waitForFrame();
2255 ASSERT_EQ(INVALID_OPERATION, mST->updateTexImage());
2256}
2257
2258TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceeds) {
2259 sp<FrameWaiter> fw(new FrameWaiter);
2260 mST->setFrameAvailableListener(fw);
2261
2262 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2263
2264 // Latch the texture contents on the primary context.
2265 fw->waitForFrame();
2266 ASSERT_EQ(OK, mST->updateTexImage());
2267
2268 // Detach from the primary context.
2269 ASSERT_EQ(OK, mST->detachFromContext());
2270
2271 // Attach to the secondary context.
2272 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2273 mSecondEglContext));
2274 ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
2275
2276 // Verify that the texture object was created and bound.
2277 GLint texBinding = -1;
2278 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
2279 EXPECT_EQ(SECOND_TEX_ID, texBinding);
2280
2281 // Try to use the texture from the secondary context.
2282 glClearColor(0.2, 0.2, 0.2, 0.2);
2283 glClear(GL_COLOR_BUFFER_BIT);
2284 glViewport(0, 0, 1, 1);
2285 mSecondTextureRenderer->drawTexture();
2286 ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
2287 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
2288}
2289
2290TEST_F(SurfaceTextureMultiContextGLTest,
2291 AttachToContextSucceedsAfterProducerDisconnect) {
2292 sp<FrameWaiter> fw(new FrameWaiter);
2293 mST->setFrameAvailableListener(fw);
2294
2295 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2296
2297 // Latch the texture contents on the primary context.
2298 fw->waitForFrame();
2299 ASSERT_EQ(OK, mST->updateTexImage());
2300
2301 // Detach from the primary context.
2302 native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
2303 ASSERT_EQ(OK, mST->detachFromContext());
2304
2305 // Attach to the secondary context.
2306 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2307 mSecondEglContext));
2308 ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
2309
2310 // Verify that the texture object was created and bound.
2311 GLint texBinding = -1;
2312 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
2313 EXPECT_EQ(SECOND_TEX_ID, texBinding);
2314
2315 // Try to use the texture from the secondary context.
2316 glClearColor(0.2, 0.2, 0.2, 0.2);
2317 glClear(GL_COLOR_BUFFER_BIT);
2318 glViewport(0, 0, 1, 1);
2319 mSecondTextureRenderer->drawTexture();
2320 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
2321 ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
2322}
2323
2324TEST_F(SurfaceTextureMultiContextGLTest,
2325 AttachToContextSucceedsBeforeUpdateTexImage) {
2326 sp<FrameWaiter> fw(new FrameWaiter);
2327 mST->setFrameAvailableListener(fw);
2328
2329 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2330
2331 // Detach from the primary context.
2332 native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
2333 ASSERT_EQ(OK, mST->detachFromContext());
2334
2335 // Attach to the secondary context.
2336 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2337 mSecondEglContext));
2338 ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
2339
2340 // Verify that the texture object was created and bound.
2341 GLint texBinding = -1;
2342 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
2343 EXPECT_EQ(SECOND_TEX_ID, texBinding);
2344
2345 // Latch the texture contents on the primary context.
2346 fw->waitForFrame();
2347 ASSERT_EQ(OK, mST->updateTexImage());
2348
2349 // Try to use the texture from the secondary context.
2350 glClearColor(0.2, 0.2, 0.2, 0.2);
2351 glClear(GL_COLOR_BUFFER_BIT);
2352 glViewport(0, 0, 1, 1);
2353 mSecondTextureRenderer->drawTexture();
2354 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
2355 ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
2356}
2357
2358TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAbandoned) {
2359 sp<FrameWaiter> fw(new FrameWaiter);
2360 mST->setFrameAvailableListener(fw);
2361
2362 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2363
2364 // Latch the texture contents on the primary context.
2365 fw->waitForFrame();
2366 ASSERT_EQ(OK, mST->updateTexImage());
2367
2368 // Detach from the primary context.
2369 ASSERT_EQ(OK, mST->detachFromContext());
2370
2371 // Attempt to attach to the secondary context.
2372 mST->abandon();
2373
2374 // Attempt to attach to the primary context.
2375 ASSERT_EQ(NO_INIT, mST->attachToContext(SECOND_TEX_ID));
2376}
2377
2378TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWhenAttached) {
2379 sp<FrameWaiter> fw(new FrameWaiter);
2380 mST->setFrameAvailableListener(fw);
2381
2382 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2383
2384 // Latch the texture contents on the primary context.
2385 fw->waitForFrame();
2386 ASSERT_EQ(OK, mST->updateTexImage());
2387
2388 // Attempt to attach to the primary context.
2389 ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID));
2390}
2391
2392TEST_F(SurfaceTextureMultiContextGLTest,
2393 AttachToContextFailsWhenAttachedBeforeUpdateTexImage) {
2394 sp<FrameWaiter> fw(new FrameWaiter);
2395 mST->setFrameAvailableListener(fw);
2396
2397 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2398
2399 // Attempt to attach to the primary context.
2400 ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID));
2401}
2402
2403TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextFailsWithNoDisplay) {
2404 sp<FrameWaiter> fw(new FrameWaiter);
2405 mST->setFrameAvailableListener(fw);
2406
2407 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2408
2409 // Latch the texture contents on the primary context.
2410 fw->waitForFrame();
2411 ASSERT_EQ(OK, mST->updateTexImage());
2412
2413 // Detach from the primary context.
2414 ASSERT_EQ(OK, mST->detachFromContext());
2415
2416 // Make there be no current display.
2417 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
2418 EGL_NO_CONTEXT));
2419 ASSERT_EQ(EGL_SUCCESS, eglGetError());
2420
2421 // Attempt to attach with no context current.
2422 ASSERT_EQ(INVALID_OPERATION, mST->attachToContext(SECOND_TEX_ID));
2423}
2424
2425TEST_F(SurfaceTextureMultiContextGLTest, AttachToContextSucceedsTwice) {
2426 sp<FrameWaiter> fw(new FrameWaiter);
2427 mST->setFrameAvailableListener(fw);
2428
2429 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2430
2431 // Latch the texture contents on the primary context.
2432 fw->waitForFrame();
2433 ASSERT_EQ(OK, mST->updateTexImage());
2434
2435 // Detach from the primary context.
2436 ASSERT_EQ(OK, mST->detachFromContext());
2437
2438 // Attach to the secondary context.
2439 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2440 mSecondEglContext));
2441 ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
2442
2443 // Detach from the secondary context.
2444 ASSERT_EQ(OK, mST->detachFromContext());
2445
2446 // Attach to the tertiary context.
2447 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2448 mThirdEglContext));
2449 ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID));
2450
2451 // Verify that the texture object was created and bound.
2452 GLint texBinding = -1;
2453 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
2454 EXPECT_EQ(THIRD_TEX_ID, texBinding);
2455
2456 // Try to use the texture from the tertiary context.
2457 glClearColor(0.2, 0.2, 0.2, 0.2);
2458 glClear(GL_COLOR_BUFFER_BIT);
2459 glViewport(0, 0, 1, 1);
2460 mThirdTextureRenderer->drawTexture();
2461 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
2462 ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
2463}
2464
2465TEST_F(SurfaceTextureMultiContextGLTest,
2466 AttachToContextSucceedsTwiceBeforeUpdateTexImage) {
2467 sp<FrameWaiter> fw(new FrameWaiter);
2468 mST->setFrameAvailableListener(fw);
2469
2470 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
2471
2472 // Detach from the primary context.
2473 ASSERT_EQ(OK, mST->detachFromContext());
2474
2475 // Attach to the secondary context.
2476 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2477 mSecondEglContext));
2478 ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
2479
2480 // Detach from the secondary context.
2481 ASSERT_EQ(OK, mST->detachFromContext());
2482
2483 // Attach to the tertiary context.
2484 ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
2485 mThirdEglContext));
2486 ASSERT_EQ(OK, mST->attachToContext(THIRD_TEX_ID));
2487
2488 // Verify that the texture object was created and bound.
2489 GLint texBinding = -1;
2490 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texBinding);
2491 EXPECT_EQ(THIRD_TEX_ID, texBinding);
2492
2493 // Latch the texture contents on the tertiary context.
2494 fw->waitForFrame();
2495 ASSERT_EQ(OK, mST->updateTexImage());
2496
2497 // Try to use the texture from the tertiary context.
2498 glClearColor(0.2, 0.2, 0.2, 0.2);
2499 glClear(GL_COLOR_BUFFER_BIT);
2500 glViewport(0, 0, 1, 1);
2501 mThirdTextureRenderer->drawTexture();
2502 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
2503 ASSERT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
Jamie Gennisce561372012-03-19 18:33:05 -07002504}
2505
Jamie Gennis5451d152011-06-08 09:40:45 -07002506} // namespace android