blob: d6357ca9f2c49eed360c83876c6bdc61b2ea7d1d [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() {
135 // Display the result
136 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
194 void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
195 GLuint shader = glCreateShader(shaderType);
196 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
197 if (shader) {
198 glShaderSource(shader, 1, &pSource, NULL);
199 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
200 glCompileShader(shader);
201 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
202 GLint compiled = 0;
203 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
204 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
205 if (!compiled) {
206 GLint infoLen = 0;
207 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
208 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
209 if (infoLen) {
210 char* buf = (char*) malloc(infoLen);
211 if (buf) {
212 glGetShaderInfoLog(shader, infoLen, NULL, buf);
213 printf("Shader compile log:\n%s\n", buf);
214 free(buf);
215 FAIL();
216 }
217 } else {
218 char* buf = (char*) malloc(0x1000);
219 if (buf) {
220 glGetShaderInfoLog(shader, 0x1000, NULL, buf);
221 printf("Shader compile log:\n%s\n", buf);
222 free(buf);
223 FAIL();
224 }
225 }
226 glDeleteShader(shader);
227 shader = 0;
228 }
229 }
230 ASSERT_TRUE(shader != 0);
231 *outShader = shader;
232 }
233
234 void createProgram(const char* pVertexSource, const char* pFragmentSource,
235 GLuint* outPgm) {
236 GLuint vertexShader, fragmentShader;
237 {
238 SCOPED_TRACE("compiling vertex shader");
239 loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
240 if (HasFatalFailure()) {
241 return;
242 }
243 }
244 {
245 SCOPED_TRACE("compiling fragment shader");
246 loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
247 if (HasFatalFailure()) {
248 return;
249 }
250 }
251
252 GLuint program = glCreateProgram();
253 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
254 if (program) {
255 glAttachShader(program, vertexShader);
256 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
257 glAttachShader(program, fragmentShader);
258 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
259 glLinkProgram(program);
260 GLint linkStatus = GL_FALSE;
261 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
262 if (linkStatus != GL_TRUE) {
263 GLint bufLength = 0;
264 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
265 if (bufLength) {
266 char* buf = (char*) malloc(bufLength);
267 if (buf) {
268 glGetProgramInfoLog(program, bufLength, NULL, buf);
269 printf("Program link log:\n%s\n", buf);
270 free(buf);
271 FAIL();
272 }
273 }
274 glDeleteProgram(program);
275 program = 0;
276 }
277 }
278 glDeleteShader(vertexShader);
279 glDeleteShader(fragmentShader);
280 ASSERT_TRUE(program != 0);
281 *outPgm = program;
282 }
283
Jamie Gennis824efa72011-06-13 13:41:01 -0700284 static int abs(int value) {
285 return value > 0 ? value : -value;
286 }
287
Jamie Gennisd99c0882011-03-10 16:24:46 -0800288 ::testing::AssertionResult checkPixel(int x, int y, int r,
Jamie Gennis824efa72011-06-13 13:41:01 -0700289 int g, int b, int a, int tolerance=2) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800290 GLubyte pixel[4];
291 String8 msg;
292 glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
293 GLenum err = glGetError();
294 if (err != GL_NO_ERROR) {
295 msg += String8::format("error reading pixel: %#x", err);
296 while ((err = glGetError()) != GL_NO_ERROR) {
297 msg += String8::format(", %#x", err);
298 }
299 fprintf(stderr, "pixel check failure: %s\n", msg.string());
300 return ::testing::AssertionFailure(
301 ::testing::Message(msg.string()));
302 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700303 if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800304 msg += String8::format("r(%d isn't %d)", pixel[0], r);
305 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700306 if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800307 if (!msg.isEmpty()) {
308 msg += " ";
309 }
310 msg += String8::format("g(%d isn't %d)", pixel[1], g);
311 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700312 if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800313 if (!msg.isEmpty()) {
314 msg += " ";
315 }
316 msg += String8::format("b(%d isn't %d)", pixel[2], b);
317 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700318 if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800319 if (!msg.isEmpty()) {
320 msg += " ";
321 }
322 msg += String8::format("a(%d isn't %d)", pixel[3], a);
323 }
324 if (!msg.isEmpty()) {
325 fprintf(stderr, "pixel check failure: %s\n", msg.string());
326 return ::testing::AssertionFailure(
327 ::testing::Message(msg.string()));
328 } else {
329 return ::testing::AssertionSuccess();
330 }
331 }
332
333 int mDisplaySecs;
334 sp<SurfaceComposerClient> mComposerClient;
335 sp<SurfaceControl> mSurfaceControl;
336
337 EGLDisplay mEglDisplay;
338 EGLSurface mEglSurface;
339 EGLContext mEglContext;
Jamie Gennis1876d132011-03-17 16:32:52 -0700340 EGLConfig mGlConfig;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800341};
342
343// XXX: Code above this point should live elsewhere
344
345class SurfaceTextureGLTest : public GLTest {
346protected:
Jamie Gennis79e31252011-10-19 15:19:19 -0700347 enum { TEX_ID = 123 };
Jamie Gennisd99c0882011-03-10 16:24:46 -0800348
349 virtual void SetUp() {
350 GLTest::SetUp();
351 mST = new SurfaceTexture(TEX_ID);
352 mSTC = new SurfaceTextureClient(mST);
353 mANW = mSTC;
354
355 const char vsrc[] =
356 "attribute vec4 vPosition;\n"
357 "varying vec2 texCoords;\n"
358 "uniform mat4 texMatrix;\n"
359 "void main() {\n"
360 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
361 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
362 " gl_Position = vPosition;\n"
363 "}\n";
364
365 const char fsrc[] =
366 "#extension GL_OES_EGL_image_external : require\n"
367 "precision mediump float;\n"
368 "uniform samplerExternalOES texSampler;\n"
369 "varying vec2 texCoords;\n"
370 "void main() {\n"
371 " gl_FragColor = texture2D(texSampler, texCoords);\n"
372 "}\n";
373
374 {
375 SCOPED_TRACE("creating shader program");
376 createProgram(vsrc, fsrc, &mPgm);
377 if (HasFatalFailure()) {
378 return;
379 }
380 }
381
382 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
383 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
384 ASSERT_NE(-1, mPositionHandle);
385 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
386 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
387 ASSERT_NE(-1, mTexSamplerHandle);
388 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
389 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
390 ASSERT_NE(-1, mTexMatrixHandle);
391 }
392
Jamie Gennis2640bfd2011-07-14 17:11:47 -0700393 virtual void TearDown() {
394 mANW.clear();
395 mSTC.clear();
396 mST.clear();
397 GLTest::TearDown();
398 }
399
Jamie Gennisd99c0882011-03-10 16:24:46 -0800400 // drawTexture draws the SurfaceTexture over the entire GL viewport.
401 void drawTexture() {
402 const GLfloat triangleVertices[] = {
403 -1.0f, 1.0f,
404 -1.0f, -1.0f,
405 1.0f, -1.0f,
406 1.0f, 1.0f,
407 };
408
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800409 glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0,
410 triangleVertices);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800411 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
412 glEnableVertexAttribArray(mPositionHandle);
413 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
414
415 glUseProgram(mPgm);
416 glUniform1i(mTexSamplerHandle, 0);
417 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
418 glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
419 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
420
Jamie Gennis1876d132011-03-17 16:32:52 -0700421 // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
422 // they're setting the defautls for that target, but when hacking things
423 // to use GL_TEXTURE_2D they are needed to achieve the same behavior.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800424 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
425 GL_LINEAR);
Jamie Gennis1876d132011-03-17 16:32:52 -0700426 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800427 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
428 GL_LINEAR);
Jamie Gennis1876d132011-03-17 16:32:52 -0700429 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800430 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
431 GL_CLAMP_TO_EDGE);
Jamie Gennis1876d132011-03-17 16:32:52 -0700432 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800433 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
434 GL_CLAMP_TO_EDGE);
Jamie Gennis1876d132011-03-17 16:32:52 -0700435 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
436
Jamie Gennisd99c0882011-03-10 16:24:46 -0800437 GLfloat texMatrix[16];
438 mST->getTransformMatrix(texMatrix);
439 glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
440
441 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
442 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
443 }
444
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700445 class FrameWaiter : public SurfaceTexture::FrameAvailableListener {
446 public:
447 FrameWaiter():
448 mPendingFrames(0) {
449 }
450
451 void waitForFrame() {
452 Mutex::Autolock lock(mMutex);
453 while (mPendingFrames == 0) {
454 mCondition.wait(mMutex);
455 }
456 mPendingFrames--;
457 }
458
459 virtual void onFrameAvailable() {
460 Mutex::Autolock lock(mMutex);
461 mPendingFrames++;
462 mCondition.signal();
463 }
464
465 int mPendingFrames;
466 Mutex mMutex;
467 Condition mCondition;
468 };
469
Jamie Gennisd99c0882011-03-10 16:24:46 -0800470 sp<SurfaceTexture> mST;
471 sp<SurfaceTextureClient> mSTC;
472 sp<ANativeWindow> mANW;
473
474 GLuint mPgm;
475 GLint mPositionHandle;
476 GLint mTexSamplerHandle;
477 GLint mTexMatrixHandle;
478};
479
480// Fill a YV12 buffer with a multi-colored checkerboard pattern
481void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
482 const int blockWidth = w > 16 ? w / 16 : 1;
483 const int blockHeight = h > 16 ? h / 16 : 1;
484 const int yuvTexOffsetY = 0;
485 int yuvTexStrideY = stride;
486 int yuvTexOffsetV = yuvTexStrideY * h;
487 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
488 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
489 int yuvTexStrideU = yuvTexStrideV;
490 for (int x = 0; x < w; x++) {
491 for (int y = 0; y < h; y++) {
492 int parityX = (x / blockWidth) & 1;
493 int parityY = (y / blockHeight) & 1;
494 unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
495 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
496 if (x < w / 2 && y < h / 2) {
497 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
498 if (x * 2 < w / 2 && y * 2 < h / 2) {
499 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
500 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
501 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
502 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
503 intensity;
504 }
505 }
506 }
507 }
508}
509
510// Fill a YV12 buffer with red outside a given rectangle and green inside it.
511void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
512 const android_native_rect_t& rect) {
513 const int yuvTexOffsetY = 0;
514 int yuvTexStrideY = stride;
515 int yuvTexOffsetV = yuvTexStrideY * h;
516 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
517 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
518 int yuvTexStrideU = yuvTexStrideV;
519 for (int x = 0; x < w; x++) {
520 for (int y = 0; y < h; y++) {
521 bool inside = rect.left <= x && x < rect.right &&
522 rect.top <= y && y < rect.bottom;
523 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
524 if (x < w / 2 && y < h / 2) {
525 bool inside = rect.left <= 2*x && 2*x < rect.right &&
526 rect.top <= 2*y && 2*y < rect.bottom;
527 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
528 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
529 inside ? 16 : 255;
530 }
531 }
532 }
533}
534
Jamie Gennis1876d132011-03-17 16:32:52 -0700535void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
536 const size_t PIXEL_SIZE = 4;
537 for (int x = 0; x < w; x++) {
538 for (int y = 0; y < h; y++) {
539 off_t offset = (y * stride + x) * PIXEL_SIZE;
540 for (int c = 0; c < 4; c++) {
541 int parityX = (x / (1 << (c+2))) & 1;
542 int parityY = (y / (1 << (c+2))) & 1;
543 buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
544 }
545 }
546 }
547}
548
Jamie Gennisfe27e2f2011-11-11 18:05:11 -0800549void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
550 uint8_t g, uint8_t b, uint8_t a) {
551 const size_t PIXEL_SIZE = 4;
552 for (int y = 0; y < h; y++) {
553 for (int x = 0; x < h; x++) {
554 off_t offset = (y * stride + x) * PIXEL_SIZE;
555 buf[offset + 0] = r;
556 buf[offset + 1] = g;
557 buf[offset + 2] = b;
558 buf[offset + 3] = a;
559 }
560 }
561}
562
Jamie Gennisce561372012-03-19 18:33:05 -0700563// Produce a single RGBA8 frame by filling a buffer with a checkerboard pattern
564// using the CPU. This assumes that the ANativeWindow is already configured to
565// allow this to be done (e.g. the format is set to RGBA8).
566//
567// Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE().
568void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) {
569 android_native_buffer_t* anb;
570 ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &anb));
571 ASSERT_TRUE(anb != NULL);
572
573 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
574 ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf->getNativeBuffer()));
575
576 uint8_t* img = NULL;
577 ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
578 (void**)(&img)));
579 fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
580 ASSERT_EQ(NO_ERROR, buf->unlock());
581 ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer()));
582}
583
Jamie Gennisd99c0882011-03-10 16:24:46 -0800584TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700585 const int texWidth = 64;
586 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800587
588 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700589 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800590 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
591 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
592
Iliyan Malchev697526b2011-05-01 11:33:26 -0700593 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800594 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
595 ASSERT_TRUE(anb != NULL);
596
597 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
598 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
599
600 // Fill the buffer with the a checkerboard pattern
601 uint8_t* img = NULL;
602 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700603 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800604 buf->unlock();
605 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
606
607 mST->updateTexImage();
608
609 glClearColor(0.2, 0.2, 0.2, 0.2);
610 glClear(GL_COLOR_BUFFER_BIT);
611
Jamie Gennisc8c51522011-06-15 14:24:38 -0700612 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800613 drawTexture();
614
615 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
616 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700617 EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255));
618 EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800619
Jamie Gennisc8c51522011-06-15 14:24:38 -0700620 EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
621 EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
622 EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800623 EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700624 EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800625 EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
626 EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
627}
628
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700629TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700630 const int texWidth = 64;
631 const int texHeight = 64;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800632
633 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700634 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800635 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
636 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
637
Iliyan Malchev697526b2011-05-01 11:33:26 -0700638 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800639 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
640 ASSERT_TRUE(anb != NULL);
641
642 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
643 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
644
645 // Fill the buffer with the a checkerboard pattern
646 uint8_t* img = NULL;
647 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700648 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800649 buf->unlock();
650 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
651
652 mST->updateTexImage();
653
654 glClearColor(0.2, 0.2, 0.2, 0.2);
655 glClear(GL_COLOR_BUFFER_BIT);
656
Jamie Gennisc8c51522011-06-15 14:24:38 -0700657 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800658 drawTexture();
659
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700660 EXPECT_TRUE(checkPixel( 0, 0, 0, 133, 0, 255));
661 EXPECT_TRUE(checkPixel(63, 0, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800662 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
663 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
664
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700665 EXPECT_TRUE(checkPixel(22, 19, 100, 255, 74, 255));
666 EXPECT_TRUE(checkPixel(45, 11, 100, 255, 74, 255));
667 EXPECT_TRUE(checkPixel(52, 12, 155, 0, 181, 255));
668 EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
669 EXPECT_TRUE(checkPixel(31, 54, 0, 71, 117, 255));
670 EXPECT_TRUE(checkPixel(29, 28, 0, 133, 0, 255));
671 EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800672}
673
674TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700675 const int texWidth = 64;
676 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800677
678 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700679 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800680 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
681 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
682
683 android_native_rect_t crops[] = {
684 {4, 6, 22, 36},
685 {0, 6, 22, 36},
686 {4, 0, 22, 36},
Jamie Gennis1876d132011-03-17 16:32:52 -0700687 {4, 6, texWidth, 36},
688 {4, 6, 22, texHeight},
Jamie Gennisd99c0882011-03-10 16:24:46 -0800689 };
690
691 for (int i = 0; i < 5; i++) {
692 const android_native_rect_t& crop(crops[i]);
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800693 SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }",
694 crop.left, crop.top, crop.right, crop.bottom).string());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800695
696 ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
697
Iliyan Malchev697526b2011-05-01 11:33:26 -0700698 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800699 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
700 ASSERT_TRUE(anb != NULL);
701
702 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800703 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
704 buf->getNativeBuffer()));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800705
706 uint8_t* img = NULL;
707 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700708 fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800709 buf->unlock();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800710 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
711 buf->getNativeBuffer()));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800712
713 mST->updateTexImage();
714
715 glClearColor(0.2, 0.2, 0.2, 0.2);
716 glClear(GL_COLOR_BUFFER_BIT);
717
Jamie Gennisc8c51522011-06-15 14:24:38 -0700718 glViewport(0, 0, 64, 64);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800719 drawTexture();
720
721 EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
722 EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255));
723 EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255));
724 EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255));
725
726 EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255));
727 EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255));
728 EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255));
729 EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255));
730 EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255));
731 EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255));
732 EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255));
733 }
734}
735
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700736// This test is intended to catch synchronization bugs between the CPU-written
737// and GPU-read buffers.
738TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
739 enum { texWidth = 16 };
740 enum { texHeight = 16 };
741 enum { numFrames = 1024 };
742
743 ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
744 ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
745 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
746 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
747 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
748 GRALLOC_USAGE_SW_WRITE_OFTEN));
749
750 struct TestPixel {
751 int x;
752 int y;
753 };
754 const TestPixel testPixels[] = {
755 { 4, 11 },
756 { 12, 14 },
757 { 7, 2 },
758 };
759 enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])};
760
761 class ProducerThread : public Thread {
762 public:
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800763 ProducerThread(const sp<ANativeWindow>& anw,
764 const TestPixel* testPixels):
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700765 mANW(anw),
766 mTestPixels(testPixels) {
767 }
768
769 virtual ~ProducerThread() {
770 }
771
772 virtual bool threadLoop() {
773 for (int i = 0; i < numFrames; i++) {
774 ANativeWindowBuffer* anb;
775 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
776 return false;
777 }
778 if (anb == NULL) {
779 return false;
780 }
781
782 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
783 if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
784 != NO_ERROR) {
785 return false;
786 }
787
788 const int yuvTexOffsetY = 0;
789 int stride = buf->getStride();
790 int yuvTexStrideY = stride;
791 int yuvTexOffsetV = yuvTexStrideY * texHeight;
792 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
793 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
794 int yuvTexStrideU = yuvTexStrideV;
795
796 uint8_t* img = NULL;
797 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
798
799 // Gray out all the test pixels first, so we're more likely to
800 // see a failure if GL is still texturing from the buffer we
801 // just dequeued.
802 for (int j = 0; j < numTestPixels; j++) {
803 int x = mTestPixels[j].x;
804 int y = mTestPixels[j].y;
805 uint8_t value = 128;
806 img[y*stride + x] = value;
807 }
808
809 // Fill the buffer with gray.
810 for (int y = 0; y < texHeight; y++) {
811 for (int x = 0; x < texWidth; x++) {
812 img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128;
813 img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128;
814 img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128;
815 }
816 }
817
818 // Set the test pixels to either white or black.
819 for (int j = 0; j < numTestPixels; j++) {
820 int x = mTestPixels[j].x;
821 int y = mTestPixels[j].y;
822 uint8_t value = 0;
823 if (j == (i % numTestPixels)) {
824 value = 255;
825 }
826 img[y*stride + x] = value;
827 }
828
829 buf->unlock();
830 if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
831 != NO_ERROR) {
832 return false;
833 }
834 }
835 return false;
836 }
837
838 sp<ANativeWindow> mANW;
839 const TestPixel* mTestPixels;
840 };
841
842 sp<FrameWaiter> fw(new FrameWaiter);
843 mST->setFrameAvailableListener(fw);
844
845 sp<Thread> pt(new ProducerThread(mANW, testPixels));
846 pt->run();
847
848 glViewport(0, 0, texWidth, texHeight);
849
850 glClearColor(0.2, 0.2, 0.2, 0.2);
851 glClear(GL_COLOR_BUFFER_BIT);
852
853 // We wait for the first two frames up front so that the producer will be
854 // likely to dequeue the buffer that's currently being textured from.
855 fw->waitForFrame();
856 fw->waitForFrame();
857
858 for (int i = 0; i < numFrames; i++) {
859 SCOPED_TRACE(String8::format("frame %d", i).string());
860
861 // We must wait for each frame to come in because if we ever do an
862 // updateTexImage call that doesn't consume a newly available buffer
863 // then the producer and consumer will get out of sync, which will cause
864 // a deadlock.
865 if (i > 1) {
866 fw->waitForFrame();
867 }
868 mST->updateTexImage();
869 drawTexture();
870
871 for (int j = 0; j < numTestPixels; j++) {
872 int x = testPixels[j].x;
873 int y = testPixels[j].y;
874 uint8_t value = 0;
875 if (j == (i % numTestPixels)) {
876 // We must y-invert the texture coords
877 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
878 } else {
879 // We must y-invert the texture coords
880 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255));
881 }
882 }
883 }
884
885 pt->requestExitAndWait();
886}
887
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700888TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700889 const int texWidth = 64;
890 const int texHeight = 66;
891
892 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
893 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
894 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
895 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
896
Jamie Gennisce561372012-03-19 18:33:05 -0700897 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
Jamie Gennis1876d132011-03-17 16:32:52 -0700898
899 mST->updateTexImage();
900
901 glClearColor(0.2, 0.2, 0.2, 0.2);
902 glClear(GL_COLOR_BUFFER_BIT);
903
Jamie Gennisc8c51522011-06-15 14:24:38 -0700904 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700905 drawTexture();
906
907 EXPECT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
908 EXPECT_TRUE(checkPixel(63, 0, 231, 231, 231, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700909 EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
910 EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700911
912 EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700913 EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700914 EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700915 EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
916 EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700917 EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700918 EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700919 EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231));
920 EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35));
921 EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700922 EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700923 EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
924 EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700925 EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700926 EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700927 EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
928}
929
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700930TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700931 const int texWidth = 64;
932 const int texHeight = 64;
933
934 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
935 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
936 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
937 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
938
Jamie Gennisce561372012-03-19 18:33:05 -0700939 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
Jamie Gennis1876d132011-03-17 16:32:52 -0700940
941 mST->updateTexImage();
942
943 glClearColor(0.2, 0.2, 0.2, 0.2);
944 glClear(GL_COLOR_BUFFER_BIT);
945
Jamie Gennisc8c51522011-06-15 14:24:38 -0700946 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700947 drawTexture();
948
949 EXPECT_TRUE(checkPixel( 0, 0, 231, 231, 231, 231));
950 EXPECT_TRUE(checkPixel(63, 0, 35, 35, 35, 35));
951 EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
952 EXPECT_TRUE(checkPixel( 0, 63, 35, 35, 35, 35));
953
954 EXPECT_TRUE(checkPixel(12, 46, 231, 231, 231, 35));
955 EXPECT_TRUE(checkPixel(16, 1, 231, 231, 35, 231));
956 EXPECT_TRUE(checkPixel(21, 12, 231, 35, 35, 231));
957 EXPECT_TRUE(checkPixel(26, 51, 231, 35, 231, 35));
958 EXPECT_TRUE(checkPixel( 5, 32, 35, 231, 231, 35));
959 EXPECT_TRUE(checkPixel(13, 8, 35, 231, 231, 231));
960 EXPECT_TRUE(checkPixel(46, 3, 35, 35, 231, 35));
961 EXPECT_TRUE(checkPixel(30, 33, 35, 35, 35, 35));
962 EXPECT_TRUE(checkPixel( 6, 52, 231, 231, 35, 35));
963 EXPECT_TRUE(checkPixel(55, 33, 35, 231, 35, 231));
964 EXPECT_TRUE(checkPixel(16, 29, 35, 35, 231, 231));
965 EXPECT_TRUE(checkPixel( 1, 30, 35, 35, 35, 231));
966 EXPECT_TRUE(checkPixel(41, 37, 35, 35, 231, 231));
967 EXPECT_TRUE(checkPixel(46, 29, 231, 231, 35, 35));
968 EXPECT_TRUE(checkPixel(15, 25, 35, 231, 35, 231));
969 EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
970}
971
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700972TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
973 class ProducerThread : public Thread {
974 public:
975 ProducerThread(const sp<ANativeWindow>& anw):
976 mANW(anw),
977 mDequeueError(NO_ERROR) {
978 }
979
980 virtual ~ProducerThread() {
981 }
982
983 virtual bool threadLoop() {
984 Mutex::Autolock lock(mMutex);
985 ANativeWindowBuffer* anb;
986
987 // Frame 1
988 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
989 return false;
990 }
991 if (anb == NULL) {
992 return false;
993 }
994 if (mANW->queueBuffer(mANW.get(), anb)
995 != NO_ERROR) {
996 return false;
997 }
998
999 // Frame 2
1000 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
1001 return false;
1002 }
1003 if (anb == NULL) {
1004 return false;
1005 }
1006 if (mANW->queueBuffer(mANW.get(), anb)
1007 != NO_ERROR) {
1008 return false;
1009 }
1010
1011 // Frame 3 - error expected
1012 mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
1013 return false;
1014 }
1015
1016 status_t getDequeueError() {
1017 Mutex::Autolock lock(mMutex);
1018 return mDequeueError;
1019 }
1020
1021 private:
1022 sp<ANativeWindow> mANW;
1023 status_t mDequeueError;
1024 Mutex mMutex;
1025 };
1026
1027 sp<FrameWaiter> fw(new FrameWaiter);
1028 mST->setFrameAvailableListener(fw);
1029 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1030 ASSERT_EQ(OK, mST->setBufferCountServer(2));
1031
1032 sp<Thread> pt(new ProducerThread(mANW));
1033 pt->run();
1034
1035 fw->waitForFrame();
1036 fw->waitForFrame();
1037
1038 // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
1039 // block waiting for a buffer to become available.
1040 usleep(100000);
1041
1042 mST->abandon();
1043
1044 pt->requestExitAndWait();
1045 ASSERT_EQ(NO_INIT,
1046 reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
1047}
1048
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001049TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
1050 int texHeight = 16;
1051 ANativeWindowBuffer* anb;
1052
1053 GLint maxTextureSize;
1054 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1055
1056 // make sure it works with small textures
1057 mST->setDefaultBufferSize(16, texHeight);
1058 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1059 EXPECT_EQ(16, anb->width);
1060 EXPECT_EQ(texHeight, anb->height);
1061 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1062 EXPECT_EQ(NO_ERROR, mST->updateTexImage());
1063
1064 // make sure it works with GL_MAX_TEXTURE_SIZE
1065 mST->setDefaultBufferSize(maxTextureSize, texHeight);
1066 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1067 EXPECT_EQ(maxTextureSize, anb->width);
1068 EXPECT_EQ(texHeight, anb->height);
1069 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1070 EXPECT_EQ(NO_ERROR, mST->updateTexImage());
1071
1072 // make sure it fails with GL_MAX_TEXTURE_SIZE+1
1073 mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
1074 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1075 EXPECT_EQ(maxTextureSize+1, anb->width);
1076 EXPECT_EQ(texHeight, anb->height);
1077 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1078 ASSERT_NE(NO_ERROR, mST->updateTexImage());
1079}
1080
Jamie Gennis5451d152011-06-08 09:40:45 -07001081/*
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001082 * This test fixture is for testing GL -> GL texture streaming. It creates an
1083 * EGLSurface and an EGLContext for the image producer to use.
1084 */
1085class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
1086protected:
1087 SurfaceTextureGLToGLTest():
1088 mProducerEglSurface(EGL_NO_SURFACE),
1089 mProducerEglContext(EGL_NO_CONTEXT) {
1090 }
1091
1092 virtual void SetUp() {
1093 SurfaceTextureGLTest::SetUp();
1094
Jamie Gennisce561372012-03-19 18:33:05 -07001095 mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001096 mANW.get(), NULL);
1097 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1098 ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
1099
Jamie Gennisce561372012-03-19 18:33:05 -07001100 mProducerEglContext = eglCreateContext(mEglDisplay, mGlConfig,
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001101 EGL_NO_CONTEXT, getContextAttribs());
1102 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1103 ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
1104 }
1105
1106 virtual void TearDown() {
1107 if (mProducerEglContext != EGL_NO_CONTEXT) {
1108 eglDestroyContext(mEglDisplay, mProducerEglContext);
1109 }
1110 if (mProducerEglSurface != EGL_NO_SURFACE) {
1111 eglDestroySurface(mEglDisplay, mProducerEglSurface);
1112 }
1113 SurfaceTextureGLTest::TearDown();
1114 }
1115
1116 EGLSurface mProducerEglSurface;
1117 EGLContext mProducerEglContext;
1118};
1119
1120TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
1121 const int texWidth = 64;
1122 const int texHeight = 64;
1123
1124 mST->setDefaultBufferSize(texWidth, texHeight);
1125
1126 // Do the producer side of things
1127 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1128 mProducerEglSurface, mProducerEglContext));
1129 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1130
1131 // This is needed to ensure we pick up a buffer of the correct size.
1132 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1133
1134 glClearColor(0.6, 0.6, 0.6, 0.6);
1135 glClear(GL_COLOR_BUFFER_BIT);
1136
1137 glEnable(GL_SCISSOR_TEST);
1138 glScissor(4, 4, 4, 4);
1139 glClearColor(1.0, 0.0, 0.0, 1.0);
1140 glClear(GL_COLOR_BUFFER_BIT);
1141
1142 glScissor(24, 48, 4, 4);
1143 glClearColor(0.0, 1.0, 0.0, 1.0);
1144 glClear(GL_COLOR_BUFFER_BIT);
1145
1146 glScissor(37, 17, 4, 4);
1147 glClearColor(0.0, 0.0, 1.0, 1.0);
1148 glClear(GL_COLOR_BUFFER_BIT);
1149
1150 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1151
1152 // Do the consumer side of things
1153 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1154 mEglContext));
1155 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1156
1157 glDisable(GL_SCISSOR_TEST);
1158
1159 mST->updateTexImage(); // Skip the first frame, which was empty
1160 mST->updateTexImage();
1161
1162 glClearColor(0.2, 0.2, 0.2, 0.2);
1163 glClear(GL_COLOR_BUFFER_BIT);
1164
1165 glViewport(0, 0, texWidth, texHeight);
1166 drawTexture();
1167
1168 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
1169 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
1170 EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
1171 EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
1172
1173 EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255));
1174 EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255));
1175 EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255));
1176 EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
1177 EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
1178 EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153));
1179 EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153));
1180 EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
1181 EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
1182 EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
1183 EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
1184 EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
1185 EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
1186 EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
1187 EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
1188 EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
1189}
1190
1191TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001192 sp<GraphicBuffer> buffers[2];
1193
1194 sp<FrameWaiter> fw(new FrameWaiter);
1195 mST->setFrameAvailableListener(fw);
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001196
Jamie Gennise3603d72011-11-19 21:20:17 -08001197 // This test requires async mode to run on a single thread.
1198 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1199 mProducerEglSurface, mProducerEglContext));
1200 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1201 EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
1202 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1203
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001204 for (int i = 0; i < 2; i++) {
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001205 // Produce a frame
1206 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1207 mProducerEglSurface, mProducerEglContext));
1208 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1209 glClear(GL_COLOR_BUFFER_BIT);
1210 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1211
1212 // Consume a frame
1213 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1214 mEglContext));
1215 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001216 fw->waitForFrame();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001217 mST->updateTexImage();
1218 buffers[i] = mST->getCurrentBuffer();
1219 }
1220
1221 // Destroy the GL texture object to release its ref on buffers[2].
1222 GLuint texID = TEX_ID;
1223 glDeleteTextures(1, &texID);
1224
1225 // Destroy the EGLSurface
1226 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
1227 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001228 mProducerEglSurface = EGL_NO_SURFACE;
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001229
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001230 // This test should have the only reference to buffer 0.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001231 EXPECT_EQ(1, buffers[0]->getStrongCount());
Jamie Gennise3603d72011-11-19 21:20:17 -08001232
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001233 // The SurfaceTexture should hold a single reference to buffer 1 in its
1234 // mCurrentBuffer member. All of the references in the slots should have
1235 // been released.
1236 EXPECT_EQ(2, buffers[1]->getStrongCount());
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001237}
1238
1239TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
1240 sp<GraphicBuffer> buffers[3];
1241
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001242 sp<FrameWaiter> fw(new FrameWaiter);
1243 mST->setFrameAvailableListener(fw);
1244
Jamie Gennise3603d72011-11-19 21:20:17 -08001245 // This test requires async mode to run on a single thread.
1246 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1247 mProducerEglSurface, mProducerEglContext));
1248 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1249 EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
1250 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1251
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001252 for (int i = 0; i < 3; i++) {
1253 // Produce a frame
1254 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1255 mProducerEglSurface, mProducerEglContext));
1256 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1257 glClear(GL_COLOR_BUFFER_BIT);
1258 EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
1259 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1260
1261 // Consume a frame
1262 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1263 mEglContext));
1264 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001265 fw->waitForFrame();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001266 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1267 buffers[i] = mST->getCurrentBuffer();
1268 }
1269
1270 // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
1271 // on buffers[2].
1272 mST->abandon();
1273
1274 // Destroy the GL texture object to release its ref on buffers[2].
1275 GLuint texID = TEX_ID;
1276 glDeleteTextures(1, &texID);
1277
1278 // Destroy the EGLSurface.
1279 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
1280 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001281 mProducerEglSurface = EGL_NO_SURFACE;
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001282
1283 EXPECT_EQ(1, buffers[0]->getStrongCount());
1284 EXPECT_EQ(1, buffers[1]->getStrongCount());
Jamie Gennise3603d72011-11-19 21:20:17 -08001285
1286 // Depending on how lazily the GL driver dequeues buffers, we may end up
1287 // with either two or three total buffers. If there are three, make sure
1288 // the last one was properly down-ref'd.
1289 if (buffers[2] != buffers[0]) {
1290 EXPECT_EQ(1, buffers[2]->getStrongCount());
1291 }
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001292}
1293
Jamie Gennis59769462011-11-19 18:04:43 -08001294TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
1295 // This test requires 3 buffers to run on a single thread.
1296 mST->setBufferCountServer(3);
1297
1298 ASSERT_TRUE(mST->isSynchronousMode());
1299
1300 for (int i = 0; i < 10; i++) {
1301 // Produce a frame
1302 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1303 mProducerEglSurface, mProducerEglContext));
1304 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1305 glClear(GL_COLOR_BUFFER_BIT);
1306 EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
1307 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1308
1309 // Consume a frame
1310 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1311 mEglContext));
1312 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1313 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1314 }
1315
1316 ASSERT_TRUE(mST->isSynchronousMode());
1317}
1318
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001319/*
1320 * This test fixture is for testing GL -> GL texture streaming from one thread
1321 * to another. It contains functionality to create a producer thread that will
1322 * perform GL rendering to an ANativeWindow that feeds frames to a
1323 * SurfaceTexture. Additionally it supports interlocking the producer and
1324 * consumer threads so that a specific sequence of calls can be
1325 * deterministically created by the test.
Jamie Gennis5451d152011-06-08 09:40:45 -07001326 *
1327 * The intended usage is as follows:
1328 *
1329 * TEST_F(...) {
1330 * class PT : public ProducerThread {
1331 * virtual void render() {
1332 * ...
1333 * swapBuffers();
1334 * }
1335 * };
1336 *
1337 * runProducerThread(new PT());
1338 *
1339 * // The order of these calls will vary from test to test and may include
1340 * // multiple frames and additional operations (e.g. GL rendering from the
1341 * // texture).
1342 * fc->waitForFrame();
1343 * mST->updateTexImage();
1344 * fc->finishFrame();
1345 * }
1346 *
1347 */
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001348class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
Jamie Gennis5451d152011-06-08 09:40:45 -07001349protected:
1350
1351 // ProducerThread is an abstract base class to simplify the creation of
1352 // OpenGL ES frame producer threads.
1353 class ProducerThread : public Thread {
1354 public:
1355 virtual ~ProducerThread() {
1356 }
1357
1358 void setEglObjects(EGLDisplay producerEglDisplay,
1359 EGLSurface producerEglSurface,
1360 EGLContext producerEglContext) {
1361 mProducerEglDisplay = producerEglDisplay;
1362 mProducerEglSurface = producerEglSurface;
1363 mProducerEglContext = producerEglContext;
1364 }
1365
1366 virtual bool threadLoop() {
1367 eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
1368 mProducerEglSurface, mProducerEglContext);
1369 render();
1370 eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
1371 EGL_NO_CONTEXT);
1372 return false;
1373 }
1374
1375 protected:
1376 virtual void render() = 0;
1377
1378 void swapBuffers() {
1379 eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
1380 }
1381
1382 EGLDisplay mProducerEglDisplay;
1383 EGLSurface mProducerEglSurface;
1384 EGLContext mProducerEglContext;
1385 };
1386
1387 // FrameCondition is a utility class for interlocking between the producer
1388 // and consumer threads. The FrameCondition object should be created and
1389 // destroyed in the consumer thread only. The consumer thread should set
1390 // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
1391 // and should call both waitForFrame and finishFrame once for each expected
1392 // frame.
1393 //
1394 // This interlocking relies on the fact that onFrameAvailable gets called
1395 // synchronously from SurfaceTexture::queueBuffer.
1396 class FrameCondition : public SurfaceTexture::FrameAvailableListener {
1397 public:
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001398 FrameCondition():
1399 mFrameAvailable(false),
1400 mFrameFinished(false) {
1401 }
1402
Jamie Gennis5451d152011-06-08 09:40:45 -07001403 // waitForFrame waits for the next frame to arrive. This should be
1404 // called from the consumer thread once for every frame expected by the
1405 // test.
1406 void waitForFrame() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001407 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001408 ALOGV("+waitForFrame");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001409 while (!mFrameAvailable) {
1410 mFrameAvailableCondition.wait(mMutex);
1411 }
1412 mFrameAvailable = false;
Steve Block6807e592011-10-20 11:56:00 +01001413 ALOGV("-waitForFrame");
Jamie Gennis5451d152011-06-08 09:40:45 -07001414 }
1415
1416 // Allow the producer to return from its swapBuffers call and continue
1417 // on to produce the next frame. This should be called by the consumer
1418 // thread once for every frame expected by the test.
1419 void finishFrame() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001420 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001421 ALOGV("+finishFrame");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001422 mFrameFinished = true;
Jamie Gennis5451d152011-06-08 09:40:45 -07001423 mFrameFinishCondition.signal();
Steve Block6807e592011-10-20 11:56:00 +01001424 ALOGV("-finishFrame");
Jamie Gennis5451d152011-06-08 09:40:45 -07001425 }
1426
1427 // This should be called by SurfaceTexture on the producer thread.
1428 virtual void onFrameAvailable() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001429 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001430 ALOGV("+onFrameAvailable");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001431 mFrameAvailable = true;
Jamie Gennis5451d152011-06-08 09:40:45 -07001432 mFrameAvailableCondition.signal();
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001433 while (!mFrameFinished) {
1434 mFrameFinishCondition.wait(mMutex);
1435 }
1436 mFrameFinished = false;
Steve Block6807e592011-10-20 11:56:00 +01001437 ALOGV("-onFrameAvailable");
Jamie Gennis5451d152011-06-08 09:40:45 -07001438 }
1439
1440 protected:
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001441 bool mFrameAvailable;
1442 bool mFrameFinished;
1443
Jamie Gennis5451d152011-06-08 09:40:45 -07001444 Mutex mMutex;
1445 Condition mFrameAvailableCondition;
1446 Condition mFrameFinishCondition;
1447 };
1448
Jamie Gennis5451d152011-06-08 09:40:45 -07001449 virtual void SetUp() {
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001450 SurfaceTextureGLToGLTest::SetUp();
Jamie Gennis5451d152011-06-08 09:40:45 -07001451 mFC = new FrameCondition();
1452 mST->setFrameAvailableListener(mFC);
1453 }
1454
1455 virtual void TearDown() {
1456 if (mProducerThread != NULL) {
1457 mProducerThread->requestExitAndWait();
1458 }
Jamie Gennis5451d152011-06-08 09:40:45 -07001459 mProducerThread.clear();
1460 mFC.clear();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001461 SurfaceTextureGLToGLTest::TearDown();
Jamie Gennis5451d152011-06-08 09:40:45 -07001462 }
1463
1464 void runProducerThread(const sp<ProducerThread> producerThread) {
1465 ASSERT_TRUE(mProducerThread == NULL);
1466 mProducerThread = producerThread;
1467 producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
1468 mProducerEglContext);
1469 producerThread->run();
1470 }
1471
Jamie Gennis5451d152011-06-08 09:40:45 -07001472 sp<ProducerThread> mProducerThread;
1473 sp<FrameCondition> mFC;
1474};
1475
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001476TEST_F(SurfaceTextureGLThreadToGLTest,
1477 UpdateTexImageBeforeFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001478 class PT : public ProducerThread {
1479 virtual void render() {
1480 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1481 glClear(GL_COLOR_BUFFER_BIT);
1482 swapBuffers();
1483 }
1484 };
1485
1486 runProducerThread(new PT());
1487
1488 mFC->waitForFrame();
1489 mST->updateTexImage();
1490 mFC->finishFrame();
1491
1492 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
Jamie Gennisd99c0882011-03-10 16:24:46 -08001493}
Jamie Gennis5451d152011-06-08 09:40:45 -07001494
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001495TEST_F(SurfaceTextureGLThreadToGLTest,
1496 UpdateTexImageAfterFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001497 class PT : public ProducerThread {
1498 virtual void render() {
1499 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1500 glClear(GL_COLOR_BUFFER_BIT);
1501 swapBuffers();
1502 }
1503 };
1504
1505 runProducerThread(new PT());
1506
1507 mFC->waitForFrame();
1508 mFC->finishFrame();
1509 mST->updateTexImage();
1510
1511 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1512}
1513
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001514TEST_F(SurfaceTextureGLThreadToGLTest,
1515 RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001516 enum { NUM_ITERATIONS = 1024 };
1517
1518 class PT : public ProducerThread {
1519 virtual void render() {
1520 for (int i = 0; i < NUM_ITERATIONS; i++) {
1521 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1522 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001523 ALOGV("+swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001524 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001525 ALOGV("-swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001526 }
1527 }
1528 };
1529
1530 runProducerThread(new PT());
1531
1532 for (int i = 0; i < NUM_ITERATIONS; i++) {
1533 mFC->waitForFrame();
Steve Block6807e592011-10-20 11:56:00 +01001534 ALOGV("+updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001535 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001536 ALOGV("-updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001537 mFC->finishFrame();
1538
1539 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1540 }
1541}
1542
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001543TEST_F(SurfaceTextureGLThreadToGLTest,
1544 RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001545 enum { NUM_ITERATIONS = 1024 };
1546
1547 class PT : public ProducerThread {
1548 virtual void render() {
1549 for (int i = 0; i < NUM_ITERATIONS; i++) {
1550 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1551 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001552 ALOGV("+swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001553 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001554 ALOGV("-swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001555 }
1556 }
1557 };
1558
1559 runProducerThread(new PT());
1560
1561 for (int i = 0; i < NUM_ITERATIONS; i++) {
1562 mFC->waitForFrame();
1563 mFC->finishFrame();
Steve Block6807e592011-10-20 11:56:00 +01001564 ALOGV("+updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001565 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001566 ALOGV("-updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001567
1568 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1569 }
1570}
1571
Jamie Gennis6e502192011-07-21 14:31:31 -07001572// XXX: This test is disabled because it is currently hanging on some devices.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001573TEST_F(SurfaceTextureGLThreadToGLTest,
1574 DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
Jamie Gennis6e502192011-07-21 14:31:31 -07001575 enum { NUM_ITERATIONS = 64 };
1576
1577 class PT : public ProducerThread {
1578 virtual void render() {
1579 for (int i = 0; i < NUM_ITERATIONS; i++) {
1580 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1581 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001582 ALOGV("+swapBuffers");
Jamie Gennis6e502192011-07-21 14:31:31 -07001583 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001584 ALOGV("-swapBuffers");
Jamie Gennis6e502192011-07-21 14:31:31 -07001585 }
1586 }
1587 };
1588
1589 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1590 ASSERT_EQ(OK, mST->setBufferCountServer(2));
1591
1592 runProducerThread(new PT());
1593
1594 // Allow three frames to be rendered and queued before starting the
1595 // rendering in this thread. For the latter two frames we don't call
1596 // updateTexImage so the next dequeue from the producer thread will block
1597 // waiting for a frame to become available.
1598 mFC->waitForFrame();
1599 mFC->finishFrame();
1600
1601 // We must call updateTexImage to consume the first frame so that the
1602 // SurfaceTexture is able to reduce the buffer count to 2. This is because
1603 // the GL driver may dequeue a buffer when the EGLSurface is created, and
1604 // that happens before we call setBufferCountServer. It's possible that the
1605 // driver does not dequeue a buffer at EGLSurface creation time, so we
1606 // cannot rely on this to cause the second dequeueBuffer call to block.
1607 mST->updateTexImage();
1608
1609 mFC->waitForFrame();
1610 mFC->finishFrame();
1611 mFC->waitForFrame();
1612 mFC->finishFrame();
1613
1614 // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
1615 // block waiting for a buffer to become available.
1616 usleep(100000);
1617
1618 // Render and present a number of images. This thread should not be blocked
1619 // by the fact that the producer thread is blocking in dequeue.
1620 for (int i = 0; i < NUM_ITERATIONS; i++) {
1621 glClear(GL_COLOR_BUFFER_BIT);
1622 eglSwapBuffers(mEglDisplay, mEglSurface);
1623 }
1624
1625 // Consume the two pending buffers to unblock the producer thread.
1626 mST->updateTexImage();
1627 mST->updateTexImage();
1628
1629 // Consume the remaining buffers from the producer thread.
1630 for (int i = 0; i < NUM_ITERATIONS-3; i++) {
1631 mFC->waitForFrame();
1632 mFC->finishFrame();
Steve Block6807e592011-10-20 11:56:00 +01001633 ALOGV("+updateTexImage");
Jamie Gennis6e502192011-07-21 14:31:31 -07001634 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001635 ALOGV("-updateTexImage");
Jamie Gennis6e502192011-07-21 14:31:31 -07001636 }
1637}
1638
Jamie Gennisfe27e2f2011-11-11 18:05:11 -08001639class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
1640protected:
1641
1642 virtual void SetUp() {
1643 SurfaceTextureGLTest::SetUp();
1644
1645 glGenFramebuffers(1, &mFbo);
1646 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1647
1648 glGenTextures(1, &mFboTex);
1649 glBindTexture(GL_TEXTURE_2D, mFboTex);
1650 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
1651 getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1652 glBindTexture(GL_TEXTURE_2D, 0);
1653 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1654
1655 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1656 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1657 GL_TEXTURE_2D, mFboTex, 0);
1658 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1659 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1660 }
1661
1662 virtual void TearDown() {
1663 SurfaceTextureGLTest::TearDown();
1664
1665 glDeleteTextures(1, &mFboTex);
1666 glDeleteFramebuffers(1, &mFbo);
1667 }
1668
1669 GLuint mFbo;
1670 GLuint mFboTex;
1671};
1672
1673// This test is intended to verify that proper synchronization is done when
1674// rendering into an FBO.
1675TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
1676 const int texWidth = 64;
1677 const int texHeight = 64;
1678
1679 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
1680 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
1681 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
1682 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
1683
1684 android_native_buffer_t* anb;
1685 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1686 ASSERT_TRUE(anb != NULL);
1687
1688 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
1689 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
1690
1691 // Fill the buffer with green
1692 uint8_t* img = NULL;
1693 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
1694 fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
1695 0, 255);
1696 buf->unlock();
1697 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
1698
1699 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1700
1701 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1702 drawTexture();
1703 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1704
1705 for (int i = 0; i < 4; i++) {
1706 SCOPED_TRACE(String8::format("frame %d", i).string());
1707
1708 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1709 ASSERT_TRUE(anb != NULL);
1710
1711 buf = new GraphicBuffer(anb, false);
1712 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
1713 buf->getNativeBuffer()));
1714
1715 // Fill the buffer with red
1716 ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
1717 (void**)(&img)));
1718 fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0,
1719 0, 255);
1720 ASSERT_EQ(NO_ERROR, buf->unlock());
1721 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
1722 buf->getNativeBuffer()));
1723
1724 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1725
1726 drawTexture();
1727
1728 EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
1729 }
1730
1731 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1732
1733 EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
1734}
1735
Jamie Gennisce561372012-03-19 18:33:05 -07001736class SurfaceTextureMultiContextGLTest : public SurfaceTextureGLTest {
1737protected:
1738 SurfaceTextureMultiContextGLTest():
1739 mSecondEglContext(EGL_NO_CONTEXT) {
1740 }
1741
1742 virtual void SetUp() {
1743 SurfaceTextureGLTest::SetUp();
1744
1745 mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig,
1746 EGL_NO_CONTEXT, getContextAttribs());
1747 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1748 ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext);
1749 }
1750
1751 virtual void TearDown() {
1752 if (mSecondEglContext != EGL_NO_CONTEXT) {
1753 eglDestroyContext(mEglDisplay, mSecondEglContext);
1754 }
1755 SurfaceTextureGLTest::TearDown();
1756 }
1757
1758 EGLContext mSecondEglContext;
1759};
1760
1761TEST_F(SurfaceTextureMultiContextGLTest, UpdateFromMultipleContextsFails) {
1762 sp<FrameWaiter> fw(new FrameWaiter);
1763 mST->setFrameAvailableListener(fw);
1764
1765 ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
1766
1767 // Latch the texture contents on the primary context.
1768 mST->updateTexImage();
1769
1770 // Attempt to latch the texture on the secondary context.
1771 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1772 mSecondEglContext));
1773 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1774 ASSERT_EQ(-EINVAL, mST->updateTexImage());
1775}
1776
Jamie Gennis5451d152011-06-08 09:40:45 -07001777} // namespace android