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