Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 638b7f74 authored by Jiwen 'Steve' Cai's avatar Jiwen 'Steve' Cai
Browse files

Overhual DvrBuffer and DvrBufferQueue API: Step 1

Adding new APIs:

dvrWriteBufferQueueGainBuffer
dvrWriteBufferQueuePostBuffer
dvrReadBufferQueueAcquireBuffer
dvrReadBufferQueueReleaseBuffer

Those new APIs streamlines DVR buffer operations:
1/ It allows static Dvr{Read,Write}Buffer objects to be statically
allocated with the queue.
2/ Symentric Gain/Post on WriteBufferQueue and Acquire/Release on
ReadBufferQueue.
3/ Use fixed buffer metadata.
4/ This is also a prerequisite to using shared memory based metadata and
async buffer IPC.

More details and discussion at: go/gvr-async-bufferhub

Special note regarding DVR API order in this CL: The new buffer queue
API entries are inserted before new PoseClient API as the PoseClient is
still blocked from being released and the new BufferQueue APIs are
expected to be released sooner than that.

Bug: 65455724
Bug: 65468551
Bug: 65458332
Bug: 65165821
Test: dvr_api-test
Change-Id: Iae8e7787d696d72ebf7457df9f98f4467cd20932
parent a60e6a45
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -66,6 +66,11 @@ class BufferHubQueue : public pdx::Client {

  explicit operator bool() const { return epoll_fd_.IsValid(); }

  int GetBufferId(size_t slot) const {
    return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
                                                      : -1;
  }

  std::shared_ptr<BufferHubBuffer> GetBuffer(size_t slot) const {
    return buffers_[slot];
  }
@@ -218,7 +223,7 @@ class BufferHubQueue : public pdx::Client {
  // Tracks the buffers belonging to this queue. Buffers are stored according to
  // "slot" in this vector. Each slot is a logical id of the buffer within this
  // queue regardless of its queue position or presence in the ring buffer.
  std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity};
  std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;

  // Buffers and related data that are available for dequeue.
  RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
+16 −2
Original line number Diff line number Diff line
@@ -44,8 +44,14 @@ void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer) {
}

void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
  if (write_buffer != nullptr) {
    ALOGW_IF(
        write_buffer->slot != -1,
        "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
        "buffer queue slot. This may indicate possible leaks.");
    delete write_buffer;
  }
}

int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) {
  return write_buffer && write_buffer->write_buffer;
@@ -107,7 +113,15 @@ void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer) {
    *read_buffer = new DvrReadBuffer;
}

void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) { delete read_buffer; }
void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
  if (read_buffer != nullptr) {
    ALOGW_IF(
        read_buffer->slot != -1,
        "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
        "buffer queue slot. This may indicate possible leaks.");
    delete read_buffer;
  }
}

int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) {
  return read_buffer && read_buffer->read_buffer;
+224 −9
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
}

int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
                                 int* out_fence_fd) {
                                 int* out_fence_fd, size_t* out_slot) {
  size_t slot;
  pdx::LocalHandle fence;
  std::shared_ptr<BufferProducer> buffer_producer;
@@ -141,6 +141,86 @@ int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,

  write_buffer->write_buffer = std::move(buffer_producer);
  *out_fence_fd = fence.Release();
  if (out_slot) {
    // TODO(b/65469368): Remove this null check once dvrWriteBufferQueueDequeue
    // is deprecated.
    *out_slot = slot;
  }
  return 0;
}

int DvrWriteBufferQueue::GainBuffer(int timeout,
                                    DvrWriteBuffer** out_write_buffer,
                                    DvrNativeBufferMetadata* out_meta,
                                    int* out_fence_fd) {
  DvrWriteBuffer write_buffer;
  int fence_fd;
  size_t slot;
  const int ret = Dequeue(timeout, &write_buffer, &fence_fd, &slot);
  if (ret < 0) {
    ALOGE_IF(
        ret != -ETIMEDOUT,
        "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer, ret=%d",
        ret);
    return ret;
  }

  if (write_buffers_[slot] == nullptr) {
    // Lazy initialization of a write_buffers_ slot. Note that a slot will only
    // be dynamically allocated once during the entire cycle life of a queue.
    write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
    write_buffers_[slot]->slot = slot;
  }

  LOG_ALWAYS_FATAL_IF(
      write_buffers_[slot]->write_buffer,
      "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
  write_buffers_[slot]->write_buffer = std::move(write_buffer.write_buffer);

  *out_write_buffer = write_buffers_[slot].release();
  *out_fence_fd = fence_fd;

  return 0;
}

int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
                                    const DvrNativeBufferMetadata* meta,
                                    int ready_fence_fd) {
  LOG_FATAL_IF(
      (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
      "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);

  // Some basic sanity checks before we put the buffer back into a slot.
  size_t slot = static_cast<size_t>(write_buffer->slot);
  if (write_buffers_[slot] != nullptr) {
    ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
    return -EINVAL;
  }
  if (write_buffer->write_buffer == nullptr) {
    ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
    return -EINVAL;
  }
  if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
    ALOGE(
        "DvrWriteBufferQueue::PostBuffer: Buffer to be released does not "
        "belong to this buffer queue.");
    return -EINVAL;
  }

  pdx::LocalHandle fence(ready_fence_fd);
  // TODO(b/65455724): All BufferHub operations should be async.
  const int ret = write_buffer->write_buffer->Post(fence, meta, sizeof(*meta));
  if (ret < 0) {
    ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
          ret);
    return ret;
  }

  // Put the DvrWriteBuffer pointer back into its slot for reuse.
  write_buffers_[slot].reset(write_buffer);
  // It's import to reset the write buffer client now. It should stay invalid
  // until next GainBuffer on the same slot.
  write_buffers_[slot]->write_buffer = nullptr;
  return 0;
}

