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 112 virtual ~StreamBufferCacheManager(); 113 114 // Client calls this function to register the buffer caching service 115 status_t RegisterStream(const StreamBufferCacheRegInfo& reg_info); 116 117 // Client calls this function to signal the manager to start caching buffer of 118 // the stream with stream_id. The manager will not cache stream buffer by 119 // requesting from the provider for a stream until this function is invoked. 120 status_t NotifyProviderReadiness(int32_t stream_id); 121 122 // Client calls this function to request for buffer of stream with stream_id. 123 // StreamBufferCacheManager only supports getting one buffer each time. Client 124 // is responsible to call NotifyProviderReadiness before calling this func. 125 // Caller owns the StreamBufferRequestResult and should keep it valid until 126 // the function is returned. The ownership of the fences of the StreamBuffer 127 // in the StreamBufferRequestResult is transferred to the caller after this 128 // function is returned. In case dummy buffer is returned, the fences are all 129 // nullptr. 130 status_t GetStreamBuffer(int32_t stream_id, StreamBufferRequestResult* res); 131 132 // Client calls this function to signal the manager to flush all buffers 133 // cached for all streams registered. After this function is called, client 134 // can still call GetStreamBuffer to trigger the stream buffer cache manager 135 // to restart caching buffers for a specific stream. 136 status_t NotifyFlushingAll(); 137 138 // Whether stream buffer cache manager can still acquire buffer from the 139 // provider successfully(e.g. if a stream is abandoned by the framework, this 140 // returns false). Once a stream is inactive, dummy buffer will be used in all 141 // following GetStreamBuffer calling. Calling NotifyFlushingAll does not make 142 // a change in this case. 143 status_t IsStreamActive(int32_t stream_id, bool* is_active); 144 145 protected: 146 StreamBufferCacheManager(); 147 148 private: 149 // Duration to wait for fence. 150 static constexpr uint32_t kSyncWaitTimeMs = 5000; 151 152 // 153 // StreamBufferCache 154 // 155 // Contains all information and status of the stream buffer cache for a 156 // specific stream with stream_id 157 // 158 class StreamBufferCache { 159 public: 160 // Create a StreamBufferCache from the StreamBufferCacheRegInfo 161 // reg_info contains the basic information about the stream this cache is 162 // for and interfaces for buffer return and request. 163 // notify is the function for each stream buffer cache to notify the manager 164 // for new thread loop work load. 165 // dummy_buffer_allocator allocates the dummy buffer needed when buffer 166 // provider can not fulfill a buffer request any more. 167 static std::unique_ptr<StreamBufferCache> Create( 168 const StreamBufferCacheRegInfo& reg_info, 169 NotifyManagerThreadWorkloadFunc notify, 170 IHalBufferAllocator* dummy_buffer_allocator); 171 172 virtual ~StreamBufferCache() = default; 173 174 // Flush the stream buffer cache if the forced_flushing flag is set or if 175 // the stream buffer cache has been notified for flushing. Otherwise, check 176 // if the stream buffer cache needs to be and can be refilled. Do so if that 177 // is true. 178 status_t UpdateCache(bool forced_flushing); 179 180 // Get a buffer for the client. The buffer returned can be a dummy buffer, 181 // in which case, the is_dummy_buffer field in res will be true. 182 status_t GetBuffer(StreamBufferRequestResult* res); 183 184 // Notify provider readiness. Client should call this function before 185 // calling Refill and GetBuffer. 186 void NotifyProviderReadiness(); 187 188 // Notify the stream buffer cache to flush all buffers it acquire from the 189 // provider. 190 void NotifyFlushing(); 191 192 // Return whether the stream that this cache is for has been deactivated 193 bool IsStreamDeactivated(); 194 195 protected: 196 StreamBufferCache(const StreamBufferCacheRegInfo& reg_info, 197 NotifyManagerThreadWorkloadFunc notify, 198 IHalBufferAllocator* dummy_buffer_allocator); 199 200 private: 201 // Flush all buffers acquired from the buffer provider. Return the acquired 202 // buffers through the return_func. 203 // The cache_access_mutex_ must be locked when calling this function. 204 status_t FlushLocked(bool forced_flushing); 205 206 // Refill the cached buffers by trying to acquire buffers from the buffer 207 // provider using request_func. If the provider can not fulfill the request 208 // by returning an empty buffer vector. The stream buffer cache will be 209 // providing dummy buffer for all following requests. 210 // TODO(b/136107942): Only one thread(currently the manager's workload thread) 211 // should call this function to avoid unexpected racing 212 // condition. This will be fixed by taking advantage of 213 // a buffer requesting task queue from which the dedicated 214 // thread fetches the task and refill the cache separately. 215 status_t Refill(); 216 217 // Whether a stream buffer cache can be refilled. 218 // The cache_access_mutex_ must be locked when calling this function. 219 bool RefillableLocked() const; 220 221 // Allocate dummy buffer for this stream buffer cache. The 222 // cache_access_mutex_ needs to be locked before calling this function. 223 status_t AllocateDummyBufferLocked(); 224 225 // Release allocated dummy buffer when StreamBufferCache exiting. 226 // The cache_access_mutex_ needs to be locked before calling this function. 227 void ReleaseDummyBufferLocked(); 228 229 // Any access to the cache content must be guarded by this mutex. 230 std::mutex cache_access_mutex_; 231 // Condition variable used in timed wait for refilling 232 std::condition_variable cache_access_cv_; 233 // Basic information about this stream buffer cache 234 const StreamBufferCacheRegInfo cache_info_; 235 // Cached StreamBuffers 236 std::vector<StreamBuffer> cached_buffers_; 237 // Whether the stream this cache is for has been deactived. The stream is 238 // labeled as deactived when kStreamDisconnected or kUnknownError is 239 // returned by a request_func_. In this case, all following request_func_ is 240 // expected to raise the same error. So dummy buffer will be used directly 241 // without wasting the effort to call request_func_ again. Error code 242 // kNoBufferAvailable and kMaxBufferExceeded should not cause this to be 243 // labeled as true. The next UpdateCache status should still try to refill 244 // the cache. 245 bool stream_deactived_ = false; 246 // Dummy StreamBuffer reserved for errorneous situation. In case there is 247 // not available cached buffers, this dummy buffer is used to allow the 248 // client to continue its ongoing work without crashing. This dummy buffer 249 // is reused and should not be returned to the buf provider. If this buffer 250 // is returned, the is_dummy_buffer_ flag in the BufferRequestResult must be 251 // set to true. 252 StreamBuffer dummy_buffer_; 253 // Whether this stream has been notified by the client for flushing. This 254 // flag should be cleared after StreamBufferCache is flushed. Once this is 255 // flagged by the client, StreamBufferCacheManager will return all buffers 256 // acquired from provider for this cache the next time the dedicated thread 257 // processes any request/return workload. 258 bool notified_flushing_ = false; 259 // StreamBufferCacheManager does not refill a StreamBufferCache until this is 260 // notified by the client. Client should notify this after the buffer provider 261 // (e.g. framework) is ready to handle buffer requests. Usually, this is set 262 // once in a session and will not be cleared in the same session. 263 bool notified_provider_readiness_ = false; 264 // Interface to notify the parent manager for new threadloop workload. 265 NotifyManagerThreadWorkloadFunc notify_for_workload_ = nullptr; 266 // Allocator of the dummy buffer for this stream. The stream buffer cache 267 // manager owns this throughout the life cycle of this stream buffer cahce. 268 IHalBufferAllocator* dummy_buffer_allocator_ = nullptr; 269 }; 270 271 // Add stream buffer cache. Lock caches_map_mutex_ before calling this func. 272 status_t AddStreamBufferCacheLocked(const StreamBufferCacheRegInfo& reg_info); 273 274 // Procedure running in the dedicated thread loop 275 void WorkloadThreadLoop(); 276 277 // Notifies the dedicated thread for new processing request. This can only be 278 // invoked after any change to the cache state is done and cache_access_mutex 279 // has been unlocked. 280 void NotifyThreadWorkload(); 281 282 // Fetch the actual StreamBufferCache given a stream_id 283 status_t GetStreamBufferCache(int32_t stream_id, 284 StreamBufferCache** stream_buffer_cache); 285 286 // Guards the stream_buffer_caches_ 287 std::mutex caches_map_mutex_; 288 // Mapping from a stream_id to the StreamBufferCache for that stream. Any 289 // access to this map must be guarded by the caches_map_mutex. 290 std::map<int32_t, std::unique_ptr<StreamBufferCache>> stream_buffer_caches_; 291 292 // Guards the thread dedicated for StreamBuffer request and return 293 std::mutex workload_mutex_; 294 // Thread dedicated for stream buffer request and return 295 std::thread workload_thread_; 296 // CV for dedicated thread guarding 297 std::condition_variable workload_cv_; 298 // Whether the dedicated thread has been notified for exiting. Change to this 299 // must be guarded by request_return_mutex_. 300 bool workload_thread_exiting_ = false; 301 // Whether a processing request has been notified. Change to this must be 302 // guarded by request_return_mutex_; 303 bool has_new_workload_ = false; 304 // The dummy buffer allocator allocates the dummy buffer. It only allocates 305 // the dummy buffer when a stream buffer cache is NotifyProviderReadiness. 306 std::unique_ptr<IHalBufferAllocator> dummy_buffer_allocator_; 307 308 // Guards NotifyFlushingAll. In case the workload thread is processing workload, 309 // the NotifyFlushingAll calling should wait until workload loop is done. This 310 // avoids the false trigger of another caching request after a stream buffer 311 // cache is flushed. 312 // For example, there are two stream cache in manager. Without using the mutex, 313 // there is a chance the following could happen: 314 // 315 // Workload thread waiting for signal 316 // | 317 // Workload thread triggered by GetBuffer 318 // | 319 // c1 request new buffer 320 // | 321 // NotifyFlushingAll (workload thread bypasses next wait due to this) 322 // | 323 // c2 return cached buffer 324 // | 325 // Next workload thread loop starts immediately 326 // | 327 // c1 return buffer 328 // | 329 // c2 request buffer <-- this should not happen and is avoid by the mutex 330 // | 331 // WaitUntilDrain 332 std::mutex flush_mutex_; 333 }; 334 335 } // namespace google_camera_hal 336 } // namespace android 337 338 #endif // HARDWARE_GOOGLE_CAMERA_HAL_UTILS_STREAM_BUFFER_CACHE_MANAGER_H_