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