• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, bool isMultiRes);
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, bool isMultiRes, sp<GraphicBuffer>* gb,
131              int* fenceFd, 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, bool isMultiRes,
157                                /*out*/bool* shouldFreeBuffer);
158  
159      /**
160       * This method notifies the manager that certain buffers has been removed from the
161       * buffer queue by detachBuffer from the consumer.
162       *
163       * The notification lets the manager update its internal handout buffer count and
164       * attached buffer counts accordingly. When buffers are detached from
165       * consumer, both handout and attached counts are decremented.
166       *
167       * Return values:
168       *
169       *  OK:        Buffer removal was processed succesfully
170       *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID
171       *             combination doesn't match what was registered, or this stream wasn't registered
172       *             to this buffer manager before, or the removed buffer count is larger than
173       *             current total handoutCount or attachedCount.
174       */
175      status_t onBuffersRemoved(int streamId, int streamSetId, bool isMultiRes, size_t count);
176  
177      /**
178       * This method notifiers the manager that a buffer is freed from the buffer queue, usually
179       * because onBufferReleased signals the caller to free a buffer via the shouldFreeBuffer flag.
180       */
181      void notifyBufferRemoved(int streamId, int streamSetId, bool isMultiRes);
182  
183      /**
184       * Dump the buffer manager statistics.
185       */
186      void     dump(int fd, const Vector<String16> &args) const;
187  
188  private:
189      // allocatedBufferWaterMark will be decreased when:
190      //   numAllocatedBuffersThisSet > numHandoutBuffersThisSet + BUFFER_WATERMARK_DEC_THRESHOLD
191      // This allows the watermark go back down after a burst of buffer requests
192      static const int BUFFER_WATERMARK_DEC_THRESHOLD = 3;
193  
194      // onBufferReleased will set shouldFreeBuffer to true when:
195      //   numAllocatedBuffersThisSet > allocatedBufferWaterMark AND
196      //   numAllocatedBuffersThisStream > numHandoutBuffersThisStream + BUFFER_FREE_THRESHOLD
197      // So after a burst of buffer requests and back to steady state, the buffer queue should have
198      // (BUFFER_FREE_THRESHOLD + steady state handout buffer count) buffers.
199      static const int BUFFER_FREE_THRESHOLD = 3;
200  
201      /**
202       * Lock to synchronize the access to the methods of this class.
203       */
204      mutable Mutex mLock;
205  
206      static const size_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
207  
208      struct GraphicBufferEntry {
209          sp<GraphicBuffer> graphicBuffer;
210          int fenceFd;
211          explicit GraphicBufferEntry(const sp<GraphicBuffer>& gb = 0, int fd = -1) :
graphicBufferGraphicBufferEntry212              graphicBuffer(gb),
213              fenceFd(fd) {}
214      };
215  
216      /**
217       * A buffer entry (indexed by stream ID) represents a single physically allocated buffer. For
218       * Gralloc V0, since each physical buffer is associated with one stream, this is
219       * a single entry map. For Gralloc V1, one physical buffer can be shared between different
220       * streams in one stream set, so this entry may include multiple entries, where the different
221       * graphic buffers have the same common Gralloc backing store.
222       */
223      typedef int StreamId;
224      typedef KeyedVector<StreamId, GraphicBufferEntry> BufferEntry;
225  
226      typedef std::list<BufferEntry> BufferList;
227  
228      /**
229       * Stream info map (indexed by stream ID) tracks all the streams registered to a particular
230       * stream set.
231       */
232      typedef KeyedVector<StreamId, StreamInfo> InfoMap;
233  
234      /**
235       * Stream set buffer count map (indexed by stream ID) tracks all buffer counts of the streams
236       * registered to a particular stream set.
237       */
238      typedef KeyedVector<StreamId, size_t> BufferCountMap;
239  
240      /**
241       * StreamSet keeps track of the stream info, free buffer list and hand-out buffer counts for
242       * each stream set.
243       */
244      struct StreamSet {
245          /**
246           * Stream set buffer count water mark representing the max number of allocated buffers
247           * (hand-out buffers + free buffers) count for each stream set. For a given stream set, when
248           * getBufferForStream() is called on this buffer manager, if the total allocated buffer
249           * count exceeds this water mark, the buffer manager will attempt to reduce it as follows:
250           *
251           * In getBufferForStream(), find a buffer associated with other streams (inside the same
252           * stream set) on the free buffer list and free it. For Gralloc V1, can just free the top
253           * of the free buffer list if the physical buffer sharing in this stream is supported.
254           *
255           * For a particular stream set, a larger allocatedBufferWaterMark increases the memory
256           * footprint of the stream set, but reduces the chance that getBufferForStream() will have
257           * to allocate a new buffer. We assume that the streams in one stream set are not streaming
258           * simultaneously, the max allocated buffer count water mark for a stream set will the max
259           * of all streams' total buffer counts. This will avoid new buffer allocation in steady
260           * streaming state.
261           *
262           * This water mark can be dynamically changed, and will grow when the hand-out buffer count
263           * of each stream increases, until it reaches the maxAllowedBufferCount.
264           */
265          size_t allocatedBufferWaterMark;
266  
267          /**
268           * The max allowed buffer count for this stream set. It is the max of total number of
269           * buffers for each stream. This is the upper bound of the allocatedBufferWaterMark.
270           */
271          size_t maxAllowedBufferCount;
272  
273          /**
274           * The stream info for all streams in this set
275           */
276          InfoMap streamInfoMap;
277          /**
278           * The count of the buffers that were handed out to the streams of this set.
279           */
280          BufferCountMap handoutBufferCountMap;
281          /**
282           * The count of the buffers that are attached to the streams of this set.
283           * An attached buffer may be free or handed out
284           */
285          BufferCountMap attachedBufferCountMap;
286  
StreamSetStreamSet287          StreamSet() {
288              allocatedBufferWaterMark = 0;
289              maxAllowedBufferCount = 0;
290          }
291      };
292  
293      /**
294       * Stream set map managed by this buffer manager.
295       */
296      struct StreamSetKey {
297          // The stream set ID
298          int id;
299          // Whether this stream set is for multi-resolution output streams. It's
300          // valid for 2 stream sets to have the same stream set ID if: one is for
301          // multi-resolution output stream, and the other one is not.
302          bool isMultiRes;
303  
304          inline bool operator<(const StreamSetKey& other) const {
305              return (isMultiRes < other.isMultiRes) ||
306                      ((isMultiRes == other.isMultiRes) && (id < other.id));
307          }
308      };
309      KeyedVector<StreamSetKey, StreamSet> mStreamSetMap;
310      KeyedVector<StreamId, wp<Camera3OutputStream>> mStreamMap;
311  
312      // TODO: There is no easy way to query the Gralloc version in this code yet, we have different
313      // code paths for different Gralloc versions, hardcode something here for now.
314      const uint32_t mGrallocVersion = GRALLOC_DEVICE_API_VERSION_0_1;
315  
316      /**
317       * Check if this stream was successfully registered already. This method needs to be called with
318       * mLock held.
319       */
320      bool checkIfStreamRegisteredLocked(int streamId, StreamSetKey streamSetKey) const;
321  
322      /**
323       * Check if other streams in the stream set has extra buffer available to be freed, and
324       * free one if so.
325       */
326      status_t checkAndFreeBufferOnOtherStreamsLocked(int streamId, StreamSetKey streamSetKey);
327  };
328  
329  } // namespace camera3
330  } // namespace android
331  
332  #endif // ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
333