OSDN Git Service

Fix minor corner cases in BufferHubQueueProducer
authorJiwen 'Steve' Cai <jwcai@google.com>
Sat, 15 Apr 2017 00:56:55 +0000 (17:56 -0700)
committerJiwen 'Steve' Cai <jwcai@google.com>
Wed, 26 Apr 2017 00:21:47 +0000 (17:21 -0700)
1/ Set reasonable return value BufferHubQueueProducer::query.
2/ Don't error out for setSharedBufferMode(false),
setAutoRefresh(false), as they are just setting default values again.
3/ Supports addition buffer metadata: transformt, crop,
data_format (a.k.a. color_format).
4/ This also changes BufferHubQueueProducer to be based of
BnInterface<IGraphicBufferProducer> so that itself can be passed via Binder.

Bug: 37342387
Bug: 36907193
Test: exoplayer_demo
Change-Id: Ie00bb79f6a249e09905ae52f85a85a67744cc90d

libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp
libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h
libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h
libs/vr/libdisplay/include/private/dvr/display_rpc.h
libs/vr/libdvr/dvr_buffer_queue.cpp
libs/vr/libdvr/include/dvr/dvr_api.h
libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
libs/vr/libvrflinger/video_compositor.cpp
libs/vr/libvrflinger/video_mesh_surface.cpp

