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

Commit 3c3f4314 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "DvrWriteBufferQueue: support buffer resizing"

parents fc89335a 656f406f
Loading
Loading
Loading
Loading
+10 −3
Original line number Original line Diff line number Diff line
@@ -104,9 +104,16 @@ Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) {
  return {};
  return {};
}
}


Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() {
Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(uint32_t width,
                                                            uint32_t height,
                                                            uint32_t format) {
  ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
  ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue.");
  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0);
  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
      ProducerQueueConfigBuilder()
          .SetDefaultWidth(width)
          .SetDefaultHeight(height)
          .SetDefaultFormat(format)
          .Build());
  if (!status) {
  if (!status) {
    ALOGE("Surface::CreateQueue: Failed to create queue: %s",
    ALOGE("Surface::CreateQueue: Failed to create queue: %s",
          status.GetErrorMessage().c_str());
          status.GetErrorMessage().c_str());
@@ -129,7 +136,7 @@ Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(
           "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
           "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
           "usage=%" PRIx64 " capacity=%zu",
           "usage=%" PRIx64 " capacity=%zu",
           width, height, layer_count, format, usage, capacity);
           width, height, layer_count, format, usage, capacity);
  auto status = CreateQueue();
  auto status = CreateQueue(width, height, format);
  if (!status)
  if (!status)
    return status.error_status();
    return status.error_status();


+3 −1
Original line number Original line Diff line number Diff line
@@ -37,7 +37,9 @@ class Surface : public pdx::ClientBase<Surface> {
  pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
  pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);


  // Creates an empty queue.
  // Creates an empty queue.
  pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue();
  pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width,
                                                          uint32_t height,
                                                          uint32_t format);


  // Creates a queue and populates it with |capacity| buffers of the specified
  // Creates a queue and populates it with |capacity| buffers of the specified
  // parameters.
  // parameters.
+3 −2
Original line number Original line Diff line number Diff line
@@ -222,8 +222,9 @@ struct DisplayProtocol {
  PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
  PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
                    SurfaceInfo(const SurfaceAttributes& attributes));
                    SurfaceInfo(const SurfaceAttributes& attributes));
  PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
  PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
  PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue,
  PDX_REMOTE_METHOD(
                    LocalChannelHandle(size_t meta_size_bytes));
      CreateQueue, kOpCreateQueue,
      LocalChannelHandle(const ProducerQueueConfig& producer_config));
  PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
  PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
                    void(const SurfaceAttributes& attributes));
                    void(const SurfaceAttributes& attributes));
};
};
+1 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ cc_library_headers {


cflags = [
cflags = [
    "-DLOG_TAG=\"libdvr\"",
    "-DLOG_TAG=\"libdvr\"",
    "-DTRACE=0",
]
]


srcs = [
srcs = [
+195 −108
Original line number Original line Diff line number Diff line
@@ -2,60 +2,174 @@
#include "include/dvr/dvr_buffer_queue.h"
#include "include/dvr/dvr_buffer_queue.h"


#include <android/native_window.h>
#include <android/native_window.h>
#include <gui/Surface.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <private/dvr/buffer_hub_queue_producer.h>
#include <private/dvr/buffer_hub_queue_producer.h>


#include "dvr_internal.h"
#include "dvr_internal.h"

#include "dvr_buffer_queue_internal.h"
#define CHECK_PARAM(param)                                               \
  LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
                      __FUNCTION__)


using namespace android;
using namespace android;
using android::dvr::BufferHubQueueProducer;
using android::dvr::BufferProducer;
using android::dvr::ConsumerQueue;
using android::dvr::ProducerQueue;

extern "C" {


namespace android {
DvrWriteBufferQueue::DvrWriteBufferQueue(
namespace dvr {
    const std::shared_ptr<ProducerQueue>& producer_queue)
    : producer_queue_(producer_queue),
      width_(producer_queue->default_width()),
      height_(producer_queue->default_height()),
      format_(producer_queue->default_format()) {}


DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
    const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
  if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
  return new DvrWriteBufferQueue{std::move(producer_queue)};
    ALOGE(
        "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata "
        "(%zu) of the write queue does not match  of size of "
        "DvrNativeBufferMetadata (%zu).",
        producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata));
    return -EINVAL;
  }
  }


DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
  if (native_window_ == nullptr) {
    const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
    // Lazy creation of |native_window|, as not everyone is using
  return new DvrReadBufferQueue{std::move(consumer_queue)};
    // DvrWriteBufferQueue as an external surface.
    sp<IGraphicBufferProducer> gbp =
        BufferHubQueueProducer::Create(producer_queue_);
    native_window_ = new Surface(gbp, true);
  }
  }


dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
  *out_window = static_cast<ANativeWindow*>(native_window_.get());
    DvrWriteBufferQueue* write_queue) {
  return 0;
  return write_queue->producer_queue.get();
}
}


}  // namespace dvr
int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
}  // namespace android
  std::unique_ptr<ConsumerQueue> consumer_queue =
      producer_queue_->CreateConsumerQueue();
  if (consumer_queue == nullptr) {
    ALOGE(
        "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue "
        "from producer queue: queue_id=%d.", producer_queue_->id());
    return -ENOMEM;
  }


