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 | * |
Yin-Chia Yeh | bf1b8b9 | 2019-03-06 14:56:08 -0800 | [diff] [blame] | 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 | * |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 119 | * Return values: |
| 120 | * |
| 121 | * OK: Getting buffer for this stream was successful. |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 122 | * ALREADY_EXISTS: Enough free buffers are already attached to this output buffer queue, |
| 123 | * user should just dequeue from the buffer queue. |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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 | */ |
Yin-Chia Yeh | bf1b8b9 | 2019-03-06 14:56:08 -0800 | [diff] [blame] | 129 | status_t getBufferForStream( |
| 130 | int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd, |
| 131 | bool noFreeBufferAtConsumer = false); |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 132 | |
| 133 | /** |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 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 | * |
Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 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 | * |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 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 |
Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 154 | * to this buffer manager before, or shouldFreeBuffer is null/ |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 155 | */ |
Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 156 | status_t onBufferReleased(int streamId, int streamSetId, /*out*/bool* shouldFreeBuffer); |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 157 | |
| 158 | /** |
Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 159 | * This method notifies the manager that certain buffers has been removed from the |
| 160 | * buffer queue by detachBuffer from the consumer. |
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 | * 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. |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 165 | * |
Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 166 | * Return values: |
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 | * 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. |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 173 | */ |
Shuzhen Wang | fd76cf5 | 2017-05-15 10:01:04 -0700 | [diff] [blame] | 174 | status_t onBuffersRemoved(int streamId, int streamSetId, size_t count); |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 175 | |
| 176 | /** |
Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 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 | /** |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 183 | * Dump the buffer manager statistics. |
| 184 | */ |
| 185 | void dump(int fd, const Vector<String16> &args) const; |
| 186 | |
| 187 | private: |
Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 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 | |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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 | |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 207 | struct GraphicBufferEntry { |
| 208 | sp<GraphicBuffer> graphicBuffer; |
| 209 | int fenceFd; |
Chih-Hung Hsieh | d19d994 | 2016-08-29 14:21:14 -0700 | [diff] [blame] | 210 | explicit GraphicBufferEntry(const sp<GraphicBuffer>& gb = 0, int fd = -1) : |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 211 | 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. |
Zhijun He | 8d1a154 | 2016-01-29 20:28:21 -0800 | [diff] [blame] | 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. |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 263 | */ |
| 264 | size_t allocatedBufferWaterMark; |
Zhijun He | 8d1a154 | 2016-01-29 20:28:21 -0800 | [diff] [blame] | 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 | |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 272 | /** |
| 273 | * The stream info for all streams in this set |
| 274 | */ |
| 275 | InfoMap streamInfoMap; |
| 276 | /** |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 277 | * The count of the buffers that were handed out to the streams of this set. |
| 278 | */ |
| 279 | BufferCountMap handoutBufferCountMap; |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 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 | |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 286 | StreamSet() { |
| 287 | allocatedBufferWaterMark = 0; |
Zhijun He | 8d1a154 | 2016-01-29 20:28:21 -0800 | [diff] [blame] | 288 | maxAllowedBufferCount = 0; |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 289 | } |
| 290 | }; |
| 291 | |
| 292 | /** |
| 293 | * Stream set map managed by this buffer manager. |
| 294 | */ |
| 295 | typedef int StreamSetId; |
| 296 | KeyedVector<StreamSetId, StreamSet> mStreamSetMap; |
Eino-Ville Talvala | 77c1a35 | 2016-06-13 12:32:43 -0700 | [diff] [blame] | 297 | KeyedVector<StreamId, wp<Camera3OutputStream>> mStreamMap; |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 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 | |
Yin-Chia Yeh | 89954d9 | 2017-05-21 17:28:53 -0700 | [diff] [blame] | 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); |
Zhijun He | 125684a | 2015-12-26 15:07:30 -0800 | [diff] [blame] | 314 | }; |
| 315 | |
| 316 | } // namespace camera3 |
| 317 | } // namespace android |
| 318 | |
| 319 | #endif // ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H |