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