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_