1#ifndef ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
2#define ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
3
4#include <gui/BufferQueueDefs.h>
5
6#include <pdx/client.h>
7#include <pdx/status.h>
8#include <private/dvr/buffer_hub_client.h>
9#include <private/dvr/epoll_file_descriptor.h>
10#include <private/dvr/ring_buffer.h>
11
12#include <memory>
13#include <vector>
14
15namespace android {
16namespace dvr {
17
18class ConsumerQueue;
19
20// |BufferHubQueue| manages a queue of |BufferHubBuffer|s. Buffers are
21// automatically re-requeued when released by the remote side.
22class BufferHubQueue : public pdx::Client {
23 public:
24  using LocalHandle = pdx::LocalHandle;
25  using LocalChannelHandle = pdx::LocalChannelHandle;
26  template <typename T>
27  using Status = pdx::Status<T>;
28
29  virtual ~BufferHubQueue() {}
30  void Initialize();
31
32  // Create a new consumer queue that is attached to the producer. Returns
33  // a new consumer queue client or nullptr on failure.
34  std::unique_ptr<ConsumerQueue> CreateConsumerQueue();
35
36  // Create a new consumer queue that is attached to the producer. This queue
37  // sets each of its imported consumer buffers to the ignored state to avoid
38  // participation in lifecycle events.
39  std::unique_ptr<ConsumerQueue> CreateSilentConsumerQueue();
40
41  // Return the default buffer width of this buffer queue.
42  size_t default_width() const { return default_width_; }
43
44  // Return the default buffer height of this buffer queue.
45  size_t default_height() const { return default_height_; }
46
47  // Return the default buffer format of this buffer queue.
48  int32_t default_format() const { return default_format_; }
49
50  // Create a new consumer in handle form for immediate transport over RPC.
51  Status<LocalChannelHandle> CreateConsumerQueueHandle();
52
53  // Return the number of buffers avaiable for dequeue.
54  size_t count() const { return available_buffers_.GetSize(); }
55
56  // Return the total number of buffers that the queue is tracking.
57  size_t capacity() const { return capacity_; }
58
59  // Return the size of metadata structure associated with this BufferBubQueue.
60  size_t metadata_size() const { return meta_size_; }
61
62  // Return whether the buffer queue is alrady full.
63  bool is_full() const { return available_buffers_.IsFull(); }
64
65  explicit operator bool() const { return epoll_fd_.IsValid(); }
66
67  std::shared_ptr<BufferHubBuffer> GetBuffer(size_t slot) const {
68    return buffers_[slot];
69  }
70
71  Status<int> GetEventMask(int events) {
72    if (auto* client_channel = GetChannel()) {
73      return client_channel->GetEventMask(events);
74    } else {
75      return pdx::ErrorStatus(EINVAL);
76    }
77  }
78
79  // Returns an fd that signals pending queue events using
80  // EPOLLIN/POLLIN/readible. Either HandleQueueEvents or WaitForBuffers may be
81  // called to handle pending queue events.
82  int queue_fd() const { return epoll_fd_.Get(); }
83
84  // Handles any pending events, returning available buffers to the queue and
85  // reaping disconnected buffers. Returns true if successful, false if an error
86  // occurred.
87  bool HandleQueueEvents() { return WaitForBuffers(0); }
88
89  // Enqueue a buffer marks buffer to be available (|Gain|'ed for producer
90  // and |Acquire|'ed for consumer. This is only used for internal bookkeeping.
91  void Enqueue(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot);
92
93  // |BufferHubQueue| will keep track of at most this value of buffers.
94  static constexpr size_t kMaxQueueCapacity =
95      android::BufferQueueDefs::NUM_BUFFER_SLOTS;
96
97  // Special epoll data field indicating that the epoll event refers to the
98  // queue.
99  static constexpr int64_t kEpollQueueEventIndex = -1;
100
101  // When pass |kNoTimeout| to |Dequeue|, it will block indefinitely without a
102  // timeout.
103  static constexpr int kNoTimeOut = -1;
104
105  int id() const { return id_; }
106  bool hung_up() const { return hung_up_; }
107
108 protected:
109  BufferHubQueue(LocalChannelHandle channel);
110  BufferHubQueue(const std::string& endpoint_path);
111
112  // Imports the queue parameters by querying BufferHub for the parameters for
113  // this channel.
114  Status<void> ImportQueue();
115
116  // Sets up the queue with the given parameters.
117  void SetupQueue(size_t meta_size_bytes_, int id);
118
119  // Called by ProducerQueue::AddBuffer and ConsumerQueue::AddBuffer only. to
120  // register a buffer for epoll and internal bookkeeping.
121  int AddBuffer(const std::shared_ptr<BufferHubBuffer>& buf, size_t slot);
122
123  // Called by ProducerQueue::DetachBuffer and ConsumerQueue::DetachBuffer only.
124  // to deregister a buffer for epoll and internal bookkeeping.
125  virtual int DetachBuffer(size_t slot);
126
127  // Dequeue a buffer from the free queue, blocking until one is available. The
128  // timeout argument specifies the number of milliseconds that |Dequeue()| will
129  // block. Specifying a timeout of -1 causes |Dequeue()| to block indefinitely,
130  // while specifying a timeout equal to zero cause |Dequeue()| to return
131  // immediately, even if no buffers are available.
132  pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout,
133                                                        size_t* slot,
134                                                        void* meta,
135                                                        LocalHandle* fence);
136
137  // Wait for buffers to be released and re-add them to the queue.
138  bool WaitForBuffers(int timeout);
139  void HandleBufferEvent(size_t slot, int poll_events);
140  void HandleQueueEvent(int poll_events);
141
142  virtual int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
143                            LocalHandle* fence) = 0;
144
145  // Called when a buffer is allocated remotely.
146  virtual Status<void> OnBufferAllocated() { return {}; }
147
148  // Data members to handle arbitrary metadata passed through BufferHub. It is
149  // fair to enforce that all buffers in the same queue share the same metadata
150  // type. |meta_size_| is used to store the size of metadata on queue creation;
151  // and |meta_buffer_tmp_| is allocated and resized to |meta_size_| on queue
152  // creation to be later used as temporary space so that we can avoid
153  // additional dynamic memory allocation in each |Enqueue| and |Dequeue| call.
154  size_t meta_size_;
155
156  // Here we intentionally choose |unique_ptr<uint8_t[]>| over vector<uint8_t>
157  // to disallow dynamic resizing for stability reasons.
158  std::unique_ptr<uint8_t[]> meta_buffer_tmp_;
159
160 private:
161  static constexpr size_t kMaxEvents = 128;
162
163  // The |u64| data field of an epoll event is interpreted as int64_t:
164  // When |index| >= 0 and |index| < kMaxQueueCapacity it refers to a specific
165  // element of |buffers_| as a direct index;
166  static bool is_buffer_event_index(int64_t index) {
167    return index >= 0 &&
168           index < static_cast<int64_t>(BufferHubQueue::kMaxQueueCapacity);
169  }
170
171  // When |index| == kEpollQueueEventIndex, it refers to the queue itself.
172  static bool is_queue_event_index(int64_t index) {
173    return index == BufferHubQueue::kEpollQueueEventIndex;
174  }
175
176  struct BufferInfo {
177    // A logical slot number that is assigned to a buffer at allocation time.
178    // The slot number remains unchanged during the entire life cycle of the
179    // buffer and should not be confused with the enqueue and dequeue order.
180    size_t slot;
181
182    // A BufferHubBuffer client.
183    std::shared_ptr<BufferHubBuffer> buffer;
184
185    // Metadata associated with the buffer.
186    std::unique_ptr<uint8_t[]> metadata;
187
188    BufferInfo() : BufferInfo(-1, 0) {}
189
190    BufferInfo(size_t slot, size_t metadata_size)
191        : slot(slot),
192          buffer(nullptr),
193          metadata(metadata_size ? new uint8_t[metadata_size] : nullptr) {}
194
195    BufferInfo(BufferInfo&& other)
196        : slot(other.slot),
197          buffer(std::move(other.buffer)),
198          metadata(std::move(other.metadata)) {}
199
200    BufferInfo& operator=(BufferInfo&& other) {
201      slot = other.slot;
202      buffer = std::move(other.buffer);
203      metadata = std::move(other.metadata);
204      return *this;
205    }
206
207   private:
208    BufferInfo(const BufferInfo&) = delete;
209    void operator=(BufferInfo&) = delete;
210  };
211
212  // Default buffer width that can be set to override the buffer width when a
213  // width and height of 0 are specified in AllocateBuffer.
214  size_t default_width_{1};
215
216  // Default buffer height that can be set to override the buffer height when a
217  // width and height of 0 are specified in AllocateBuffer.
218  size_t default_height_{1};
219
220  // Default buffer format that can be set to override the buffer format when it
221  // isn't specified in AllocateBuffer.
222  int32_t default_format_{PIXEL_FORMAT_RGBA_8888};
223
224  // Buffer queue:
225  // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|.
226  std::vector<std::shared_ptr<BufferHubBuffer>> buffers_;
227
228  // |epollhup_pending_| tracks whether a slot of |buffers_| get detached before
229  // its corresponding EPOLLHUP event got handled. This could happen as the
230  // following sequence:
231  // 1. Producer queue's client side allocates a new buffer (at slot 1).
232  // 2. Producer queue's client side replaces an existing buffer (at slot 0).
233  //    This is implemented by first detaching the buffer and then allocating a
234  //    new buffer.
235  // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
236  //    event on the queue which indicates a new buffer is available and the
237  //    EPOLLHUP event for slot 0. Consumer handles these two events in order.
238  // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
239  //    slot 0 and (the new) slot 1 buffer will be imported. During the import
240  //    of the buffer at slot 1, consumer client detaches the old buffer so that
241  //    the new buffer can be registered. At the same time
242  //    |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
243  //    was detached prior to EPOLLHUP event.
244  // 5. Consumer client continues to handle the EPOLLHUP. Since
245  //    |epollhup_pending_[slot]| is marked as true, it can safely ignore the
246  //    event without detaching the newly allocated buffer at slot 1.
247  //
248  // In normal situations where the previously described sequence doesn't
249  // happen, an EPOLLHUP event should trigger a regular buffer detach.
250  std::vector<bool> epollhup_pending_;
251
252  // |available_buffers_| uses |dvr::RingBuffer| to implementation queue
253  // sematics. When |Dequeue|, we pop the front element from
254  // |available_buffers_|, and  that buffer's reference count will decrease by
255  // one, while another reference in |buffers_| keeps the last reference to
256  // prevent the buffer from being deleted.
257  RingBuffer<BufferInfo> available_buffers_;
258
259  // Fences (acquire fence for consumer and release fence for consumer) , one
260  // for each buffer slot.
261  std::vector<LocalHandle> fences_;
262
263  // Keep track with how many buffers have been added into the queue.
264  size_t capacity_;
265
266  // Epoll fd used to wait for BufferHub events.
267  EpollFileDescriptor epoll_fd_;
268
269  // Flag indicating that the other side hung up. For ProducerQueues this
270  // triggers when BufferHub dies or explicitly closes the queue channel. For
271  // ConsumerQueues this can either mean the same or that the ProducerQueue on
272  // the other end hung up.
273  bool hung_up_{false};
274
275  // Global id for the queue that is consistent across processes.
276  int id_;
277
278  BufferHubQueue(const BufferHubQueue&) = delete;
279  void operator=(BufferHubQueue&) = delete;
280};
281
282class ProducerQueue : public pdx::ClientBase<ProducerQueue, BufferHubQueue> {
283 public:
284  template <typename Meta>
285  static std::unique_ptr<ProducerQueue> Create() {
286    return BASE::Create(sizeof(Meta));
287  }
288  static std::unique_ptr<ProducerQueue> Create(size_t meta_size_bytes) {
289    return BASE::Create(meta_size_bytes);
290  }
291
292  // Usage bits in |usage_set_mask| will be automatically masked on. Usage bits
293  // in |usage_clear_mask| will be automatically masked off. Note that
294  // |usage_set_mask| and |usage_clear_mask| may conflict with each other, but
295  // |usage_set_mask| takes precedence over |usage_clear_mask|. All buffer
296  // allocation through this producer queue shall not have any of the usage bits
297  // in |usage_deny_set_mask| set. Allocation calls violating this will be
298  // rejected. All buffer allocation through this producer queue must have all
299  // the usage bits in |usage_deny_clear_mask| set. Allocation calls violating
300  // this will be rejected. Note that |usage_deny_set_mask| and
301  // |usage_deny_clear_mask| shall not conflict with each other. Such
302  // configuration will be treated as invalid input on creation.
303  template <typename Meta>
304  static std::unique_ptr<ProducerQueue> Create(uint32_t usage_set_mask,
305                                               uint32_t usage_clear_mask,
306                                               uint32_t usage_deny_set_mask,
307                                               uint32_t usage_deny_clear_mask) {
308    return BASE::Create(sizeof(Meta), usage_set_mask, usage_clear_mask,
309                        usage_deny_set_mask, usage_deny_clear_mask);
310  }
311  static std::unique_ptr<ProducerQueue> Create(size_t meta_size_bytes,
312                                               uint32_t usage_set_mask,
313                                               uint32_t usage_clear_mask,
314                                               uint32_t usage_deny_set_mask,
315                                               uint32_t usage_deny_clear_mask) {
316    return BASE::Create(meta_size_bytes, usage_set_mask, usage_clear_mask,
317                        usage_deny_set_mask, usage_deny_clear_mask);
318  }
319
320  // Import a |ProducerQueue| from a channel handle.
321  static std::unique_ptr<ProducerQueue> Import(LocalChannelHandle handle) {
322    return BASE::Create(std::move(handle));
323  }
324
325  // Get a buffer producer. Note that the method doesn't check whether the
326  // buffer slot has a valid buffer that has been allocated already. When no
327  // buffer has been imported before it returns |nullptr|; otherwise it returns
328  // a shared pointer to a |BufferProducer|.
329  std::shared_ptr<BufferProducer> GetBuffer(size_t slot) const {
330    return std::static_pointer_cast<BufferProducer>(
331        BufferHubQueue::GetBuffer(slot));
332  }
333
334  // Allocate producer buffer to populate the queue. Once allocated, a producer
335  // buffer is automatically enqueue'd into the ProducerQueue and available to
336  // use (i.e. in |Gain|'ed mode).
337  // Returns Zero on success and negative error code when buffer allocation
338  // fails.
339  int AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
340                     uint32_t format, uint64_t usage, size_t* out_slot);
341
342  // Add a producer buffer to populate the queue. Once added, a producer buffer
343  // is available to use (i.e. in |Gain|'ed mode).
344  int AddBuffer(const std::shared_ptr<BufferProducer>& buf, size_t slot);
345
346  // Detach producer buffer from the queue.
347  // Returns Zero on success and negative error code when buffer detach
348  // fails.
349  int DetachBuffer(size_t slot) override;
350
351  // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
352  // and caller should call Post() once it's done writing to release the buffer
353  // to the consumer side.
354  pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
355      int timeout, size_t* slot, LocalHandle* release_fence);
356
357 private:
358  friend BASE;
359
360  // Constructors are automatically exposed through ProducerQueue::Create(...)
361  // static template methods inherited from ClientBase, which take the same
362  // arguments as the constructors.
363  explicit ProducerQueue(size_t meta_size);
364  ProducerQueue(LocalChannelHandle handle);
365  ProducerQueue(size_t meta_size, uint64_t usage_set_mask,
366                uint64_t usage_clear_mask, uint64_t usage_deny_set_mask,
367                uint64_t usage_deny_clear_mask);
368
369  int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
370                    LocalHandle* release_fence) override;
371};
372
373// Explicit specializations of ProducerQueue::Create for void metadata type.
374template <>
375inline std::unique_ptr<ProducerQueue> ProducerQueue::Create<void>() {
376  return ProducerQueue::Create(0);
377}
378template <>
379inline std::unique_ptr<ProducerQueue> ProducerQueue::Create<void>(
380    uint32_t usage_set_mask, uint32_t usage_clear_mask,
381    uint32_t usage_deny_set_mask, uint32_t usage_deny_clear_mask) {
382  return ProducerQueue::Create(0, usage_set_mask, usage_clear_mask,
383                               usage_deny_set_mask, usage_deny_clear_mask);
384}
385
386class ConsumerQueue : public BufferHubQueue {
387 public:
388  // Get a buffer consumer. Note that the method doesn't check whether the
389  // buffer slot has a valid buffer that has been imported already. When no
390  // buffer has been imported before it returns nullptr; otherwise returns a
391  // shared pointer to a BufferConsumer.
392  std::shared_ptr<BufferConsumer> GetBuffer(size_t slot) const {
393    return std::static_pointer_cast<BufferConsumer>(
394        BufferHubQueue::GetBuffer(slot));
395  }
396
397  // Import a ConsumerQueue from a channel handle. |ignore_on_import| controls
398  // whether or not buffers are set to be ignored when imported. This may be
399  // used to avoid participation in the buffer lifecycle by a consumer queue
400  // that is only used to spawn other consumer queues, such as in an
401  // intermediate service.
402  static std::unique_ptr<ConsumerQueue> Import(LocalChannelHandle handle,
403                                               bool ignore_on_import = false) {
404    return std::unique_ptr<ConsumerQueue>(
405        new ConsumerQueue(std::move(handle), ignore_on_import));
406  }
407
408  // Import newly created buffers from the service side.
409  // Returns number of buffers successfully imported or an error.
410  Status<size_t> ImportBuffers();
411
412  // Dequeue a consumer buffer to read. The returned buffer in |Acquired|'ed
413  // mode, and caller should call Releasse() once it's done writing to release
414  // the buffer to the producer side. |meta| is passed along from BufferHub,
415  // The user of BufferProducer is responsible with making sure that the
416  // Dequeue() is done with the corect metadata type and size with those used
417  // when the buffer is orignally created.
418  template <typename Meta>
419  pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
420      int timeout, size_t* slot, Meta* meta, LocalHandle* acquire_fence) {
421    return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence);
422  }
423  pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
424      int timeout, size_t* slot, LocalHandle* acquire_fence) {
425    return Dequeue(timeout, slot, nullptr, 0, acquire_fence);
426  }
427
428  pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
429      int timeout, size_t* slot, void* meta, size_t meta_size,
430      LocalHandle* acquire_fence);
431
432 private:
433  friend BufferHubQueue;
434
435  ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import = false);
436
437  // Add a consumer buffer to populate the queue. Once added, a consumer buffer
438  // is NOT available to use until the producer side |Post| it. |WaitForBuffers|
439  // will catch the |Post| and |Acquire| the buffer to make it available for
440  // consumer.
441  int AddBuffer(const std::shared_ptr<BufferConsumer>& buf, size_t slot);
442
443  int OnBufferReady(const std::shared_ptr<BufferHubBuffer>& buf,
444                    LocalHandle* acquire_fence) override;
445
446  Status<void> OnBufferAllocated() override;
447
448  // Flag indicating that imported (consumer) buffers should be ignored when
449  // imported to avoid participating in the buffer ownership flow.
450  bool ignore_on_import_;
451};
452
453}  // namespace dvr
454}  // namespace android
455
456#endif  // ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
457