CpuConsumer_test.cpp revision d8e812ce6fe9ae0388e98b08456e1d18b9498239
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 192// Fill a RAW sensor buffer with a multi-colored checkerboard pattern. 193// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern 194// of [ R, B; G, W] 195void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) { 196 ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride); 197 // Blocks need to be even-width/height, aim for 8-wide otherwise 198 const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; 199 const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; 200 for (int y = 0; y < h; y+=2) { 201 uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y; 202 uint16_t *bPtr2 = bPtr1 + stride; 203 for (int x = 0; x < w; x+=2) { 204 int blockX = (x / blockWidth ) & 1; 205 int blockY = (y / blockHeight) & 1; 206 unsigned short r = (blockX == blockY) ? 1000 : 200; 207 unsigned short g = blockY ? 1000: 200; 208 unsigned short b = blockX ? 1000: 200; 209 // GR row 210 *bPtr1++ = g; 211 *bPtr1++ = r; 212 // BG row 213 *bPtr2++ = b; 214 *bPtr2++ = g; 215 } 216 } 217 218} 219 220void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { 221 uint32_t w = buf.width; 222 uint32_t h = buf.height; 223 const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1; 224 const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1; 225 const int blockRows = h / blockHeight; 226 const int blockCols = w / blockWidth; 227 228 // Top-left square is red 229 checkPixel(buf, 0, 0, 1000, 200, 200); 230 checkPixel(buf, 1, 0, 1000, 200, 200); 231 checkPixel(buf, 0, 1, 1000, 200, 200); 232 checkPixel(buf, 1, 1, 1000, 200, 200); 233 234 // One-right square is blue 235 checkPixel(buf, blockWidth, 0, 200, 200, 1000); 236 checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000); 237 checkPixel(buf, blockWidth, 1, 200, 200, 1000); 238 checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000); 239 240 // One-down square is green 241 checkPixel(buf, 0, blockHeight, 200, 1000, 200); 242 checkPixel(buf, 1, blockHeight, 200, 1000, 200); 243 checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200); 244 checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200); 245 246 // One-diag square is white 247 checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000); 248 checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000); 249 checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000); 250 checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000); 251 252 // Test bottom-right pixel 253 const int maxBlockX = ((w-1) / blockWidth) & 0x1; 254 const int maxBlockY = ((w-1) / blockHeight) & 0x1; 255 unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200; 256 unsigned short maxG = maxBlockY ? 1000: 200; 257 unsigned short maxB = maxBlockX ? 1000: 200; 258 checkPixel(buf, w-1, h-1, maxR, maxG, maxB); 259} 260 261void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, 262 const android_native_rect_t& rect); 263 264void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride); 265 266void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r, 267 uint8_t g, uint8_t b, uint8_t a); 268 269// Configures the ANativeWindow producer-side interface based on test parameters 270void configureANW(const sp<ANativeWindow>& anw, 271 const CpuConsumerTestParams& params, 272 int maxBufferSlack) { 273 status_t err; 274 err = native_window_set_buffers_geometry(anw.get(), 275 params.width, params.height, params.format); 276 ASSERT_NO_ERROR(err, "set_buffers_geometry error: "); 277 278 err = native_window_set_usage(anw.get(), 279 GRALLOC_USAGE_SW_WRITE_OFTEN); 280 ASSERT_NO_ERROR(err, "set_usage error: "); 281 282 int minUndequeuedBuffers; 283 err = anw.get()->query(anw.get(), 284 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 285 &minUndequeuedBuffers); 286 ASSERT_NO_ERROR(err, "query error: "); 287 288 ALOGVV("Setting buffer count to %d", 289 maxBufferSlack + 1 + minUndequeuedBuffers); 290 err = native_window_set_buffer_count(anw.get(), 291 maxBufferSlack + 1 + minUndequeuedBuffers); 292 ASSERT_NO_ERROR(err, "set_buffer_count error: "); 293 294} 295 296// Produce one frame of image data; assumes format and resolution configuration 297// is already done. 298void produceOneFrame(const sp<ANativeWindow>& anw, 299 const CpuConsumerTestParams& params, 300 int64_t timestamp, uint32_t *stride) { 301 status_t err; 302 ANativeWindowBuffer* anb; 303 ALOGVV("Dequeue buffer from %p", anw.get()); 304 err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); 305 ASSERT_NO_ERROR(err, "dequeueBuffer error: "); 306 307 ASSERT_TRUE(anb != NULL); 308 309 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); 310 311 *stride = buf->getStride(); 312 uint8_t* img = NULL; 313 314 ALOGVV("Lock buffer from %p for write", anw.get()); 315 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 316 ASSERT_NO_ERROR(err, "lock error: "); 317 318 switch (params.format) { 319 case HAL_PIXEL_FORMAT_YV12: 320 fillYV12Buffer(img, params.width, params.height, *stride); 321 break; 322 case HAL_PIXEL_FORMAT_RAW_SENSOR: 323 fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); 324 break; 325 default: 326 FAIL() << "Unknown pixel format under test!"; 327 break; 328 } 329 ALOGVV("Unlock buffer from %p", anw.get()); 330 err = buf->unlock(); 331 ASSERT_NO_ERROR(err, "unlock error: "); 332 333 ALOGVV("Set timestamp to %p", anw.get()); 334 err = native_window_set_buffers_timestamp(anw.get(), timestamp); 335 ASSERT_NO_ERROR(err, "set_buffers_timestamp error: "); 336 337 ALOGVV("Queue buffer to %p", anw.get()); 338 err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1); 339 ASSERT_NO_ERROR(err, "queueBuffer error:"); 340}; 341 342TEST_P(CpuConsumerTest, FromCpuSingle) { 343 status_t err; 344 CpuConsumerTestParams params = GetParam(); 345 346 // Set up 347 348 ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1)); 349 350 // Produce 351 352 const int64_t time = 12345678L; 353 uint32_t stride; 354 ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, 355 &stride)); 356 357 // Consume 358 359 CpuConsumer::LockedBuffer b; 360 err = mCC->lockNextBuffer(&b); 361 ASSERT_NO_ERROR(err, "getNextBuffer error: "); 362 363 ASSERT_TRUE(b.data != NULL); 364 EXPECT_EQ(params.width, b.width); 365 EXPECT_EQ(params.height, b.height); 366 EXPECT_EQ(params.format, b.format); 367 EXPECT_EQ(stride, b.stride); 368 EXPECT_EQ(time, b.timestamp); 369 370 checkBayerRawBuffer(b); 371 mCC->unlockBuffer(b); 372} 373 374TEST_P(CpuConsumerTest, FromCpuManyInQueue) { 375 status_t err; 376 CpuConsumerTestParams params = GetParam(); 377 378 const int numInQueue = 5; 379 // Set up 380 381 ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue)); 382 383 // Produce 384 385 const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L}; 386 uint32_t stride[numInQueue]; 387 388 for (int i = 0; i < numInQueue; i++) { 389 ALOGV("Producing frame %d", i); 390 ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i], 391 &stride[i])); 392 } 393 394 // Consume 395 396 for (int i = 0; i < numInQueue; i++) { 397 ALOGV("Consuming frame %d", i); 398 CpuConsumer::LockedBuffer b; 399 err = mCC->lockNextBuffer(&b); 400 ASSERT_NO_ERROR(err, "getNextBuffer error: "); 401 402 ASSERT_TRUE(b.data != NULL); 403 EXPECT_EQ(params.width, b.width); 404 EXPECT_EQ(params.height, b.height); 405 EXPECT_EQ(params.format, b.format); 406 EXPECT_EQ(stride[i], b.stride); 407 EXPECT_EQ(time[i], b.timestamp); 408 409 checkBayerRawBuffer(b); 410 411 mCC->unlockBuffer(b); 412 } 413} 414 415TEST_P(CpuConsumerTest, FromCpuLockMax) { 416 status_t err; 417 CpuConsumerTestParams params = GetParam(); 418 419 // Set up 420 421 ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); 422 423 // Produce 424 425 const int64_t time = 1234L; 426 uint32_t stride; 427 428 for (int i = 0; i < params.maxLockedBuffers + 1; i++) { 429 ALOGV("Producing frame %d", i); 430 ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, 431 &stride)); 432 } 433 434 // Consume 435 436 CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers]; 437 for (int i = 0; i < params.maxLockedBuffers; i++) { 438 ALOGV("Locking frame %d", i); 439 err = mCC->lockNextBuffer(&b[i]); 440 ASSERT_NO_ERROR(err, "getNextBuffer error: "); 441 442 ASSERT_TRUE(b[i].data != NULL); 443 EXPECT_EQ(params.width, b[i].width); 444 EXPECT_EQ(params.height, b[i].height); 445 EXPECT_EQ(params.format, b[i].format); 446 EXPECT_EQ(stride, b[i].stride); 447 EXPECT_EQ(time, b[i].timestamp); 448 449 checkBayerRawBuffer(b[i]); 450 } 451 452 ALOGV("Locking frame %d (too many)", params.maxLockedBuffers); 453 CpuConsumer::LockedBuffer bTooMuch; 454 err = mCC->lockNextBuffer(&bTooMuch); 455 ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks"; 456 457 ALOGV("Unlocking frame 0"); 458 err = mCC->unlockBuffer(b[0]); 459 ASSERT_NO_ERROR(err, "Could not unlock buffer 0: "); 460 461 ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers); 462 err = mCC->lockNextBuffer(&bTooMuch); 463 ASSERT_NO_ERROR(err, "Did not allow new lock after unlock"); 464 465 ASSERT_TRUE(bTooMuch.data != NULL); 466 EXPECT_EQ(params.width, bTooMuch.width); 467 EXPECT_EQ(params.height, bTooMuch.height); 468 EXPECT_EQ(params.format, bTooMuch.format); 469 EXPECT_EQ(stride, bTooMuch.stride); 470 EXPECT_EQ(time, bTooMuch.timestamp); 471 472 checkBayerRawBuffer(bTooMuch); 473 474 ALOGV("Unlocking extra buffer"); 475 err = mCC->unlockBuffer(bTooMuch); 476 ASSERT_NO_ERROR(err, "Could not unlock extra buffer: "); 477 478 ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1); 479 err = mCC->lockNextBuffer(&b[0]); 480 ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow"; 481 482 for (int i = 1; i < params.maxLockedBuffers; i++) { 483 mCC->unlockBuffer(b[i]); 484 } 485 486 delete[] b; 487 488} 489 490CpuConsumerTestParams rawTestSets[] = { 491 { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, 492 { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, 493 { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, 494 { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, 495 { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, 496 { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR} 497}; 498 499INSTANTIATE_TEST_CASE_P(RawTests, 500 CpuConsumerTest, 501 ::testing::ValuesIn(rawTestSets)); 502 503} // namespace android 504