blob: c06400e5219a0efb42b015042140153ae00b0b6a [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() {
Jamie Gennisd99c0882011-03-10 16:24:46 -080049 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
50 ASSERT_EQ(EGL_SUCCESS, eglGetError());
51 ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
52
53 EGLint majorVersion;
54 EGLint minorVersion;
55 EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
56 ASSERT_EQ(EGL_SUCCESS, eglGetError());
57 RecordProperty("EglVersionMajor", majorVersion);
58 RecordProperty("EglVersionMajor", minorVersion);
59
Jamie Gennisd99c0882011-03-10 16:24:46 -080060 EGLint numConfigs = 0;
Jamie Gennis1876d132011-03-17 16:32:52 -070061 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
Jamie Gennisd99c0882011-03-10 16:24:46 -080062 1, &numConfigs));
63 ASSERT_EQ(EGL_SUCCESS, eglGetError());
64
65 char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
66 if (displaySecsEnv != NULL) {
67 mDisplaySecs = atoi(displaySecsEnv);
68 if (mDisplaySecs < 0) {
69 mDisplaySecs = 0;
70 }
71 } else {
72 mDisplaySecs = 0;
73 }
74
75 if (mDisplaySecs > 0) {
76 mComposerClient = new SurfaceComposerClient;
77 ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
78
Jamie Gennisfc850122011-04-25 16:40:05 -070079 mSurfaceControl = mComposerClient->createSurface(
Jamie Gennisd99c0882011-03-10 16:24:46 -080080 String8("Test Surface"), 0,
81 getSurfaceWidth(), getSurfaceHeight(),
82 PIXEL_FORMAT_RGB_888, 0);
83
84 ASSERT_TRUE(mSurfaceControl != NULL);
85 ASSERT_TRUE(mSurfaceControl->isValid());
86
Mathias Agopian698c0872011-06-28 19:09:31 -070087 SurfaceComposerClient::openGlobalTransaction();
Jamie Gennis5dd0c4f2011-06-13 19:06:52 -070088 ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
Jamie Gennisd99c0882011-03-10 16:24:46 -080089 ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
Mathias Agopian698c0872011-06-28 19:09:31 -070090 SurfaceComposerClient::closeGlobalTransaction();
Jamie Gennisd99c0882011-03-10 16:24:46 -080091
92 sp<ANativeWindow> window = mSurfaceControl->getSurface();
Jamie Gennis1876d132011-03-17 16:32:52 -070093 mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
Jamie Gennisd99c0882011-03-10 16:24:46 -080094 window.get(), NULL);
95 } else {
96 EGLint pbufferAttribs[] = {
97 EGL_WIDTH, getSurfaceWidth(),
98 EGL_HEIGHT, getSurfaceHeight(),
99 EGL_NONE };
100
Jamie Gennis1876d132011-03-17 16:32:52 -0700101 mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800102 pbufferAttribs);
103 }
104 ASSERT_EQ(EGL_SUCCESS, eglGetError());
105 ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
106
Jamie Gennis1876d132011-03-17 16:32:52 -0700107 mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
Jamie Gennisd99c0882011-03-10 16:24:46 -0800108 getContextAttribs());
109 ASSERT_EQ(EGL_SUCCESS, eglGetError());
110 ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
111
112 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
113 mEglContext));
114 ASSERT_EQ(EGL_SUCCESS, eglGetError());
115
116 EGLint w, h;
117 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
118 ASSERT_EQ(EGL_SUCCESS, eglGetError());
119 EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
120 ASSERT_EQ(EGL_SUCCESS, eglGetError());
121 RecordProperty("EglSurfaceWidth", w);
122 RecordProperty("EglSurfaceHeight", h);
123
124 glViewport(0, 0, w, h);
125 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
126 }
127
128 virtual void TearDown() {
129 // Display the result
130 if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
131 eglSwapBuffers(mEglDisplay, mEglSurface);
132 sleep(mDisplaySecs);
133 }
134
135 if (mComposerClient != NULL) {
136 mComposerClient->dispose();
137 }
138 if (mEglContext != EGL_NO_CONTEXT) {
139 eglDestroyContext(mEglDisplay, mEglContext);
140 }
141 if (mEglSurface != EGL_NO_SURFACE) {
142 eglDestroySurface(mEglDisplay, mEglSurface);
143 }
144 if (mEglDisplay != EGL_NO_DISPLAY) {
145 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
146 EGL_NO_CONTEXT);
147 eglTerminate(mEglDisplay);
148 }
149 ASSERT_EQ(EGL_SUCCESS, eglGetError());
150 }
151
152 virtual EGLint const* getConfigAttribs() {
153 static EGLint sDefaultConfigAttribs[] = {
154 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
155 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
156 EGL_RED_SIZE, 8,
157 EGL_GREEN_SIZE, 8,
158 EGL_BLUE_SIZE, 8,
159 EGL_ALPHA_SIZE, 8,
160 EGL_DEPTH_SIZE, 16,
161 EGL_STENCIL_SIZE, 8,
162 EGL_NONE };
163
164 return sDefaultConfigAttribs;
165 }
166
167 virtual EGLint const* getContextAttribs() {
168 static EGLint sDefaultContextAttribs[] = {
169 EGL_CONTEXT_CLIENT_VERSION, 2,
170 EGL_NONE };
171
172 return sDefaultContextAttribs;
173 }
174
175 virtual EGLint getSurfaceWidth() {
Jamie Gennisc8c51522011-06-15 14:24:38 -0700176 return 512;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800177 }
178
179 virtual EGLint getSurfaceHeight() {
Jamie Gennisc8c51522011-06-15 14:24:38 -0700180 return 512;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800181 }
182
183 void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
184 GLuint shader = glCreateShader(shaderType);
185 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
186 if (shader) {
187 glShaderSource(shader, 1, &pSource, NULL);
188 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
189 glCompileShader(shader);
190 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
191 GLint compiled = 0;
192 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
193 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
194 if (!compiled) {
195 GLint infoLen = 0;
196 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
197 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
198 if (infoLen) {
199 char* buf = (char*) malloc(infoLen);
200 if (buf) {
201 glGetShaderInfoLog(shader, infoLen, NULL, buf);
202 printf("Shader compile log:\n%s\n", buf);
203 free(buf);
204 FAIL();
205 }
206 } else {
207 char* buf = (char*) malloc(0x1000);
208 if (buf) {
209 glGetShaderInfoLog(shader, 0x1000, NULL, buf);
210 printf("Shader compile log:\n%s\n", buf);
211 free(buf);
212 FAIL();
213 }
214 }
215 glDeleteShader(shader);
216 shader = 0;
217 }
218 }
219 ASSERT_TRUE(shader != 0);
220 *outShader = shader;
221 }
222
223 void createProgram(const char* pVertexSource, const char* pFragmentSource,
224 GLuint* outPgm) {
225 GLuint vertexShader, fragmentShader;
226 {
227 SCOPED_TRACE("compiling vertex shader");
228 loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
229 if (HasFatalFailure()) {
230 return;
231 }
232 }
233 {
234 SCOPED_TRACE("compiling fragment shader");
235 loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
236 if (HasFatalFailure()) {
237 return;
238 }
239 }
240
241 GLuint program = glCreateProgram();
242 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
243 if (program) {
244 glAttachShader(program, vertexShader);
245 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
246 glAttachShader(program, fragmentShader);
247 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
248 glLinkProgram(program);
249 GLint linkStatus = GL_FALSE;
250 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
251 if (linkStatus != GL_TRUE) {
252 GLint bufLength = 0;
253 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
254 if (bufLength) {
255 char* buf = (char*) malloc(bufLength);
256 if (buf) {
257 glGetProgramInfoLog(program, bufLength, NULL, buf);
258 printf("Program link log:\n%s\n", buf);
259 free(buf);
260 FAIL();
261 }
262 }
263 glDeleteProgram(program);
264 program = 0;
265 }
266 }
267 glDeleteShader(vertexShader);
268 glDeleteShader(fragmentShader);
269 ASSERT_TRUE(program != 0);
270 *outPgm = program;
271 }
272
Jamie Gennis824efa72011-06-13 13:41:01 -0700273 static int abs(int value) {
274 return value > 0 ? value : -value;
275 }
276
Jamie Gennisd99c0882011-03-10 16:24:46 -0800277 ::testing::AssertionResult checkPixel(int x, int y, int r,
Jamie Gennis824efa72011-06-13 13:41:01 -0700278 int g, int b, int a, int tolerance=2) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800279 GLubyte pixel[4];
280 String8 msg;
281 glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
282 GLenum err = glGetError();
283 if (err != GL_NO_ERROR) {
284 msg += String8::format("error reading pixel: %#x", err);
285 while ((err = glGetError()) != GL_NO_ERROR) {
286 msg += String8::format(", %#x", err);
287 }
288 fprintf(stderr, "pixel check failure: %s\n", msg.string());
289 return ::testing::AssertionFailure(
290 ::testing::Message(msg.string()));
291 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700292 if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800293 msg += String8::format("r(%d isn't %d)", pixel[0], r);
294 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700295 if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800296 if (!msg.isEmpty()) {
297 msg += " ";
298 }
299 msg += String8::format("g(%d isn't %d)", pixel[1], g);
300 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700301 if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800302 if (!msg.isEmpty()) {
303 msg += " ";
304 }
305 msg += String8::format("b(%d isn't %d)", pixel[2], b);
306 }
Jamie Gennis824efa72011-06-13 13:41:01 -0700307 if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
Jamie Gennisd99c0882011-03-10 16:24:46 -0800308 if (!msg.isEmpty()) {
309 msg += " ";
310 }
311 msg += String8::format("a(%d isn't %d)", pixel[3], a);
312 }
313 if (!msg.isEmpty()) {
314 fprintf(stderr, "pixel check failure: %s\n", msg.string());
315 return ::testing::AssertionFailure(
316 ::testing::Message(msg.string()));
317 } else {
318 return ::testing::AssertionSuccess();
319 }
320 }
321
322 int mDisplaySecs;
323 sp<SurfaceComposerClient> mComposerClient;
324 sp<SurfaceControl> mSurfaceControl;
325
326 EGLDisplay mEglDisplay;
327 EGLSurface mEglSurface;
328 EGLContext mEglContext;
Jamie Gennis1876d132011-03-17 16:32:52 -0700329 EGLConfig mGlConfig;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800330};
331
332// XXX: Code above this point should live elsewhere
333
334class SurfaceTextureGLTest : public GLTest {
335protected:
336 static const GLint TEX_ID = 123;
337
338 virtual void SetUp() {
339 GLTest::SetUp();
340 mST = new SurfaceTexture(TEX_ID);
341 mSTC = new SurfaceTextureClient(mST);
342 mANW = mSTC;
343
344 const char vsrc[] =
345 "attribute vec4 vPosition;\n"
346 "varying vec2 texCoords;\n"
347 "uniform mat4 texMatrix;\n"
348 "void main() {\n"
349 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
350 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
351 " gl_Position = vPosition;\n"
352 "}\n";
353
354 const char fsrc[] =
355 "#extension GL_OES_EGL_image_external : require\n"
356 "precision mediump float;\n"
357 "uniform samplerExternalOES texSampler;\n"
358 "varying vec2 texCoords;\n"
359 "void main() {\n"
360 " gl_FragColor = texture2D(texSampler, texCoords);\n"
361 "}\n";
362
363 {
364 SCOPED_TRACE("creating shader program");
365 createProgram(vsrc, fsrc, &mPgm);
366 if (HasFatalFailure()) {
367 return;
368 }
369 }
370
371 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
372 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
373 ASSERT_NE(-1, mPositionHandle);
374 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
375 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
376 ASSERT_NE(-1, mTexSamplerHandle);
377 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
378 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
379 ASSERT_NE(-1, mTexMatrixHandle);
380 }
381
382 // drawTexture draws the SurfaceTexture over the entire GL viewport.
383 void drawTexture() {
384 const GLfloat triangleVertices[] = {
385 -1.0f, 1.0f,
386 -1.0f, -1.0f,
387 1.0f, -1.0f,
388 1.0f, 1.0f,
389 };
390
391 glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
392 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
393 glEnableVertexAttribArray(mPositionHandle);
394 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
395
396 glUseProgram(mPgm);
397 glUniform1i(mTexSamplerHandle, 0);
398 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
399 glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
400 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
401
Jamie Gennis1876d132011-03-17 16:32:52 -0700402 // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
403 // they're setting the defautls for that target, but when hacking things
404 // to use GL_TEXTURE_2D they are needed to achieve the same behavior.
405 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
406 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
407 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
408 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
409 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
410 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
411 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
412 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
413
Jamie Gennisd99c0882011-03-10 16:24:46 -0800414 GLfloat texMatrix[16];
415 mST->getTransformMatrix(texMatrix);
416 glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
417
418 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
419 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
420 }
421
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700422 class FrameWaiter : public SurfaceTexture::FrameAvailableListener {
423 public:
424 FrameWaiter():
425 mPendingFrames(0) {
426 }
427
428 void waitForFrame() {
429 Mutex::Autolock lock(mMutex);
430 while (mPendingFrames == 0) {
431 mCondition.wait(mMutex);
432 }
433 mPendingFrames--;
434 }
435
436 virtual void onFrameAvailable() {
437 Mutex::Autolock lock(mMutex);
438 mPendingFrames++;
439 mCondition.signal();
440 }
441
442 int mPendingFrames;
443 Mutex mMutex;
444 Condition mCondition;
445 };
446
Jamie Gennisd99c0882011-03-10 16:24:46 -0800447 sp<SurfaceTexture> mST;
448 sp<SurfaceTextureClient> mSTC;
449 sp<ANativeWindow> mANW;
450
451 GLuint mPgm;
452 GLint mPositionHandle;
453 GLint mTexSamplerHandle;
454 GLint mTexMatrixHandle;
455};
456
457// Fill a YV12 buffer with a multi-colored checkerboard pattern
458void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
459 const int blockWidth = w > 16 ? w / 16 : 1;
460 const int blockHeight = h > 16 ? h / 16 : 1;
461 const int yuvTexOffsetY = 0;
462 int yuvTexStrideY = stride;
463 int yuvTexOffsetV = yuvTexStrideY * h;
464 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
465 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
466 int yuvTexStrideU = yuvTexStrideV;
467 for (int x = 0; x < w; x++) {
468 for (int y = 0; y < h; y++) {
469 int parityX = (x / blockWidth) & 1;
470 int parityY = (y / blockHeight) & 1;
471 unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
472 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
473 if (x < w / 2 && y < h / 2) {
474 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
475 if (x * 2 < w / 2 && y * 2 < h / 2) {
476 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
477 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
478 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
479 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
480 intensity;
481 }
482 }
483 }
484 }
485}
486
487// Fill a YV12 buffer with red outside a given rectangle and green inside it.
488void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
489 const android_native_rect_t& rect) {
490 const int yuvTexOffsetY = 0;
491 int yuvTexStrideY = stride;
492 int yuvTexOffsetV = yuvTexStrideY * h;
493 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
494 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
495 int yuvTexStrideU = yuvTexStrideV;
496 for (int x = 0; x < w; x++) {
497 for (int y = 0; y < h; y++) {
498 bool inside = rect.left <= x && x < rect.right &&
499 rect.top <= y && y < rect.bottom;
500 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
501 if (x < w / 2 && y < h / 2) {
502 bool inside = rect.left <= 2*x && 2*x < rect.right &&
503 rect.top <= 2*y && 2*y < rect.bottom;
504 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
505 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
506 inside ? 16 : 255;
507 }
508 }
509 }
510}
511
Jamie Gennis1876d132011-03-17 16:32:52 -0700512void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
513 const size_t PIXEL_SIZE = 4;
514 for (int x = 0; x < w; x++) {
515 for (int y = 0; y < h; y++) {
516 off_t offset = (y * stride + x) * PIXEL_SIZE;
517 for (int c = 0; c < 4; c++) {
518 int parityX = (x / (1 << (c+2))) & 1;
519 int parityY = (y / (1 << (c+2))) & 1;
520 buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
521 }
522 }
523 }
524}
525
Jamie Gennisd99c0882011-03-10 16:24:46 -0800526TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700527 const int texWidth = 64;
528 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800529
530 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700531 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800532 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
533 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
534
Iliyan Malchev697526b2011-05-01 11:33:26 -0700535 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800536 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
537 ASSERT_TRUE(anb != NULL);
538
539 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
540 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
541
542 // Fill the buffer with the a checkerboard pattern
543 uint8_t* img = NULL;
544 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700545 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800546 buf->unlock();
547 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
548
549 mST->updateTexImage();
550
551 glClearColor(0.2, 0.2, 0.2, 0.2);
552 glClear(GL_COLOR_BUFFER_BIT);
553
Jamie Gennisc8c51522011-06-15 14:24:38 -0700554 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800555 drawTexture();
556
557 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
558 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700559 EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255));
560 EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800561
Jamie Gennisc8c51522011-06-15 14:24:38 -0700562 EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
563 EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
564 EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800565 EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700566 EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800567 EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
568 EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
569}
570
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700571TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700572 const int texWidth = 64;
573 const int texHeight = 64;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800574
575 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700576 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800577 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
578 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
579
Iliyan Malchev697526b2011-05-01 11:33:26 -0700580 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800581 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
582 ASSERT_TRUE(anb != NULL);
583
584 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
585 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
586
587 // Fill the buffer with the a checkerboard pattern
588 uint8_t* img = NULL;
589 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700590 fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
Jamie Gennisd99c0882011-03-10 16:24:46 -0800591 buf->unlock();
592 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
593
594 mST->updateTexImage();
595
596 glClearColor(0.2, 0.2, 0.2, 0.2);
597 glClear(GL_COLOR_BUFFER_BIT);
598
Jamie Gennisc8c51522011-06-15 14:24:38 -0700599 glViewport(0, 0, texWidth, texHeight);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800600 drawTexture();
601
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700602 EXPECT_TRUE(checkPixel( 0, 0, 0, 133, 0, 255));
603 EXPECT_TRUE(checkPixel(63, 0, 255, 127, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800604 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
605 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
606
Jamie Gennisd05bb2e2011-06-14 15:41:45 -0700607 EXPECT_TRUE(checkPixel(22, 19, 100, 255, 74, 255));
608 EXPECT_TRUE(checkPixel(45, 11, 100, 255, 74, 255));
609 EXPECT_TRUE(checkPixel(52, 12, 155, 0, 181, 255));
610 EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
611 EXPECT_TRUE(checkPixel(31, 54, 0, 71, 117, 255));
612 EXPECT_TRUE(checkPixel(29, 28, 0, 133, 0, 255));
613 EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800614}
615
616TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
Jamie Gennis1876d132011-03-17 16:32:52 -0700617 const int texWidth = 64;
618 const int texHeight = 66;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800619
620 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
Jamie Gennis1876d132011-03-17 16:32:52 -0700621 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
Jamie Gennisd99c0882011-03-10 16:24:46 -0800622 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
623 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
624
625 android_native_rect_t crops[] = {
626 {4, 6, 22, 36},
627 {0, 6, 22, 36},
628 {4, 0, 22, 36},
Jamie Gennis1876d132011-03-17 16:32:52 -0700629 {4, 6, texWidth, 36},
630 {4, 6, 22, texHeight},
Jamie Gennisd99c0882011-03-10 16:24:46 -0800631 };
632
633 for (int i = 0; i < 5; i++) {
634 const android_native_rect_t& crop(crops[i]);
635 SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left,
636 crop.top, crop.right, crop.bottom).string());
637
638 ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
639
Iliyan Malchev697526b2011-05-01 11:33:26 -0700640 ANativeWindowBuffer* anb;
Jamie Gennisd99c0882011-03-10 16:24:46 -0800641 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
642 ASSERT_TRUE(anb != NULL);
643
644 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
645 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
646
647 uint8_t* img = NULL;
648 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
Jamie Gennis1876d132011-03-17 16:32:52 -0700649 fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800650 buf->unlock();
651 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
652
653 mST->updateTexImage();
654
655 glClearColor(0.2, 0.2, 0.2, 0.2);
656 glClear(GL_COLOR_BUFFER_BIT);
657
Jamie Gennisc8c51522011-06-15 14:24:38 -0700658 glViewport(0, 0, 64, 64);
Jamie Gennisd99c0882011-03-10 16:24:46 -0800659 drawTexture();
660
661 EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
662 EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255));
663 EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255));
664 EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255));
665
666 EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255));
667 EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255));
668 EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255));
669 EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255));
670 EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255));
671 EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255));
672 EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255));
673 }
674}
675
Jamie Gennisdfcff4b2011-06-17 11:39:18 -0700676// This test is intended to catch synchronization bugs between the CPU-written
677// and GPU-read buffers.
678TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
679 enum { texWidth = 16 };
680 enum { texHeight = 16 };
681 enum { numFrames = 1024 };
682
683 ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
684 ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
685 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
686 texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
687 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
688 GRALLOC_USAGE_SW_WRITE_OFTEN));
689
690 struct TestPixel {
691 int x;
692 int y;
693 };
694 const TestPixel testPixels[] = {
695 { 4, 11 },
696 { 12, 14 },
697 { 7, 2 },
698 };
699 enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])};
700
701 class ProducerThread : public Thread {
702 public:
703 ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels):
704 mANW(anw),
705 mTestPixels(testPixels) {
706 }
707
708 virtual ~ProducerThread() {
709 }
710
711 virtual bool threadLoop() {
712 for (int i = 0; i < numFrames; i++) {
713 ANativeWindowBuffer* anb;
714 if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
715 return false;
716 }
717 if (anb == NULL) {
718 return false;
719 }
720
721 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
722 if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
723 != NO_ERROR) {
724 return false;
725 }
726
727 const int yuvTexOffsetY = 0;
728 int stride = buf->getStride();
729 int yuvTexStrideY = stride;
730 int yuvTexOffsetV = yuvTexStrideY * texHeight;
731 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
732 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
733 int yuvTexStrideU = yuvTexStrideV;
734
735 uint8_t* img = NULL;
736 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
737
738 // Gray out all the test pixels first, so we're more likely to
739 // see a failure if GL is still texturing from the buffer we
740 // just dequeued.
741 for (int j = 0; j < numTestPixels; j++) {
742 int x = mTestPixels[j].x;
743 int y = mTestPixels[j].y;
744 uint8_t value = 128;
745 img[y*stride + x] = value;
746 }
747
748 // Fill the buffer with gray.
749 for (int y = 0; y < texHeight; y++) {
750 for (int x = 0; x < texWidth; x++) {
751 img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128;
752 img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128;
753 img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128;
754 }
755 }
756
757 // Set the test pixels to either white or black.
758 for (int j = 0; j < numTestPixels; j++) {
759 int x = mTestPixels[j].x;
760 int y = mTestPixels[j].y;
761 uint8_t value = 0;
762 if (j == (i % numTestPixels)) {
763 value = 255;
764 }
765 img[y*stride + x] = value;
766 }
767
768 buf->unlock();
769 if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
770 != NO_ERROR) {
771 return false;
772 }
773 }
774 return false;
775 }
776
777 sp<ANativeWindow> mANW;
778 const TestPixel* mTestPixels;
779 };
780
781 sp<FrameWaiter> fw(new FrameWaiter);
782 mST->setFrameAvailableListener(fw);
783
784 sp<Thread> pt(new ProducerThread(mANW, testPixels));
785 pt->run();
786
787 glViewport(0, 0, texWidth, texHeight);
788
789 glClearColor(0.2, 0.2, 0.2, 0.2);
790 glClear(GL_COLOR_BUFFER_BIT);
791
792 // We wait for the first two frames up front so that the producer will be
793 // likely to dequeue the buffer that's currently being textured from.
794 fw->waitForFrame();
795 fw->waitForFrame();
796
797 for (int i = 0; i < numFrames; i++) {
798 SCOPED_TRACE(String8::format("frame %d", i).string());
799
800 // We must wait for each frame to come in because if we ever do an
801 // updateTexImage call that doesn't consume a newly available buffer
802 // then the producer and consumer will get out of sync, which will cause
803 // a deadlock.
804 if (i > 1) {
805 fw->waitForFrame();
806 }
807 mST->updateTexImage();
808 drawTexture();
809
810 for (int j = 0; j < numTestPixels; j++) {
811 int x = testPixels[j].x;
812 int y = testPixels[j].y;
813 uint8_t value = 0;
814 if (j == (i % numTestPixels)) {
815 // We must y-invert the texture coords
816 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
817 } else {
818 // We must y-invert the texture coords
819 EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255));
820 }
821 }
822 }
823
824 pt->requestExitAndWait();
825}
826
Jamie Gennis1876d132011-03-17 16:32:52 -0700827// XXX: This test is disabled because there are currently no drivers that can
828// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
829TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
830 const int texWidth = 64;
831 const int texHeight = 66;
832
833 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
834 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
835 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
836 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
837
838 android_native_buffer_t* anb;
839 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
840 ASSERT_TRUE(anb != NULL);
841
842 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
843 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
844
845 // Fill the buffer with the a checkerboard pattern
846 uint8_t* img = NULL;
847 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
848 fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
849 buf->unlock();
850 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
851
852 mST->updateTexImage();
853
854 glClearColor(0.2, 0.2, 0.2, 0.2);
855 glClear(GL_COLOR_BUFFER_BIT);
856
Jamie Gennisc8c51522011-06-15 14:24:38 -0700857 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700858 drawTexture();
859
860 EXPECT_TRUE(checkPixel( 0, 0, 35, 35, 35, 35));
861 EXPECT_TRUE(checkPixel(63, 0, 231, 231, 231, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700862 EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
863 EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700864
865 EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700866 EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
867 EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700868 EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
869 EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700870 EXPECT_TRUE(checkPixel(37, 33, 228, 38, 38, 38));
Jamie Gennis1876d132011-03-17 16:32:52 -0700871 EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700872 EXPECT_TRUE(checkPixel(36, 47, 228, 35, 231, 231));
873 EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
874 EXPECT_TRUE(checkPixel(48, 3, 228, 228, 38, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700875 EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700876 EXPECT_TRUE(checkPixel(24, 25, 41, 41, 231, 231));
877 EXPECT_TRUE(checkPixel(10, 9, 38, 38, 231, 231));
Jamie Gennis1876d132011-03-17 16:32:52 -0700878 EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
Jamie Gennisc8c51522011-06-15 14:24:38 -0700879 EXPECT_TRUE(checkPixel(56, 31, 38, 228, 231, 35));
Jamie Gennis1876d132011-03-17 16:32:52 -0700880 EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
881}
882
883// XXX: This test is disabled because there are currently no drivers that can
884// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
885TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
886 const int texWidth = 64;
887 const int texHeight = 64;
888
889 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
890 texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
891 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
892 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
893
894 android_native_buffer_t* anb;
895 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
896 ASSERT_TRUE(anb != NULL);
897
898 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
899 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
900
901 // Fill the buffer with the a checkerboard pattern
902 uint8_t* img = NULL;
903 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
904 fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
905 buf->unlock();
906 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
907
908 mST->updateTexImage();
909
910 glClearColor(0.2, 0.2, 0.2, 0.2);
911 glClear(GL_COLOR_BUFFER_BIT);
912
Jamie Gennisc8c51522011-06-15 14:24:38 -0700913 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700914 drawTexture();
915
916 EXPECT_TRUE(checkPixel( 0, 0, 231, 231, 231, 231));
917 EXPECT_TRUE(checkPixel(63, 0, 35, 35, 35, 35));
918 EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
919 EXPECT_TRUE(checkPixel( 0, 63, 35, 35, 35, 35));
920
921 EXPECT_TRUE(checkPixel(12, 46, 231, 231, 231, 35));
922 EXPECT_TRUE(checkPixel(16, 1, 231, 231, 35, 231));
923 EXPECT_TRUE(checkPixel(21, 12, 231, 35, 35, 231));
924 EXPECT_TRUE(checkPixel(26, 51, 231, 35, 231, 35));
925 EXPECT_TRUE(checkPixel( 5, 32, 35, 231, 231, 35));
926 EXPECT_TRUE(checkPixel(13, 8, 35, 231, 231, 231));
927 EXPECT_TRUE(checkPixel(46, 3, 35, 35, 231, 35));
928 EXPECT_TRUE(checkPixel(30, 33, 35, 35, 35, 35));
929 EXPECT_TRUE(checkPixel( 6, 52, 231, 231, 35, 35));
930 EXPECT_TRUE(checkPixel(55, 33, 35, 231, 35, 231));
931 EXPECT_TRUE(checkPixel(16, 29, 35, 35, 231, 231));
932 EXPECT_TRUE(checkPixel( 1, 30, 35, 35, 35, 231));
933 EXPECT_TRUE(checkPixel(41, 37, 35, 35, 231, 231));
934 EXPECT_TRUE(checkPixel(46, 29, 231, 231, 35, 35));
935 EXPECT_TRUE(checkPixel(15, 25, 35, 231, 35, 231));
936 EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
937}
938
939// XXX: This test is disabled because there are currently no drivers that can
940// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
941TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
942 const int texWidth = 64;
943 const int texHeight = 64;
944
945 mST->setDefaultBufferSize(texWidth, texHeight);
946
947 // Do the producer side of things
948 EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
949 mANW.get(), NULL);
950 ASSERT_EQ(EGL_SUCCESS, eglGetError());
951 ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
952
953 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
954 mEglContext));
955 ASSERT_EQ(EGL_SUCCESS, eglGetError());
956
957 glClearColor(0.6, 0.6, 0.6, 0.6);
958 glClear(GL_COLOR_BUFFER_BIT);
959
960 glEnable(GL_SCISSOR_TEST);
961 glScissor(4, 4, 4, 4);
962 glClearColor(1.0, 0.0, 0.0, 1.0);
963 glClear(GL_COLOR_BUFFER_BIT);
964
965 glScissor(24, 48, 4, 4);
966 glClearColor(0.0, 1.0, 0.0, 1.0);
967 glClear(GL_COLOR_BUFFER_BIT);
968
969 glScissor(37, 17, 4, 4);
970 glClearColor(0.0, 0.0, 1.0, 1.0);
971 glClear(GL_COLOR_BUFFER_BIT);
972
973 eglSwapBuffers(mEglDisplay, stcEglSurface);
974
975 // Do the consumer side of things
976 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
977 mEglContext));
978 ASSERT_EQ(EGL_SUCCESS, eglGetError());
979
980 glDisable(GL_SCISSOR_TEST);
981
982 mST->updateTexImage();
983
984 glClearColor(0.2, 0.2, 0.2, 0.2);
985 glClear(GL_COLOR_BUFFER_BIT);
986
Jamie Gennisc8c51522011-06-15 14:24:38 -0700987 glViewport(0, 0, texWidth, texHeight);
Jamie Gennis1876d132011-03-17 16:32:52 -0700988 drawTexture();
989
990 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153));
991 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153));
992 EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
993 EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
994
995 EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255));
996 EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255));
997 EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255));
998 EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
999 EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
1000 EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153));
1001 EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153));
1002 EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
1003 EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
1004 EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
1005 EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
1006 EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
1007 EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
1008 EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
1009 EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
1010 EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
1011}
1012
Jamie Gennis5451d152011-06-08 09:40:45 -07001013/*
1014 * This test is for testing GL -> GL texture streaming via SurfaceTexture. It
1015 * contains functionality to create a producer thread that will perform GL
1016 * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
1017 * Additionally it supports interlocking the producer and consumer threads so
1018 * that a specific sequence of calls can be deterministically created by the
1019 * test.
1020 *
1021 * The intended usage is as follows:
1022 *
1023 * TEST_F(...) {
1024 * class PT : public ProducerThread {
1025 * virtual void render() {
1026 * ...
1027 * swapBuffers();
1028 * }
1029 * };
1030 *
1031 * runProducerThread(new PT());
1032 *
1033 * // The order of these calls will vary from test to test and may include
1034 * // multiple frames and additional operations (e.g. GL rendering from the
1035 * // texture).
1036 * fc->waitForFrame();
1037 * mST->updateTexImage();
1038 * fc->finishFrame();
1039 * }
1040 *
1041 */
1042class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
1043protected:
1044
1045 // ProducerThread is an abstract base class to simplify the creation of
1046 // OpenGL ES frame producer threads.
1047 class ProducerThread : public Thread {
1048 public:
1049 virtual ~ProducerThread() {
1050 }
1051
1052 void setEglObjects(EGLDisplay producerEglDisplay,
1053 EGLSurface producerEglSurface,
1054 EGLContext producerEglContext) {
1055 mProducerEglDisplay = producerEglDisplay;
1056 mProducerEglSurface = producerEglSurface;
1057 mProducerEglContext = producerEglContext;
1058 }
1059
1060 virtual bool threadLoop() {
1061 eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
1062 mProducerEglSurface, mProducerEglContext);
1063 render();
1064 eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
1065 EGL_NO_CONTEXT);
1066 return false;
1067 }
1068
1069 protected:
1070 virtual void render() = 0;
1071
1072 void swapBuffers() {
1073 eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
1074 }
1075
1076 EGLDisplay mProducerEglDisplay;
1077 EGLSurface mProducerEglSurface;
1078 EGLContext mProducerEglContext;
1079 };
1080
1081 // FrameCondition is a utility class for interlocking between the producer
1082 // and consumer threads. The FrameCondition object should be created and
1083 // destroyed in the consumer thread only. The consumer thread should set
1084 // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
1085 // and should call both waitForFrame and finishFrame once for each expected
1086 // frame.
1087 //
1088 // This interlocking relies on the fact that onFrameAvailable gets called
1089 // synchronously from SurfaceTexture::queueBuffer.
1090 class FrameCondition : public SurfaceTexture::FrameAvailableListener {
1091 public:
1092 // waitForFrame waits for the next frame to arrive. This should be
1093 // called from the consumer thread once for every frame expected by the
1094 // test.
1095 void waitForFrame() {
1096 LOGV("+waitForFrame");
1097 Mutex::Autolock lock(mMutex);
1098 status_t result = mFrameAvailableCondition.wait(mMutex);
1099 LOGV("-waitForFrame");
1100 }
1101
1102 // Allow the producer to return from its swapBuffers call and continue
1103 // on to produce the next frame. This should be called by the consumer
1104 // thread once for every frame expected by the test.
1105 void finishFrame() {
1106 LOGV("+finishFrame");
1107 Mutex::Autolock lock(mMutex);
1108 mFrameFinishCondition.signal();
1109 LOGV("-finishFrame");
1110 }
1111
1112 // This should be called by SurfaceTexture on the producer thread.
1113 virtual void onFrameAvailable() {
1114 LOGV("+onFrameAvailable");
1115 Mutex::Autolock lock(mMutex);
1116 mFrameAvailableCondition.signal();
1117 mFrameFinishCondition.wait(mMutex);
1118 LOGV("-onFrameAvailable");
1119 }
1120
1121 protected:
1122 Mutex mMutex;
1123 Condition mFrameAvailableCondition;
1124 Condition mFrameFinishCondition;
1125 };
1126
1127 SurfaceTextureGLToGLTest():
1128 mProducerEglSurface(EGL_NO_SURFACE),
1129 mProducerEglContext(EGL_NO_CONTEXT) {
1130 }
1131
1132 virtual void SetUp() {
1133 SurfaceTextureGLTest::SetUp();
1134
1135 EGLConfig myConfig = {0};
1136 EGLint numConfigs = 0;
1137 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
1138 1, &numConfigs));
1139 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1140
1141 mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
1142 mANW.get(), NULL);
1143 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1144 ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
1145
1146 mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
1147 EGL_NO_CONTEXT, getContextAttribs());
1148 ASSERT_EQ(EGL_SUCCESS, eglGetError());
1149 ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
1150
1151 mFC = new FrameCondition();
1152 mST->setFrameAvailableListener(mFC);
1153 }
1154
1155 virtual void TearDown() {
1156 if (mProducerThread != NULL) {
1157 mProducerThread->requestExitAndWait();
1158 }
1159 if (mProducerEglContext != EGL_NO_CONTEXT) {
1160 eglDestroyContext(mEglDisplay, mProducerEglContext);
1161 }
1162 if (mProducerEglSurface != EGL_NO_SURFACE) {
1163 eglDestroySurface(mEglDisplay, mProducerEglSurface);
1164 }
1165 mProducerThread.clear();
1166 mFC.clear();
1167 }
1168
1169 void runProducerThread(const sp<ProducerThread> producerThread) {
1170 ASSERT_TRUE(mProducerThread == NULL);
1171 mProducerThread = producerThread;
1172 producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
1173 mProducerEglContext);
1174 producerThread->run();
1175 }
1176
1177 EGLSurface mProducerEglSurface;
1178 EGLContext mProducerEglContext;
1179 sp<ProducerThread> mProducerThread;
1180 sp<FrameCondition> mFC;
1181};
1182
1183// XXX: This test is disabled because it causes hangs on some devices.
1184TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) {
1185 class PT : public ProducerThread {
1186 virtual void render() {
1187 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1188 glClear(GL_COLOR_BUFFER_BIT);
1189 swapBuffers();
1190 }
1191 };
1192
1193 runProducerThread(new PT());
1194
1195 mFC->waitForFrame();
1196 mST->updateTexImage();
1197 mFC->finishFrame();
1198
1199 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
Jamie Gennisd99c0882011-03-10 16:24:46 -08001200}
Jamie Gennis5451d152011-06-08 09:40:45 -07001201
Jamie Gennis2510d952011-06-13 13:43:51 -07001202// XXX: This test is disabled because it causes hangs on some devices.
1203TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) {
Jamie Gennis5451d152011-06-08 09:40:45 -07001204 class PT : public ProducerThread {
1205 virtual void render() {
1206 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1207 glClear(GL_COLOR_BUFFER_BIT);
1208 swapBuffers();
1209 }
1210 };
1211
1212 runProducerThread(new PT());
1213
1214 mFC->waitForFrame();
1215 mFC->finishFrame();
1216 mST->updateTexImage();
1217
1218 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1219}
1220
1221// XXX: This test is disabled because it causes hangs on some devices.
1222TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
1223 enum { NUM_ITERATIONS = 1024 };
1224
1225 class PT : public ProducerThread {
1226 virtual void render() {
1227 for (int i = 0; i < NUM_ITERATIONS; i++) {
1228 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1229 glClear(GL_COLOR_BUFFER_BIT);
1230 LOGV("+swapBuffers");
1231 swapBuffers();
1232 LOGV("-swapBuffers");
1233 }
1234 }
1235 };
1236
1237 runProducerThread(new PT());
1238
1239 for (int i = 0; i < NUM_ITERATIONS; i++) {
1240 mFC->waitForFrame();
1241 LOGV("+updateTexImage");
1242 mST->updateTexImage();
1243 LOGV("-updateTexImage");
1244 mFC->finishFrame();
1245
1246 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1247 }
1248}
1249
1250// XXX: This test is disabled because it causes hangs on some devices.
1251TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) {
1252 enum { NUM_ITERATIONS = 1024 };
1253
1254 class PT : public ProducerThread {
1255 virtual void render() {
1256 for (int i = 0; i < NUM_ITERATIONS; i++) {
1257 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
1258 glClear(GL_COLOR_BUFFER_BIT);
1259 LOGV("+swapBuffers");
1260 swapBuffers();
1261 LOGV("-swapBuffers");
1262 }
1263 }
1264 };
1265
1266 runProducerThread(new PT());
1267
1268 for (int i = 0; i < NUM_ITERATIONS; i++) {
1269 mFC->waitForFrame();
1270 mFC->finishFrame();
1271 LOGV("+updateTexImage");
1272 mST->updateTexImage();
1273 LOGV("-updateTexImage");
1274
1275 // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
1276 }
1277}
1278
1279} // namespace android