@@ -236,7 +316,29 @@ int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
  if (!write_queue || !write_buffer || !out_fence_fd)
    return -EINVAL;

  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
  // TODO(b/65469368): Deprecate this API once new GainBuffer API is in use.
  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd, nullptr);
}

int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
                                  DvrWriteBuffer** out_write_buffer,
                                  DvrNativeBufferMetadata* out_meta,
                                  int* out_fence_fd) {
  if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
    return -EINVAL;

  return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
                                 out_fence_fd);
}

int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
                                  DvrWriteBuffer* write_buffer,
                                  const DvrNativeBufferMetadata* meta,
                                  int ready_fence_fd) {
  if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
    return -EINVAL;

  return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
}

int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
@@ -268,8 +370,8 @@ int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
}

int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
                                int* out_fence_fd, void* out_meta,
                                size_t meta_size_bytes) {
                                int* out_fence_fd, size_t* out_slot,
                                void* out_meta, size_t meta_size_bytes) {
  if (meta_size_bytes != consumer_queue_->metadata_size()) {
    ALOGE(
        "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
@@ -291,6 +393,95 @@ int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,

  read_buffer->read_buffer = buffer_status.take();
  *out_fence_fd = acquire_fence.Release();

  if (out_slot) {
    // TODO(b/65469368): Remove this null check once dvrReadBufferQueueDequeue
    // is deprecated.
    *out_slot = slot;
  }
  return 0;
}

int DvrReadBufferQueue::AcquireBuffer(int timeout,
                                      DvrReadBuffer** out_read_buffer,
                                      DvrNativeBufferMetadata* out_meta,
                                      int* out_fence_fd) {
  DvrReadBuffer read_buffer;
  int fence_fd;
  size_t slot;
  const int ret = Dequeue(timeout, &read_buffer, &fence_fd, &slot, out_meta,
                          sizeof(*out_meta));
  if (ret < 0) {
    ALOGE_IF(
        ret != -ETIMEDOUT,
        "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer, error=%d",
        ret);
    return ret;
  }

  if (read_buffers_[slot] == nullptr) {
    // Lazy initialization of a read_buffers_ slot. Note that a slot will only
    // be dynamically allocated once during the entire cycle life of a queue.
    read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
    read_buffers_[slot]->slot = slot;
  }

  LOG_FATAL_IF(
      read_buffers_[slot]->read_buffer,
      "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
  read_buffers_[slot]->read_buffer = std::move(read_buffer.read_buffer);

  *out_read_buffer = read_buffers_[slot].release();
  *out_fence_fd = fence_fd;

  return 0;
}

int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
                                      const DvrNativeBufferMetadata* meta,
                                      int release_fence_fd) {
  LOG_FATAL_IF(
      (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
      "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);

  // Some basic sanity checks before we put the buffer back into a slot.
  size_t slot = static_cast<size_t>(read_buffer->slot);
  if (read_buffers_[slot] != nullptr) {
    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
    return -EINVAL;
  }
  if (read_buffer->read_buffer == nullptr) {
    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
    return -EINVAL;
  }
  if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
    ALOGE(
        "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
        "belong to this buffer queue.");
    return -EINVAL;
  }

  pdx::LocalHandle fence(release_fence_fd);
  int ret = 0;
  if (fence) {
    ret = read_buffer->read_buffer->Release(fence);
  } else {
    // TODO(b/65458354): Send metadata back to producer once shared memory based
    // metadata is implemented.
    // TODO(b/65455724): All BufferHub operations should be async.
    ret = read_buffer->read_buffer->ReleaseAsync();
  }
  if (ret < 0) {
    ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
          ret);
    return ret;
  }

  // Put the DvrReadBuffer pointer back into its slot for reuse.
  read_buffers_[slot].reset(read_buffer);
  // It's import to reset the read buffer client now. It should stay invalid
  // until next AcquireBuffer on the same slot.
  read_buffers_[slot]->read_buffer = nullptr;
  return 0;
}

@@ -311,9 +502,11 @@ void DvrReadBufferQueue::SetBufferRemovedCallback(
  } else {
    consumer_queue_->SetBufferRemovedCallback(
        [callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
          DvrReadBuffer read_buffer{
              std::static_pointer_cast<BufferConsumer>(buffer)};
          callback(&read_buffer, context);
          // When buffer is removed from the queue, the slot is already invalid.
          auto read_buffer = std::make_unique<DvrReadBuffer>();
          read_buffer->read_buffer =
              std::static_pointer_cast<BufferConsumer>(buffer);
          callback(read_buffer.release(), context);
        });
  }
}
@@ -366,8 +559,30 @@ int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
  if (meta_size_bytes != 0 && !out_meta)
    return -EINVAL;

  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
                             meta_size_bytes);
  // TODO(b/65469368): Deprecate this API once new AcquireBuffer API is in use.
  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, nullptr,
                             out_meta, meta_size_bytes);
}

