1 /*
2  * Copyright 2016 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 #ifndef ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
18 #define ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
19 
20 #include <list>
21 #include <algorithm>
22 #include <ui/GraphicBuffer.h>
23 #include <utils/RefBase.h>
24 #include <utils/KeyedVector.h>
25 #include "Camera3OutputStream.h"
26 
27 namespace android {
28 
29 namespace camera3 {
30 
31 struct StreamInfo;
32 class Camera3OutputStream;
33 
34 /**
35  * A class managing the graphic buffers that is used by camera output streams. It allocates and
36  * hands out Gralloc buffers to the clients (e.g., Camera3OutputStream) based on the requests.
37  * When clients request a buffer, buffer manager will pick a buffer if there are some already
38  * allocated buffer available, will allocate a buffer otherwise. When there are too many allocated
39  * buffer maintained by the buffer manager, it will dynamically deallocate some buffers that are
40  * solely owned by this buffer manager.
41  * In doing so, it reduces the memory footprint unless it is already minimal without impacting
42  * performance.
43  *
44  */
45 class Camera3BufferManager: public virtual RefBase {
46 public:
47     explicit Camera3BufferManager();
48 
49     virtual ~Camera3BufferManager();
50 
51     /**
52      * This method registers an output stream to this buffer manager by using the provided stream
53      * information.
54      *
55      * The stream info includes the necessary information such as stream size, format, buffer count,
56      * usage flags, etc. for the buffer manager to allocate and hand out buffers for this stream.
57      *
58      * It's illegal to call this method if the stream is not CONFIGURED yet, as some critical
59      * stream properties (e.g., combined usage flags) are only available in this state. It is also
60      * illegal to call this method with an invalid stream set ID (CAMERA3_STREAM_SET_ID_INVALID),
61      * as the invalid stream set ID indicates that this stream doesn't intend to use buffer manager.
62      *
63      *
64      * Once a stream is successfully registered to this buffer manager, the buffer manager takes
65      * over the buffer allocation role and provides buffers to this stream via getBufferForStream().
66      * The returned buffer can be sent to the camera HAL for image output, and then queued to the
67      * ANativeWindow (Surface) for downstream consumer to acquire. Once the image buffer is released
68      * by the consumer end point, the BufferQueueProducer callback onBufferReleased will call
69      * returnBufferForStream() to return the free buffer to this buffer manager. If the stream
70      * uses buffer manager to manage the stream buffers, it should disable the BufferQueue
71      * allocation via IGraphicBufferProducer::allowAllocation(false).
72      *
73      * Registering an already registered stream has no effect.
74      *
75      * Return values:
76      *
77      *  OK:                Registration of the new stream was successful.
78      *  BAD_VALUE:         This stream is not at CONFIGURED state, or the stream ID or stream set
79      *                     ID are invalid, or attempting to register the same stream to multiple
80      *                     stream sets, or other stream properties are invalid.
81      *  INVALID_OPERATION: This buffer manager doesn't support buffer sharing across this stream
82      *                     and other streams that were already registered with the same stream set
83      *                     ID.
84      */
85     status_t registerStream(wp<Camera3OutputStream>& stream, const StreamInfo &streamInfo);
86 
87     /**
88      * This method unregisters a stream from this buffer manager.
89      *
90      * After a stream is unregistered, further getBufferForStream() calls will fail for this stream.
91      * After all streams for a given stream set are unregistered, all the buffers solely owned (for
92      * this stream set) by this buffer manager will be freed; all buffers subsequently returned to
93      * this buffer manager for this stream set will be freed immediately.
94      *
95      * Return values:
96      *
97      *  OK:        Removal of the a stream from this buffer manager was successful.
98      *  BAD_VALUE: stream ID or stream set ID are invalid, or stream ID and stream set ID
99      *             combination doesn't match what was registered, or this stream wasn't registered
100      *             to this buffer manager before.
101      */
102     status_t unregisterStream(int streamId, int streamSetId);
103 
104     /**
105      * This method obtains a buffer for a stream from this buffer manager.
106      *
107      * This method returns the first free buffer from the free buffer list (associated with this
108      * stream set) if there is any. Otherwise, it will allocate a buffer for this stream, return
109      * it and increment its count of handed-out buffers. When the total number of allocated buffers
110      * is too high, it may deallocate the unused buffers to save memory footprint of this stream
111      * set.
112      *
113      * After this call, the client takes over the ownership of this buffer if it is not freed.
114      *
115      * Sometimes free buffers are discarded from consumer side and the dequeueBuffer call returns
116      * TIMED_OUT, in this case calling getBufferForStream again with noFreeBufferAtConsumer set to
117      * true will notify buffer manager to update its states and also tries to allocate a new buffer.
118      *
119      * Return values:
120      *
121      *  OK:        Getting buffer for this stream was successful.
122      *  ALREADY_EXISTS: Enough free buffers are already attached to this output buffer queue,
123      *             user should just dequeue from the buffer queue.
124      *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID
125      *             combination doesn't match what was registered, or this stream wasn't registered
126      *             to this buffer manager before.
127      *  NO_MEMORY: Unable to allocate a buffer for this stream at this time.
128      */
129     status_t getBufferForStream(
130             int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd,
131             bool noFreeBufferAtConsumer = false);
132 
133     /**
134      * This method notifies the manager that a buffer has been released by the consumer.
135      *
136      * The buffer is not returned to the buffer manager, but is available for the stream the buffer
137      * is attached to for dequeuing.
138      *
139      * The notification lets the manager know how many buffers are directly available to the stream.
140      *
141      * If onBufferReleased is called for a given released buffer,
142      * returnBufferForStream may not be called for the same buffer, until the
143      * buffer has been reused. The manager will call detachBuffer on the stream
144      * if it needs the released buffer otherwise.
145      *
146      * When shouldFreeBuffer is set to true, caller must detach and free one buffer from the
147      * buffer queue, and then call notifyBufferRemoved to update the manager.
148      *
149      * Return values:
150      *
151      *  OK:        Buffer release was processed succesfully
152      *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID
153      *             combination doesn't match what was registered, or this stream wasn't registered
154      *             to this buffer manager before, or shouldFreeBuffer is null/
155      */
156     status_t onBufferReleased(int streamId, int streamSetId, /*out*/bool* shouldFreeBuffer);
157 
158     /**
159      * This method notifies the manager that certain buffers has been removed from the
160      * buffer queue by detachBuffer from the consumer.
161      *
162      * The notification lets the manager update its internal handout buffer count and
163      * attached buffer counts accordingly. When buffers are detached from
164      * consumer, both handout and attached counts are decremented.
165      *
166      * Return values:
167      *
168      *  OK:        Buffer removal was processed succesfully
169      *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID
170      *             combination doesn't match what was registered, or this stream wasn't registered
171      *             to this buffer manager before, or the removed buffer count is larger than
172      *             current total handoutCount or attachedCount.
173      */
174     status_t onBuffersRemoved(int streamId, int streamSetId, size_t count);
175 
176     /**
177      * This method notifiers the manager that a buffer is freed from the buffer queue, usually
178      * because onBufferReleased signals the caller to free a buffer via the shouldFreeBuffer flag.
179      */
180     void notifyBufferRemoved(int streamId, int streamSetId);
181 
182     /**
183      * Dump the buffer manager statistics.
184      */
185     void     dump(int fd, const Vector<String16> &args) const;
186 
187 private:
188     // allocatedBufferWaterMark will be decreased when:
189     //   numAllocatedBuffersThisSet > numHandoutBuffersThisSet + BUFFER_WATERMARK_DEC_THRESHOLD
190     // This allows the watermark go back down after a burst of buffer requests
191     static const int BUFFER_WATERMARK_DEC_THRESHOLD = 3;
192 
193     // onBufferReleased will set shouldFreeBuffer to true when:
194     //   numAllocatedBuffersThisSet > allocatedBufferWaterMark AND
195     //   numAllocatedBuffersThisStream > numHandoutBuffersThisStream + BUFFER_FREE_THRESHOLD
196     // So after a burst of buffer requests and back to steady state, the buffer queue should have
197     // (BUFFER_FREE_THRESHOLD + steady state handout buffer count) buffers.
198     static const int BUFFER_FREE_THRESHOLD = 3;
199 
200     /**
201      * Lock to synchronize the access to the methods of this class.
202      */
203     mutable Mutex mLock;
204 
205     static const size_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
206 
207     struct GraphicBufferEntry {
208         sp<GraphicBuffer> graphicBuffer;
209         int fenceFd;
210         explicit GraphicBufferEntry(const sp<GraphicBuffer>& gb = 0, int fd = -1) :
graphicBufferGraphicBufferEntry211             graphicBuffer(gb),
212             fenceFd(fd) {}
213     };
214 
215     /**
216      * A buffer entry (indexed by stream ID) represents a single physically allocated buffer. For
217      * Gralloc V0, since each physical buffer is associated with one stream, this is
218      * a single entry map. For Gralloc V1, one physical buffer can be shared between different
219      * streams in one stream set, so this entry may include multiple entries, where the different
220      * graphic buffers have the same common Gralloc backing store.
221      */
222     typedef int StreamId;
223     typedef KeyedVector<StreamId, GraphicBufferEntry> BufferEntry;
224 
225     typedef std::list<BufferEntry> BufferList;
226 
227     /**
228      * Stream info map (indexed by stream ID) tracks all the streams registered to a particular
229      * stream set.
230      */
231     typedef KeyedVector<StreamId, StreamInfo> InfoMap;
232 
233     /**
234      * Stream set buffer count map (indexed by stream ID) tracks all buffer counts of the streams
235      * registered to a particular stream set.
236      */
237     typedef KeyedVector<StreamId, size_t> BufferCountMap;
238 
239     /**
240      * StreamSet keeps track of the stream info, free buffer list and hand-out buffer counts for
241      * each stream set.
242      */
243     struct StreamSet {
244         /**
245          * Stream set buffer count water mark representing the max number of allocated buffers
246          * (hand-out buffers + free buffers) count for each stream set. For a given stream set, when
247          * getBufferForStream() is called on this buffer manager, if the total allocated buffer
248          * count exceeds this water mark, the buffer manager will attempt to reduce it as follows:
249          *
250          * In getBufferForStream(), find a buffer associated with other streams (inside the same
251          * stream set) on the free buffer list and free it. For Gralloc V1, can just free the top
252          * of the free buffer list if the physical buffer sharing in this stream is supported.
253          *
254          * For a particular stream set, a larger allocatedBufferWaterMark increases the memory
255          * footprint of the stream set, but reduces the chance that getBufferForStream() will have
256          * to allocate a new buffer. We assume that the streams in one stream set are not streaming
257          * simultaneously, the max allocated buffer count water mark for a stream set will the max
258          * of all streams' total buffer counts. This will avoid new buffer allocation in steady
259          * streaming state.
260          *
261          * This water mark can be dynamically changed, and will grow when the hand-out buffer count
262          * of each stream increases, until it reaches the maxAllowedBufferCount.
263          */
264         size_t allocatedBufferWaterMark;
265 
266         /**
267          * The max allowed buffer count for this stream set. It is the max of total number of
268          * buffers for each stream. This is the upper bound of the allocatedBufferWaterMark.
269          */
270         size_t maxAllowedBufferCount;
271 
272         /**
273          * The stream info for all streams in this set
274          */
275         InfoMap streamInfoMap;
276         /**
277          * The count of the buffers that were handed out to the streams of this set.
278          */
279         BufferCountMap handoutBufferCountMap;
280         /**
281          * The count of the buffers that are attached to the streams of this set.
282          * An attached buffer may be free or handed out
283          */
284         BufferCountMap attachedBufferCountMap;
285 
StreamSetStreamSet286         StreamSet() {
287             allocatedBufferWaterMark = 0;
288             maxAllowedBufferCount = 0;
289         }
290     };
291 
292     /**
293      * Stream set map managed by this buffer manager.
294      */
295     typedef int StreamSetId;
296     KeyedVector<StreamSetId, StreamSet> mStreamSetMap;
297     KeyedVector<StreamId, wp<Camera3OutputStream>> mStreamMap;
298 
299     // TODO: There is no easy way to query the Gralloc version in this code yet, we have different
300     // code paths for different Gralloc versions, hardcode something here for now.
301     const uint32_t mGrallocVersion = GRALLOC_DEVICE_API_VERSION_0_1;
302 
303     /**
304      * Check if this stream was successfully registered already. This method needs to be called with
305      * mLock held.
306      */
307     bool checkIfStreamRegisteredLocked(int streamId, int streamSetId) const;
308 
309     /**
310      * Check if other streams in the stream set has extra buffer available to be freed, and
311      * free one if so.
312      */
313     status_t checkAndFreeBufferOnOtherStreamsLocked(int streamId, int streamSetId);
314 };
315 
316 } // namespace camera3
317 } // namespace android
318 
319 #endif // ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
320