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
29 namespace android {
30
31 class StreamSplitterTest : public ::testing::Test {
32
33 protected:
StreamSplitterTest()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
~StreamSplitterTest()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
49 struct DummyListener : public BnConsumerListener {
onFrameAvailableandroid::DummyListener50 virtual void onFrameAvailable(const BufferItem& /* item */) {}
onBuffersReleasedandroid::DummyListener51 virtual void onBuffersReleased() {}
onSidebandStreamChangedandroid::DummyListener52 virtual void onSidebandStreamChanged() {}
53 };
54
55 static const uint32_t TEST_DATA = 0x12345678u;
56
TEST_F(StreamSplitterTest,OneInputOneOutput)57 TEST_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));
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));
119 }
120
TEST_F(StreamSplitterTest,OneInputMultipleOutputs)121 TEST_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));
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));
194 }
195
TEST_F(StreamSplitterTest,OutputAbandonment)196 TEST_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));
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));
234 }
235
236 } // namespace android
237