blob: 56c1702929bd2fdfcc88d905ef072134f33a2f60 [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 Gennis5451d152011-06-08 09:40:45 -070017//#define LOG_NDEBUG 0
18
Jamie Gennisd99c0882011-03-10 16:24:46 -080019#include <gtest/gtest.h>
20#include <gui/SurfaceTexture.h>
21#include <gui/SurfaceTextureClient.h>
22#include <ui/GraphicBuffer.h>
23#include <utils/String8.h>
Jamie Gennis5451d152011-06-08 09:40:45 -070024#include <utils/threads.h>
Jamie Gennisd99c0882011-03-10 16:24:46 -080025
26#include <surfaceflinger/ISurfaceComposer.h>
27#include <surfaceflinger/Surface.h>
28#include <surfaceflinger/SurfaceComposerClient.h>
29
30#include <EGL/egl.h>
31#include <EGL/eglext.h>
32#include <GLES2/gl2.h>
33#include <GLES2/gl2ext.h>
34
35#include <ui/FramebufferNativeWindow.h>
36
37namespace android {
38
39class GLTest : public ::testing::Test {
40protected:
41
42 GLTest():
43 mEglDisplay(EGL_NO_DISPLAY),
44 mEglSurface(EGL_NO_SURFACE),
45 mEglContext(EGL_NO_CONTEXT) {
46 }
47
48 virtual void SetUp() {
49 EGLBoolean returnValue;
50
51 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
52 ASSERT_EQ(EGL_SUCCESS, eglGetError());
53 ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
54
55 EGLint majorVersion;
56 EGLint minorVersion;
57 EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
58 ASSERT_EQ(EGL_SUCCESS, eglGetError());
59 RecordProperty("EglVersionMajor", majorVersion);
60 RecordProperty("EglVersionMajor", minorVersion);
61
62 EGLConfig myConfig = {0};
63 EGLint numConfigs = 0;
64 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
65 1, &numConfigs));
66 ASSERT_EQ(EGL_SUCCESS, eglGetError());
67
68 char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
69 if (displaySecsEnv != NULL) {
70 mDisplaySecs = atoi(displaySecsEnv);
71 if (mDisplaySecs < 0) {
72 mDisplaySecs = 0;
73 }
74 } else {
75 mDisplaySecs = 0;
76 }
77
78 if (mDisplaySecs > 0) {
79 mComposerClient = new SurfaceComposerClient;
80 ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
81
Jamie Gennisfc850122011-04-25 16:40:05 -070082 mSurfaceControl = mComposerClient->createSurface(
Jamie Gennisd99c0882011-03-10 16:24:46 -080083 String8("Test Surface"), 0,
84 getSurfaceWidth(), getSurfaceHeight(),
85 PIXEL_FORMAT_RGB_888, 0);
86
87 ASSERT_TRUE(mSurfaceControl != NULL);
88 ASSERT_TRUE(mSurfaceControl->isValid());
89
90 ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
91 ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
92 ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
93 ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
94
95 sp<ANativeWindow> window = mSurfaceControl->getSurface();
96 mEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
97 window.get(), NULL);
98 } else {
99 EGLint pbufferAttribs[] = {
100 EGL_WIDTH, getSurfaceWidth(),
101 EGL_HEIGHT, getSurfaceHeight(),
102 EGL_NONE };
103
104 mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig,
105 pbufferAttribs);
106 }
107 ASSERT_EQ(EGL_SUCCESS, eglGetError());
108 ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
109
110 mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
111 getContextAttribs());
112 ASSERT_EQ(EGL_SUCCESS, eglGetError());
113 ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
114
115 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
116 mEglContext));
117 ASSERT_EQ(EGL_SUCCESS, eglGetError());
118
119 EGLint w, h;
120 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
121 ASSERT_EQ(EGL_SUCCESS, eglGetError());
122 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
123 ASSERT_EQ(EGL_SUCCESS, eglGetError());
124 RecordProperty("EglSurfaceWidth", w);
125 RecordProperty("EglSurfaceHeight", h);
126
127 glViewport(0, 0, w, h);
128 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
129 }
130
131 virtual void TearDown() {
132 // Display the result
133 if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
134 eglSwapBuffers(mEglDisplay, mEglSurface);
135 sleep(mDisplaySecs);
136 }
137
138 if (mComposerClient != NULL) {
139 mComposerClient->dispose();
140 }
141 if (mEglContext != EGL_NO_CONTEXT) {
142 eglDestroyContext(mEglDisplay, mEglContext);
143 }
144 if (mEglSurface != EGL_NO_SURFACE) {
145 eglDestroySurface(mEglDisplay, mEglSurface);
146 }
147 if (mEglDisplay != EGL_NO_DISPLAY) {
148 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
149 EGL_NO_CONTEXT);
150 eglTerminate(mEglDisplay);
151 }
152 ASSERT_EQ(EGL_SUCCESS, eglGetError());
153 }
154
155 virtual EGLint const* getConfigAttribs() {
156 static EGLint sDefaultConfigAttribs[] = {
157 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
158 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
159 EGL_RED_SIZE, 8,
160 EGL_GREEN_SIZE, 8,
161 EGL_BLUE_SIZE, 8,
162 EGL_ALPHA_SIZE, 8,
163 EGL_DEPTH_SIZE, 16,
164 EGL_STENCIL_SIZE, 8,
165 EGL_NONE };
166
167 return sDefaultConfigAttribs;
168 }
169
170 virtual EGLint const* getContextAttribs() {
171 static EGLint sDefaultContextAttribs[] = {
172 EGL_CONTEXT_CLIENT_VERSION, 2,
173 EGL_NONE };
174
175 return sDefaultContextAttribs;
176 }
177
178 virtual EGLint getSurfaceWidth() {
179 return 64;
180 }
181
182 virtual EGLint getSurfaceHeight() {
183 return 64;
184 }
185
186 void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
187 GLuint shader = glCreateShader(shaderType);
188 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
189 if (shader) {
190 glShaderSource(shader, 1, &pSource, NULL);
191 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
192 glCompileShader(shader);
193 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
194 GLint compiled = 0;
195 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
196 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
197 if (!compiled) {
198 GLint infoLen = 0;
199 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
200 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
201 if (infoLen) {
202 char* buf = (char*) malloc(infoLen);
203 if (buf) {
204 glGetShaderInfoLog(shader, infoLen, NULL, buf);
205 printf("Shader compile log:\n%s\n", buf);
206 free(buf);
207 FAIL();
208 }
209 } else {
210 char* buf = (char*) malloc(0x1000);
211 if (buf) {
212 glGetShaderInfoLog(shader, 0x1000, NULL, buf);
213 printf("Shader compile log:\n%s\n", buf);
214 free(buf);
215 FAIL();
216 }
217 }
218 glDeleteShader(shader);
219 shader = 0;
220 }
221 }
222 ASSERT_TRUE(shader != 0);
223 *outShader = shader;
224 }
225
226 void createProgram(const char* pVertexSource, const char* pFragmentSource,
227 GLuint* outPgm) {
228 GLuint vertexShader, fragmentShader;
229 {
230 SCOPED_TRACE("compiling vertex shader");
231 loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
232 if (HasFatalFailure()) {
233 return;
234 }
235 }
236 {
237 SCOPED_TRACE("compiling fragment shader");
238 loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
239 if (HasFatalFailure()) {
240 return;
241 }
242 }
243
244 GLuint program = glCreateProgram();
245 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
246 if (program) {
247 glAttachShader(program, vertexShader);
248 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
249 glAttachShader(program, fragmentShader);
250 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
251 glLinkProgram(program);
252 GLint linkStatus = GL_FALSE;
253 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
254 if (linkStatus != GL_TRUE) {
255 GLint bufLength = 0;
256 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
257 if (bufLength) {
258 char* buf = (char*) malloc(bufLength);
259 if (buf) {
260 glGetProgramInfoLog(program, bufLength, NULL, buf);
261 printf("Program link log:\n%s\n", buf);
262 free(buf);
263 FAIL();
264 }
265 }
266 glDeleteProgram(program);
267 program = 0;
268 }
269 }
270 glDeleteShader(vertexShader);
271 glDeleteShader(fragmentShader);
272 ASSERT_TRUE(program != 0);
273 *outPgm = program;
274 }
275
Jamie Gennis824efa72011-06-13 13:41:01 -0700276 static int abs(int value) {
277 return value > 0 ? value : -value;
278 }
279
Jamie Gennisd99c0882011-03-10 16:24:46 -0800280 ::testing::AssertionResult checkPixel(int x, int y, int r,
Jamie Gennis824efa72011-06-13 13:41:01 -0700281 int g, int b, int a, int tolerance=2) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800282 GLubyte pixel[4];
283 String8 msg;
284 glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
285 GLenum err = glGetError();
286 if (err != GL_NO_ERROR) {
287 msg += String8::format("error reading pixel: %#x", err);
288 while ((err = glGetError()) != GL_NO_ERROR) {
289 msg += String8::format(", %#x", err);
290 }
291 fprintf(stderr, "pixel check failure: %s\n", msg.string());
292 return ::testing::AssertionFailure(
293 ::testing::Message(msg.string()));
294 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700295 if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800296 msg += String8::format("r(%d isn't %d)", pixel[0], r);
297 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700298 if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800299 if (!msg.isEmpty()) {
300 msg += " ";
301 }
302 msg += String8::format("g(%d isn't %d)", pixel[1], g);
303 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700304 if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800305 if (!msg.isEmpty()) {
306 msg += " ";
307 }
308 msg += String8::format("b(%d isn't %d)", pixel[2], b);
309 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700310 if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800311 if (!msg.isEmpty()) {
312 msg += " ";
313 }
314 msg += String8::format("a(%d isn't %d)", pixel[3], a);
315 }
316 if (!msg.isEmpty()) {
317 fprintf(stderr, "pixel check failure: %s\n", msg.string());
318 return ::testing::AssertionFailure(
319 ::testing::Message(msg.string()));
320 } else {
321 return ::testing::AssertionSuccess();
322 }
323 }
324
325 int mDisplaySecs;
326 sp<SurfaceComposerClient> mComposerClient;
327 sp<SurfaceControl> mSurfaceControl;
328
329 EGLDisplay mEglDisplay;
330 EGLSurface mEglSurface;
331 EGLContext mEglContext;
332};
333
334// XXX: Code above this point should live elsewhere
335
336class SurfaceTextureGLTest : public GLTest {
337protected:
338 static const GLint TEX_ID = 123;
339
340 virtual void SetUp() {
341 GLTest::SetUp();
342 mST = new SurfaceTexture(TEX_ID);
343 mSTC = new SurfaceTextureClient(mST);
344 mANW = mSTC;
345
346 const char vsrc[] =
347 "attribute vec4 vPosition;\n"
348 "varying vec2 texCoords;\n"
349 "uniform mat4 texMatrix;\n"
350 "void main() {\n"
351 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
352 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
353 " gl_Position = vPosition;\n"
354 "}\n";
355
356 const char fsrc[] =
357 "#extension GL_OES_EGL_image_external : require\n"
358 "precision mediump float;\n"
359 "uniform samplerExternalOES texSampler;\n"
360 "varying vec2 texCoords;\n"
361 "void main() {\n"
362 " gl_FragColor = texture2D(texSampler, texCoords);\n"
363 "}\n";
364
365 {
366 SCOPED_TRACE("creating shader program");
367 createProgram(vsrc, fsrc, &mPgm);
368 if (HasFatalFailure()) {
369 return;
370 }
371 }
372
373 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
374 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
375 ASSERT_NE(-1, mPositionHandle);
376 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
377 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
378 ASSERT_NE(-1, mTexSamplerHandle);
379 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
380 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
381 ASSERT_NE(-1, mTexMatrixHandle);
382 }
383
384 // drawTexture draws the SurfaceTexture over the entire GL viewport.
385 void drawTexture() {
386 const GLfloat triangleVertices[] = {
387 -1.0f, 1.0f,
388 -1.0f, -1.0f,
389 1.0f, -1.0f,
390 1.0f, 1.0f,
391 };
392
393 glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
394 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
395 glEnableVertexAttribArray(mPositionHandle);
396 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
397
398 glUseProgram(mPgm);
399 glUniform1i(mTexSamplerHandle, 0);
400 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
401 glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
402 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
403
404 GLfloat texMatrix[16];
405 mST->getTransformMatrix(texMatrix);
406 glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
407
408 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
409 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
410 }
411
412 sp<SurfaceTexture> mST;
413 sp<SurfaceTextureClient> mSTC;
414 sp<ANativeWindow> mANW;
415
416 GLuint mPgm;
417 GLint mPositionHandle;
418 GLint mTexSamplerHandle;
419 GLint mTexMatrixHandle;
420};
421
422// Fill a YV12 buffer with a multi-colored checkerboard pattern
423void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
424 const int blockWidth = w > 16 ? w / 16 : 1;
425 const int blockHeight = h > 16 ? h / 16 : 1;
426 const int yuvTexOffsetY = 0;
427 int yuvTexStrideY = stride;
428 int yuvTexOffsetV = yuvTexStrideY * h;
429 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
430 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
431 int yuvTexStrideU = yuvTexStrideV;
432 for (int x = 0; x < w; x++) {
433 for (int y = 0; y < h; y++) {
434 int parityX = (x / blockWidth) & 1;
435 int parityY = (y / blockHeight) & 1;
436 unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
437 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
438 if (x < w / 2 && y < h / 2) {
439 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
440 if (x * 2 < w / 2 && y * 2 < h / 2) {
441 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
442 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
443 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
444 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
445 intensity;
446 }
447 }
448 }
449 }
450}
451
452// Fill a YV12 buffer with red outside a given rectangle and green inside it.
453void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
454 const android_native_rect_t& rect) {
455 const int yuvTexOffsetY = 0;
456 int yuvTexStrideY = stride;
457 int yuvTexOffsetV = yuvTexStrideY * h;
458 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
459 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
460 int yuvTexStrideU = yuvTexStrideV;
461 for (int x = 0; x < w; x++) {
462 for (int y = 0; y < h; y++) {
463 bool inside = rect.left <= x && x < rect.right &&
464 rect.top <= y && y < rect.bottom;
465 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
466 if (x < w / 2 && y < h / 2) {
467 bool inside = rect.left <= 2*x && 2*x < rect.right &&
468 rect.top <= 2*y && 2*y < rect.bottom;
469 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
470 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
471 inside ? 16 : 255;
472 }
473 }
474 }
475}
476
477TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
478 const int yuvTexWidth = 64;
479 const int yuvTexHeight = 66;
480
481 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
482 yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
483 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
484 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
485
Iliyan Malchev697526b2011-05-01 11:33:26 -0700486 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800487 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
488 ASSERT_TRUE(anb != NULL);
489
490 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
491 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
492
493 // Fill the buffer with the a checkerboard pattern
494 uint8_t* img = NULL;
495 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
496 fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
497 buf->unlock();
498 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
499
500 mST->updateTexImage();
501
502 glClearColor(0.2, 0.2, 0.2, 0.2);
503 glClear(GL_COLOR_BUFFER_BIT);
504
505 drawTexture();
506
507 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
508 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
509 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
510 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
511
512 EXPECT_TRUE(checkPixel(22, 44, 247, 70, 255, 255));
513 EXPECT_TRUE(checkPixel(45, 52, 209, 32, 235, 255));
514 EXPECT_TRUE(checkPixel(52, 51, 100, 255, 73, 255));
515 EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
516 EXPECT_TRUE(checkPixel(31, 9, 148, 71, 110, 255));
517 EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
518 EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
519}
520
521// XXX: This test is disabled because it it currently broken on all devices to
522// which I have access. Some of the checkPixel calls are not correct because
523// I just copied them from the npot test above and haven't bothered to figure
524// out the correct values.
525TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) {
526 const int yuvTexWidth = 64;
527 const int yuvTexHeight = 64;
528
529 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
530 yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
531 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
532 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
533
Iliyan Malchev697526b2011-05-01 11:33:26 -0700534 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800535 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
536 ASSERT_TRUE(anb != NULL);
537
538 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
539 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
540
541 // Fill the buffer with the a checkerboard pattern
542 uint8_t* img = NULL;
543 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
544 fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
545 buf->unlock();
546 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
547
548 mST->updateTexImage();
549
550 glClearColor(0.2, 0.2, 0.2, 0.2);
551 glClear(GL_COLOR_BUFFER_BIT);
552
553 drawTexture();
554
555 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
556 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
557 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
558 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
559
560 EXPECT_TRUE(checkPixel(22, 19, 247, 70, 255, 255));
561 EXPECT_TRUE(checkPixel(45, 11, 209, 32, 235, 255));
562 EXPECT_TRUE(checkPixel(52, 12, 100, 255, 73, 255));
563 EXPECT_TRUE(checkPixel( 7, 32, 155, 0, 118, 255));
564 EXPECT_TRUE(checkPixel(31, 54, 148, 71, 110, 255));
565 EXPECT_TRUE(checkPixel(29, 28, 255, 127, 255, 255));
566 EXPECT_TRUE(checkPixel(36, 41, 155, 29, 0, 255));
567}
568
569TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
570 const int yuvTexWidth = 64;
571 const int yuvTexHeight = 66;
572
573 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
574 yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
575 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
576 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
577
578 android_native_rect_t crops[] = {
579 {4, 6, 22, 36},
580 {0, 6, 22, 36},
581 {4, 0, 22, 36},
582 {4, 6, yuvTexWidth, 36},
583 {4, 6, 22, yuvTexHeight},
584 };
585
586 for (int i = 0; i < 5; i++) {
587 const android_native_rect_t& crop(crops[i]);
588 SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left,
589 crop.top, crop.right, crop.bottom).string());
590
591 ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
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 uint8_t* img = NULL;
601 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
602 fillYV12BufferRect(img, yuvTexWidth, yuvTexHeight, buf->getStride(), crop);
603 buf->unlock();
604 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
605
606 mST->updateTexImage();
607
608 glClearColor(0.2, 0.2, 0.2, 0.2);
609 glClear(GL_COLOR_BUFFER_BIT);
610
611 drawTexture();
612
613 EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
614 EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255));
615 EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255));
616 EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255));
617
618 EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255));
619 EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255));
620 EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255));
621 EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255));
622 EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255));
623 EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255));
624 EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255));
625 }
626}
627
Jamie Gennis5451d152011-06-08 09:40:45 -0700628/*
629 * This test is for testing GL -> GL texture streaming via SurfaceTexture. It
630 * contains functionality to create a producer thread that will perform GL
631 * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
632 * Additionally it supports interlocking the producer and consumer threads so
633 * that a specific sequence of calls can be deterministically created by the
634 * test.
635 *
636 * The intended usage is as follows:
637 *
638 * TEST_F(...) {
639 * class PT : public ProducerThread {
640 * virtual void render() {
641 * ...
642 * swapBuffers();
643 * }
644 * };
645 *
646 * runProducerThread(new PT());
647 *
648 * // The order of these calls will vary from test to test and may include
649 * // multiple frames and additional operations (e.g. GL rendering from the
650 * // texture).
651 * fc->waitForFrame();
652 * mST->updateTexImage();
653 * fc->finishFrame();
654 * }
655 *
656 */
657class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
658protected:
659
660 // ProducerThread is an abstract base class to simplify the creation of
661 // OpenGL ES frame producer threads.
662 class ProducerThread : public Thread {
663 public:
664 virtual ~ProducerThread() {
665 }
666
667 void setEglObjects(EGLDisplay producerEglDisplay,
668 EGLSurface producerEglSurface,
669 EGLContext producerEglContext) {
670 mProducerEglDisplay = producerEglDisplay;
671 mProducerEglSurface = producerEglSurface;
672 mProducerEglContext = producerEglContext;
673 }
674
675 virtual bool threadLoop() {
676 eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
677 mProducerEglSurface, mProducerEglContext);
678 render();
679 eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
680 EGL_NO_CONTEXT);
681 return false;
682 }
683
684 protected:
685 virtual void render() = 0;
686
687 void swapBuffers() {
688 eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
689 }
690
691 EGLDisplay mProducerEglDisplay;
692 EGLSurface mProducerEglSurface;
693 EGLContext mProducerEglContext;
694 };
695
696 // FrameCondition is a utility class for interlocking between the producer
697 // and consumer threads. The FrameCondition object should be created and
698 // destroyed in the consumer thread only. The consumer thread should set
699 // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
700 // and should call both waitForFrame and finishFrame once for each expected
701 // frame.
702 //
703 // This interlocking relies on the fact that onFrameAvailable gets called
704 // synchronously from SurfaceTexture::queueBuffer.
705 class FrameCondition : public SurfaceTexture::FrameAvailableListener {
706 public:
707 // waitForFrame waits for the next frame to arrive. This should be
708 // called from the consumer thread once for every frame expected by the
709 // test.
710 void waitForFrame() {
711 LOGV("+waitForFrame");
712 Mutex::Autolock lock(mMutex);
713 status_t result = mFrameAvailableCondition.wait(mMutex);
714 LOGV("-waitForFrame");
715 }
716
717 // Allow the producer to return from its swapBuffers call and continue
718 // on to produce the next frame. This should be called by the consumer
719 // thread once for every frame expected by the test.
720 void finishFrame() {
721 LOGV("+finishFrame");
722 Mutex::Autolock lock(mMutex);
723 mFrameFinishCondition.signal();
724 LOGV("-finishFrame");
725 }
726
727 // This should be called by SurfaceTexture on the producer thread.
728 virtual void onFrameAvailable() {
729 LOGV("+onFrameAvailable");
730 Mutex::Autolock lock(mMutex);
731 mFrameAvailableCondition.signal();
732 mFrameFinishCondition.wait(mMutex);
733 LOGV("-onFrameAvailable");
734 }
735
736 protected:
737 Mutex mMutex;
738 Condition mFrameAvailableCondition;
739 Condition mFrameFinishCondition;
740 };
741
742 SurfaceTextureGLToGLTest():
743 mProducerEglSurface(EGL_NO_SURFACE),
744 mProducerEglContext(EGL_NO_CONTEXT) {
745 }
746
747 virtual void SetUp() {
748 SurfaceTextureGLTest::SetUp();
749
750 EGLConfig myConfig = {0};
751 EGLint numConfigs = 0;
752 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
753 1, &numConfigs));
754 ASSERT_EQ(EGL_SUCCESS, eglGetError());
755
756 mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
757 mANW.get(), NULL);
758 ASSERT_EQ(EGL_SUCCESS, eglGetError());
759 ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
760
761 mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
762 EGL_NO_CONTEXT, getContextAttribs());
763 ASSERT_EQ(EGL_SUCCESS, eglGetError());
764 ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
765
766 mFC = new FrameCondition();
767 mST->setFrameAvailableListener(mFC);
768 }
769
770 virtual void TearDown() {
771 if (mProducerThread != NULL) {
772 mProducerThread->requestExitAndWait();
773 }
774 if (mProducerEglContext != EGL_NO_CONTEXT) {
775 eglDestroyContext(mEglDisplay, mProducerEglContext);
776 }
777 if (mProducerEglSurface != EGL_NO_SURFACE) {
778 eglDestroySurface(mEglDisplay, mProducerEglSurface);
779 }
780 mProducerThread.clear();
781 mFC.clear();
782 }
783
784 void runProducerThread(const sp<ProducerThread> producerThread) {
785 ASSERT_TRUE(mProducerThread == NULL);
786 mProducerThread = producerThread;
787 producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
788 mProducerEglContext);
789 producerThread->run();
790 }
791
792 EGLSurface mProducerEglSurface;
793 EGLContext mProducerEglContext;
794 sp<ProducerThread> mProducerThread;
795 sp<FrameCondition> mFC;
796};
797
798// XXX: This test is disabled because it causes hangs on some devices.
799TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) {
800 class PT : public ProducerThread {
801 virtual void render() {
802 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
803 glClear(GL_COLOR_BUFFER_BIT);
804 swapBuffers();
805 }
806 };
807
808 runProducerThread(new PT());
809
810 mFC->waitForFrame();
811 mST->updateTexImage();
812 mFC->finishFrame();
813
814 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
Jamie Gennisd99c0882011-03-10 16:24:46 -0800815}
Jamie Gennis5451d152011-06-08 09:40:45 -0700816
Jamie Gennis2510d952011-06-13 13:43:51 -0700817// XXX: This test is disabled because it causes hangs on some devices.
818TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) {
Jamie Gennis5451d152011-06-08 09:40:45 -0700819 class PT : public ProducerThread {
820 virtual void render() {
821 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
822 glClear(GL_COLOR_BUFFER_BIT);
823 swapBuffers();
824 }
825 };
826
827 runProducerThread(new PT());
828
829 mFC->waitForFrame();
830 mFC->finishFrame();
831 mST->updateTexImage();
832
833 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
834}
835
836// XXX: This test is disabled because it causes hangs on some devices.
837TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
838 enum { NUM_ITERATIONS = 1024 };
839
840 class PT : public ProducerThread {
841 virtual void render() {
842 for (int i = 0; i < NUM_ITERATIONS; i++) {
843 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
844 glClear(GL_COLOR_BUFFER_BIT);
845 LOGV("+swapBuffers");
846 swapBuffers();
847 LOGV("-swapBuffers");
848 }
849 }
850 };
851
852 runProducerThread(new PT());
853
854 for (int i = 0; i < NUM_ITERATIONS; i++) {
855 mFC->waitForFrame();
856 LOGV("+updateTexImage");
857 mST->updateTexImage();
858 LOGV("-updateTexImage");
859 mFC->finishFrame();
860
861 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
862 }
863}
864
865// XXX: This test is disabled because it causes hangs on some devices.
866TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) {
867 enum { NUM_ITERATIONS = 1024 };
868
869 class PT : public ProducerThread {
870 virtual void render() {
871 for (int i = 0; i < NUM_ITERATIONS; i++) {
872 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
873 glClear(GL_COLOR_BUFFER_BIT);
874 LOGV("+swapBuffers");
875 swapBuffers();
876 LOGV("-swapBuffers");
877 }
878 }
879 };
880
881 runProducerThread(new PT());
882
883 for (int i = 0; i < NUM_ITERATIONS; i++) {
884 mFC->waitForFrame();
885 mFC->finishFrame();
886 LOGV("+updateTexImage");
887 mST->updateTexImage();
888 LOGV("-updateTexImage");
889
890 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
891 }
892}
893
894} // namespace android