| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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; | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 32 | class Camera3OutputStream; | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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: | 
| Mathias Agopian | 2752e5b | 2017-02-27 18:26:48 -0800 | [diff] [blame] | 47 | explicit Camera3BufferManager(); | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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 | */ | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 85 | status_t registerStream(wp<Camera3OutputStream>& stream, const StreamInfo &streamInfo); | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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 | * Return values: | 
|  | 116 | * | 
|  | 117 | *  OK:        Getting buffer for this stream was successful. | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 118 | *  ALREADY_EXISTS: Enough free buffers are already attached to this output buffer queue, | 
|  | 119 | *             user should just dequeue from the buffer queue. | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 120 | *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID | 
|  | 121 | *             combination doesn't match what was registered, or this stream wasn't registered | 
|  | 122 | *             to this buffer manager before. | 
|  | 123 | *  NO_MEMORY: Unable to allocate a buffer for this stream at this time. | 
|  | 124 | */ | 
|  | 125 | status_t getBufferForStream(int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd); | 
|  | 126 |  | 
|  | 127 | /** | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 128 | * This method notifies the manager that a buffer has been released by the consumer. | 
|  | 129 | * | 
|  | 130 | * The buffer is not returned to the buffer manager, but is available for the stream the buffer | 
|  | 131 | * is attached to for dequeuing. | 
|  | 132 | * | 
|  | 133 | * The notification lets the manager know how many buffers are directly available to the stream. | 
|  | 134 | * | 
|  | 135 | * If onBufferReleased is called for a given released buffer, | 
|  | 136 | * returnBufferForStream may not be called for the same buffer, until the | 
|  | 137 | * buffer has been reused. The manager will call detachBuffer on the stream | 
|  | 138 | * if it needs the released buffer otherwise. | 
|  | 139 | * | 
| Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 140 | * When shouldFreeBuffer is set to true, caller must detach and free one buffer from the | 
|  | 141 | * buffer queue, and then call notifyBufferRemoved to update the manager. | 
|  | 142 | * | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 143 | * Return values: | 
|  | 144 | * | 
|  | 145 | *  OK:        Buffer release was processed succesfully | 
|  | 146 | *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID | 
|  | 147 | *             combination doesn't match what was registered, or this stream wasn't registered | 
| Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 148 | *             to this buffer manager before, or shouldFreeBuffer is null/ | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 149 | */ | 
| Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 150 | status_t onBufferReleased(int streamId, int streamSetId, /*out*/bool* shouldFreeBuffer); | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 151 |  | 
|  | 152 | /** | 
| Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 153 | * This method notifies the manager that certain buffers has been removed from the | 
|  | 154 | * buffer queue by detachBuffer from the consumer. | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 155 | * | 
| Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 156 | * The notification lets the manager update its internal handout buffer count and | 
|  | 157 | * attached buffer counts accordingly. When buffers are detached from | 
|  | 158 | * consumer, both handout and attached counts are decremented. | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 159 | * | 
| Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 160 | * Return values: | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 161 | * | 
| Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 162 | *  OK:        Buffer removal was processed succesfully | 
|  | 163 | *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID | 
|  | 164 | *             combination doesn't match what was registered, or this stream wasn't registered | 
|  | 165 | *             to this buffer manager before, or the removed buffer count is larger than | 
|  | 166 | *             current total handoutCount or attachedCount. | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 167 | */ | 
| Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 168 | status_t onBuffersRemoved(int streamId, int streamSetId, size_t count); | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 169 |  | 
|  | 170 | /** | 
| Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 171 | * This method notifiers the manager that a buffer is freed from the buffer queue, usually | 
|  | 172 | * because onBufferReleased signals the caller to free a buffer via the shouldFreeBuffer flag. | 
|  | 173 | */ | 
|  | 174 | void notifyBufferRemoved(int streamId, int streamSetId); | 
|  | 175 |  | 
|  | 176 | /** | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 177 | * Dump the buffer manager statistics. | 
|  | 178 | */ | 
|  | 179 | void     dump(int fd, const Vector<String16> &args) const; | 
|  | 180 |  | 
|  | 181 | private: | 
| Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 182 | // allocatedBufferWaterMark will be decreased when: | 
|  | 183 | //   numAllocatedBuffersThisSet > numHandoutBuffersThisSet + BUFFER_WATERMARK_DEC_THRESHOLD | 
|  | 184 | // This allows the watermark go back down after a burst of buffer requests | 
|  | 185 | static const int BUFFER_WATERMARK_DEC_THRESHOLD = 3; | 
|  | 186 |  | 
|  | 187 | // onBufferReleased will set shouldFreeBuffer to true when: | 
|  | 188 | //   numAllocatedBuffersThisSet > allocatedBufferWaterMark AND | 
|  | 189 | //   numAllocatedBuffersThisStream > numHandoutBuffersThisStream + BUFFER_FREE_THRESHOLD | 
|  | 190 | // So after a burst of buffer requests and back to steady state, the buffer queue should have | 
|  | 191 | // (BUFFER_FREE_THRESHOLD + steady state handout buffer count) buffers. | 
|  | 192 | static const int BUFFER_FREE_THRESHOLD = 3; | 
|  | 193 |  | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 194 | /** | 
|  | 195 | * Lock to synchronize the access to the methods of this class. | 
|  | 196 | */ | 
|  | 197 | mutable Mutex mLock; | 
|  | 198 |  | 
|  | 199 | static const size_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS; | 
|  | 200 |  | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 201 | struct GraphicBufferEntry { | 
|  | 202 | sp<GraphicBuffer> graphicBuffer; | 
|  | 203 | int fenceFd; | 
| Chih-Hung Hsieh | d19d994 | 2016-08-29 14:21:14 -0700 | [diff] [blame] | 204 | explicit GraphicBufferEntry(const sp<GraphicBuffer>& gb = 0, int fd = -1) : | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 205 | graphicBuffer(gb), | 
|  | 206 | fenceFd(fd) {} | 
|  | 207 | }; | 
|  | 208 |  | 
|  | 209 | /** | 
|  | 210 | * A buffer entry (indexed by stream ID) represents a single physically allocated buffer. For | 
|  | 211 | * Gralloc V0, since each physical buffer is associated with one stream, this is | 
|  | 212 | * a single entry map. For Gralloc V1, one physical buffer can be shared between different | 
|  | 213 | * streams in one stream set, so this entry may include multiple entries, where the different | 
|  | 214 | * graphic buffers have the same common Gralloc backing store. | 
|  | 215 | */ | 
|  | 216 | typedef int StreamId; | 
|  | 217 | typedef KeyedVector<StreamId, GraphicBufferEntry> BufferEntry; | 
|  | 218 |  | 
|  | 219 | typedef std::list<BufferEntry> BufferList; | 
|  | 220 |  | 
|  | 221 | /** | 
|  | 222 | * Stream info map (indexed by stream ID) tracks all the streams registered to a particular | 
|  | 223 | * stream set. | 
|  | 224 | */ | 
|  | 225 | typedef KeyedVector<StreamId, StreamInfo> InfoMap; | 
|  | 226 |  | 
|  | 227 | /** | 
|  | 228 | * Stream set buffer count map (indexed by stream ID) tracks all buffer counts of the streams | 
|  | 229 | * registered to a particular stream set. | 
|  | 230 | */ | 
|  | 231 | typedef KeyedVector<StreamId, size_t> BufferCountMap; | 
|  | 232 |  | 
|  | 233 | /** | 
|  | 234 | * StreamSet keeps track of the stream info, free buffer list and hand-out buffer counts for | 
|  | 235 | * each stream set. | 
|  | 236 | */ | 
|  | 237 | struct StreamSet { | 
|  | 238 | /** | 
|  | 239 | * Stream set buffer count water mark representing the max number of allocated buffers | 
|  | 240 | * (hand-out buffers + free buffers) count for each stream set. For a given stream set, when | 
|  | 241 | * getBufferForStream() is called on this buffer manager, if the total allocated buffer | 
|  | 242 | * count exceeds this water mark, the buffer manager will attempt to reduce it as follows: | 
|  | 243 | * | 
|  | 244 | * In getBufferForStream(), find a buffer associated with other streams (inside the same | 
|  | 245 | * stream set) on the free buffer list and free it. For Gralloc V1, can just free the top | 
|  | 246 | * of the free buffer list if the physical buffer sharing in this stream is supported. | 
|  | 247 | * | 
|  | 248 | * For a particular stream set, a larger allocatedBufferWaterMark increases the memory | 
|  | 249 | * footprint of the stream set, but reduces the chance that getBufferForStream() will have | 
|  | 250 | * to allocate a new buffer. We assume that the streams in one stream set are not streaming | 
|  | 251 | * simultaneously, the max allocated buffer count water mark for a stream set will the max | 
|  | 252 | * of all streams' total buffer counts. This will avoid new buffer allocation in steady | 
|  | 253 | * streaming state. | 
| Zhijun He | 8d1a154 | 2016-01-29 20:28:21 -0800 | [diff] [blame] | 254 | * | 
|  | 255 | * This water mark can be dynamically changed, and will grow when the hand-out buffer count | 
|  | 256 | * of each stream increases, until it reaches the maxAllowedBufferCount. | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 257 | */ | 
|  | 258 | size_t allocatedBufferWaterMark; | 
| Zhijun He | 8d1a154 | 2016-01-29 20:28:21 -0800 | [diff] [blame] | 259 |  | 
|  | 260 | /** | 
|  | 261 | * The max allowed buffer count for this stream set. It is the max of total number of | 
|  | 262 | * buffers for each stream. This is the upper bound of the allocatedBufferWaterMark. | 
|  | 263 | */ | 
|  | 264 | size_t maxAllowedBufferCount; | 
|  | 265 |  | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 266 | /** | 
|  | 267 | * The stream info for all streams in this set | 
|  | 268 | */ | 
|  | 269 | InfoMap streamInfoMap; | 
|  | 270 | /** | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 271 | * The count of the buffers that were handed out to the streams of this set. | 
|  | 272 | */ | 
|  | 273 | BufferCountMap handoutBufferCountMap; | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 274 | /** | 
|  | 275 | * The count of the buffers that are attached to the streams of this set. | 
|  | 276 | * An attached buffer may be free or handed out | 
|  | 277 | */ | 
|  | 278 | BufferCountMap attachedBufferCountMap; | 
|  | 279 |  | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 280 | StreamSet() { | 
|  | 281 | allocatedBufferWaterMark = 0; | 
| Zhijun He | 8d1a154 | 2016-01-29 20:28:21 -0800 | [diff] [blame] | 282 | maxAllowedBufferCount = 0; | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 283 | } | 
|  | 284 | }; | 
|  | 285 |  | 
|  | 286 | /** | 
|  | 287 | * Stream set map managed by this buffer manager. | 
|  | 288 | */ | 
|  | 289 | typedef int StreamSetId; | 
|  | 290 | KeyedVector<StreamSetId, StreamSet> mStreamSetMap; | 
| Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 291 | KeyedVector<StreamId, wp<Camera3OutputStream>> mStreamMap; | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 292 |  | 
|  | 293 | // TODO: There is no easy way to query the Gralloc version in this code yet, we have different | 
|  | 294 | // code paths for different Gralloc versions, hardcode something here for now. | 
|  | 295 | const uint32_t mGrallocVersion = GRALLOC_DEVICE_API_VERSION_0_1; | 
|  | 296 |  | 
|  | 297 | /** | 
|  | 298 | * Check if this stream was successfully registered already. This method needs to be called with | 
|  | 299 | * mLock held. | 
|  | 300 | */ | 
|  | 301 | bool checkIfStreamRegisteredLocked(int streamId, int streamSetId) const; | 
|  | 302 |  | 
| Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 303 | /** | 
|  | 304 | * Check if other streams in the stream set has extra buffer available to be freed, and | 
|  | 305 | * free one if so. | 
|  | 306 | */ | 
|  | 307 | status_t checkAndFreeBufferOnOtherStreamsLocked(int streamId, int streamSetId); | 
| Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 308 | }; | 
|  | 309 |  | 
|  | 310 | } // namespace camera3 | 
|  | 311 | } // namespace android | 
|  | 312 |  | 
|  | 313 | #endif // ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H |