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