extern "C" {
  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
  return 0;
}


void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
  if (write_queue != nullptr && write_queue->native_window != nullptr)
                                 int* out_fence_fd) {
    ANativeWindow_release(write_queue->native_window);
  size_t slot;
  pdx::LocalHandle fence;
  std::shared_ptr<BufferProducer> buffer_producer;

  // Need to retry N+1 times, where N is total number of buffers in the queue.
  // As in the worst case, we will dequeue all N buffers and reallocate them, on
  // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension.
  size_t max_retries = 1 + producer_queue_->capacity();
  size_t retry = 0;

  for (; retry < max_retries; retry++) {
    auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence);
    if (!buffer_status) {
      ALOGE_IF(buffer_status.error() != ETIMEDOUT,
               "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s",
               buffer_status.GetErrorMessage().c_str());
      return -buffer_status.error();
    }

    buffer_producer = buffer_status.take();
    if (!buffer_producer)
      return -ENOMEM;

    if (width_ == buffer_producer->width() &&
        height_ == buffer_producer->height() &&
        format_ == buffer_producer->format()) {
      // Producer queue returns a buffer matches the current request.
      break;
    }

    // Needs reallocation. Note that if there are already multiple available
    // buffers in the queue, the next one returned from |queue_->Dequeue| may
    // still have the old buffer dimension or format. Retry up to N+1 times or
    // until we dequeued a buffer with new configuration.
    ALOGD_IF(TRACE,
             "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu "
             "(w=%u, h=%u, fmt=%u) is different from the buffer returned "
             "(w=%u, h=%u, fmt=%u). Need re-allocation.",
             slot, width_, height_, format_, buffer_producer->width(),
             buffer_producer->height(), buffer_producer->format());

    // Currently, we are not storing |layer_count| and |usage| in queue
    // configuration. Copy those setup from the last buffer dequeued before we
    // remove it.
    uint32_t old_layer_count = buffer_producer->layer_count();
    uint64_t old_usage = buffer_producer->usage();

    // Allocate a new producer buffer with new buffer configs. Note that if
    // there are already multiple available buffers in the queue, the next one
    // returned from |queue_->Dequeue| may still have the old buffer dimension
    // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until
    // we dequeued a buffer with new configuration.
    auto detach_status = producer_queue_->DetachBuffer(slot);
    if (!detach_status) {
      ALOGE("DvrWriteBufferQueue::Dequeue: Failed to detach buffer: %s",
            detach_status.GetErrorMessage().c_str());
      return -detach_status.error();
    }

    auto allocate_status = producer_queue_->AllocateBuffer(
        width_, height_, old_layer_count, format_, old_usage, &slot);
    if (!allocate_status) {
      ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
            allocate_status.GetErrorMessage().c_str());
      return -allocate_status.error();
    }
  }

  if (retry >= max_retries) {
    ALOGE(
        "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after "
        "resizing.");
    return -ENOMEM;
  }

  write_buffer->write_buffer = std::move(buffer_producer);
  *out_fence_fd = fence.Release();
  return 0;
}


int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) {
  if (width == 0 || height == 0) {
    ALOGE(
        "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, "
        "h=%u.",
        width, height);
    return -EINVAL;
  }

  width_ = width;
  height_ = height;
  return 0;
}

void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
  delete write_queue;
  delete write_queue;
}
}


ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
  if (!write_queue || !write_queue->producer_queue)
  if (!write_queue)
    return -EINVAL;
    return -EINVAL;


  return write_queue->producer_queue->capacity();
  return write_queue->capacity();
}
}


int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
  if (!write_queue)
  if (!write_queue)
    return -EINVAL;
    return -EINVAL;


  return write_queue->producer_queue->id();
  return write_queue->id();
}
}


int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
@@ -63,74 +177,81 @@ int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
  if (!write_queue || !out_window)
  if (!write_queue || !out_window)
    return -EINVAL;
    return -EINVAL;


  if (write_queue->producer_queue->metadata_size() !=
  return write_queue->GetNativeWindow(out_window);
      sizeof(DvrNativeBufferMetadata)) {
    ALOGE(
        "The size of buffer metadata (%zu) of the write queue does not match "
        "of size of DvrNativeBufferMetadata (%zu).",
        write_queue->producer_queue->metadata_size(),
        sizeof(DvrNativeBufferMetadata));
    return -EINVAL;
}
}


  // Lazy creation of |native_window|.
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
  if (write_queue->native_window == nullptr) {
                                       DvrReadBufferQueue** out_read_queue) {
    sp<IGraphicBufferProducer> gbp =
  if (!write_queue || !out_read_queue)
        dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
    return -EINVAL;
    sp<Surface> surface = new Surface(gbp, true);

    write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
  return write_queue->CreateReadQueue(out_read_queue);
    ANativeWindow_acquire(write_queue->native_window);
}
}


  *out_window = write_queue->native_window;
