CpuConsumer_test.cpp revision e41b318bc4708e1dee9364e73215ff0d51fb76a1
1/* 2 * Copyright (C) 2012 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#define LOG_TAG "CpuConsumer_test" 18//#define LOG_NDEBUG 0 19//#define LOG_NNDEBUG 0 20 21#ifdef LOG_NNDEBUG 22#define ALOGVV(...) ALOGV(__VA_ARGS__) 23#else 24#define ALOGVV(...) ((void)0) 25#endif 26 27#include <gtest/gtest.h> 28#include <gui/CpuConsumer.h> 29#include <gui/SurfaceTextureClient.h> 30#include <ui/GraphicBuffer.h> 31#include <utils/String8.h> 32#include <utils/Thread.h> 33#include <utils/Mutex.h> 34#include <utils/Condition.h> 35 36#include <ui/FramebufferNativeWindow.h> 37 38namespace android { 39 40struct CpuConsumerTestParams { 41 uint32_t width; 42 uint32_t height; 43 int maxLockedBuffers; 44 PixelFormat format; 45}; 46 47::std::ostream& operator<<(::std::ostream& os, const CpuConsumerTestParams& p) { 48 return os << "[ (" << p.width << ", " << p.height << "), B:" 49 << p.maxLockedBuffers << ", F:0x" 50 << ::std::hex << p.format << "]"; 51} 52 53class CpuConsumerTest : public ::testing::TestWithParam<CpuConsumerTestParams> { 54protected: 55 56 virtual void SetUp() { 57 const ::testing::TestInfo* const test_info = 58 ::testing::UnitTest::GetInstance()->current_test_info(); 59 CpuConsumerTestParams params = GetParam(); 60 ALOGV("** Starting test %s (%d x %d, %d, 0x%x)", 61 test_info->name(), 62 params.width, params.height, 63 params.maxLockedBuffers, params.format); 64 mCC = new CpuConsumer(params.maxLockedBuffers); 65 String8 name("CpuConsumer_Under_Test"); 66 mCC->setName(name); 67 mSTC = new SurfaceTextureClient(mCC->getProducerInterface()); 68 mANW = mSTC; 69 } 70 71 virtual void TearDown() { 72 mANW.clear(); 73 mSTC.clear(); 74 mCC.clear(); 75 } 76 77 class FrameWaiter : public CpuConsumer::FrameAvailableListener { 78 public: 79 FrameWaiter(): 80 mPendingFrames(0) { 81 } 82 83 void waitForFrame() { 84 Mutex::Autolock lock(mMutex); 85 while (mPendingFrames == 0) { 86 mCondition.wait(mMutex); 87 } 88 mPendingFrames--; 89 } 90 91 virtual void onFrameAvailable() { 92 Mutex::Autolock lock(mMutex); 93 mPendingFrames++; 94 mCondition.signal(); 95 } 96 97 int mPendingFrames; 98 Mutex mMutex; 99 Condition mCondition; 100 }; 101 102 // Note that SurfaceTexture will lose the notifications 103 // onBuffersReleased and onFrameAvailable as there is currently 104 // no way to forward the events. This DisconnectWaiter will not let the 105 // disconnect finish until finishDisconnect() is called. It will 106 // also block until a disconnect is called 107 class DisconnectWaiter : public BufferQueue::ConsumerListener { 108 public: 109 DisconnectWaiter () : 110 mWaitForDisconnect(false), 111 mPendingFrames(0) { 112 } 113 114 void waitForFrame() { 115 Mutex::Autolock lock(mMutex); 116 while (mPendingFrames == 0) { 117 mFrameCondition.wait(mMutex); 118 } 119 mPendingFrames--; 120 } 121 122 virtual void onFrameAvailable() { 123 Mutex::Autolock lock(mMutex); 124 mPendingFrames++; 125 mFrameCondition.signal(); 126 } 127 128 virtual void onBuffersReleased() { 129 Mutex::Autolock lock(mMutex); 130 while (!mWaitForDisconnect) { 131 mDisconnectCondition.wait(mMutex); 132 } 133 } 134 135 void finishDisconnect() { 136 Mutex::Autolock lock(mMutex); 137 mWaitForDisconnect = true; 138 mDisconnectCondition.signal(); 139 } 140 141 private: 142 Mutex mMutex; 143 144 bool mWaitForDisconnect; 145 Condition mDisconnectCondition; 146 147 int mPendingFrames; 148 Condition mFrameCondition; 149 }; 150 151 sp<CpuConsumer> mCC; 152 sp<SurfaceTextureClient> mSTC; 153 sp<ANativeWindow> mANW; 154}; 155 156#define ASSERT_NO_ERROR(err, msg) \ 157 ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err) 158 159void checkPixel(const CpuConsumer::LockedBuffer &buf, 160 uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) { 161 // Ignores components that don't exist for given pixel 162 switch(buf.format) { 163 case HAL_PIXEL_FORMAT_RAW_SENSOR: { 164 String8 msg; 165 uint16_t *bPtr = (uint16_t*)buf.data; 166 bPtr += y * buf.stride + x; 167 // GRBG Bayer mosaic; only check the matching channel 168 switch( ((y & 1) << 1) | (x & 1) ) { 169 case 0: // G 170 case 3: // G 171 EXPECT_EQ(g, *bPtr); 172 break; 173 case 1: // R 174 EXPECT_EQ(r, *bPtr); 175 break; 176 case 2: // B 177 EXPECT_EQ(b, *bPtr); 178 break; 179 } 180 break; 181 } 182 default: { 183 ADD_FAILURE() << "Unknown format for check:" << buf.format; 184 break; 185 } 186 } 187} 188 189// Fill a YV12 buffer with a multi-colored checkerboard pattern 190void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) { 191 const int blockWidth = w > 16 ? w / 16 : 1; 192 const int blockHeight = h > 16 ? h / 16 : 1; 193 const int yuvTexOffsetY = 0; 194 int yuvTexStrideY = stride; 195 int yuvTexOffsetV = yuvTexStrideY * h; 196 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 197 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; 198 int yuvTexStrideU = yuvTexStrideV; 199 for (int x = 0; x < w; x++) { 200 for (int y = 0; y < h; y++) { 201 int parityX = (x / blockWidth) & 1; 202 int parityY = (y / blockHeight) & 1; 203 unsigned char intensity = (parityX ^ parityY) ? 63 : 191; 204 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; 205 if (x < w / 2 && y < h / 2) { 206 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; 207 if (x * 2 < w / 2 && y * 2 < h / 2) { 208 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = 209 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = 210 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = 211 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = 212 intensity; 213 } 214 } 215 } 216 } 217} 218 219// Fill a RAW sensor buffer with a multi-colored checkerboard pattern. 220// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern 221// of [ R, B; G, W] 222void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) { 223 ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride); 224 // Blocks need to be even-width/height, aim for 8-wide otherwise 225 const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; 226 const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; 227 for (int y = 0; y < h; y+=2) { 228 uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y; 229 uint16_t *bPtr2 = bPtr1 + stride; 230 for (int x = 0; x < w; x+=2) { 231 int blockX = (x / blockWidth ) & 1; 232 int blockY = (y / blockHeight) & 1; 233 unsigned short r = (blockX == blockY) ? 1000 : 200; 234 unsigned short g = blockY ? 1000: 200; 235 unsigned short b = blockX ? 1000: 200; 236 // GR row 237 *bPtr1++ = g; 238 *bPtr1++ = r; 239 // BG row 240 *bPtr2++ = b; 241 *bPtr2++ = g; 242 } 243 } 244 245} 246 247void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { 248 uint32_t w = buf.width; 249 uint32_t h = buf.height; 250 const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; 251 const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; 252 const int blockRows = h / blockHeight; 253 const int blockCols = w / blockWidth; 254 255 // Top-left square is red 256 checkPixel(buf, 0, 0, 1000, 200, 200); 257 checkPixel(buf, 1, 0, 1000, 200, 200); 258 checkPixel(buf, 0, 1, 1000, 200, 200); 259 checkPixel(buf, 1, 1, 1000, 200, 200); 260 261 // One-right square is blue 262 checkPixel(buf, blockWidth, 0, 200, 200, 1000); 263 checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000); 264 checkPixel(buf, blockWidth, 1, 200, 200, 1000); 265 checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000); 266 267 // One-down square is green 268 checkPixel(buf, 0, blockHeight, 200, 1000, 200); 269 checkPixel(buf, 1, blockHeight, 200, 1000, 200); 270 checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200); 271 checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200); 272 273 // One-diag square is white 274 checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000); 275 checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000); 276 checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000); 277 checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000); 278 279 // Test bottom-right pixel 280 const int maxBlockX = ((w-1) / blockWidth) & 0x1; 281 const int maxBlockY = ((w-1) / blockHeight) & 0x1; 282 unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200; 283 unsigned short maxG = maxBlockY ? 1000: 200; 284 unsigned short maxB = maxBlockX ? 1000: 200; 285 checkPixel(buf, w-1, h-1, maxR, maxG, maxB); 286} 287 288// Fill a YV12 buffer with red outside a given rectangle and green inside it. 289void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, 290 const android_native_rect_t& rect) { 291 const int yuvTexOffsetY = 0; 292 int yuvTexStrideY = stride; 293 int yuvTexOffsetV = yuvTexStrideY * h; 294 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 295 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; 296 int yuvTexStrideU = yuvTexStrideV; 297 for (int x = 0; x < w; x++) { 298 for (int y = 0; y < h; y++) { 299 bool inside = rect.left <= x && x < rect.right && 300 rect.top <= y && y < rect.bottom; 301 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64; 302 if (x < w / 2 && y < h / 2) { 303 bool inside = rect.left <= 2*x && 2*x < rect.right && 304 rect.top <= 2*y && 2*y < rect.bottom; 305 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16; 306 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = 307 inside ? 16 : 255; 308 } 309 } 310 } 311} 312 313void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) { 314 const size_t PIXEL_SIZE = 4; 315 for (int x = 0; x < w; x++) { 316 for (int y = 0; y < h; y++) { 317 off_t offset = (y * stride + x) * PIXEL_SIZE; 318 for (int c = 0; c < 4; c++) { 319 int parityX = (x / (1 << (c+2))) & 1; 320 int parityY = (y / (1 << (c+2))) & 1; 321 buf[offset + c] = (parityX ^ parityY) ? 231 : 35; 322 } 323 } 324 } 325} 326 327void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, 328 uint8_t g, uint8_t b, uint8_t a) { 329 const size_t PIXEL_SIZE = 4; 330 for (int y = 0; y < h; y++) { 331 for (int x = 0; x < h; x++) { 332 off_t offset = (y * stride + x) * PIXEL_SIZE; 333 buf[offset + 0] = r; 334 buf[offset + 1] = g; 335 buf[offset + 2] = b; 336 buf[offset + 3] = a; 337 } 338 } 339} 340 341// Configures the ANativeWindow producer-side interface based on test parameters 342void configureANW(const sp<ANativeWindow>& anw, 343 const CpuConsumerTestParams& params, 344 int maxBufferSlack) { 345 status_t err; 346 err = native_window_set_buffers_geometry(anw.get(), 347 params.width, params.height, params.format); 348 ASSERT_NO_ERROR(err, "set_buffers_geometry error: "); 349 350 err = native_window_set_usage(anw.get(), 351 GRALLOC_USAGE_SW_WRITE_OFTEN); 352 ASSERT_NO_ERROR(err, "set_usage error: "); 353 354 int minUndequeuedBuffers; 355 err = anw.get()->query(anw.get(), 356 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 357 &minUndequeuedBuffers); 358 ASSERT_NO_ERROR(err, "query error: "); 359 360 ALOGVV("Setting buffer count to %d", 361 maxBufferSlack + 1 + minUndequeuedBuffers); 362 err = native_window_set_buffer_count(anw.get(), 363 maxBufferSlack + 1 + minUndequeuedBuffers); 364 ASSERT_NO_ERROR(err, "set_buffer_count error: "); 365 366} 367 368// Produce one frame of image data; assumes format and resolution configuration 369// is already done. 370void produceOneFrame(const sp<ANativeWindow>& anw, 371 const CpuConsumerTestParams& params, 372 int64_t timestamp, uint32_t *stride) { 373 status_t err; 374 ANativeWindowBuffer* anb; 375 ALOGVV("Dequeue buffer from %p", anw.get()); 376 err = anw->dequeueBuffer(anw.get(), &anb); 377 ASSERT_NO_ERROR(err, "dequeueBuffer error: "); 378 379 ASSERT_TRUE(anb != NULL); 380 381 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); 382 383 ALOGVV("Lock buffer from %p", anw.get()); 384 err = anw->lockBuffer(anw.get(), buf->getNativeBuffer()); 385 ASSERT_NO_ERROR(err, "lockBuffer error: "); 386 387 *stride = buf->getStride(); 388 uint8_t* img = NULL; 389 390 ALOGVV("Lock buffer from %p for write", anw.get()); 391 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 392 ASSERT_NO_ERROR(err, "lock error: "); 393 394 switch (params.format) { 395 case HAL_PIXEL_FORMAT_YV12: 396 fillYV12Buffer(img, params.width, params.height, *stride); 397 break; 398 case HAL_PIXEL_FORMAT_RAW_SENSOR: 399 fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); 400 break; 401 default: 402 FAIL() << "Unknown pixel format under test!"; 403 break; 404 } 405 ALOGVV("Unlock buffer from %p", anw.get()); 406 err = buf->unlock(); 407 ASSERT_NO_ERROR(err, "unlock error: "); 408 409 ALOGVV("Set timestamp to %p", anw.get()); 410 err = native_window_set_buffers_timestamp(anw.get(), timestamp); 411 ASSERT_NO_ERROR(err, "set_buffers_timestamp error: "); 412 413 ALOGVV("Queue buffer to %p", anw.get()); 414 err = anw->queueBuffer(anw.get(), buf->getNativeBuffer()); 415 ASSERT_NO_ERROR(err, "queueBuffer error:"); 416}; 417 418TEST_P(CpuConsumerTest, FromCpuSingle) { 419 status_t err; 420 CpuConsumerTestParams params = GetParam(); 421 422 // Set up 423 424 ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1)); 425 426 // Produce 427 428 const int64_t time = 12345678L; 429 uint32_t stride; 430 ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, 431 &stride)); 432 433 // Consume 434 435 CpuConsumer::LockedBuffer b; 436 err = mCC->lockNextBuffer(&b); 437 ASSERT_NO_ERROR(err, "getNextBuffer error: "); 438 439 ASSERT_TRUE(b.data != NULL); 440 EXPECT_EQ(params.width, b.width); 441 EXPECT_EQ(params.height, b.height); 442 EXPECT_EQ(params.format, b.format); 443 EXPECT_EQ(stride, b.stride); 444 EXPECT_EQ(time, b.timestamp); 445 446 checkBayerRawBuffer(b); 447 mCC->unlockBuffer(b); 448} 449 450TEST_P(CpuConsumerTest, FromCpuManyInQueue) { 451 status_t err; 452 CpuConsumerTestParams params = GetParam(); 453 454 const int numInQueue = 5; 455 // Set up 456 457 ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue)); 458 459 // Produce 460 461 const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L}; 462 uint32_t stride[numInQueue]; 463 464 for (int i = 0; i < numInQueue; i++) { 465 ALOGV("Producing frame %d", i); 466 ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i], 467 &stride[i])); 468 } 469 470 // Consume 471 472 for (int i = 0; i < numInQueue; i++) { 473 ALOGV("Consuming frame %d", i); 474 CpuConsumer::LockedBuffer b; 475 err = mCC->lockNextBuffer(&b); 476 ASSERT_NO_ERROR(err, "getNextBuffer error: "); 477 478 ASSERT_TRUE(b.data != NULL); 479 EXPECT_EQ(params.width, b.width); 480 EXPECT_EQ(params.height, b.height); 481 EXPECT_EQ(params.format, b.format); 482 EXPECT_EQ(stride[i], b.stride); 483 EXPECT_EQ(time[i], b.timestamp); 484 485 checkBayerRawBuffer(b); 486 487 mCC->unlockBuffer(b); 488 } 489} 490 491TEST_P(CpuConsumerTest, FromCpuLockMax) { 492 status_t err; 493 CpuConsumerTestParams params = GetParam(); 494 495 // Set up 496 497 ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); 498 499 // Produce 500 501 const int64_t time = 1234L; 502 uint32_t stride; 503 504 for (int i = 0; i < params.maxLockedBuffers + 1; i++) { 505 ALOGV("Producing frame %d", i); 506 ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, 507 &stride)); 508 } 509 510 // Consume 511 512 CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers]; 513 for (int i = 0; i < params.maxLockedBuffers; i++) { 514 ALOGV("Locking frame %d", i); 515 err = mCC->lockNextBuffer(&b[i]); 516 ASSERT_NO_ERROR(err, "getNextBuffer error: "); 517 518 ASSERT_TRUE(b[i].data != NULL); 519 EXPECT_EQ(params.width, b[i].width); 520 EXPECT_EQ(params.height, b[i].height); 521 EXPECT_EQ(params.format, b[i].format); 522 EXPECT_EQ(stride, b[i].stride); 523 EXPECT_EQ(time, b[i].timestamp); 524 525 checkBayerRawBuffer(b[i]); 526 } 527 528 ALOGV("Locking frame %d (too many)", params.maxLockedBuffers); 529 CpuConsumer::LockedBuffer bTooMuch; 530 err = mCC->lockNextBuffer(&bTooMuch); 531 ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks"; 532 533 ALOGV("Unlocking frame 0"); 534 err = mCC->unlockBuffer(b[0]); 535 ASSERT_NO_ERROR(err, "Could not unlock buffer 0: "); 536 537 ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers); 538 err = mCC->lockNextBuffer(&bTooMuch); 539 ASSERT_NO_ERROR(err, "Did not allow new lock after unlock"); 540 541 ASSERT_TRUE(bTooMuch.data != NULL); 542 EXPECT_EQ(params.width, bTooMuch.width); 543 EXPECT_EQ(params.height, bTooMuch.height); 544 EXPECT_EQ(params.format, bTooMuch.format); 545 EXPECT_EQ(stride, bTooMuch.stride); 546 EXPECT_EQ(time, bTooMuch.timestamp); 547 548 checkBayerRawBuffer(bTooMuch); 549 550 ALOGV("Unlocking extra buffer"); 551 err = mCC->unlockBuffer(bTooMuch); 552 ASSERT_NO_ERROR(err, "Could not unlock extra buffer: "); 553 554 ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1); 555 err = mCC->lockNextBuffer(&b[0]); 556 ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow"; 557 558 for (int i = 1; i < params.maxLockedBuffers; i++) { 559 mCC->unlockBuffer(b[i]); 560 } 561 562 delete[] b; 563 564} 565 566CpuConsumerTestParams rawTestSets[] = { 567 { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, 568 { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, 569 { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, 570 { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, 571 { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, 572 { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR} 573}; 574 575INSTANTIATE_TEST_CASE_P(RawTests, 576 CpuConsumerTest, 577 ::testing::ValuesIn(rawTestSets)); 578 579} // namespace android 580