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