blob: 71cf57712e5e5bc74d993e860c6f424254945ddf [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 Gennisd99c0882011-03-10 16:24:46 -0800563TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700564 const int texWidth = 64;
565 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800566
567 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700568 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800569 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
570 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
571
Iliyan Malchev697526b2011-05-01 11:33:26 -0700572 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800573 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
574 ASSERT_TRUE(anb != NULL);
575
576 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
577 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
578
579 // Fill the buffer with the a checkerboard pattern
580 uint8_t* img = NULL;
581 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700582 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800583 buf->unlock();
584 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
585
586 mST->updateTexImage();
587
588 glClearColor(0.2, 0.2, 0.2, 0.2);
589 glClear(GL_COLOR_BUFFER_BIT);
590
Jamie Gennisc8c51522011-06-15 14:24:38 -0700591 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800592 drawTexture();
593
594 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
595 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700596 EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255));
597 EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800598
Jamie Gennisc8c51522011-06-15 14:24:38 -0700599 EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
600 EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
601 EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800602 EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700603 EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800604 EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
605 EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
606}
607
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700608TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700609 const int texWidth = 64;
610 const int texHeight = 64;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800611
612 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700613 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800614 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
615 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
616
Iliyan Malchev697526b2011-05-01 11:33:26 -0700617 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800618 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
619 ASSERT_TRUE(anb != NULL);
620
621 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
622 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
623
624 // Fill the buffer with the a checkerboard pattern
625 uint8_t* img = NULL;
626 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700627 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800628 buf->unlock();
629 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
630
631 mST->updateTexImage();
632
633 glClearColor(0.2, 0.2, 0.2, 0.2);
634 glClear(GL_COLOR_BUFFER_BIT);
635
Jamie Gennisc8c51522011-06-15 14:24:38 -0700636 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800637 drawTexture();
638
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700639 EXPECT_TRUE(checkPixel( 0, 0, 0, 133, 0, 255));
640 EXPECT_TRUE(checkPixel(63, 0, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800641 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
642 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
643
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700644 EXPECT_TRUE(checkPixel(22, 19, 100, 255, 74, 255));
645 EXPECT_TRUE(checkPixel(45, 11, 100, 255, 74, 255));
646 EXPECT_TRUE(checkPixel(52, 12, 155, 0, 181, 255));
647 EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
648 EXPECT_TRUE(checkPixel(31, 54, 0, 71, 117, 255));
649 EXPECT_TRUE(checkPixel(29, 28, 0, 133, 0, 255));
650 EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800651}
652
653TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700654 const int texWidth = 64;
655 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800656
657 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700658 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800659 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
660 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
661
662 android_native_rect_t crops[] = {
663 {4, 6, 22, 36},
664 {0, 6, 22, 36},
665 {4, 0, 22, 36},
Jamie Gennis1876d132011-03-17 16:32:52 -0700666 {4, 6, texWidth, 36},
667 {4, 6, 22, texHeight},
Jamie Gennisd99c0882011-03-10 16:24:46 -0800668 };
669
670 for (int i = 0; i < 5; i++) {
671 const android_native_rect_t& crop(crops[i]);
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800672 SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }",
673 crop.left, crop.top, crop.right, crop.bottom).string());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800674
675 ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
676
Iliyan Malchev697526b2011-05-01 11:33:26 -0700677 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800678 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
679 ASSERT_TRUE(anb != NULL);
680
681 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800682 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
683 buf->getNativeBuffer()));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800684
685 uint8_t* img = NULL;
686 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700687 fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800688 buf->unlock();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800689 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
690 buf->getNativeBuffer()));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800691
692 mST->updateTexImage();
693
694 glClearColor(0.2, 0.2, 0.2, 0.2);
695 glClear(GL_COLOR_BUFFER_BIT);
696
Jamie Gennisc8c51522011-06-15 14:24:38 -0700697 glViewport(0, 0, 64, 64);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800698 drawTexture();
699
700 EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
701 EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255));
702 EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255));
703 EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255));
704
705 EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255));
706 EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255));
707 EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255));
708 EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255));
709 EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255));
710 EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255));
711 EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255));
712 }
713}
714
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700715// This test is intended to catch synchronization bugs between the CPU-written
716// and GPU-read buffers.
717TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
718 enum { texWidth = 16 };
719 enum { texHeight = 16 };
720 enum { numFrames = 1024 };
721
722 ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
723 ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
724 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
725 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
726 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
727 GRALLOC_USAGE_SW_WRITE_OFTEN));
728
729 struct TestPixel {
730 int x;
731 int y;
732 };
733 const TestPixel testPixels[] = {
734 { 4, 11 },
735 { 12, 14 },
736 { 7, 2 },
737 };
738 enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])};
739
740 class ProducerThread : public Thread {
741 public:
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -0800742 ProducerThread(const sp<ANativeWindow>& anw,
743 const TestPixel* testPixels):
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700744 mANW(anw),
745 mTestPixels(testPixels) {
746 }
747
748 virtual ~ProducerThread() {
749 }
750
751 virtual bool threadLoop() {
752 for (int i = 0; i < numFrames; i++) {
753 ANativeWindowBuffer* anb;
754 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
755 return false;
756 }
757 if (anb == NULL) {
758 return false;
759 }
760
761 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
762 if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
763 != NO_ERROR) {
764 return false;
765 }
766
767 const int yuvTexOffsetY = 0;
768 int stride = buf->getStride();
769 int yuvTexStrideY = stride;
770 int yuvTexOffsetV = yuvTexStrideY * texHeight;
771 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
772 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
773 int yuvTexStrideU = yuvTexStrideV;
774
775 uint8_t* img = NULL;
776 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
777
778 // Gray out all the test pixels first, so we're more likely to
779 // see a failure if GL is still texturing from the buffer we
780 // just dequeued.
781 for (int j = 0; j < numTestPixels; j++) {
782 int x = mTestPixels[j].x;
783 int y = mTestPixels[j].y;
784 uint8_t value = 128;
785 img[y*stride + x] = value;
786 }
787
788 // Fill the buffer with gray.
789 for (int y = 0; y < texHeight; y++) {
790 for (int x = 0; x < texWidth; x++) {
791 img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128;
792 img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128;
793 img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128;
794 }
795 }
796
797 // Set the test pixels to either white or black.
798 for (int j = 0; j < numTestPixels; j++) {
799 int x = mTestPixels[j].x;
800 int y = mTestPixels[j].y;
801 uint8_t value = 0;
802 if (j == (i % numTestPixels)) {
803 value = 255;
804 }
805 img[y*stride + x] = value;
806 }
807
808 buf->unlock();
809 if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
810 != NO_ERROR) {
811 return false;
812 }
813 }
814 return false;
815 }
816
817 sp<ANativeWindow> mANW;
818 const TestPixel* mTestPixels;
819 };
820
821 sp<FrameWaiter> fw(new FrameWaiter);
822 mST->setFrameAvailableListener(fw);
823
824 sp<Thread> pt(new ProducerThread(mANW, testPixels));
825 pt->run();
826
827 glViewport(0, 0, texWidth, texHeight);
828
829 glClearColor(0.2, 0.2, 0.2, 0.2);
830 glClear(GL_COLOR_BUFFER_BIT);
831
832 // We wait for the first two frames up front so that the producer will be
833 // likely to dequeue the buffer that's currently being textured from.
834 fw->waitForFrame();
835 fw->waitForFrame();
836
837 for (int i = 0; i < numFrames; i++) {
838 SCOPED_TRACE(String8::format("frame %d", i).string());
839
840 // We must wait for each frame to come in because if we ever do an
841 // updateTexImage call that doesn't consume a newly available buffer
842 // then the producer and consumer will get out of sync, which will cause
843 // a deadlock.
844 if (i > 1) {
845 fw->waitForFrame();
846 }
847 mST->updateTexImage();
848 drawTexture();
849
850 for (int j = 0; j < numTestPixels; j++) {
851 int x = testPixels[j].x;
852 int y = testPixels[j].y;
853 uint8_t value = 0;
854 if (j == (i % numTestPixels)) {
855 // We must y-invert the texture coords
856 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
857 } else {
858 // We must y-invert the texture coords
859 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255));
860 }
861 }
862 }
863
864 pt->requestExitAndWait();
865}
866
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700867TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700868 const int texWidth = 64;
869 const int texHeight = 66;
870
871 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
872 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
873 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
874 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
875
876 android_native_buffer_t* anb;
877 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
878 ASSERT_TRUE(anb != NULL);
879
880 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
881 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
882
883 // Fill the buffer with the a checkerboard pattern
884 uint8_t* img = NULL;
885 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
886 fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
887 buf->unlock();
888 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
889
890 mST->updateTexImage();
891
892 glClearColor(0.2, 0.2, 0.2, 0.2);
893 glClear(GL_COLOR_BUFFER_BIT);
894
Jamie Gennisc8c51522011-06-15 14:24:38 -0700895 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700896 drawTexture();
897
898 EXPECT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
899 EXPECT_TRUE(checkPixel(63, 0, 231, 231, 231, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700900 EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
901 EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700902
903 EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700904 EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700905 EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700906 EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
907 EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700908 EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700909 EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700910 EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231));
911 EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35));
912 EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700913 EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700914 EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
915 EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700916 EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700917 EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700918 EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
919}
920
Jamie Gennis1f8e09f2011-07-19 17:58:43 -0700921TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700922 const int texWidth = 64;
923 const int texHeight = 64;
924
925 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
926 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
927 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
928 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
929
930 android_native_buffer_t* anb;
931 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
932 ASSERT_TRUE(anb != NULL);
933
934 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
935 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
936
937 // Fill the buffer with the a checkerboard pattern
938 uint8_t* img = NULL;
939 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
940 fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
941 buf->unlock();
942 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
943
944 mST->updateTexImage();
945
946 glClearColor(0.2, 0.2, 0.2, 0.2);
947 glClear(GL_COLOR_BUFFER_BIT);
948
Jamie Gennisc8c51522011-06-15 14:24:38 -0700949 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700950 drawTexture();
951
952 EXPECT_TRUE(checkPixel( 0, 0, 231, 231, 231, 231));
953 EXPECT_TRUE(checkPixel(63, 0, 35, 35, 35, 35));
954 EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
955 EXPECT_TRUE(checkPixel( 0, 63, 35, 35, 35, 35));
956
957 EXPECT_TRUE(checkPixel(12, 46, 231, 231, 231, 35));
958 EXPECT_TRUE(checkPixel(16, 1, 231, 231, 35, 231));
959 EXPECT_TRUE(checkPixel(21, 12, 231, 35, 35, 231));
960 EXPECT_TRUE(checkPixel(26, 51, 231, 35, 231, 35));
961 EXPECT_TRUE(checkPixel( 5, 32, 35, 231, 231, 35));
962 EXPECT_TRUE(checkPixel(13, 8, 35, 231, 231, 231));
963 EXPECT_TRUE(checkPixel(46, 3, 35, 35, 231, 35));
964 EXPECT_TRUE(checkPixel(30, 33, 35, 35, 35, 35));
965 EXPECT_TRUE(checkPixel( 6, 52, 231, 231, 35, 35));
966 EXPECT_TRUE(checkPixel(55, 33, 35, 231, 35, 231));
967 EXPECT_TRUE(checkPixel(16, 29, 35, 35, 231, 231));
968 EXPECT_TRUE(checkPixel( 1, 30, 35, 35, 35, 231));
969 EXPECT_TRUE(checkPixel(41, 37, 35, 35, 231, 231));
970 EXPECT_TRUE(checkPixel(46, 29, 231, 231, 35, 35));
971 EXPECT_TRUE(checkPixel(15, 25, 35, 231, 35, 231));
972 EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
973}
974
Jamie Gennis7b305ff2011-07-19 12:08:33 -0700975TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
976 class ProducerThread : public Thread {
977 public:
978 ProducerThread(const sp<ANativeWindow>& anw):
979 mANW(anw),
980 mDequeueError(NO_ERROR) {
981 }
982
983 virtual ~ProducerThread() {
984 }
985
986 virtual bool threadLoop() {
987 Mutex::Autolock lock(mMutex);
988 ANativeWindowBuffer* anb;
989
990 // Frame 1
991 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
992 return false;
993 }
994 if (anb == NULL) {
995 return false;
996 }
997 if (mANW->queueBuffer(mANW.get(), anb)
998 != NO_ERROR) {
999 return false;
1000 }
1001
1002 // Frame 2
1003 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
1004 return false;
1005 }
1006 if (anb == NULL) {
1007 return false;
1008 }
1009 if (mANW->queueBuffer(mANW.get(), anb)
1010 != NO_ERROR) {
1011 return false;
1012 }
1013
1014 // Frame 3 - error expected
1015 mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
1016 return false;
1017 }
1018
1019 status_t getDequeueError() {
1020 Mutex::Autolock lock(mMutex);
1021 return mDequeueError;
1022 }
1023
1024 private:
1025 sp<ANativeWindow> mANW;
1026 status_t mDequeueError;
1027 Mutex mMutex;
1028 };
1029
1030 sp<FrameWaiter> fw(new FrameWaiter);
1031 mST->setFrameAvailableListener(fw);
1032 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1033 ASSERT_EQ(OK, mST->setBufferCountServer(2));
1034
1035 sp<Thread> pt(new ProducerThread(mANW));
1036 pt->run();
1037
1038 fw->waitForFrame();
1039 fw->waitForFrame();
1040
1041 // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
1042 // block waiting for a buffer to become available.
1043 usleep(100000);
1044
1045 mST->abandon();
1046
1047 pt->requestExitAndWait();
1048 ASSERT_EQ(NO_INIT,
1049 reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
1050}
1051
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001052TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
1053 int texHeight = 16;
1054 ANativeWindowBuffer* anb;
1055
1056 GLint maxTextureSize;
1057 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
1058
1059 // make sure it works with small textures
1060 mST->setDefaultBufferSize(16, texHeight);
1061 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1062 EXPECT_EQ(16, anb->width);
1063 EXPECT_EQ(texHeight, anb->height);
1064 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1065 EXPECT_EQ(NO_ERROR, mST->updateTexImage());
1066
1067 // make sure it works with GL_MAX_TEXTURE_SIZE
1068 mST->setDefaultBufferSize(maxTextureSize, texHeight);
1069 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1070 EXPECT_EQ(maxTextureSize, anb->width);
1071 EXPECT_EQ(texHeight, anb->height);
1072 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1073 EXPECT_EQ(NO_ERROR, mST->updateTexImage());
1074
1075 // make sure it fails with GL_MAX_TEXTURE_SIZE+1
1076 mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
1077 EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1078 EXPECT_EQ(maxTextureSize+1, anb->width);
1079 EXPECT_EQ(texHeight, anb->height);
1080 EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
1081 ASSERT_NE(NO_ERROR, mST->updateTexImage());
1082}
1083
Jamie Gennis5451d152011-06-08 09:40:45 -07001084/*
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001085 * This test fixture is for testing GL -> GL texture streaming. It creates an
1086 * EGLSurface and an EGLContext for the image producer to use.
1087 */
1088class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
1089protected:
1090 SurfaceTextureGLToGLTest():
1091 mProducerEglSurface(EGL_NO_SURFACE),
1092 mProducerEglContext(EGL_NO_CONTEXT) {
1093 }
1094
1095 virtual void SetUp() {
1096 SurfaceTextureGLTest::SetUp();
1097
1098 EGLConfig myConfig = {0};
1099 EGLint numConfigs = 0;
1100 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
1101 1, &numConfigs));
1102 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1103
1104 mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
1105 mANW.get(), NULL);
1106 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1107 ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
1108
1109 mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
1110 EGL_NO_CONTEXT, getContextAttribs());
1111 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1112 ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
1113 }
1114
1115 virtual void TearDown() {
1116 if (mProducerEglContext != EGL_NO_CONTEXT) {
1117 eglDestroyContext(mEglDisplay, mProducerEglContext);
1118 }
1119 if (mProducerEglSurface != EGL_NO_SURFACE) {
1120 eglDestroySurface(mEglDisplay, mProducerEglSurface);
1121 }
1122 SurfaceTextureGLTest::TearDown();
1123 }
1124
1125 EGLSurface mProducerEglSurface;
1126 EGLContext mProducerEglContext;
1127};
1128
1129TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
1130 const int texWidth = 64;
1131 const int texHeight = 64;
1132
1133 mST->setDefaultBufferSize(texWidth, texHeight);
1134
1135 // Do the producer side of things
1136 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1137 mProducerEglSurface, mProducerEglContext));
1138 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1139
1140 // This is needed to ensure we pick up a buffer of the correct size.
1141 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1142
1143 glClearColor(0.6, 0.6, 0.6, 0.6);
1144 glClear(GL_COLOR_BUFFER_BIT);
1145
1146 glEnable(GL_SCISSOR_TEST);
1147 glScissor(4, 4, 4, 4);
1148 glClearColor(1.0, 0.0, 0.0, 1.0);
1149 glClear(GL_COLOR_BUFFER_BIT);
1150
1151 glScissor(24, 48, 4, 4);
1152 glClearColor(0.0, 1.0, 0.0, 1.0);
1153 glClear(GL_COLOR_BUFFER_BIT);
1154
1155 glScissor(37, 17, 4, 4);
1156 glClearColor(0.0, 0.0, 1.0, 1.0);
1157 glClear(GL_COLOR_BUFFER_BIT);
1158
1159 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1160
1161 // Do the consumer side of things
1162 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1163 mEglContext));
1164 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1165
1166 glDisable(GL_SCISSOR_TEST);
1167
1168 mST->updateTexImage(); // Skip the first frame, which was empty
1169 mST->updateTexImage();
1170
1171 glClearColor(0.2, 0.2, 0.2, 0.2);
1172 glClear(GL_COLOR_BUFFER_BIT);
1173
1174 glViewport(0, 0, texWidth, texHeight);
1175 drawTexture();
1176
1177 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
1178 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
1179 EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
1180 EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
1181
1182 EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255));
1183 EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255));
1184 EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255));
1185 EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
1186 EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
1187 EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153));
1188 EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153));
1189 EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
1190 EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
1191 EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
1192 EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
1193 EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
1194 EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
1195 EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
1196 EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
1197 EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
1198}
1199
1200TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001201 sp<GraphicBuffer> buffers[2];
1202
1203 sp<FrameWaiter> fw(new FrameWaiter);
1204 mST->setFrameAvailableListener(fw);
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001205
Jamie Gennise3603d72011-11-19 21:20:17 -08001206 // This test requires async mode to run on a single thread.
1207 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1208 mProducerEglSurface, mProducerEglContext));
1209 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1210 EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
1211 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1212
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001213 for (int i = 0; i < 2; i++) {
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001214 // Produce a frame
1215 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1216 mProducerEglSurface, mProducerEglContext));
1217 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1218 glClear(GL_COLOR_BUFFER_BIT);
1219 eglSwapBuffers(mEglDisplay, mProducerEglSurface);
1220
1221 // Consume a frame
1222 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1223 mEglContext));
1224 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001225 fw->waitForFrame();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001226 mST->updateTexImage();
1227 buffers[i] = mST->getCurrentBuffer();
1228 }
1229
1230 // Destroy the GL texture object to release its ref on buffers[2].
1231 GLuint texID = TEX_ID;
1232 glDeleteTextures(1, &texID);
1233
1234 // Destroy the EGLSurface
1235 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
1236 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001237 mProducerEglSurface = EGL_NO_SURFACE;
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001238
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001239 // This test should have the only reference to buffer 0.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001240 EXPECT_EQ(1, buffers[0]->getStrongCount());
Jamie Gennise3603d72011-11-19 21:20:17 -08001241
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001242 // The SurfaceTexture should hold a single reference to buffer 1 in its
1243 // mCurrentBuffer member. All of the references in the slots should have
1244 // been released.
1245 EXPECT_EQ(2, buffers[1]->getStrongCount());
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001246}
1247
1248TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
1249 sp<GraphicBuffer> buffers[3];
1250
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001251 sp<FrameWaiter> fw(new FrameWaiter);
1252 mST->setFrameAvailableListener(fw);
1253
Jamie Gennise3603d72011-11-19 21:20:17 -08001254 // This test requires async mode to run on a single thread.
1255 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1256 mProducerEglSurface, mProducerEglContext));
1257 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1258 EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
1259 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1260
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001261 for (int i = 0; i < 3; i++) {
1262 // Produce a frame
1263 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1264 mProducerEglSurface, mProducerEglContext));
1265 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1266 glClear(GL_COLOR_BUFFER_BIT);
1267 EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
1268 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1269
1270 // Consume a frame
1271 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1272 mEglContext));
1273 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001274 fw->waitForFrame();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001275 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1276 buffers[i] = mST->getCurrentBuffer();
1277 }
1278
1279 // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
1280 // on buffers[2].
1281 mST->abandon();
1282
1283 // Destroy the GL texture object to release its ref on buffers[2].
1284 GLuint texID = TEX_ID;
1285 glDeleteTextures(1, &texID);
1286
1287 // Destroy the EGLSurface.
1288 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
1289 ASSERT_EQ(EGL_SUCCESS, eglGetError());
Jamie Gennisfa5b40e2012-03-15 14:01:24 -07001290 mProducerEglSurface = EGL_NO_SURFACE;
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001291
1292 EXPECT_EQ(1, buffers[0]->getStrongCount());
1293 EXPECT_EQ(1, buffers[1]->getStrongCount());
Jamie Gennise3603d72011-11-19 21:20:17 -08001294
1295 // Depending on how lazily the GL driver dequeues buffers, we may end up
1296 // with either two or three total buffers. If there are three, make sure
1297 // the last one was properly down-ref'd.
1298 if (buffers[2] != buffers[0]) {
1299 EXPECT_EQ(1, buffers[2]->getStrongCount());
1300 }
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001301}
1302
Jamie Gennis59769462011-11-19 18:04:43 -08001303TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
1304 // This test requires 3 buffers to run on a single thread.
1305 mST->setBufferCountServer(3);
1306
1307 ASSERT_TRUE(mST->isSynchronousMode());
1308
1309 for (int i = 0; i < 10; i++) {
1310 // Produce a frame
1311 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
1312 mProducerEglSurface, mProducerEglContext));
1313 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1314 glClear(GL_COLOR_BUFFER_BIT);
1315 EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
1316 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1317
1318 // Consume a frame
1319 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
1320 mEglContext));
1321 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1322 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1323 }
1324
1325 ASSERT_TRUE(mST->isSynchronousMode());
1326}
1327
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001328/*
1329 * This test fixture is for testing GL -> GL texture streaming from one thread
1330 * to another. It contains functionality to create a producer thread that will
1331 * perform GL rendering to an ANativeWindow that feeds frames to a
1332 * SurfaceTexture. Additionally it supports interlocking the producer and
1333 * consumer threads so that a specific sequence of calls can be
1334 * deterministically created by the test.
Jamie Gennis5451d152011-06-08 09:40:45 -07001335 *
1336 * The intended usage is as follows:
1337 *
1338 * TEST_F(...) {
1339 * class PT : public ProducerThread {
1340 * virtual void render() {
1341 * ...
1342 * swapBuffers();
1343 * }
1344 * };
1345 *
1346 * runProducerThread(new PT());
1347 *
1348 * // The order of these calls will vary from test to test and may include
1349 * // multiple frames and additional operations (e.g. GL rendering from the
1350 * // texture).
1351 * fc->waitForFrame();
1352 * mST->updateTexImage();
1353 * fc->finishFrame();
1354 * }
1355 *
1356 */
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001357class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
Jamie Gennis5451d152011-06-08 09:40:45 -07001358protected:
1359
1360 // ProducerThread is an abstract base class to simplify the creation of
1361 // OpenGL ES frame producer threads.
1362 class ProducerThread : public Thread {
1363 public:
1364 virtual ~ProducerThread() {
1365 }
1366
1367 void setEglObjects(EGLDisplay producerEglDisplay,
1368 EGLSurface producerEglSurface,
1369 EGLContext producerEglContext) {
1370 mProducerEglDisplay = producerEglDisplay;
1371 mProducerEglSurface = producerEglSurface;
1372 mProducerEglContext = producerEglContext;
1373 }
1374
1375 virtual bool threadLoop() {
1376 eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
1377 mProducerEglSurface, mProducerEglContext);
1378 render();
1379 eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
1380 EGL_NO_CONTEXT);
1381 return false;
1382 }
1383
1384 protected:
1385 virtual void render() = 0;
1386
1387 void swapBuffers() {
1388 eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
1389 }
1390
1391 EGLDisplay mProducerEglDisplay;
1392 EGLSurface mProducerEglSurface;
1393 EGLContext mProducerEglContext;
1394 };
1395
1396 // FrameCondition is a utility class for interlocking between the producer
1397 // and consumer threads. The FrameCondition object should be created and
1398 // destroyed in the consumer thread only. The consumer thread should set
1399 // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
1400 // and should call both waitForFrame and finishFrame once for each expected
1401 // frame.
1402 //
1403 // This interlocking relies on the fact that onFrameAvailable gets called
1404 // synchronously from SurfaceTexture::queueBuffer.
1405 class FrameCondition : public SurfaceTexture::FrameAvailableListener {
1406 public:
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001407 FrameCondition():
1408 mFrameAvailable(false),
1409 mFrameFinished(false) {
1410 }
1411
Jamie Gennis5451d152011-06-08 09:40:45 -07001412 // waitForFrame waits for the next frame to arrive. This should be
1413 // called from the consumer thread once for every frame expected by the
1414 // test.
1415 void waitForFrame() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001416 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001417 ALOGV("+waitForFrame");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001418 while (!mFrameAvailable) {
1419 mFrameAvailableCondition.wait(mMutex);
1420 }
1421 mFrameAvailable = false;
Steve Block6807e592011-10-20 11:56:00 +01001422 ALOGV("-waitForFrame");
Jamie Gennis5451d152011-06-08 09:40:45 -07001423 }
1424
1425 // Allow the producer to return from its swapBuffers call and continue
1426 // on to produce the next frame. This should be called by the consumer
1427 // thread once for every frame expected by the test.
1428 void finishFrame() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001429 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001430 ALOGV("+finishFrame");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001431 mFrameFinished = true;
Jamie Gennis5451d152011-06-08 09:40:45 -07001432 mFrameFinishCondition.signal();
Steve Block6807e592011-10-20 11:56:00 +01001433 ALOGV("-finishFrame");
Jamie Gennis5451d152011-06-08 09:40:45 -07001434 }
1435
1436 // This should be called by SurfaceTexture on the producer thread.
1437 virtual void onFrameAvailable() {
Jamie Gennis5451d152011-06-08 09:40:45 -07001438 Mutex::Autolock lock(mMutex);
Steve Block6807e592011-10-20 11:56:00 +01001439 ALOGV("+onFrameAvailable");
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001440 mFrameAvailable = true;
Jamie Gennis5451d152011-06-08 09:40:45 -07001441 mFrameAvailableCondition.signal();
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001442 while (!mFrameFinished) {
1443 mFrameFinishCondition.wait(mMutex);
1444 }
1445 mFrameFinished = false;
Steve Block6807e592011-10-20 11:56:00 +01001446 ALOGV("-onFrameAvailable");
Jamie Gennis5451d152011-06-08 09:40:45 -07001447 }
1448
1449 protected:
Jamie Gennis2640bfd2011-07-14 17:11:47 -07001450 bool mFrameAvailable;
1451 bool mFrameFinished;
1452
Jamie Gennis5451d152011-06-08 09:40:45 -07001453 Mutex mMutex;
1454 Condition mFrameAvailableCondition;
1455 Condition mFrameFinishCondition;
1456 };
1457
Jamie Gennis5451d152011-06-08 09:40:45 -07001458 virtual void SetUp() {
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001459 SurfaceTextureGLToGLTest::SetUp();
Jamie Gennis5451d152011-06-08 09:40:45 -07001460 mFC = new FrameCondition();
1461 mST->setFrameAvailableListener(mFC);
1462 }
1463
1464 virtual void TearDown() {
1465 if (mProducerThread != NULL) {
1466 mProducerThread->requestExitAndWait();
1467 }
Jamie Gennis5451d152011-06-08 09:40:45 -07001468 mProducerThread.clear();
1469 mFC.clear();
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001470 SurfaceTextureGLToGLTest::TearDown();
Jamie Gennis5451d152011-06-08 09:40:45 -07001471 }
1472
1473 void runProducerThread(const sp<ProducerThread> producerThread) {
1474 ASSERT_TRUE(mProducerThread == NULL);
1475 mProducerThread = producerThread;
1476 producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
1477 mProducerEglContext);
1478 producerThread->run();
1479 }
1480
Jamie Gennis5451d152011-06-08 09:40:45 -07001481 sp<ProducerThread> mProducerThread;
1482 sp<FrameCondition> mFC;
1483};
1484
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001485TEST_F(SurfaceTextureGLThreadToGLTest,
1486 UpdateTexImageBeforeFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001487 class PT : public ProducerThread {
1488 virtual void render() {
1489 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1490 glClear(GL_COLOR_BUFFER_BIT);
1491 swapBuffers();
1492 }
1493 };
1494
1495 runProducerThread(new PT());
1496
1497 mFC->waitForFrame();
1498 mST->updateTexImage();
1499 mFC->finishFrame();
1500
1501 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
Jamie Gennisd99c0882011-03-10 16:24:46 -08001502}
Jamie Gennis5451d152011-06-08 09:40:45 -07001503
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001504TEST_F(SurfaceTextureGLThreadToGLTest,
1505 UpdateTexImageAfterFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001506 class PT : public ProducerThread {
1507 virtual void render() {
1508 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1509 glClear(GL_COLOR_BUFFER_BIT);
1510 swapBuffers();
1511 }
1512 };
1513
1514 runProducerThread(new PT());
1515
1516 mFC->waitForFrame();
1517 mFC->finishFrame();
1518 mST->updateTexImage();
1519
1520 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1521}
1522
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001523TEST_F(SurfaceTextureGLThreadToGLTest,
1524 RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001525 enum { NUM_ITERATIONS = 1024 };
1526
1527 class PT : public ProducerThread {
1528 virtual void render() {
1529 for (int i = 0; i < NUM_ITERATIONS; i++) {
1530 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1531 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001532 ALOGV("+swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001533 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001534 ALOGV("-swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001535 }
1536 }
1537 };
1538
1539 runProducerThread(new PT());
1540
1541 for (int i = 0; i < NUM_ITERATIONS; i++) {
1542 mFC->waitForFrame();
Steve Block6807e592011-10-20 11:56:00 +01001543 ALOGV("+updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001544 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001545 ALOGV("-updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001546 mFC->finishFrame();
1547
1548 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1549 }
1550}
1551
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001552TEST_F(SurfaceTextureGLThreadToGLTest,
1553 RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001554 enum { NUM_ITERATIONS = 1024 };
1555
1556 class PT : public ProducerThread {
1557 virtual void render() {
1558 for (int i = 0; i < NUM_ITERATIONS; i++) {
1559 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1560 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001561 ALOGV("+swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001562 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001563 ALOGV("-swapBuffers");
Jamie Gennis5451d152011-06-08 09:40:45 -07001564 }
1565 }
1566 };
1567
1568 runProducerThread(new PT());
1569
1570 for (int i = 0; i < NUM_ITERATIONS; i++) {
1571 mFC->waitForFrame();
1572 mFC->finishFrame();
Steve Block6807e592011-10-20 11:56:00 +01001573 ALOGV("+updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001574 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001575 ALOGV("-updateTexImage");
Jamie Gennis5451d152011-06-08 09:40:45 -07001576
1577 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1578 }
1579}
1580
Jamie Gennis6e502192011-07-21 14:31:31 -07001581// XXX: This test is disabled because it is currently hanging on some devices.
Jamie Gennis6f4cdfe2011-11-19 17:49:21 -08001582TEST_F(SurfaceTextureGLThreadToGLTest,
1583 DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
Jamie Gennis6e502192011-07-21 14:31:31 -07001584 enum { NUM_ITERATIONS = 64 };
1585
1586 class PT : public ProducerThread {
1587 virtual void render() {
1588 for (int i = 0; i < NUM_ITERATIONS; i++) {
1589 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1590 glClear(GL_COLOR_BUFFER_BIT);
Steve Block6807e592011-10-20 11:56:00 +01001591 ALOGV("+swapBuffers");
Jamie Gennis6e502192011-07-21 14:31:31 -07001592 swapBuffers();
Steve Block6807e592011-10-20 11:56:00 +01001593 ALOGV("-swapBuffers");
Jamie Gennis6e502192011-07-21 14:31:31 -07001594 }
1595 }
1596 };
1597
1598 ASSERT_EQ(OK, mST->setSynchronousMode(true));
1599 ASSERT_EQ(OK, mST->setBufferCountServer(2));
1600
1601 runProducerThread(new PT());
1602
1603 // Allow three frames to be rendered and queued before starting the
1604 // rendering in this thread. For the latter two frames we don't call
1605 // updateTexImage so the next dequeue from the producer thread will block
1606 // waiting for a frame to become available.
1607 mFC->waitForFrame();
1608 mFC->finishFrame();
1609
1610 // We must call updateTexImage to consume the first frame so that the
1611 // SurfaceTexture is able to reduce the buffer count to 2. This is because
1612 // the GL driver may dequeue a buffer when the EGLSurface is created, and
1613 // that happens before we call setBufferCountServer. It's possible that the
1614 // driver does not dequeue a buffer at EGLSurface creation time, so we
1615 // cannot rely on this to cause the second dequeueBuffer call to block.
1616 mST->updateTexImage();
1617
1618 mFC->waitForFrame();
1619 mFC->finishFrame();
1620 mFC->waitForFrame();
1621 mFC->finishFrame();
1622
1623 // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
1624 // block waiting for a buffer to become available.
1625 usleep(100000);
1626
1627 // Render and present a number of images. This thread should not be blocked
1628 // by the fact that the producer thread is blocking in dequeue.
1629 for (int i = 0; i < NUM_ITERATIONS; i++) {
1630 glClear(GL_COLOR_BUFFER_BIT);
1631 eglSwapBuffers(mEglDisplay, mEglSurface);
1632 }
1633
1634 // Consume the two pending buffers to unblock the producer thread.
1635 mST->updateTexImage();
1636 mST->updateTexImage();
1637
1638 // Consume the remaining buffers from the producer thread.
1639 for (int i = 0; i < NUM_ITERATIONS-3; i++) {
1640 mFC->waitForFrame();
1641 mFC->finishFrame();
Steve Block6807e592011-10-20 11:56:00 +01001642 ALOGV("+updateTexImage");
Jamie Gennis6e502192011-07-21 14:31:31 -07001643 mST->updateTexImage();
Steve Block6807e592011-10-20 11:56:00 +01001644 ALOGV("-updateTexImage");
Jamie Gennis6e502192011-07-21 14:31:31 -07001645 }
1646}
1647
Jamie Gennisfe27e2f2011-11-11 18:05:11 -08001648class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
1649protected:
1650
1651 virtual void SetUp() {
1652 SurfaceTextureGLTest::SetUp();
1653
1654 glGenFramebuffers(1, &mFbo);
1655 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1656
1657 glGenTextures(1, &mFboTex);
1658 glBindTexture(GL_TEXTURE_2D, mFboTex);
1659 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
1660 getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1661 glBindTexture(GL_TEXTURE_2D, 0);
1662 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1663
1664 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1665 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1666 GL_TEXTURE_2D, mFboTex, 0);
1667 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1668 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
1669 }
1670
1671 virtual void TearDown() {
1672 SurfaceTextureGLTest::TearDown();
1673
1674 glDeleteTextures(1, &mFboTex);
1675 glDeleteFramebuffers(1, &mFbo);
1676 }
1677
1678 GLuint mFbo;
1679 GLuint mFboTex;
1680};
1681
1682// This test is intended to verify that proper synchronization is done when
1683// rendering into an FBO.
1684TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
1685 const int texWidth = 64;
1686 const int texHeight = 64;
1687
1688 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
1689 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
1690 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
1691 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
1692
1693 android_native_buffer_t* anb;
1694 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1695 ASSERT_TRUE(anb != NULL);
1696
1697 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
1698 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
1699
1700 // Fill the buffer with green
1701 uint8_t* img = NULL;
1702 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
1703 fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
1704 0, 255);
1705 buf->unlock();
1706 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
1707
1708 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1709
1710 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1711 drawTexture();
1712 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1713
1714 for (int i = 0; i < 4; i++) {
1715 SCOPED_TRACE(String8::format("frame %d", i).string());
1716
1717 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
1718 ASSERT_TRUE(anb != NULL);
1719
1720 buf = new GraphicBuffer(anb, false);
1721 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
1722 buf->getNativeBuffer()));
1723
1724 // Fill the buffer with red
1725 ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
1726 (void**)(&img)));
1727 fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0,
1728 0, 255);
1729 ASSERT_EQ(NO_ERROR, buf->unlock());
1730 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
1731 buf->getNativeBuffer()));
1732
1733 ASSERT_EQ(NO_ERROR, mST->updateTexImage());
1734
1735 drawTexture();
1736
1737 EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
1738 }
1739
1740 glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
1741
1742 EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
1743}
1744
Jamie Gennis5451d152011-06-08 09:40:45 -07001745} // namespace android