blob: 4184463496d4fd2465a7ae9d75eb8e15c940fd30 [file] [log] [blame]
Jamie Gennisf3cedb62011-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
17#include <gtest/gtest.h>
18#include <gui/SurfaceTexture.h>
19#include <gui/SurfaceTextureClient.h>
20#include <ui/GraphicBuffer.h>
21#include <utils/String8.h>
22
23#include <surfaceflinger/ISurfaceComposer.h>
24#include <surfaceflinger/Surface.h>
25#include <surfaceflinger/SurfaceComposerClient.h>
26
27#include <EGL/egl.h>
28#include <EGL/eglext.h>
29#include <GLES2/gl2.h>
30#include <GLES2/gl2ext.h>
31
32#include <ui/FramebufferNativeWindow.h>
33
34namespace android {
35
36class GLTest : public ::testing::Test {
37protected:
38
39 GLTest():
40 mEglDisplay(EGL_NO_DISPLAY),
41 mEglSurface(EGL_NO_SURFACE),
42 mEglContext(EGL_NO_CONTEXT) {
43 }
44
45 virtual void SetUp() {
46 EGLBoolean returnValue;
47
48 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
49 ASSERT_EQ(EGL_SUCCESS, eglGetError());
50 ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
51
52 EGLint majorVersion;
53 EGLint minorVersion;
54 EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
55 ASSERT_EQ(EGL_SUCCESS, eglGetError());
56 RecordProperty("EglVersionMajor", majorVersion);
57 RecordProperty("EglVersionMajor", minorVersion);
58
59 EGLConfig myConfig = {0};
60 EGLint numConfigs = 0;
61 EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
62 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
79 mSurfaceControl = mComposerClient->createSurface(getpid(),
80 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
87 ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
88 ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
89 ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
90 ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
91
92 sp<ANativeWindow> window = mSurfaceControl->getSurface();
93 mEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
94 window.get(), NULL);
95 } else {
96 EGLint pbufferAttribs[] = {
97 EGL_WIDTH, getSurfaceWidth(),
98 EGL_HEIGHT, getSurfaceHeight(),
99 EGL_NONE };
100
101 mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig,
102 pbufferAttribs);
103 }
104 ASSERT_EQ(EGL_SUCCESS, eglGetError());
105 ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
106
107 mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
108 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() {
176 return 64;
177 }
178
179 virtual EGLint getSurfaceHeight() {
180 return 64;
181 }
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
273 ::testing::AssertionResult checkPixel(int x, int y, int r,
274 int g, int b, int a) {
275 GLubyte pixel[4];
276 String8 msg;
277 glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
278 GLenum err = glGetError();
279 if (err != GL_NO_ERROR) {
280 msg += String8::format("error reading pixel: %#x", err);
281 while ((err = glGetError()) != GL_NO_ERROR) {
282 msg += String8::format(", %#x", err);
283 }
284 fprintf(stderr, "pixel check failure: %s\n", msg.string());
285 return ::testing::AssertionFailure(
286 ::testing::Message(msg.string()));
287 }
288 if (r >= 0 && GLubyte(r) != pixel[0]) {
289 msg += String8::format("r(%d isn't %d)", pixel[0], r);
290 }
291 if (g >= 0 && GLubyte(g) != pixel[1]) {
292 if (!msg.isEmpty()) {
293 msg += " ";
294 }
295 msg += String8::format("g(%d isn't %d)", pixel[1], g);
296 }
297 if (b >= 0 && GLubyte(b) != pixel[2]) {
298 if (!msg.isEmpty()) {
299 msg += " ";
300 }
301 msg += String8::format("b(%d isn't %d)", pixel[2], b);
302 }
303 if (a >= 0 && GLubyte(a) != pixel[3]) {
304 if (!msg.isEmpty()) {
305 msg += " ";
306 }
307 msg += String8::format("a(%d isn't %d)", pixel[3], a);
308 }
309 if (!msg.isEmpty()) {
310 fprintf(stderr, "pixel check failure: %s\n", msg.string());
311 return ::testing::AssertionFailure(
312 ::testing::Message(msg.string()));
313 } else {
314 return ::testing::AssertionSuccess();
315 }
316 }
317
318 int mDisplaySecs;
319 sp<SurfaceComposerClient> mComposerClient;
320 sp<SurfaceControl> mSurfaceControl;
321
322 EGLDisplay mEglDisplay;
323 EGLSurface mEglSurface;
324 EGLContext mEglContext;
325};
326
327// XXX: Code above this point should live elsewhere
328
329class SurfaceTextureGLTest : public GLTest {
330protected:
331 static const GLint TEX_ID = 123;
332
333 virtual void SetUp() {
334 GLTest::SetUp();
335 mST = new SurfaceTexture(TEX_ID);
336 mSTC = new SurfaceTextureClient(mST);
337 mANW = mSTC;
338
339 const char vsrc[] =
340 "attribute vec4 vPosition;\n"
341 "varying vec2 texCoords;\n"
342 "uniform mat4 texMatrix;\n"
343 "void main() {\n"
344 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
345 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
346 " gl_Position = vPosition;\n"
347 "}\n";
348
349 const char fsrc[] =
350 "#extension GL_OES_EGL_image_external : require\n"
351 "precision mediump float;\n"
352 "uniform samplerExternalOES texSampler;\n"
353 "varying vec2 texCoords;\n"
354 "void main() {\n"
355 " gl_FragColor = texture2D(texSampler, texCoords);\n"
356 "}\n";
357
358 {
359 SCOPED_TRACE("creating shader program");
360 createProgram(vsrc, fsrc, &mPgm);
361 if (HasFatalFailure()) {
362 return;
363 }
364 }
365
366 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
367 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
368 ASSERT_NE(-1, mPositionHandle);
369 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
370 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
371 ASSERT_NE(-1, mTexSamplerHandle);
372 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
373 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
374 ASSERT_NE(-1, mTexMatrixHandle);
375 }
376
377 // drawTexture draws the SurfaceTexture over the entire GL viewport.
378 void drawTexture() {
379 const GLfloat triangleVertices[] = {
380 -1.0f, 1.0f,
381 -1.0f, -1.0f,
382 1.0f, -1.0f,
383 1.0f, 1.0f,
384 };
385
386 glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
387 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
388 glEnableVertexAttribArray(mPositionHandle);
389 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
390
391 glUseProgram(mPgm);
392 glUniform1i(mTexSamplerHandle, 0);
393 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
394 glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
395 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
396
397 GLfloat texMatrix[16];
398 mST->getTransformMatrix(texMatrix);
399 glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
400
401 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
402 ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
403 }
404
405 sp<SurfaceTexture> mST;
406 sp<SurfaceTextureClient> mSTC;
407 sp<ANativeWindow> mANW;
408
409 GLuint mPgm;
410 GLint mPositionHandle;
411 GLint mTexSamplerHandle;
412 GLint mTexMatrixHandle;
413};
414
415// Fill a YV12 buffer with a multi-colored checkerboard pattern
416void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
417 const int blockWidth = w > 16 ? w / 16 : 1;
418 const int blockHeight = h > 16 ? h / 16 : 1;
419 const int yuvTexOffsetY = 0;
420 int yuvTexStrideY = stride;
421 int yuvTexOffsetV = yuvTexStrideY * h;
422 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
423 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
424 int yuvTexStrideU = yuvTexStrideV;
425 for (int x = 0; x < w; x++) {
426 for (int y = 0; y < h; y++) {
427 int parityX = (x / blockWidth) & 1;
428 int parityY = (y / blockHeight) & 1;
429 unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
430 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
431 if (x < w / 2 && y < h / 2) {
432 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
433 if (x * 2 < w / 2 && y * 2 < h / 2) {
434 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
435 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
436 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
437 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
438 intensity;
439 }
440 }
441 }
442 }
443}
444
445// Fill a YV12 buffer with red outside a given rectangle and green inside it.
446void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
447 const android_native_rect_t& rect) {
448 const int yuvTexOffsetY = 0;
449 int yuvTexStrideY = stride;
450 int yuvTexOffsetV = yuvTexStrideY * h;
451 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
452 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
453 int yuvTexStrideU = yuvTexStrideV;
454 for (int x = 0; x < w; x++) {
455 for (int y = 0; y < h; y++) {
456 bool inside = rect.left <= x && x < rect.right &&
457 rect.top <= y && y < rect.bottom;
458 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
459 if (x < w / 2 && y < h / 2) {
460 bool inside = rect.left <= 2*x && 2*x < rect.right &&
461 rect.top <= 2*y && 2*y < rect.bottom;
462 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
463 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
464 inside ? 16 : 255;
465 }
466 }
467 }
468}
469
470TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
471 const int yuvTexWidth = 64;
472 const int yuvTexHeight = 66;
473
474 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
475 yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
476 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
477 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
478
479 android_native_buffer_t* anb;
480 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
481 ASSERT_TRUE(anb != NULL);
482
483 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
484 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
485
486 // Fill the buffer with the a checkerboard pattern
487 uint8_t* img = NULL;
488 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
489 fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
490 buf->unlock();
491 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
492
493 mST->updateTexImage();
494
495 glClearColor(0.2, 0.2, 0.2, 0.2);
496 glClear(GL_COLOR_BUFFER_BIT);
497
498 drawTexture();
499
500 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
501 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
502 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
503 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
504
505 EXPECT_TRUE(checkPixel(22, 44, 247, 70, 255, 255));
506 EXPECT_TRUE(checkPixel(45, 52, 209, 32, 235, 255));
507 EXPECT_TRUE(checkPixel(52, 51, 100, 255, 73, 255));
508 EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
509 EXPECT_TRUE(checkPixel(31, 9, 148, 71, 110, 255));
510 EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
511 EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
512}
513
514// XXX: This test is disabled because it it currently broken on all devices to
515// which I have access. Some of the checkPixel calls are not correct because
516// I just copied them from the npot test above and haven't bothered to figure
517// out the correct values.
518TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) {
519 const int yuvTexWidth = 64;
520 const int yuvTexHeight = 64;
521
522 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
523 yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
524 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
525 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
526
527 android_native_buffer_t* anb;
528 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
529 ASSERT_TRUE(anb != NULL);
530
531 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
532 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
533
534 // Fill the buffer with the a checkerboard pattern
535 uint8_t* img = NULL;
536 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
537 fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
538 buf->unlock();
539 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
540
541 mST->updateTexImage();
542
543 glClearColor(0.2, 0.2, 0.2, 0.2);
544 glClear(GL_COLOR_BUFFER_BIT);
545
546 drawTexture();
547
548 EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
549 EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
550 EXPECT_TRUE(checkPixel(63, 63, 0, 133, 0, 255));
551 EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
552
553 EXPECT_TRUE(checkPixel(22, 19, 247, 70, 255, 255));
554 EXPECT_TRUE(checkPixel(45, 11, 209, 32, 235, 255));
555 EXPECT_TRUE(checkPixel(52, 12, 100, 255, 73, 255));
556 EXPECT_TRUE(checkPixel( 7, 32, 155, 0, 118, 255));
557 EXPECT_TRUE(checkPixel(31, 54, 148, 71, 110, 255));
558 EXPECT_TRUE(checkPixel(29, 28, 255, 127, 255, 255));
559 EXPECT_TRUE(checkPixel(36, 41, 155, 29, 0, 255));
560}
561
562TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
563 const int yuvTexWidth = 64;
564 const int yuvTexHeight = 66;
565
566 ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
567 yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
568 ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
569 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
570
571 android_native_rect_t crops[] = {
572 {4, 6, 22, 36},
573 {0, 6, 22, 36},
574 {4, 0, 22, 36},
575 {4, 6, yuvTexWidth, 36},
576 {4, 6, 22, yuvTexHeight},
577 };
578
579 for (int i = 0; i < 5; i++) {
580 const android_native_rect_t& crop(crops[i]);
581 SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left,
582 crop.top, crop.right, crop.bottom).string());
583
584 ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
585
586 android_native_buffer_t* anb;
587 ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
588 ASSERT_TRUE(anb != NULL);
589
590 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
591 ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
592
593 uint8_t* img = NULL;
594 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
595 fillYV12BufferRect(img, yuvTexWidth, yuvTexHeight, buf->getStride(), crop);
596 buf->unlock();
597 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
598
599 mST->updateTexImage();
600
601 glClearColor(0.2, 0.2, 0.2, 0.2);
602 glClear(GL_COLOR_BUFFER_BIT);
603
604 drawTexture();
605
606 EXPECT_TRUE(checkPixel( 0, 0, 82, 255, 35, 255));
607 EXPECT_TRUE(checkPixel(63, 0, 82, 255, 35, 255));
608 EXPECT_TRUE(checkPixel(63, 63, 82, 255, 35, 255));
609 EXPECT_TRUE(checkPixel( 0, 63, 82, 255, 35, 255));
610
611 EXPECT_TRUE(checkPixel(25, 14, 82, 255, 35, 255));
612 EXPECT_TRUE(checkPixel(35, 31, 82, 255, 35, 255));
613 EXPECT_TRUE(checkPixel(57, 6, 82, 255, 35, 255));
614 EXPECT_TRUE(checkPixel( 5, 42, 82, 255, 35, 255));
615 EXPECT_TRUE(checkPixel(32, 33, 82, 255, 35, 255));
616 EXPECT_TRUE(checkPixel(16, 26, 82, 255, 35, 255));
617 EXPECT_TRUE(checkPixel(46, 51, 82, 255, 35, 255));
618 }
619}
620
621}