1/*
2 * Copyright (C) 2017 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 "BufferItemConsumer_test"
18//#define LOG_NDEBUG 0
19
20#include <gtest/gtest.h>
21#include <gui/BufferItemConsumer.h>
22#include <gui/IProducerListener.h>
23#include <gui/Surface.h>
24
25namespace android {
26
27static constexpr int kWidth = 100;
28static constexpr int kHeight = 100;
29static constexpr int kMaxLockedBuffers = 3;
30static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
31static constexpr int kFrameSleepUs = 30 * 1000;
32
33class BufferItemConsumerTest : public ::testing::Test {
34   protected:
35    struct BufferFreedListener
36        : public BufferItemConsumer::BufferFreedListener {
37        explicit BufferFreedListener(BufferItemConsumerTest* test)
38            : mTest(test) {}
39        void onBufferFreed(const wp<GraphicBuffer>& /* gBuffer */) override {
40            mTest->HandleBufferFreed();
41        }
42        BufferItemConsumerTest* mTest;
43    };
44
45    void SetUp() override {
46        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
47        mBIC =
48            new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true);
49        String8 name("BufferItemConsumer_Under_Test");
50        mBIC->setName(name);
51        mBFL = new BufferFreedListener(this);
52        mBIC->setBufferFreedListener(mBFL);
53
54        sp<IProducerListener> producerListener = new DummyProducerListener();
55        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
56        ASSERT_EQ(NO_ERROR,
57                  mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
58                                     true, &bufferOutput));
59        ASSERT_EQ(NO_ERROR,
60                  mProducer->setMaxDequeuedBufferCount(kMaxLockedBuffers));
61    }
62
63    int GetFreedBufferCount() {
64        std::lock_guard<std::mutex> lock(mMutex);
65        return mFreedBufferCount;
66    }
67
68    void HandleBufferFreed() {
69        std::lock_guard<std::mutex> lock(mMutex);
70        mFreedBufferCount++;
71        ALOGV("HandleBufferFreed, mFreedBufferCount=%d", mFreedBufferCount);
72    }
73
74    void DequeueBuffer(int* outSlot) {
75        ASSERT_NE(outSlot, nullptr);
76
77        int slot;
78        sp<Fence> outFence;
79        status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth, kHeight, 0, 0,
80                                                nullptr, nullptr);
81        ASSERT_GE(ret, 0);
82
83        ALOGV("dequeueBuffer: slot=%d", slot);
84        if (ret & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
85            ret = mProducer->requestBuffer(slot, &mBuffers[slot]);
86            ASSERT_EQ(NO_ERROR, ret);
87        }
88        *outSlot = slot;
89    }
90
91    void QueueBuffer(int slot) {
92        ALOGV("enqueueBuffer: slot=%d", slot);
93        IGraphicBufferProducer::QueueBufferInput bufferInput(
94            0ULL, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
95            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
96        IGraphicBufferProducer::QueueBufferOutput bufferOutput;
97        status_t ret = mProducer->queueBuffer(slot, bufferInput, &bufferOutput);
98        ASSERT_EQ(NO_ERROR, ret);
99    }
100
101    void AcquireBuffer(int* outSlot) {
102        ASSERT_NE(outSlot, nullptr);
103        BufferItem buffer;
104        status_t ret = mBIC->acquireBuffer(&buffer, 0, false);
105        ASSERT_EQ(NO_ERROR, ret);
106
107        ALOGV("acquireBuffer: slot=%d", buffer.mSlot);
108        *outSlot = buffer.mSlot;
109    }
110
111    void ReleaseBuffer(int slot) {
112        ALOGV("releaseBuffer: slot=%d", slot);
113        BufferItem buffer;
114        buffer.mSlot = slot;
115        buffer.mGraphicBuffer = mBuffers[slot];
116        status_t ret = mBIC->releaseBuffer(buffer, Fence::NO_FENCE);
117        ASSERT_EQ(NO_ERROR, ret);
118    }
119
120
121    std::mutex mMutex;
122    int mFreedBufferCount{0};
123
124    sp<BufferItemConsumer> mBIC;
125    sp<BufferFreedListener> mBFL;
126    sp<IGraphicBufferProducer> mProducer;
127    sp<IGraphicBufferConsumer> mConsumer;
128    sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
129};
130
131// Test that detaching buffer from consumer side triggers onBufferFreed.
132TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) {
133    int slot;
134    // Producer: generate a dummy buffer.
135    DequeueBuffer(&slot);
136    QueueBuffer(slot);
137
138    ASSERT_EQ(0, GetFreedBufferCount());
139    // Consumer: acquire the buffer and then detach it.
140    AcquireBuffer(&slot);
141    status_t ret = mBIC->detachBuffer(slot);
142    ASSERT_EQ(NO_ERROR, ret);
143
144    // Sleep to give some time for callbacks to happen.
145    usleep(kFrameSleepUs);
146    ASSERT_EQ(1, GetFreedBufferCount());
147}
148
149// Test that detaching buffer from producer side triggers onBufferFreed.
150TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromProducer) {
151    int slot;
152    // Let buffer go through the cycle at least once.
153    DequeueBuffer(&slot);
154    QueueBuffer(slot);
155    AcquireBuffer(&slot);
156    ReleaseBuffer(slot);
157
158    ASSERT_EQ(0, GetFreedBufferCount());
159
160    // Producer: generate the buffer again.
161    DequeueBuffer(&slot);
162
163    // Producer: detach the buffer.
164    status_t ret = mProducer->detachBuffer(slot);
165    ASSERT_EQ(NO_ERROR, ret);
166
167    // Sleep to give some time for callbacks to happen.
168    usleep(kFrameSleepUs);
169    ASSERT_EQ(1, GetFreedBufferCount());
170}
171
172// Test that abandoning BufferItemConsumer triggers onBufferFreed.
173TEST_F(BufferItemConsumerTest, TriggerBufferFreed_AbandonBufferItemConsumer) {
174    int slot;
175    // Let buffer go through the cycle at least once.
176    DequeueBuffer(&slot);
177    QueueBuffer(slot);
178    AcquireBuffer(&slot);
179    ReleaseBuffer(slot);
180
181    // Abandon the BufferItemConsumer.
182    mBIC->abandon();
183
184    // Sleep to give some time for callbacks to happen.
185    usleep(kFrameSleepUs);
186    ASSERT_EQ(1, GetFreedBufferCount());
187}
188
189// Test that delete BufferItemConsumer triggers onBufferFreed.
190TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) {
191    int slot;
192    // Let buffer go through the cycle at least once.
193    DequeueBuffer(&slot);
194    QueueBuffer(slot);
195    AcquireBuffer(&slot);
196    ReleaseBuffer(slot);
197
198    // Delete the BufferItemConsumer.
199    mBIC.clear();
200
201    // Sleep to give some time for callbacks to happen.
202    usleep(kFrameSleepUs);
203    ASSERT_EQ(1, GetFreedBufferCount());
204}
205
206}  // namespace android
207