int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
                                    DvrReadBuffer** out_read_buffer,
                                    DvrNativeBufferMetadata* out_meta,
                                    int* out_fence_fd) {
  if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
    return -EINVAL;

  return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
                                   out_fence_fd);
}

int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
                                    DvrReadBuffer* read_buffer,
                                    const DvrNativeBufferMetadata* meta,
                                    int release_fence_fd) {
  if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
    return -EINVAL;

  return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
}

int dvrReadBufferQueueSetBufferAvailableCallback(
+22 −2
Original line number Diff line number Diff line
@@ -5,10 +5,14 @@
#include <private/dvr/buffer_hub_queue_client.h>
#include <sys/cdefs.h>

#include <array>
#include <memory>

#include "dvr_internal.h"

struct ANativeWindow;

typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
typedef struct DvrReadBuffer DvrReadBuffer;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
typedef struct DvrWriteBuffer DvrWriteBuffer;
@@ -17,6 +21,7 @@ typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer,
                                                        void* context);

struct DvrWriteBufferQueue {
  using BufferHubQueue = android::dvr::BufferHubQueue;
  using ProducerQueue = android::dvr::ProducerQueue;

  // Create a concrete object for DvrWriteBufferQueue.
@@ -37,19 +42,28 @@ struct DvrWriteBufferQueue {

  int GetNativeWindow(ANativeWindow** out_window);
  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd,
              size_t* out_slot);
  int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer,
                 DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
  int PostBuffer(DvrWriteBuffer* write_buffer,
                 const DvrNativeBufferMetadata* meta, int ready_fence_fd);
  int ResizeBuffer(uint32_t width, uint32_t height);

 private:
  std::shared_ptr<ProducerQueue> producer_queue_;
  std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity>
      write_buffers_;

  uint32_t width_;
  uint32_t height_;
  uint32_t format_;

  android::sp<android::Surface> native_window_;
};

struct DvrReadBufferQueue {
  using BufferHubQueue = android::dvr::BufferHubQueue;
  using ConsumerQueue = android::dvr::ConsumerQueue;

  explicit DvrReadBufferQueue(
@@ -61,7 +75,11 @@ struct DvrReadBufferQueue {

  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
  int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
              void* out_meta, size_t meta_size_bytes);
              size_t* out_slot, void* out_meta, size_t meta_size_bytes);
  int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer,
                    DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
  int ReleaseBuffer(DvrReadBuffer* read_buffer,
                    const DvrNativeBufferMetadata* meta, int release_fence_fd);
  void SetBufferAvailableCallback(
      DvrReadBufferQueueBufferAvailableCallback callback, void* context);
  void SetBufferRemovedCallback(
@@ -70,6 +88,8 @@ struct DvrReadBufferQueue {

 private:
  std::shared_ptr<ConsumerQueue> consumer_queue_;
  std::array<std::unique_ptr<DvrReadBuffer>, BufferHubQueue::kMaxQueueCapacity>
      read_buffers_;
};

#endif  // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+10 −0
Original line number Diff line number Diff line
@@ -34,10 +34,20 @@ DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
extern "C" {

struct DvrWriteBuffer {
  // The slot nubmer of the buffer, a valid slot number must be in the range of
  // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
  // DvrWriteBuffer acquired from a DvrWriteBufferQueue.
  int32_t slot = -1;

  std::shared_ptr<android::dvr::BufferProducer> write_buffer;
};

struct DvrReadBuffer {
  // The slot nubmer of the buffer, a valid slot number must be in the range of
  // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
  // DvrReadBuffer acquired from a DvrReadBufferQueue.
  int32_t slot = -1;

  std::shared_ptr<android::dvr::BufferConsumer> read_buffer;
};

Loading