int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
  return 0;
                               DvrWriteBuffer* write_buffer,
                               int* out_fence_fd) {
  if (!write_queue || !write_buffer || !out_fence_fd)
    return -EINVAL;

  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
}
}


int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
                                       DvrReadBufferQueue** out_read_queue) {
                                    uint32_t width, uint32_t height) {
  if (!write_queue || !write_queue->producer_queue || !out_read_queue)
  if (!write_queue)
    return -EINVAL;
    return -EINVAL;


  auto read_queue = std::make_unique<DvrReadBufferQueue>();
  return write_queue->ResizeBuffer(width, height);
  read_queue->consumer_queue =
}
      write_queue->producer_queue->CreateConsumerQueue();

  if (read_queue->consumer_queue == nullptr) {
// ReadBufferQueue

DvrReadBufferQueue::DvrReadBufferQueue(
    const std::shared_ptr<ConsumerQueue>& consumer_queue)
    : consumer_queue_(consumer_queue) {}

int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
  std::unique_ptr<ConsumerQueue> consumer_queue =
      consumer_queue_->CreateConsumerQueue();
  if (consumer_queue == nullptr) {
    ALOGE(
    ALOGE(
        "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
        "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
        "from DvrWriteBufferQueue[%p].",
        "from producer queue: queue_id=%d.", consumer_queue_->id());
        write_queue);
    return -ENOMEM;
    return -ENOMEM;
  }
  }


  *out_read_queue = read_queue.release();
  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
  return 0;
  return 0;
}
}


int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
                               DvrWriteBuffer* write_buffer,
                                int* out_fence_fd, void* out_meta,
                               int* out_fence_fd) {
                                size_t meta_size_bytes) {
  if (!write_queue || !write_queue->producer_queue || !write_buffer ||
  if (meta_size_bytes != consumer_queue_->metadata_size()) {
      !out_fence_fd) {
    ALOGE(
        "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
        "but actual (%zu).",
        consumer_queue_->metadata_size(), meta_size_bytes);
    return -EINVAL;
    return -EINVAL;
  }
  }


  size_t slot;
  size_t slot;
  pdx::LocalHandle release_fence;
  pdx::LocalHandle acquire_fence;
  auto buffer_status =
  auto buffer_status = consumer_queue_->Dequeue(
      write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
      timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
  if (!buffer_status) {
  if (!buffer_status) {
    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
             "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
             "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s",
             buffer_status.GetErrorMessage().c_str());
             buffer_status.GetErrorMessage().c_str());
    return -buffer_status.error();
    return -buffer_status.error();
  }
  }


  write_buffer->write_buffer = buffer_status.take();
  read_buffer->read_buffer = buffer_status.take();
  *out_fence_fd = release_fence.Release();
  *out_fence_fd = acquire_fence.Release();
  return 0;
  return 0;
}
}


// ReadBufferQueue
void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
  delete read_queue;
  delete read_queue;
}
}
@@ -139,66 +260,32 @@ ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
  if (!read_queue)
  if (!read_queue)
    return -EINVAL;
    return -EINVAL;


  return read_queue->consumer_queue->capacity();
  return read_queue->capacity();
}
}


int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
  if (!read_queue)
  if (!read_queue)
    return -EINVAL;
    return -EINVAL;


  return read_queue->consumer_queue->id();
  return read_queue->id();
}
}


int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
                                      DvrReadBufferQueue** out_read_queue) {
                                      DvrReadBufferQueue** out_read_queue) {
  if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
  if (!read_queue || !out_read_queue)
    return -EINVAL;
    return -EINVAL;


  auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
  return read_queue->CreateReadQueue(out_read_queue);
  new_read_queue->consumer_queue =
      read_queue->consumer_queue->CreateConsumerQueue();
  if (new_read_queue->consumer_queue == nullptr) {
    ALOGE(
        "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
        "from DvrReadBufferQueue[%p].",
        read_queue);
    return -ENOMEM;
  }

  *out_read_queue = new_read_queue.release();
  return 0;
}
}


int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
                              DvrReadBuffer* read_buffer, int* out_fence_fd,
                              DvrReadBuffer* read_buffer, int* out_fence_fd,
                              void* out_meta, size_t meta_size_bytes) {
                              void* out_meta, size_t meta_size_bytes) {
  if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
  if (!read_queue || !read_buffer || !out_fence_fd || !out_meta)
      !out_fence_fd || !out_meta) {
    return -EINVAL;
    return -EINVAL;
  }

  if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
    ALOGE(
        "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
        "but actual (%zu).",
        read_queue->consumer_queue->metadata_size(), meta_size_bytes);
    return -EINVAL;
  }


  size_t slot;
  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
  pdx::LocalHandle acquire_fence;
                             meta_size_bytes);
  auto buffer_status = read_queue->consumer_queue->Dequeue(
      timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
  if (!buffer_status) {
    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
             "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s",
             buffer_status.GetErrorMessage().c_str());
    return -buffer_status.error();
  }

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


}  // extern "C"
}  // extern "C"
Loading