1 /* 2 * Copyright (C) 2019 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 HARDWARE_GOOGLE_CAMERA_HAL_UTILS_STREAM_BUFFER_CACHE_MANAGER_H_ 18 #define HARDWARE_GOOGLE_CAMERA_HAL_UTILS_STREAM_BUFFER_CACHE_MANAGER_H_ 19 20 #include <utils/Errors.h> 21 22 #include <condition_variable> 23 #include <functional> 24 #include <map> 25 #include <memory> 26 #include <mutex> 27 #include <set> 28 #include <thread> 29 #include <vector> 30 31 #include "gralloc_buffer_allocator.h" 32 #include "hal_types.h" 33 34 namespace android { 35 namespace google_camera_hal { 36 37 // Function to request buffer for a specific stream. The size of buffers vector 38 // should be extended by the callee. The caller owns the acquire fences of the 39 // acquired StreamBuffer. The caller owns the std::vector that contain the 40 // allocated buffers. The buffers themselves are released through the buffer 41 // return function or through result processing functions. 42 using StreamBufferRequestFunc = 43 std::function<status_t(uint32_t num_buffer, std::vector<StreamBuffer>* buffers, 44 StreamBufferRequestError* status)>; 45 46 // Function to return buffer for a specific stream 47 using StreamBufferReturnFunc = 48 std::function<status_t(const std::vector<StreamBuffer>& buffers)>; 49 50 // Function to notify the manager for a new thread loop workload 51 using NotifyManagerThreadWorkloadFunc = std::function<void()>; 52 // 53 // StreamBufferCacheRegInfo 54 // 55 // Contains all information needed to register a StreamBufferCache into manager 56 // 57 struct StreamBufferCacheRegInfo { 58 // Interface to request buffer for this cache 59 StreamBufferRequestFunc request_func = nullptr; 60 // Interface to return buffer from this cache 61 StreamBufferReturnFunc return_func = nullptr; 62 // Stream to be registered 63 int32_t stream_id = -1; 64 // Width of the stream 65 uint32_t width = 0; 66 // Height of the stream 67 uint32_t height = 0; 68 // Format of the stream 69 android_pixel_format_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; 70 // Producer flags of the stream 71 uint64_t producer_flags = 0; 72 // Consumer flags of the stream 73 uint64_t consumer_flags = 0; 74 // Number of buffers that the manager needs to cache 75 uint32_t num_buffers_to_cache = 1; 76 }; 77 78 // 79 // StreamBufferRequestResult 80 // 81 // Contains all information returned to the client by GetStreamBuffer function. 82 // 83 struct StreamBufferRequestResult { 84 // Whether the returned StreamBuffer is a dummy buffer or an actual buffer 85 // obtained from the buffer provider. Client should return the buffer from 86 // providers through the normal result processing functions. There is no need 87 // for clients to return or recycle a dummy buffer returned. 88 bool is_dummy_buffer = false; 89 // StreamBuffer obtained 90 StreamBuffer buffer; 91 }; 92 93 // 94 // StreamBufferCacheManager 95 // 96 // A StreamBufferCacheManager manages a list of StreamBufferCache for registered 97 // streams. A client needs to register a stream first. It then needs to signal 98 // the manager to start caching buffers for that stream. It can then get stream 99 // buffers from the manager. The buffers obtained, not matter buffers from buf 100 // provider or a dummy buffer, do not need to be returned to the manager. The 101 // client should notify the manager to flush all buffers cached before a session 102 // can successfully end. 103 // 104 // The manager uses a dedicated thread to asynchronously request/return buffers 105 // while clients threads fetch buffers and notify for a change of state. 106 // 107 class StreamBufferCacheManager { 108 public: 109 // Create an instance of the StreamBufferCacheManager 110 static std::unique_ptr<StreamBufferCacheManager> Create( 111 const std::set<int32_t>& hal_buffer_managed_stream_ids); 112 113 virtual ~StreamBufferCacheManager(); 114 115 // Client calls this function to register the buffer caching service 116 status_t RegisterStream(const StreamBufferCacheRegInfo& reg_info); 117 118 // Client calls this function to signal the manager to start caching buffer of 119 // the stream with stream_id. The manager will not cache stream buffer by 120 // requesting from the provider for a stream until this function is invoked. 121 status_t NotifyProviderReadiness(int32_t stream_id); 122 123 // Client calls this function to request for buffer of stream with stream_id. 124 // StreamBufferCacheManager only supports getting one buffer each time. Client 125 // is responsible to call NotifyProviderReadiness before calling this func. 126 // Caller owns the StreamBufferRequestResult and should keep it valid until 127 // the function is returned. The ownership of the fences of the StreamBuffer 128 // in the StreamBufferRequestResult is transferred to the caller after this 129 // function is returned. In case dummy buffer is returned, the fences are all 130 // nullptr. 131 status_t GetStreamBuffer(int32_t stream_id, StreamBufferRequestResult* res); 132 133 // Client calls this function to signal the manager to flush all buffers 134 // cached for all streams registered. After this function is called, client 135 // can still call GetStreamBuffer to trigger the stream buffer cache manager 136 // to restart caching buffers for a specific stream. 137 status_t NotifyFlushingAll(); 138 139 // Whether stream buffer cache manager can still acquire buffer from the 140 // provider successfully(e.g. if a stream is abandoned by the framework, this 141 // returns false). Once a stream is inactive, dummy buffer will be used in all 142 // following GetStreamBuffer calling. Calling NotifyFlushingAll does not make 143 // a change in this case. 144 status_t IsStreamActive(int32_t stream_id, bool* is_active); 145 146 protected: 147 StreamBufferCacheManager( 148 const std::set<int32_t>& hal_buffer_managed_stream_ids); 149 150 private: 151 // Duration to wait for fence. 152 static constexpr uint32_t kSyncWaitTimeMs = 5000; 153 154 // 155 // StreamBufferCache 156 // 157 // Contains all information and status of the stream buffer cache for a 158 // specific stream with stream_id 159 // 160 class StreamBufferCache { 161 public: 162 // Create a StreamBufferCache from the StreamBufferCacheRegInfo 163 // reg_info contains the basic information about the stream this cache is 164 // for and interfaces for buffer return and request. 165 // notify is the function for each stream buffer cache to notify the manager 166 // for new thread loop work load. 167 // dummy_buffer_allocator allocates the dummy buffer needed when buffer 168 // provider can not fulfill a buffer request any more. 169 static std::unique_ptr<StreamBufferCache> Create( 170 const StreamBufferCacheRegInfo& reg_info, 171 NotifyManagerThreadWorkloadFunc notify, 172 IHalBufferAllocator* dummy_buffer_allocator); 173 174 virtual ~StreamBufferCache() = default; 175 176 // Flush the stream buffer cache if the forced_flushing flag is set or if 177 // the stream buffer cache has been notified for flushing. Otherwise, check 178 // if the stream buffer cache needs to be and can be refilled. Do so if that 179 // is true. 180 status_t UpdateCache(bool forced_flushing); 181 182 // Get a buffer for the client. The buffer returned can be a dummy buffer, 183 // in which case, the is_dummy_buffer field in res will be true. 184 status_t GetBuffer(StreamBufferRequestResult* res); 185 186 // Activate or deactivate the stream buffer cache manager. The stream 187 // buffer cache manager needs to be active before calling Refill and 188 // GetBuffer. If no inflight buffer needs to be maintained, this function is 189 // called with false to flush all buffers acquired from the provider. The 190 // Stream buffer cache manager should only be invoked when the buffer 191 // provider (the camera service/framework) is ready to provide buffers (e.g. 192 // when the first capture request arrives). Similarly, it should be 193 // deactivated in cases like when the framework asks for a flush. 194 void SetManagerState(bool active); 195 196 // Return whether the stream that this cache is for has been deactivated 197 bool IsStreamDeactivated(); 198 199 protected: 200 StreamBufferCache(const StreamBufferCacheRegInfo& reg_info, 201 NotifyManagerThreadWorkloadFunc notify, 202 IHalBufferAllocator* dummy_buffer_allocator); 203 204 private: 205 // Flush all buffers acquired from the buffer provider. Return the acquired 206 // buffers through the return_func. 207 // The cache_access_mutex_ must be locked when calling this function. 208 status_t FlushLocked(bool forced_flushing); 209 210 // Refill the cached buffers by trying to acquire buffers from the buffer 211 // provider using request_func. If the provider can not fulfill the request 212 // by returning an empty buffer vector. The stream buffer cache will be 213 // providing dummy buffer for all following requests. 214 // TODO(b/136107942): Only one thread(currently the manager's workload thread) 215 // should call this function to avoid unexpected racing 216 // condition. This will be fixed by taking advantage of 217 // a buffer requesting task queue from which the dedicated 218 // thread fetches the task and refill the cache separately. 219 status_t Refill(); 220 221 // Whether a stream buffer cache can be refilled. 222 // The cache_access_mutex_ must be locked when calling this function. 223 bool RefillableLocked() const; 224 225 // Allocate dummy buffer for this stream buffer cache. The 226 // cache_access_mutex_ needs to be locked before calling this function. 227 status_t AllocateDummyBufferLocked(); 228 229 // Release allocated dummy buffer when StreamBufferCache exiting. 230 // The cache_access_mutex_ needs to be locked before calling this function. 231 void ReleaseDummyBufferLocked(); 232 233 // Any access to the cache content must be guarded by this mutex. 234 std::mutex cache_access_mutex_; 235 // Condition variable used in timed wait for refilling 236 std::condition_variable cache_access_cv_; 237 // Basic information about this stream buffer cache 238 const StreamBufferCacheRegInfo cache_info_; 239 // Cached StreamBuffers 240 std::vector<StreamBuffer> cached_buffers_; 241 // Whether the stream this cache is for has been deactived. The stream is 242 // labeled as deactived when kStreamDisconnected or kUnknownError is 243 // returned by a request_func_. In this case, all following request_func_ is 244 // expected to raise the same error. So dummy buffer will be used directly 245 // without wasting the effort to call request_func_ again. Error code 246 // kNoBufferAvailable and kMaxBufferExceeded should not cause this to be 247 // labeled as true. The next UpdateCache status should still try to refill 248 // the cache. 249 bool stream_deactived_ = false; 250 // Dummy StreamBuffer reserved for errorneous situation. In case there is 251 // not available cached buffers, this dummy buffer is used to allow the 252 // client to continue its ongoing work without crashing. This dummy buffer 253 // is reused and should not be returned to the buf provider. If this buffer 254 // is returned, the is_dummy_buffer_ flag in the BufferRequestResult must be 255 // set to true. 256 StreamBuffer dummy_buffer_; 257 // StreamBufferCacheManager does not refill a StreamBufferCache until this 258 // is set true by the client. Client should set this flag to true after the 259 // buffer provider (e.g. framework) is ready to handle buffer requests, or 260 // when a new request is submitted for an idle camera device (no inflight 261 // requests). 262 bool is_active_ = false; 263 // Interface to notify the parent manager for new threadloop workload. 264 NotifyManagerThreadWorkloadFunc notify_for_workload_ = nullptr; 265 // Allocator of the dummy buffer for this stream. The stream buffer cache 266 // manager owns this throughout the life cycle of this stream buffer cahce. 267 IHalBufferAllocator* dummy_buffer_allocator_ = nullptr; 268 }; 269 270 // Add stream buffer cache. Lock caches_map_mutex_ before calling this func. 271 status_t AddStreamBufferCacheLocked(const StreamBufferCacheRegInfo& reg_info); 272 273 // Procedure running in the dedicated thread loop 274 void WorkloadThreadLoop(); 275 276 // Notifies the dedicated thread for new processing request. This can only be 277 // invoked after any change to the cache state is done and cache_access_mutex 278 // has been unlocked. 279 void NotifyThreadWorkload(); 280 281 // Fetch the actual StreamBufferCache given a stream_id 282 status_t GetStreamBufferCache(int32_t stream_id, 283 StreamBufferCache** stream_buffer_cache); 284 285 // Guards the stream_buffer_caches_ 286 std::mutex caches_map_mutex_; 287 288 const std::set<int32_t>& hal_buffer_managed_streams_; 289 290 // Mapping from a stream_id to the StreamBufferCache for that stream. Any 291 // access to this map must be guarded by the caches_map_mutex. 292 std::map<int32_t, std::unique_ptr<StreamBufferCache>> stream_buffer_caches_; 293 294 // Guards the thread dedicated for StreamBuffer request and return 295 std::mutex workload_mutex_; 296 // Thread dedicated for stream buffer request and return 297 std::thread workload_thread_; 298 // CV for dedicated thread guarding 299 std::condition_variable workload_cv_; 300 // Whether the dedicated thread has been notified for exiting. Change to this 301 // must be guarded by request_return_mutex_. 302 bool workload_thread_exiting_ = false; 303 // Whether a processing request has been notified. Change to this must be 304 // guarded by request_return_mutex_; 305 bool has_new_workload_ = false; 306 // The dummy buffer allocator allocates the dummy buffer. It only allocates 307 // the dummy buffer when a stream buffer cache is NotifyProviderReadiness. 308 std::unique_ptr<IHalBufferAllocator> dummy_buffer_allocator_; 309 310 // Guards NotifyFlushingAll. In case the workload thread is processing workload, 311 // the NotifyFlushingAll calling should wait until workload loop is done. This 312 // avoids the false trigger of another caching request after a stream buffer 313 // cache is flushed. 314 // For example, there are two stream cache in manager. Without using the mutex, 315 // there is a chance the following could happen: 316 // 317 // Workload thread waiting for signal 318 // | 319 // Workload thread triggered by GetBuffer 320 // | 321 // c1 request new buffer 322 // | 323 // NotifyFlushingAll (workload thread bypasses next wait due to this) 324 // | 325 // c2 return cached buffer 326 // | 327 // Next workload thread loop starts immediately 328 // | 329 // c1 return buffer 330 // | 331 // c2 request buffer <-- this should not happen and is avoid by the mutex 332 // | 333 // WaitUntilDrain 334 std::mutex flush_mutex_; 335 }; 336 337 } // namespace google_camera_hal 338 } // namespace android 339 340 #endif // HARDWARE_GOOGLE_CAMERA_HAL_UTILS_STREAM_BUFFER_CACHE_MANAGER_H_ 341