Home | History | Annotate | Download | only in libdvr
      1 #include "include/dvr/dvr_api.h"
      2 #include "include/dvr/dvr_buffer_queue.h"
      3 
      4 #include <android/native_window.h>
      5 #include <gui/BufferHubProducer.h>
      6 
      7 #include "dvr_internal.h"
      8 #include "dvr_buffer_queue_internal.h"
      9 
     10 using namespace android;
     11 using android::dvr::BufferConsumer;
     12 using android::dvr::BufferHubBuffer;
     13 using android::dvr::BufferProducer;
     14 using android::dvr::ConsumerQueue;
     15 using android::dvr::ProducerQueue;
     16 using android::dvr::ProducerQueueConfigBuilder;
     17 using android::dvr::UsagePolicy;
     18 
     19 extern "C" {
     20 
     21 DvrWriteBufferQueue::DvrWriteBufferQueue(
     22     const std::shared_ptr<ProducerQueue>& producer_queue)
     23     : producer_queue_(producer_queue),
     24       width_(producer_queue->default_width()),
     25       height_(producer_queue->default_height()),
     26       format_(producer_queue->default_format()) {}
     27 
     28 int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
     29   if (native_window_ == nullptr) {
     30     // Lazy creation of |native_window|, as not everyone is using
     31     // DvrWriteBufferQueue as an external surface.
     32     sp<IGraphicBufferProducer> gbp = BufferHubProducer::Create(producer_queue_);
     33     native_window_ = new Surface(gbp, true);
     34   }
     35 
     36   *out_window = static_cast<ANativeWindow*>(native_window_.get());
     37   return 0;
     38 }
     39 
     40 int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
     41   std::unique_ptr<ConsumerQueue> consumer_queue =
     42       producer_queue_->CreateConsumerQueue();
     43   if (consumer_queue == nullptr) {
     44     ALOGE(
     45         "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
     46         "from producer queue: queue_id=%d.", producer_queue_->id());
     47     return -ENOMEM;
     48   }
     49 
     50   *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
     51   return 0;
     52 }
     53 
     54 int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
     55                                  int* out_fence_fd) {
     56   DvrNativeBufferMetadata meta;
     57   DvrWriteBuffer* buffer = nullptr;
     58   int fence_fd = -1;
     59   if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd))
     60     return ret;
     61   if (!buffer)
     62     return -ENOMEM;
     63 
     64   write_buffers_[buffer->slot].reset(buffer);
     65   write_buffer->write_buffer = std::move(buffer->write_buffer);
     66   *out_fence_fd = fence_fd;
     67   return 0;
     68 }
     69 
     70 int DvrWriteBufferQueue::GainBuffer(int timeout,
     71                                     DvrWriteBuffer** out_write_buffer,
     72                                     DvrNativeBufferMetadata* out_meta,
     73                                     int* out_fence_fd) {
     74   size_t slot;
     75   pdx::LocalHandle release_fence;
     76 
     77   // Need to retry N+1 times, where N is total number of buffers in the queue.
     78   // As in the worst case, we will dequeue all N buffers and reallocate them, on
     79   // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension.
     80   size_t max_retries = 1 + producer_queue_->capacity();
     81   size_t retry = 0;
     82 
     83   for (; retry < max_retries; retry++) {
     84     auto buffer_status =
     85         producer_queue_->Dequeue(timeout, &slot, out_meta, &release_fence);
     86     if (!buffer_status) {
     87       ALOGE_IF(buffer_status.error() != ETIMEDOUT,
     88                "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s",
     89                buffer_status.GetErrorMessage().c_str());
     90       return -buffer_status.error();
     91     }
     92 
     93     if (write_buffers_[slot] == nullptr) {
     94       // Lazy initialization of a write_buffers_ slot. Note that a slot will
     95       // only be dynamically allocated once during the entire cycle life of a
     96       // queue.
     97       write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
     98       write_buffers_[slot]->slot = slot;
     99     }
    100 
    101     LOG_ALWAYS_FATAL_IF(
    102         write_buffers_[slot]->write_buffer,
    103         "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
    104     write_buffers_[slot]->write_buffer = std::move(buffer_status.take());
    105 
    106     const auto& buffer_producer = write_buffers_[slot]->write_buffer;
    107     if (!buffer_producer)
    108       return -ENOMEM;
    109 
    110     if (width_ == buffer_producer->width() &&
    111         height_ == buffer_producer->height() &&
    112         format_ == buffer_producer->format()) {
    113       // Producer queue returns a buffer matches the current request.
    114       break;
    115     }
    116 
    117     // Needs reallocation. Note that if there are already multiple available
    118     // buffers in the queue, the next one returned from |queue_->Dequeue| may
    119     // still have the old buffer dimension or format. Retry up to N+1 times or
    120     // until we dequeued a buffer with new configuration.
    121     ALOGD_IF(TRACE,
    122              "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu "
    123              "(w=%u, h=%u, fmt=%u) is different from the buffer returned "
    124              "(w=%u, h=%u, fmt=%u). Need re-allocation.",
    125              slot, width_, height_, format_, buffer_producer->width(),
    126              buffer_producer->height(), buffer_producer->format());
    127 
    128     // Currently, we are not storing |layer_count| and |usage| in queue
    129     // configuration. Copy those setup from the last buffer dequeued before we
    130     // remove it.
    131     uint32_t old_layer_count = buffer_producer->layer_count();
    132     uint64_t old_usage = buffer_producer->usage();
    133 
    134     // Allocate a new producer buffer with new buffer configs. Note that if
    135     // there are already multiple available buffers in the queue, the next one
    136     // returned from |queue_->Dequeue| may still have the old buffer dimension
    137     // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until
    138     // we dequeued a buffer with new configuration.
    139     auto remove_status = producer_queue_->RemoveBuffer(slot);
    140     if (!remove_status) {
    141       ALOGE("DvrWriteBufferQueue::Dequeue: Failed to remove buffer: %s",
    142             remove_status.GetErrorMessage().c_str());
    143       return -remove_status.error();
    144     }
    145     // Make sure that the previously allocated buffer is dereferenced from
    146     // write_buffers_ array.
    147     write_buffers_[slot]->write_buffer = nullptr;
    148 
    149     auto allocate_status = producer_queue_->AllocateBuffer(
    150         width_, height_, old_layer_count, format_, old_usage);
    151     if (!allocate_status) {
    152       ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
    153             allocate_status.GetErrorMessage().c_str());
    154       return -allocate_status.error();
    155     }
    156   }
    157 
    158   if (retry >= max_retries) {
    159     ALOGE(
    160         "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after "
    161         "resizing.");
    162     return -ENOMEM;
    163   }
    164 
    165   *out_write_buffer = write_buffers_[slot].release();
    166   *out_fence_fd = release_fence.Release();
    167 
    168   return 0;
    169 }
    170 
    171 int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
    172                                     const DvrNativeBufferMetadata* meta,
    173                                     int ready_fence_fd) {
    174   LOG_FATAL_IF(
    175       (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
    176       "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
    177 
    178   // Some basic sanity checks before we put the buffer back into a slot.
    179   size_t slot = static_cast<size_t>(write_buffer->slot);
    180   if (write_buffers_[slot] != nullptr) {
    181     ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
    182     return -EINVAL;
    183   }
    184   if (write_buffer->write_buffer == nullptr) {
    185     ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
    186     return -EINVAL;
    187   }
    188   if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
    189     ALOGE(
    190         "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not "
    191         "belong to this buffer queue. Posting buffer: id=%d, buffer in "
    192         "queue: id=%d",
    193         write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot));
    194     return -EINVAL;
    195   }
    196 
    197   write_buffer->write_buffer->SetQueueIndex(next_post_index_++);
    198   pdx::LocalHandle fence(ready_fence_fd);
    199   const int ret = write_buffer->write_buffer->PostAsync(meta, fence);
    200   if (ret < 0) {
    201     ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
    202           ret);
    203     return ret;
    204   }
    205 
    206   // Put the DvrWriteBuffer pointer back into its slot for reuse.
    207   write_buffers_[slot].reset(write_buffer);
    208   // It's import to reset the write buffer client now. It should stay invalid
    209   // until next GainBuffer on the same slot.
    210   write_buffers_[slot]->write_buffer = nullptr;
    211   return 0;
    212 }
    213 
    214 int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
    215   if (width == 0 || height == 0) {
    216     ALOGE(
    217         "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
    218         "h=%u.",
    219         width, height);
    220     return -EINVAL;
    221   }
    222 
    223   width_ = width;
    224   height_ = height;
    225   return 0;
    226 }
    227 
    228 int dvrWriteBufferQueueCreate(uint32_t width, uint32_t height, uint32_t format,
    229                               uint32_t layer_count, uint64_t usage,
    230                               size_t capacity, size_t metadata_size,
    231                               DvrWriteBufferQueue** out_write_queue) {
    232   if (!out_write_queue)
    233     return -EINVAL;
    234 
    235   auto config_builder = ProducerQueueConfigBuilder()
    236                             .SetDefaultWidth(width)
    237                             .SetDefaultHeight(height)
    238                             .SetDefaultFormat(format)
    239                             .SetMetadataSize(metadata_size);
    240   std::unique_ptr<ProducerQueue> producer_queue =
    241       ProducerQueue::Create(config_builder.Build(), UsagePolicy{});
    242   if (!producer_queue) {
    243     ALOGE("dvrWriteBufferQueueCreate: Failed to create producer queue.");
    244     return -ENOMEM;
    245   }
    246 
    247   auto status = producer_queue->AllocateBuffers(width, height, layer_count,
    248                                                 format, usage, capacity);
    249   if (!status.ok()) {
    250     ALOGE("dvrWriteBufferQueueCreate: Failed to allocate buffers.");
    251     return -ENOMEM;
    252   }
    253 
    254   *out_write_queue = new DvrWriteBufferQueue(std::move(producer_queue));
    255   return 0;
    256 }
    257 
    258 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
    259   delete write_queue;
    260 }
    261 
    262 ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
    263   if (!write_queue)
    264     return -EINVAL;
    265 
    266   return write_queue->capacity();
    267 }
    268 
    269 int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
    270   if (!write_queue)
    271     return -EINVAL;
    272 
    273   return write_queue->id();
    274 }
    275 
    276 int dvrWriteBufferQueueGetANativeWindow(DvrWriteBufferQueue* write_queue,
    277                                         ANativeWindow** out_window) {
    278   if (!write_queue || !out_window)
    279     return -EINVAL;
    280 
    281   return write_queue->GetNativeWindow(out_window);
    282 }
    283 
    284 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
    285                                        DvrReadBufferQueue** out_read_queue) {
    286   if (!write_queue || !out_read_queue)
    287     return -EINVAL;
    288 
    289   return write_queue->CreateReadQueue(out_read_queue);
    290 }
    291 
    292 int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
    293                                   DvrWriteBuffer** out_write_buffer,
    294                                   DvrNativeBufferMetadata* out_meta,
    295                                   int* out_fence_fd) {
    296   if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
    297     return -EINVAL;
    298 
    299   return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
    300                                  out_fence_fd);
    301 }
    302 
    303 int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
    304                                   DvrWriteBuffer* write_buffer,
    305                                   const DvrNativeBufferMetadata* meta,
    306                                   int ready_fence_fd) {
    307   if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
    308     return -EINVAL;
    309 
    310   return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
    311 }
    312 
    313 int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
    314                                     uint32_t width, uint32_t height) {
    315   if (!write_queue)
    316     return -EINVAL;
    317 
    318   return write_queue->ResizeBuffer(width, height);
    319 }
    320 
    321 // ReadBufferQueue
    322 
    323 DvrReadBufferQueue::DvrReadBufferQueue(
    324     const std::shared_ptr<ConsumerQueue>& consumer_queue)
    325     : consumer_queue_(consumer_queue) {}
    326 
    327 int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
    328   std::unique_ptr<ConsumerQueue> consumer_queue =
    329       consumer_queue_->CreateConsumerQueue();
    330   if (consumer_queue == nullptr) {
    331     ALOGE(
    332         "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
    333         "from producer queue: queue_id=%d.", consumer_queue_->id());
    334     return -ENOMEM;
    335   }
    336 
    337   *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
    338   return 0;
    339 }
    340 
    341 int DvrReadBufferQueue::AcquireBuffer(int timeout,
    342                                       DvrReadBuffer** out_read_buffer,
    343                                       DvrNativeBufferMetadata* out_meta,
    344                                       int* out_fence_fd) {
    345   size_t slot;
    346   pdx::LocalHandle acquire_fence;
    347   auto buffer_status =
    348       consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence);
    349   if (!buffer_status) {
    350     ALOGE_IF(buffer_status.error() != ETIMEDOUT,
    351              "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s",
    352              buffer_status.GetErrorMessage().c_str());
    353     return -buffer_status.error();
    354   }
    355 
    356   if (read_buffers_[slot] == nullptr) {
    357     // Lazy initialization of a read_buffers_ slot. Note that a slot will only
    358     // be dynamically allocated once during the entire cycle life of a queue.
    359     read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
    360     read_buffers_[slot]->slot = slot;
    361   }
    362 
    363   LOG_FATAL_IF(
    364       read_buffers_[slot]->read_buffer,
    365       "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
    366   read_buffers_[slot]->read_buffer = std::move(buffer_status.take());
    367 
    368   *out_read_buffer = read_buffers_[slot].release();
    369   *out_fence_fd = acquire_fence.Release();
    370 
    371   return 0;
    372 }
    373 
    374 int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
    375                                       const DvrNativeBufferMetadata* meta,
    376                                       int release_fence_fd) {
    377   LOG_FATAL_IF(
    378       (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
    379       "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
    380 
    381   // Some basic sanity checks before we put the buffer back into a slot.
    382   size_t slot = static_cast<size_t>(read_buffer->slot);
    383   if (read_buffers_[slot] != nullptr) {
    384     ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
    385     return -EINVAL;
    386   }
    387   if (read_buffer->read_buffer == nullptr) {
    388     ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
    389     return -EINVAL;
    390   }
    391   if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
    392     if (consumer_queue_->GetBufferId(slot) > 0) {
    393       ALOGE(
    394           "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
    395           "belong to this queue (queue_id=%d): attempting to release buffer "
    396           "(buffer_id=%d) at slot %d which holds a different buffer "
    397           "(buffer_id=%d).",
    398           consumer_queue_->id(), read_buffer->read_buffer->id(),
    399           static_cast<int>(slot), consumer_queue_->GetBufferId(slot));
    400     } else {
    401       ALOGI(
    402           "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released may not "
    403           "belong to this queue (queue_id=%d): attempting to release buffer "
    404           "(buffer_id=%d) at slot %d which is empty.",
    405           consumer_queue_->id(), read_buffer->read_buffer->id(),
    406           static_cast<int>(slot));
    407     }
    408   }
    409 
    410   pdx::LocalHandle fence(release_fence_fd);
    411   int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence);
    412   if (ret < 0) {
    413     ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
    414           ret);
    415     return ret;
    416   }
    417 
    418   // Put the DvrReadBuffer pointer back into its slot for reuse.
    419   read_buffers_[slot].reset(read_buffer);
    420   // It's import to reset the read buffer client now. It should stay invalid
    421   // until next AcquireBuffer on the same slot.
    422   read_buffers_[slot]->read_buffer = nullptr;
    423   return 0;
    424 }
    425 
    426 void DvrReadBufferQueue::SetBufferAvailableCallback(
    427     DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
    428   if (callback == nullptr) {
    429     consumer_queue_->SetBufferAvailableCallback(nullptr);
    430   } else {
    431     consumer_queue_->SetBufferAvailableCallback(
    432         [callback, context]() { callback(context); });
    433   }
    434 }
    435 
    436 void DvrReadBufferQueue::SetBufferRemovedCallback(
    437     DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
    438   if (callback == nullptr) {
    439     consumer_queue_->SetBufferRemovedCallback(nullptr);
    440   } else {
    441     consumer_queue_->SetBufferRemovedCallback(
    442         [callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
    443           // When buffer is removed from the queue, the slot is already invalid.
    444           auto read_buffer = std::make_unique<DvrReadBuffer>();
    445           read_buffer->read_buffer =
    446               std::static_pointer_cast<BufferConsumer>(buffer);
    447           callback(read_buffer.release(), context);
    448         });
    449   }
    450 }
    451 
    452 int DvrReadBufferQueue::HandleEvents() {
    453   // TODO(jwcai) Probably should change HandleQueueEvents to return Status.
    454   consumer_queue_->HandleQueueEvents();
    455   return 0;
    456 }
    457 
    458 void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
    459   delete read_queue;
    460 }
    461 
    462 ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
    463   if (!read_queue)
    464     return -EINVAL;
    465 
    466   return read_queue->capacity();
    467 }
    468 
    469 int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
    470   if (!read_queue)
    471     return -EINVAL;
    472 
    473   return read_queue->id();
    474 }
    475 
    476 int dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue) {
    477   if (!read_queue)
    478     return -EINVAL;
    479 
    480   return read_queue->event_fd();
    481 }
    482 
    483 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
    484                                       DvrReadBufferQueue** out_read_queue) {
    485   if (!read_queue || !out_read_queue)
    486     return -EINVAL;
    487 
    488   return read_queue->CreateReadQueue(out_read_queue);
    489 }
    490 
    491 int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
    492                               DvrReadBuffer* read_buffer, int* out_fence_fd,
    493                               void* out_meta, size_t meta_size_bytes) {
    494   if (!read_queue || !read_buffer || !out_fence_fd)
    495     return -EINVAL;
    496 
    497   if (meta_size_bytes != 0 && !out_meta)
    498     return -EINVAL;
    499 
    500   return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
    501                              meta_size_bytes);
    502 }
    503 
    504 int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
    505                                     DvrReadBuffer** out_read_buffer,
    506                                     DvrNativeBufferMetadata* out_meta,
    507                                     int* out_fence_fd) {
    508   if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
    509     return -EINVAL;
    510 
    511   return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
    512                                    out_fence_fd);
    513 }
    514 
    515 int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
    516                                     DvrReadBuffer* read_buffer,
    517                                     const DvrNativeBufferMetadata* meta,
    518                                     int release_fence_fd) {
    519   if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
    520     return -EINVAL;
    521 
    522   return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
    523 }
    524 
    525 int dvrReadBufferQueueSetBufferAvailableCallback(
    526     DvrReadBufferQueue* read_queue,
    527     DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
    528   if (!read_queue)
    529     return -EINVAL;
    530 
    531   read_queue->SetBufferAvailableCallback(callback, context);
    532   return 0;
    533 }
    534 
    535 int dvrReadBufferQueueSetBufferRemovedCallback(
    536     DvrReadBufferQueue* read_queue,
    537     DvrReadBufferQueueBufferRemovedCallback callback, void* context) {
    538   if (!read_queue)
    539     return -EINVAL;
    540 
    541   read_queue->SetBufferRemovedCallback(callback, context);
    542   return 0;
    543 }
    544 
    545 int dvrReadBufferQueueHandleEvents(DvrReadBufferQueue* read_queue) {
    546   if (!read_queue)
    547     return -EINVAL;
    548 
    549   return read_queue->HandleEvents();
    550 }
    551 
    552 }  // extern "C"
    553