index a826a69..00ff137 100644 (file)
@@ -8,17 +8,17 @@ namespace dvr {
 /* static */
 std::shared_ptr<BufferHubQueueCore> BufferHubQueueCore::Create() {
   auto core = std::shared_ptr<BufferHubQueueCore>(new BufferHubQueueCore());
-  core->producer_ = ProducerQueue::Create<BufferMetadata>();
+  core->producer_ = ProducerQueue::Create<NativeBufferMetadata>();
   return core;
 }
 
 /* static */
 std::shared_ptr<BufferHubQueueCore> BufferHubQueueCore::Create(
     const std::shared_ptr<ProducerQueue>& producer) {
-  if (producer->metadata_size() != sizeof(BufferMetadata)) {
+  if (producer->metadata_size() != sizeof(NativeBufferMetadata)) {
     ALOGE(
         "BufferHubQueueCore::Create producer's metadata size is different than "
-        "the size of BufferHubQueueCore::BufferMetadata");
+        "the size of BufferHubQueueCore::NativeBufferMetadata");
     return nullptr;
   }
 
index e236c31..8216a39 100644 (file)
@@ -56,7 +56,8 @@ status_t BufferHubQueueProducer::setMaxDequeuedBufferCount(
 
   if (max_dequeued_buffers <= 0 ||
       max_dequeued_buffers >
-          static_cast<int>(BufferHubQueue::kMaxQueueCapacity)) {
+          static_cast<int>(BufferHubQueue::kMaxQueueCapacity -
+                           BufferHubQueueCore::kDefaultUndequeuedBuffers)) {
     ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]",
           max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity);
     return BAD_VALUE;
@@ -121,7 +122,8 @@ status_t BufferHubQueueProducer::dequeueBuffer(
   }
 
   if (static_cast<int32_t>(core_->producer_->capacity()) <
-      max_dequeued_buffer_count_) {
+      max_dequeued_buffer_count_ +
+          BufferHubQueueCore::kDefaultUndequeuedBuffers) {
     // Lazy allocation. When the capacity of |core_->producer_| has not reach
     // |max_dequeued_buffer_count_|, allocate new buffer.
     // TODO(jwcai) To save memory, the really reasonable thing to do is to go
@@ -232,16 +234,14 @@ status_t BufferHubQueueProducer::queueBuffer(int slot,
   }
 
   int64_t timestamp;
-  int scaling_mode;
-  sp<Fence> fence;
-  Rect crop(Rect::EMPTY_RECT);
-
-  // TODO(jwcai) The following attributes are ignored.
   bool is_auto_timestamp;
-  android_dataspace data_space;
+  android_dataspace dataspace;
+  Rect crop(Rect::EMPTY_RECT);
+  int scaling_mode;
   uint32_t transform;
+  sp<Fence> fence;
 
-  input.deflate(&timestamp, &is_auto_timestamp, &data_space, &crop,
+  input.deflate(&timestamp, &is_auto_timestamp, &dataspace, &crop,
                 &scaling_mode, &transform, &fence);
 
   // Check input scaling mode is valid.
@@ -302,7 +302,17 @@ status_t BufferHubQueueProducer::queueBuffer(int slot,
 
   LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
 
-  BufferHubQueueCore::BufferMetadata meta_data = {.timestamp = timestamp};
+  BufferHubQueueCore::NativeBufferMetadata meta_data = {};
+  meta_data.timestamp = timestamp;
+  meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
+  meta_data.dataspace = static_cast<int32_t>(dataspace);
+  meta_data.crop_left = crop.left;
+  meta_data.crop_top = crop.top;
+  meta_data.crop_right = crop.right;
+  meta_data.crop_bottom = crop.bottom;
+  meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
+  meta_data.transform = static_cast<int32_t>(transform);
+
   buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data));
   core_->buffers_[slot].mBufferState.queue();
 
@@ -369,7 +379,10 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) {
   int value = 0;
   switch (what) {
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-      value = 0;
+      // TODO(b/36187402) This should be the maximum number of buffers that this
+      // producer queue's consumer can acquire. Set to be at least one. Need to
+      // find a way to set from the consumer side.
+      value = BufferHubQueueCore::kDefaultUndequeuedBuffers;
       break;
     case NATIVE_WINDOW_BUFFER_AGE:
       value = 0;
@@ -394,11 +407,16 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) {
       // IGraphicBufferConsumer parity.
       value = 0;
       break;
-    // The following queries are currently considered as unsupported.
-    // TODO(jwcai) Need to carefully check the whether they should be
-    // supported after all.
-    case NATIVE_WINDOW_STICKY_TRANSFORM:
     case NATIVE_WINDOW_DEFAULT_DATASPACE:
+      // TODO(jwcai) Return the default value android::BufferQueue is using as
+      // there is no way dvr::ConsumerQueue can set it.
+      value = 0;  // HAL_DATASPACE_UNKNOWN
+      break;
+    case NATIVE_WINDOW_STICKY_TRANSFORM:
+      // TODO(jwcai) Return the default value android::BufferQueue is using as
+      // there is no way dvr::ConsumerQueue can set it.
+      value = 0;
+      break;
     default:
       return BAD_VALUE;
   }
@@ -432,7 +450,16 @@ status_t BufferHubQueueProducer::connect(
     case NATIVE_WINDOW_API_MEDIA:
     case NATIVE_WINDOW_API_CAMERA:
       core_->connected_api_ = api;
-      // TODO(jwcai) Fill output.
+
+      output->width = core_->producer_->default_width();
+      output->height = core_->producer_->default_height();
+
+      // default values, we don't use them yet.
+      output->transformHint = 0;
+      output->numPendingBuffers = 0;
+      output->nextFrameNumber = 0;
+      output->bufferReplaced = false;
+
       break;
     default:
       ALOGE("BufferHubQueueProducer::connect: unknow API %d", api);
@@ -503,16 +530,23 @@ String8 BufferHubQueueProducer::getConsumerName() const {
   return String8("BufferHubQueue::DummyConsumer");
 }
 
-status_t BufferHubQueueProducer::setSharedBufferMode(
-    bool /* shared_buffer_mode */) {
-  ALOGE("BufferHubQueueProducer::setSharedBufferMode not implemented.");
-  // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
-  return INVALID_OPERATION;
+status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) {
+  if (shared_buffer_mode) {
+    ALOGE("BufferHubQueueProducer::setSharedBufferMode(true) is not supported.");
+    // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
+    return INVALID_OPERATION;
+  }
+  // Setting to default should just work as a no-op.
+  return NO_ERROR;
 }
 
-status_t BufferHubQueueProducer::setAutoRefresh(bool /* auto_refresh */) {
-  ALOGE("BufferHubQueueProducer::setAutoRefresh not implemented.");
-  return INVALID_OPERATION;
+status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) {
+  if (auto_refresh) {
+    ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported.");
+    return INVALID_OPERATION;
+  }
+  // Setting to default should just work as a no-op.
+  return NO_ERROR;
 }
 
 status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
@@ -545,8 +579,8 @@ status_t BufferHubQueueProducer::getUniqueId(uint64_t* out_id) const {
 IBinder* BufferHubQueueProducer::onAsBinder() {
   // BufferHubQueueProducer is a non-binder implementation of
   // IGraphicBufferProducer.
-  ALOGW("BufferHubQueueProducer::onAsBinder is not supported.");
-  return nullptr;
+  ALOGW("BufferHubQueueProducer::onAsBinder is not efficiently supported.");
+  return this;
 }
 
 }  // namespace dvr
index 255793f..6467c3c 100644 (file)
@@ -215,11 +215,11 @@ class BufferHubQueue : public pdx::Client {
   //    This is implemented by first detaching the buffer and then allocating a
   //    new buffer.
   // 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
-  //    event on the queue which indicates a new buffer is avaiable and the
+  //    event on the queue which indicates a new buffer is available and the
   //    EPOLLHUP event for slot 0. Consumer handles these two events in order.
   // 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
   //    slot 0 and (the new) slot 1 buffer will be imported. During the import
-  //    of the buffer at slot 1, consuemr client detaches the old buffer so that
+  //    of the buffer at slot 1, consumer client detaches the old buffer so that
   //    the new buffer can be registered. At the same time
   //    |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
   //    was detached prior to EPOLLHUP event.
index e353187..9a8a2c9 100644 (file)
@@ -19,16 +19,54 @@ class BufferHubQueueCore {
  public:
   static constexpr int kNoConnectedApi = -1;
 
+  // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
+  // side logic doesn't limit the number of buffer it can acquire
+  // simultaneously. We need a way for consumer logic to configure and enforce
+  // that.
+  static constexpr int kDefaultUndequeuedBuffers = 1;
+
   // Create a BufferHubQueueCore instance by creating a new producer queue.
   static std::shared_ptr<BufferHubQueueCore> Create();
 
-  // Create a BufferHubQueueCore instance by importing an existing prodcuer queue.
+  // Create a BufferHubQueueCore instance by importing an existing prodcuer
+  // queue.
   static std::shared_ptr<BufferHubQueueCore> Create(
       const std::shared_ptr<ProducerQueue>& producer);
 
-  struct BufferMetadata {
+  // The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
+  // will populate. This must be aligned with the |DvrNativeBufferMetadata|
+  // defined in |dvr_buffer_queue.h|. Please do not remove, modify, or reorder
+  // existing data members. If new fields need to be added, please take extra
+  // care to make sure that new data field is padded properly the size of the
+  // struct stays same.
+  // TODO(b/37578558) Move |dvr_api.h| into a header library so that this
+  // structure won't be copied between |dvr_api.h| and |buffer_hub_qeue_core.h|.
+  struct NativeBufferMetadata {
     // Timestamp of the frame.
     int64_t timestamp;
+
+    // Whether the buffer is using auto timestamp.
+    int32_t is_auto_timestamp;
+
+    // Must be one of the HAL_DATASPACE_XXX value defined in system/graphics.h
+    int32_t dataspace;
+
+    // Crop extracted from an ACrop or android::Crop object.
+    int32_t crop_left;
+    int32_t crop_top;
+    int32_t crop_right;
+    int32_t crop_bottom;
+
+    // Must be one of the NATIVE_WINDOW_SCALING_MODE_XXX value defined in
+    // system/window.h.
+    int32_t scaling_mode;
+
+    // Must be one of the ANATIVEWINDOW_TRANSFORM_XXX value defined in
+    // android/native_window.h
+    int32_t transform;
+
+    // Reserved bytes for so that the struct is forward compatible.
+    int32_t reserved[16];
   };
 
   class NativeBuffer
index 43e5ce3..b345498 100644 (file)
@@ -8,7 +8,7 @@
 namespace android {
 namespace dvr {
 
-class BufferHubQueueProducer : public IGraphicBufferProducer {
+class BufferHubQueueProducer : public BnInterface<IGraphicBufferProducer> {
  public:
   BufferHubQueueProducer(const std::shared_ptr<BufferHubQueueCore>& core);
 
index c12b090..778032f 100644 (file)
@@ -140,10 +140,6 @@ struct DisplaySurfaceInfo {
                            manager_attributes);
 };
 
-struct VideoMeshSurfaceBufferMetadata {
-  int64_t timestamp_ns;
-};
-
 struct AlignmentMarker {
  public:
   float horizontal;
index dfde21d..50c94cb 100644 (file)
@@ -1,3 +1,4 @@
+#include "include/dvr/dvr_api.h"
 #include "include/dvr/dvr_buffer_queue.h"
 
 #include <android/native_window.h>
@@ -30,6 +31,16 @@ int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
   CHECK_PARAM(write_queue);
   CHECK_PARAM(out_window);
 
+  if (write_queue->producer_queue_->metadata_size() !=
+      sizeof(DvrNativeBufferMetadata)) {
+    ALOGE(
+        "The size of buffer metadata (%u) of the write queue does not match of "
+        "size of DvrNativeBufferMetadata (%u).",
+        write_queue->producer_queue_->metadata_size(),
+        sizeof(DvrNativeBufferMetadata));
+    return -EINVAL;
+  }
+
   // Lazy creation of |native_window_|.
   if (write_queue->native_window_ == nullptr) {
     std::shared_ptr<dvr::BufferHubQueueCore> core =
index 56f937b..3cd401d 100644 (file)
@@ -219,6 +219,43 @@ typedef DvrHwcRecti (*DvrHwcFrameGetLayerDamagedRegionPtr)(DvrHwcFrame* frame,
                                                            size_t layer_index,
                                                            size_t index);
 
+// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
+// will populate. A DvrWriteBufferQueue must be created with this metadata iff
+// ANativeWindow access is needed. Note that this struct must stay in sync with
+// BufferHubQueueCore::NativeBufferMetadata. Please do not remove, modify, or
+// reorder existing data members. If new fields need to be added, please take
+// extra care to make sure that new data field is padded properly the size of
+// the struct stays same.
+// TODO(b/37578558) Move |dvr_api.h| into a header library so that this structure
+// won't be copied between |dvr_api.h| and |buffer_hub_qeue_core.h|.
+struct DvrNativeBufferMetadata {
+  // Timestamp of the frame.
+  int64_t timestamp;
+
+  // Whether the buffer is using auto timestamp.
+  int32_t is_auto_timestamp;
+
+  // Must be one of the HAL_DATASPACE_XXX value defined in system/graphics.h
+  int32_t dataspace;
+
+  // Crop extracted from an ACrop or android::Crop object.
+  int32_t crop_left;
+  int32_t crop_top;
+  int32_t crop_right;
+  int32_t crop_bottom;
+
+  // Must be one of the NATIVE_WINDOW_SCALING_MODE_XXX value defined in
+  // system/window.h.
+  int32_t scaling_mode;
+
+  // Must be one of the ANATIVEWINDOW_TRANSFORM_XXX value defined in
+  // android/native_window.h
+  int32_t transform;
+
+  // Reserved bytes for so that the struct is forward compatible.
+  int32_t reserved[16];
+};
+
 struct DvrApi_v1 {
   // Display manager client
   DvrDisplayManagerClientCreatePtr display_manager_client_create;
index 1c9eadd..ea1273e 100644 (file)
@@ -1,3 +1,4 @@
+#include <dvr/dvr_api.h>
 #include <dvr/dvr_buffer_queue.h>
 #include <gui/Surface.h>
 #include <private/dvr/buffer_hub_queue_client.h>
@@ -146,8 +147,21 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
 
 TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
   ANativeWindow* window = nullptr;
+
+  // The |write_queue_| doesn't have proper metadata (must be
+  // DvrNativeBufferMetadata) configured during creation.
   int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
+  ASSERT_EQ(-EINVAL, ret);
+  ASSERT_EQ(nullptr, window);
+
+  // A write queue with DvrNativeBufferMetadata should work fine.
+  std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
+      write_queue(new DvrWriteBufferQueue, dvrWriteBufferQueueDestroy);
+  write_queue->producer_queue_ =
+      ProducerQueue::Create<DvrNativeBufferMetadata>(0, 0, 0, 0);
+  ASSERT_NE(nullptr, write_queue->producer_queue_);
 
+  ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
   ASSERT_EQ(0, ret);
   ASSERT_NE(nullptr, window);
 
index 411e3a3..c5a5b64 100644 (file)
@@ -71,7 +71,7 @@ VideoCompositor::VideoCompositor(
 
 GLuint VideoCompositor::GetActiveTextureId(EGLDisplay display) {
   size_t slot;
-  VideoMeshSurfaceBufferMetadata metadata;
+  BufferHubQueueCore::NativeBufferMetadata metadata;
 
   while (true) {
     // A native way to pick the active texture: always dequeue all buffers from
index d915a4a..ce0dfca 100644 (file)
@@ -1,5 +1,6 @@
 #include "video_mesh_surface.h"
 
+#include <private/dvr/buffer_hub_queue_core.h>
 #include <private/dvr/display_rpc.h>
 
 using android::pdx::LocalChannelHandle;
@@ -49,7 +50,8 @@ LocalChannelHandle VideoMeshSurface::OnCreateProducerQueue(Message& message) {
     REPLY_ERROR_RETURN(message, EALREADY, {});
   }
 
-  auto producer = ProducerQueue::Create<VideoMeshSurfaceBufferMetadata>();
+  auto producer =
+      ProducerQueue::Create<BufferHubQueueCore::NativeBufferMetadata>();
   consumer_queue_ = producer->CreateConsumerQueue();
 
   return std::move(producer->GetChannelHandle());