1/*
2 * Copyright 2014 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 "StreamSplitter_test"
18//#define LOG_NDEBUG 0
19
20#include <gui/BufferItem.h>
21#include <gui/BufferQueue.h>
22#include <gui/IConsumerListener.h>
23#include <gui/ISurfaceComposer.h>
24#include <gui/StreamSplitter.h>
25#include <private/gui/ComposerService.h>
26
27#include <gtest/gtest.h>
28
29namespace android {
30
31class StreamSplitterTest : public ::testing::Test {
32
33protected:
34    StreamSplitterTest() {
35        const ::testing::TestInfo* const testInfo =
36            ::testing::UnitTest::GetInstance()->current_test_info();
37        ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
38                testInfo->name());
39    }
40
41    ~StreamSplitterTest() {
42        const ::testing::TestInfo* const testInfo =
43            ::testing::UnitTest::GetInstance()->current_test_info();
44        ALOGV("End test:   %s.%s", testInfo->test_case_name(),
45                testInfo->name());
46    }
47};
48
49struct DummyListener : public BnConsumerListener {
50    virtual void onFrameAvailable(const BufferItem& /* item */) {}
51    virtual void onBuffersReleased() {}
52    virtual void onSidebandStreamChanged() {}
53};
54
55static const uint32_t TEST_DATA = 0x12345678u;
56
57TEST_F(StreamSplitterTest, OneInputOneOutput) {
58    sp<IGraphicBufferProducer> inputProducer;
59    sp<IGraphicBufferConsumer> inputConsumer;
60    BufferQueue::createBufferQueue(&inputProducer, &inputConsumer);
61
62    sp<IGraphicBufferProducer> outputProducer;
63    sp<IGraphicBufferConsumer> outputConsumer;
64    BufferQueue::createBufferQueue(&outputProducer, &outputConsumer);
65    ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false));
66
67    sp<StreamSplitter> splitter;
68    status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter);
69    ASSERT_EQ(OK, status);
70    ASSERT_EQ(OK, splitter->addOutput(outputProducer));
71
72    // Never allow the output BufferQueue to allocate a buffer
73    ASSERT_EQ(OK, outputProducer->allowAllocation(false));
74
75    IGraphicBufferProducer::QueueBufferOutput qbOutput;
76    ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener,
77            NATIVE_WINDOW_API_CPU, false, &qbOutput));
78
79    int slot;
80    sp<Fence> fence;
81    sp<GraphicBuffer> buffer;
82    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
83            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
84                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
85    ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
86
87    uint32_t* dataIn;
88    ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
89            reinterpret_cast<void**>(&dataIn)));
90    *dataIn = TEST_DATA;
91    ASSERT_EQ(OK, buffer->unlock());
92
93    IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
94            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
95            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
96    ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
97
98    // Now that we have dequeued/allocated one buffer, prevent any further
99    // allocations
100    ASSERT_EQ(OK, inputProducer->allowAllocation(false));
101
102    BufferItem item;
103    ASSERT_EQ(OK, outputConsumer->acquireBuffer(&item, 0));
104
105    uint32_t* dataOut;
106    ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
107            reinterpret_cast<void**>(&dataOut)));
108    ASSERT_EQ(*dataOut, TEST_DATA);
109    ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
110
111    ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
112            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
113
114    // This should succeed even with allocation disabled since it will have
115    // received the buffer back from the output BufferQueue
116    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
117            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
118                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
119}
120
121TEST_F(StreamSplitterTest, OneInputMultipleOutputs) {
122    const int NUM_OUTPUTS = 4;
123
124    sp<IGraphicBufferProducer> inputProducer;
125    sp<IGraphicBufferConsumer> inputConsumer;
126    BufferQueue::createBufferQueue(&inputProducer, &inputConsumer);
127
128    sp<IGraphicBufferProducer> outputProducers[NUM_OUTPUTS] = {};
129    sp<IGraphicBufferConsumer> outputConsumers[NUM_OUTPUTS] = {};
130    for (int output = 0; output < NUM_OUTPUTS; ++output) {
131        BufferQueue::createBufferQueue(&outputProducers[output],
132                &outputConsumers[output]);
133        ASSERT_EQ(OK, outputConsumers[output]->consumerConnect(
134                    new DummyListener, false));
135    }
136
137    sp<StreamSplitter> splitter;
138    status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter);
139    ASSERT_EQ(OK, status);
140    for (int output = 0; output < NUM_OUTPUTS; ++output) {
141        ASSERT_EQ(OK, splitter->addOutput(outputProducers[output]));
142
143        // Never allow the output BufferQueues to allocate a buffer
144        ASSERT_EQ(OK, outputProducers[output]->allowAllocation(false));
145    }
146
147    IGraphicBufferProducer::QueueBufferOutput qbOutput;
148    ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener,
149            NATIVE_WINDOW_API_CPU, false, &qbOutput));
150
151    int slot;
152    sp<Fence> fence;
153    sp<GraphicBuffer> buffer;
154    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
155            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
156                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
157    ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
158
159    uint32_t* dataIn;
160    ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
161            reinterpret_cast<void**>(&dataIn)));
162    *dataIn = TEST_DATA;
163    ASSERT_EQ(OK, buffer->unlock());
164
165    IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
166            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
167            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
168    ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
169
170    // Now that we have dequeued/allocated one buffer, prevent any further
171    // allocations
172    ASSERT_EQ(OK, inputProducer->allowAllocation(false));
173
174    for (int output = 0; output < NUM_OUTPUTS; ++output) {
175        BufferItem item;
176        ASSERT_EQ(OK, outputConsumers[output]->acquireBuffer(&item, 0));
177
178        uint32_t* dataOut;
179        ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
180                    reinterpret_cast<void**>(&dataOut)));
181        ASSERT_EQ(*dataOut, TEST_DATA);
182        ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
183
184        ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mSlot,
185                    item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
186                    Fence::NO_FENCE));
187    }
188
189    // This should succeed even with allocation disabled since it will have
190    // received the buffer back from the output BufferQueues
191    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
192            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
193                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
194}
195
196TEST_F(StreamSplitterTest, OutputAbandonment) {
197    sp<IGraphicBufferProducer> inputProducer;
198    sp<IGraphicBufferConsumer> inputConsumer;
199    BufferQueue::createBufferQueue(&inputProducer, &inputConsumer);
200
201    sp<IGraphicBufferProducer> outputProducer;
202    sp<IGraphicBufferConsumer> outputConsumer;
203    BufferQueue::createBufferQueue(&outputProducer, &outputConsumer);
204    ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false));
205
206    sp<StreamSplitter> splitter;
207    status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter);
208    ASSERT_EQ(OK, status);
209    ASSERT_EQ(OK, splitter->addOutput(outputProducer));
210
211    IGraphicBufferProducer::QueueBufferOutput qbOutput;
212    ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener,
213            NATIVE_WINDOW_API_CPU, false, &qbOutput));
214
215    int slot;
216    sp<Fence> fence;
217    sp<GraphicBuffer> buffer;
218    ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
219            inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
220                    GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
221    ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer));
222
223    // Abandon the output
224    outputConsumer->consumerDisconnect();
225
226    IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
227            HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
228            NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
229    ASSERT_EQ(OK, inputProducer->queueBuffer(slot, qbInput, &qbOutput));
230
231    // Input should be abandoned
232    ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
233            GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr));
234}
235
236} // namespace android
237