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 // Activate or deactivate the stream buffer cache manager. The stream 185 // buffer cache manager needs to be active before calling Refill and 186 // GetBuffer. If no inflight buffer needs to be maintained, this function is 187 // called with false to flush all buffers acquired from the provider. The 188 // Stream buffer cache manager should only be invoked when the buffer 189 // provider (the camera service/framework) is ready to provide buffers (e.g. 190 // when the first capture request arrives). Similarly, it should be 191 // deactivated in cases like when the framework asks for a flush. 192 void SetManagerState(bool active); 193 194 // Return whether the stream that this cache is for has been deactivated 195 bool IsStreamDeactivated(); 196 197 protected: 198 StreamBufferCache(const StreamBufferCacheRegInfo& reg_info, 199 NotifyManagerThreadWorkloadFunc notify, 200 IHalBufferAllocator* dummy_buffer_allocator); 201 202 private: 203 // Flush all buffers acquired from the buffer provider. Return the acquired 204 // buffers through the return_func. 205 // The cache_access_mutex_ must be locked when calling this function. 206 status_t FlushLocked(bool forced_flushing); 207 208 // Refill the cached buffers by trying to acquire buffers from the buffer 209 // provider using request_func. If the provider can not fulfill the request 210 // by returning an empty buffer vector. The stream buffer cache will be 211 // providing dummy buffer for all following requests. 212 // TODO(b/136107942): Only one thread(currently the manager's workload thread) 213 // should call this function to avoid unexpected racing 214 // condition. This will be fixed by taking advantage of 215 // a buffer requesting task queue from which the dedicated 216 // thread fetches the task and refill the cache separately. 217 status_t Refill(); 218 219 // Whether a stream buffer cache can be refilled. 220 // The cache_access_mutex_ must be locked when calling this function. 221 bool RefillableLocked() const; 222 223 // Allocate dummy buffer for this stream buffer cache. The 224 // cache_access_mutex_ needs to be locked before calling this function. 225 status_t AllocateDummyBufferLocked(); 226 227 // Release allocated dummy buffer when StreamBufferCache exiting. 228 // The cache_access_mutex_ needs to be locked before calling this function. 229 void ReleaseDummyBufferLocked(); 230 231 // Any access to the cache content must be guarded by this mutex. 232 std::mutex cache_access_mutex_; 233 // Condition variable used in timed wait for refilling 234 std::condition_variable cache_access_cv_; 235 // Basic information about this stream buffer cache 236 const StreamBufferCacheRegInfo cache_info_; 237 // Cached StreamBuffers 238 std::vector<StreamBuffer> cached_buffers_; 239 // Whether the stream this cache is for has been deactived. The stream is 240 // labeled as deactived when kStreamDisconnected or kUnknownError is 241 // returned by a request_func_. In this case, all following request_func_ is 242 // expected to raise the same error. So dummy buffer will be used directly 243 // without wasting the effort to call request_func_ again. Error code 244 // kNoBufferAvailable and kMaxBufferExceeded should not cause this to be 245 // labeled as true. The next UpdateCache status should still try to refill 246 // the cache. 247 bool stream_deactived_ = false; 248 // Dummy StreamBuffer reserved for errorneous situation. In case there is 249 // not available cached buffers, this dummy buffer is used to allow the 250 // client to continue its ongoing work without crashing. This dummy buffer 251 // is reused and should not be returned to the buf provider. If this buffer 252 // is returned, the is_dummy_buffer_ flag in the BufferRequestResult must be 253 // set to true. 254 StreamBuffer dummy_buffer_; 255 // StreamBufferCacheManager does not refill a StreamBufferCache until this 256 // is set true by the client. Client should set this flag to true after the 257 // buffer provider (e.g. framework) is ready to handle buffer requests, or 258 // when a new request is submitted for an idle camera device (no inflight 259 // requests). 260 bool is_active_ = false; 261 // Interface to notify the parent manager for new threadloop workload. 262 NotifyManagerThreadWorkloadFunc notify_for_workload_ = nullptr; 263 // Allocator of the dummy buffer for this stream. The stream buffer cache 264 // manager owns this throughout the life cycle of this stream buffer cahce. 265 IHalBufferAllocator* dummy_buffer_allocator_ = nullptr; 266 }; 267 268 // Add stream buffer cache. Lock caches_map_mutex_ before calling this func. 269 status_t AddStreamBufferCacheLocked(const StreamBufferCacheRegInfo& reg_info); 270 271 // Procedure running in the dedicated thread loop 272 void WorkloadThreadLoop(); 273 274 // Notifies the dedicated thread for new processing request. This can only be 275 // invoked after any change to the cache state is done and cache_access_mutex 276 // has been unlocked. 277 void NotifyThreadWorkload(); 278 279 // Fetch the actual StreamBufferCache given a stream_id 280 status_t GetStreamBufferCache(int32_t stream_id, 281 StreamBufferCache** stream_buffer_cache); 282 283 // Guards the stream_buffer_caches_ 284 std::mutex caches_map_mutex_; 285 // Mapping from a stream_id to the StreamBufferCache for that stream. Any 286 // access to this map must be guarded by the caches_map_mutex. 287 std::map<int32_t, std::unique_ptr<StreamBufferCache>> stream_buffer_caches_; 288 289 // Guards the thread dedicated for StreamBuffer request and return 290 std::mutex workload_mutex_; 291 // Thread dedicated for stream buffer request and return 292 std::thread workload_thread_; 293 // CV for dedicated thread guarding 294 std::condition_variable workload_cv_; 295 // Whether the dedicated thread has been notified for exiting. Change to this 296 // must be guarded by request_return_mutex_. 297 bool workload_thread_exiting_ = false; 298 // Whether a processing request has been notified. Change to this must be 299 // guarded by request_return_mutex_; 300 bool has_new_workload_ = false; 301 // The dummy buffer allocator allocates the dummy buffer. It only allocates 302 // the dummy buffer when a stream buffer cache is NotifyProviderReadiness. 303 std::unique_ptr<IHalBufferAllocator> dummy_buffer_allocator_; 304 305 // Guards NotifyFlushingAll. In case the workload thread is processing workload, 306 // the NotifyFlushingAll calling should wait until workload loop is done. This 307 // avoids the false trigger of another caching request after a stream buffer 308 // cache is flushed. 309 // For example, there are two stream cache in manager. Without using the mutex, 310 // there is a chance the following could happen: 311 // 312 // Workload thread waiting for signal 313 // | 314 // Workload thread triggered by GetBuffer 315 // | 316 // c1 request new buffer 317 // | 318 // NotifyFlushingAll (workload thread bypasses next wait due to this) 319 // | 320 // c2 return cached buffer 321 // | 322 // Next workload thread loop starts immediately 323 // | 324 // c1 return buffer 325 // | 326 // c2 request buffer <-- this should not happen and is avoid by the mutex 327 // | 328 // WaitUntilDrain 329 std::mutex flush_mutex_; 330 }; 331 332 } // namespace google_camera_hal 333 } // namespace android 334 335 #endif // HARDWARE_GOOGLE_CAMERA_HAL_UTILS_STREAM_BUFFER_CACHE_MANAGER_H_ 336