DvrWriteBufferQueue: support buffer resizing

Currently, the buffer resising is implemented at the C API's
implementation level, i.e. it's a pure client side logic out of the core
BufferHubQueue C++/PDX implementation. The logic is similar to
BufferHubQueueProducer's buffer resizing logic.

Other minor changes:
1/ Use ProducerQueueConfig in DisplaySurface as well, and plumb default
width, height, and format to bufferhubd when a BufferHubQueue is created
through a Display Surface.
2/ Added detailed dvr_buffer_queue comments.
3/ Since we now have more and more logic in dvr_buffer_queue, refactored
Dvr{Read,Write}BufferQueue to be C++-styled class.

Bug: 38324405
Test: buffer_hub_queue_producer-test, buffer_hub_queue-test, dvr_api-test
Change-Id: I7186fc04e84eafda46eca316a94739bb3b5c07ca
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 5a0c3d0..fbb39f3 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -104,9 +104,16 @@
   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.");
-  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0);
+  auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
+      ProducerQueueConfigBuilder()
+          .SetDefaultWidth(width)
+          .SetDefaultHeight(height)
+          .SetDefaultFormat(format)
+          .Build());
   if (!status) {
     ALOGE("Surface::CreateQueue: Failed to create queue: %s",
           status.GetErrorMessage().c_str());
@@ -129,7 +136,7 @@
            "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
            "usage=%" PRIx64 " capacity=%zu",
            width, height, layer_count, format, usage, capacity);
-  auto status = CreateQueue();
+  auto status = CreateQueue(width, height, format);
   if (!status)
     return status.error_status();
 
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index e5b3340..61883ce 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -37,7 +37,9 @@
   pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
 
   // 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
   // parameters.
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index b857d48..cfbda7a 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -213,8 +213,9 @@
   PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
                     SurfaceInfo(const SurfaceAttributes& attributes));
   PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
-  PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue,
-                    LocalChannelHandle(size_t meta_size_bytes));
+  PDX_REMOTE_METHOD(
+      CreateQueue, kOpCreateQueue,
+      LocalChannelHandle(const ProducerQueueConfig& producer_config));
   PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
                     void(const SurfaceAttributes& attributes));
 };
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 2b4ebbe..a788cce 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -21,6 +21,7 @@
 
 cflags = [
     "-DLOG_TAG=\"libdvr\"",
+    "-DTRACE=0",
 ]
 
 srcs = [
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index f668510..d76eaf6 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,60 +2,174 @@
 #include "include/dvr/dvr_buffer_queue.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 "dvr_internal.h"
-
-#define CHECK_PARAM(param)                                               \
-  LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
-                      __FUNCTION__)
+#include "dvr_buffer_queue_internal.h"
 
 using namespace android;
-
-namespace android {
-namespace dvr {
-
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
-    const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
-  return new DvrWriteBufferQueue{std::move(producer_queue)};
-}
-
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
-    const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
-  return new DvrReadBufferQueue{std::move(consumer_queue)};
-}
-
-dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
-    DvrWriteBufferQueue* write_queue) {
-  return write_queue->producer_queue.get();
-}
-
-}  // namespace dvr
-}  // namespace android
+using android::dvr::BufferHubQueueProducer;
+using android::dvr::BufferProducer;
+using android::dvr::ConsumerQueue;
+using android::dvr::ProducerQueue;
 
 extern "C" {
 
-void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
-  if (write_queue != nullptr && write_queue->native_window != nullptr)
-    ANativeWindow_release(write_queue->native_window);
+DvrWriteBufferQueue::DvrWriteBufferQueue(
+    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()) {}
 
+int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
+  if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
+    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;
+  }
+
+  if (native_window_ == nullptr) {
+    // Lazy creation of |native_window|, as not everyone is using
+    // DvrWriteBufferQueue as an external surface.
+    sp<IGraphicBufferProducer> gbp =
+        BufferHubQueueProducer::Create(producer_queue_);
+    native_window_ = new Surface(gbp, true);
+  }
+
+  *out_window = static_cast<ANativeWindow*>(native_window_.get());
+  return 0;
+}
+
+int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+  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;
+  }
+
+  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
+  return 0;
+}
+
+int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
+                                 int* out_fence_fd) {
+  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;
 }
 
 ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
-  if (!write_queue || !write_queue->producer_queue)
+  if (!write_queue)
     return -EINVAL;
 
-  return write_queue->producer_queue->capacity();
+  return write_queue->capacity();
 }
 
 int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
   if (!write_queue)
     return -EINVAL;
 
-  return write_queue->producer_queue->id();
+  return write_queue->id();
 }
 
 int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
@@ -63,131 +177,68 @@
   if (!write_queue || !out_window)
     return -EINVAL;
 
-  if (write_queue->producer_queue->metadata_size() !=
-      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|.
-  if (write_queue->native_window == nullptr) {
-    sp<IGraphicBufferProducer> gbp =
-        dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
-    sp<Surface> surface = new Surface(gbp, true);
-    write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
-    ANativeWindow_acquire(write_queue->native_window);
-  }
-
-  *out_window = write_queue->native_window;
-  return 0;
+  return write_queue->GetNativeWindow(out_window);
 }
 
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue) {
-  if (!write_queue || !write_queue->producer_queue || !out_read_queue)
+  if (!write_queue || !out_read_queue)
     return -EINVAL;
 
-  auto read_queue = std::make_unique<DvrReadBufferQueue>();
-  read_queue->consumer_queue =
-      write_queue->producer_queue->CreateConsumerQueue();
-  if (read_queue->consumer_queue == nullptr) {
-    ALOGE(
-        "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
-        "from DvrWriteBufferQueue[%p].",
-        write_queue);
-    return -ENOMEM;
-  }
-
-  *out_read_queue = read_queue.release();
-  return 0;
+  return write_queue->CreateReadQueue(out_read_queue);
 }
 
 int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
                                DvrWriteBuffer* write_buffer,
                                int* out_fence_fd) {
-  if (!write_queue || !write_queue->producer_queue || !write_buffer ||
-      !out_fence_fd) {
+  if (!write_queue || !write_buffer || !out_fence_fd)
     return -EINVAL;
-  }
 
-  size_t slot;
-  pdx::LocalHandle release_fence;
-  auto buffer_status =
-      write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
-  if (!buffer_status) {
-    ALOGE_IF(buffer_status.error() != ETIMEDOUT,
-             "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
-             buffer_status.GetErrorMessage().c_str());
-    return -buffer_status.error();
-  }
+  return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
+}
 
-  write_buffer->write_buffer = buffer_status.take();
-  *out_fence_fd = release_fence.Release();
-  return 0;
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+                                    uint32_t width, uint32_t height) {
+  if (!write_queue)
+    return -EINVAL;
+
+  return write_queue->ResizeBuffer(width, height);
 }
 
 // ReadBufferQueue
-void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
-  delete read_queue;
-}
 
-ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
+DvrReadBufferQueue::DvrReadBufferQueue(
+    const std::shared_ptr<ConsumerQueue>& consumer_queue)
+    : consumer_queue_(consumer_queue) {}
 
-  return read_queue->consumer_queue->capacity();
-}
-
-int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
-  if (!read_queue)
-    return -EINVAL;
-
-  return read_queue->consumer_queue->id();
-}
-
-int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
-                                      DvrReadBufferQueue** out_read_queue) {
-  if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
-    return -EINVAL;
-
-  auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
-  new_read_queue->consumer_queue =
-      read_queue->consumer_queue->CreateConsumerQueue();
-  if (new_read_queue->consumer_queue == nullptr) {
+int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+  std::unique_ptr<ConsumerQueue> consumer_queue =
+      consumer_queue_->CreateConsumerQueue();
+  if (consumer_queue == nullptr) {
     ALOGE(
-        "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
-        "from DvrReadBufferQueue[%p].",
-        read_queue);
+        "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
+        "from producer queue: queue_id=%d.", consumer_queue_->id());
     return -ENOMEM;
   }
 
-  *out_read_queue = new_read_queue.release();
+  *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
   return 0;
 }
 
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
-                              DvrReadBuffer* read_buffer, int* out_fence_fd,
-                              void* out_meta, size_t meta_size_bytes) {
-  if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
-      !out_fence_fd || !out_meta) {
-    return -EINVAL;
-  }
-
-  if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
+int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
+                                int* out_fence_fd, void* out_meta,
+                                size_t meta_size_bytes) {
+  if (meta_size_bytes != consumer_queue_->metadata_size()) {
     ALOGE(
-        "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
+        "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
         "but actual (%zu).",
-        read_queue->consumer_queue->metadata_size(), meta_size_bytes);
+        consumer_queue_->metadata_size(), meta_size_bytes);
     return -EINVAL;
   }
 
   size_t slot;
   pdx::LocalHandle acquire_fence;
-  auto buffer_status = read_queue->consumer_queue->Dequeue(
+  auto buffer_status = consumer_queue_->Dequeue(
       timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
   if (!buffer_status) {
     ALOGE_IF(buffer_status.error() != ETIMEDOUT,
@@ -201,4 +252,40 @@
   return 0;
 }
 
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
+  delete read_queue;
+}
+
+ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
+  if (!read_queue)
+    return -EINVAL;
+
+  return read_queue->capacity();
+}
+
+int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
+  if (!read_queue)
+    return -EINVAL;
+
+  return read_queue->id();
+}
+
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+                                      DvrReadBufferQueue** out_read_queue) {
+  if (!read_queue || !out_read_queue)
+    return -EINVAL;
+
+  return read_queue->CreateReadQueue(out_read_queue);
+}
+
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+                              DvrReadBuffer* read_buffer, int* out_fence_fd,
+                              void* out_meta, size_t meta_size_bytes) {
+  if (!read_queue || !read_buffer || !out_fence_fd || !out_meta)
+    return -EINVAL;
+
+  return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
+                             meta_size_bytes);
+}
+
 }  // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
new file mode 100644
index 0000000..f012873
--- /dev/null
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -0,0 +1,62 @@
+#ifndef ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+#define ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <sys/cdefs.h>
+
+#include <memory>
+
+struct ANativeWindow;
+
+struct DvrWriteBufferQueue {
+  using ProducerQueue = android::dvr::ProducerQueue;
+
+  // Create a concrete object for DvrWriteBufferQueue.
+  //
+  // @param producer_queue The BufferHub's ProducerQueue that is used to back
+  //     this DvrWriteBufferQueue, must not be NULL.
+  explicit DvrWriteBufferQueue(
+      const std::shared_ptr<ProducerQueue>& producer_queue);
+
+  int id() const { return producer_queue_->id(); }
+  uint32_t width() const { return width_; };
+  uint32_t height() const { return height_; };
+  uint32_t format() const { return format_; };
+  size_t capacity() const { return producer_queue_->capacity(); }
+  const std::shared_ptr<ProducerQueue>& producer_queue() const {
+    return producer_queue_;
+  }
+
+  int GetNativeWindow(ANativeWindow** out_window);
+  int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+  int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+  int ResizeBuffer(uint32_t width, uint32_t height);
+
+ private:
+  std::shared_ptr<ProducerQueue> producer_queue_;
+
+  uint32_t width_;
+  uint32_t height_;
+  uint32_t format_;
+  android::sp<android::Surface> native_window_;
+};
+
+struct DvrReadBufferQueue {
+  using ConsumerQueue = android::dvr::ConsumerQueue;
+
+  explicit DvrReadBufferQueue(
+      const std::shared_ptr<ConsumerQueue>& consumer_queue);
+
+  int id() const { return consumer_queue_->id(); }
+  size_t capacity() const { return consumer_queue_->capacity(); }
+
+  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);
+
+ private:
+  std::shared_ptr<ConsumerQueue> consumer_queue_;
+};
+
+#endif  // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index ffe090d..4b53642 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -8,6 +8,7 @@
 #include <private/dvr/display_manager_client.h>
 
 #include "dvr_internal.h"
+#include "dvr_buffer_queue_internal.h"
 
 using android::AHardwareBuffer_convertToGrallocUsageBits;
 using android::dvr::BufferConsumer;
@@ -16,7 +17,6 @@
 using android::dvr::display::SurfaceAttributes;
 using android::dvr::display::SurfaceAttribute;
 using android::dvr::display::SurfaceState;
-using android::dvr::CreateDvrReadBufferQueueFromConsumerQueue;
 using android::pdx::rpc::EmptyVariant;
 
 namespace {
@@ -220,7 +220,7 @@
     return -status.error();
   }
 
-  *queue_out = CreateDvrReadBufferQueueFromConsumerQueue(status.take());
+  *queue_out = new DvrReadBufferQueue(status.take());
   return 0;
 }
 
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 6431f1c..28b6c28 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -10,8 +10,6 @@
 typedef struct DvrBuffer DvrBuffer;
 typedef struct DvrReadBuffer DvrReadBuffer;
 typedef struct DvrWriteBuffer DvrWriteBuffer;
-typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
-typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 
 }  // extern "C"
 
@@ -20,9 +18,7 @@
 
 class BufferProducer;
 class BufferConsumer;
-class ConsumerQueue;
 class IonBuffer;
-class ProducerQueue;
 
 DvrBuffer* CreateDvrBufferFromIonBuffer(
     const std::shared_ptr<IonBuffer>& ion_buffer);
@@ -32,20 +28,11 @@
 DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
     const std::shared_ptr<BufferProducer>& buffer_producer);
 
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
-    const std::shared_ptr<ConsumerQueue>& consumer_queue);
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
-    const std::shared_ptr<ProducerQueue>& producer_queue);
-ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
-    DvrWriteBufferQueue* write_queue);
-
 }  // namespace dvr
 }  // namespace android
 
 extern "C" {
 
-struct ANativeWindow;
-
 struct DvrWriteBuffer {
   std::shared_ptr<android::dvr::BufferProducer> write_buffer;
 };
@@ -58,15 +45,6 @@
   std::shared_ptr<android::dvr::IonBuffer> buffer;
 };
 
-struct DvrWriteBufferQueue {
-  std::shared_ptr<android::dvr::ProducerQueue> producer_queue;
-  ANativeWindow* native_window{nullptr};
-};
-
-struct DvrReadBufferQueue {
-  std::shared_ptr<android::dvr::ConsumerQueue> consumer_queue;
-};
-
 }  // extern "C"
 
 #endif  // ANDROID_DVR_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index 1fe9874..2affacd 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -5,13 +5,13 @@
 #include <private/dvr/display_client.h>
 
 #include "dvr_internal.h"
+#include "dvr_buffer_queue_internal.h"
 
 using android::dvr::display::DisplayClient;
 using android::dvr::display::Surface;
 using android::dvr::display::SurfaceAttributes;
 using android::dvr::display::SurfaceAttributeValue;
 using android::dvr::CreateDvrReadBufferFromBufferConsumer;
-using android::dvr::CreateDvrWriteBufferQueueFromProducerQueue;
 
 namespace {
 
@@ -152,7 +152,7 @@
     return -status.error();
   }
 
-  *out_writer = CreateDvrWriteBufferQueueFromProducerQueue(status.take());
+  *out_writer = new DvrWriteBufferQueue(status.take());
   return 0;
 }
 
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index dd669dc..3165bfc 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,29 +12,122 @@
 typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
 typedef struct DvrReadBufferQueue DvrReadBufferQueue;
 
-// WriteBufferQueue
+// Destroy a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
 void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
+
+// Get the total number of buffers in a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return The capacity on success; or negative error code.
 ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
+
+// Get the system unique queue id of a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return Queue id on success; or negative error code.
 int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue);
 
-// Returns ANativeWindow. Can be casted to a Java Surface using
-// ANativeWindow_toSurface NDK API. Note that this method does not acquire an
-// additional reference to the ANativeWindow returned, don't call
-// ANativeWindow_release on it.
+// Gets an ANativeWindow backed by the DvrWriteBufferQueue
+//
+// Can be casted to a Java Surface using ANativeWindow_toSurface NDK API. Note
+// that the native window is lazily created at the first time |GetNativeWindow|
+// is called, and the created ANativeWindow will be cached so that multiple
+// calls to this method will return the same object. Also note that this method
+// does not acquire an additional reference to the ANativeWindow returned, don't
+// call ANativeWindow_release on it.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_window The pointer of an ANativeWindow will be filled here if
+//     the method call succeeds.
+// @return Zero on success; or -EINVAL if this DvrWriteBufferQueue does not
+//     support being used as an android Surface.
 int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
                                           ANativeWindow** out_window);
 
+// Create a read buffer queue from an existing write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+//     if the method call succeeds.
+// @return Zero on success, or negative error code.
 int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
                                        DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to write into.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+//     block. Specifying a timeout of -1 causes it to block indefinitely,
+//     while specifying a timeout equal to zero cause it to return immediately,
+//     even if no buffers are available.
+// @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
+//     dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+//     signals the release of underlying buffer. The producer should wait until
+//     this fence clears before writing data into it.
+// @return Zero on success, or negative error code.
 int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
                                DvrWriteBuffer* out_buffer, int* out_fence_fd);
 
-// ReadeBufferQueue
+// Overrides buffer dimension with new width and height.
+//
+// After the call successfully returns, each |dvrWriteBufferQueueDequeue| call
+// will return buffer with newly assigned |width| and |height|. When necessary,
+// old buffer will be removed from the buffer queue and replaced with new buffer
+// matching the new buffer size.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param width Desired width, cannot be Zero.
+// @param height Desired height, cannot be Zero.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+                                    uint32_t width, uint32_t height);
+
+// Destroy a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
 void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue);
+
+// Get the total number of buffers in a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return The capacity on success; or negative error code.
 ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue);
+
+// Get the system unique queue id of a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Queue id on success; or negative error code.
 int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue);
+
+// Create a read buffer queue from an existing read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+//     if the method call succeeds.
+// @return Zero on success, or negative error code.
 int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
                                       DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to read from.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+//     block. Specifying a timeout of -1 causes it to block indefinitely,
+//     while specifying a timeout equal to zero cause it to return immediately,
+//     even if no buffers are available.
+// @param out_buffer A targeting DvrReadBuffer object to hold the output of the
+//     dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+//     signals the release of underlying buffer. The consumer should wait until
+//     this fence clears before reading data from it.
+// @param out_meta The memory area where a metadata object will be filled.
+// @param meta_size_bytes Size of the metadata object caller expects. If it
+//     doesn't match the size of actually metadata transported by the buffer
+//     queue, the method returns -EINVAL.
+// @return Zero on success, or negative error code.
 int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
                               DvrReadBuffer* out_buffer, int* out_fence_fd,
                               void* out_meta, size_t meta_size_bytes);
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 2426a49..8a55b20 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -7,17 +7,18 @@
 #include <gtest/gtest.h>
 
 #include "../dvr_internal.h"
+#include "../dvr_buffer_queue_internal.h"
 
 namespace android {
 namespace dvr {
 
 namespace {
 
-static constexpr int kBufferWidth = 100;
-static constexpr int kBufferHeight = 1;
-static constexpr int kLayerCount = 1;
-static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferWidth = 100;
+static constexpr uint32_t kBufferHeight = 1;
+static constexpr uint32_t kLayerCount = 1;
+static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
 static constexpr size_t kQueueCapacity = 3;
 
 typedef uint64_t TestMeta;
@@ -25,9 +26,14 @@
 class DvrBufferQueueTest : public ::testing::Test {
  protected:
   void SetUp() override {
-    auto config = ProducerQueueConfigBuilder().SetMetadata<TestMeta>().Build();
-    write_queue_ = CreateDvrWriteBufferQueueFromProducerQueue(
-        ProducerQueue::Create(config, UsagePolicy{}));
+    auto config = ProducerQueueConfigBuilder()
+                      .SetDefaultWidth(kBufferWidth)
+                      .SetDefaultHeight(kBufferHeight)
+                      .SetDefaultFormat(kBufferFormat)
+                      .SetMetadata<TestMeta>()
+                      .Build();
+    write_queue_ =
+        new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{}));
     ASSERT_NE(nullptr, write_queue_);
   }
 
@@ -41,10 +47,9 @@
   void AllocateBuffers(size_t buffer_count) {
     size_t out_slot;
     for (size_t i = 0; i < buffer_count; i++) {
-      auto status =
-          GetProducerQueueFromDvrWriteBufferQueue(write_queue_)
-              ->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount,
-                               kBufferFormat, kBufferUsage, &out_slot);
+      auto status = write_queue_->producer_queue()->AllocateBuffer(
+          kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
+          &out_slot);
       ASSERT_TRUE(status.ok());
     }
   }
@@ -202,9 +207,9 @@
                     .SetMetadata<DvrNativeBufferMetadata>()
                     .Build();
   std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
-      write_queue(CreateDvrWriteBufferQueueFromProducerQueue(
-                      ProducerQueue::Create(config, UsagePolicy{})),
-                  dvrWriteBufferQueueDestroy);
+      write_queue(
+          new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
+          dvrWriteBufferQueueDestroy);
   ASSERT_NE(nullptr, write_queue.get());
 
   ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
@@ -215,6 +220,90 @@
   ASSERT_TRUE(Surface::isValid(surface));
 }
 
+// Create buffer queue of three buffers and dequeue three buffers out of it.
+// Before each dequeue operation, we resize the buffer queue and expect the
+// queue always return buffer with desired dimension.
+TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+  static constexpr int kTimeout = 0;
+  int fence_fd = -1;
+
+  DvrWriteBuffer* wb1 = nullptr;
+  DvrWriteBuffer* wb2 = nullptr;
+  DvrWriteBuffer* wb3 = nullptr;
+  AHardwareBuffer* ahb1 = nullptr;
+  AHardwareBuffer* ahb2 = nullptr;
+  AHardwareBuffer* ahb3 = nullptr;
+  AHardwareBuffer_Desc buffer_desc;
+
+  dvrWriteBufferCreateEmpty(&wb1);
+  ASSERT_NE(nullptr, wb1);
+  dvrWriteBufferCreateEmpty(&wb2);
+  ASSERT_NE(nullptr, wb2);
+  dvrWriteBufferCreateEmpty(&wb3);
+  ASSERT_NE(nullptr, wb3);
+
+  AllocateBuffers(kQueueCapacity);
+
+  // Resize before dequeuing.
+  constexpr int w1 = 10;
+  int ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+
+  // Gain first buffer for writing. All buffers will be resized.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+  ALOGD_IF(TRACE, "TestResiveBuffer, gain buffer %p", wb1);
+  pdx::LocalHandle release_fence1(fence_fd);
+
+  // Check the buffer dimension.
+  ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+  ASSERT_EQ(0, ret);
+  AHardwareBuffer_describe(ahb1, &buffer_desc);
+  ASSERT_EQ(w1, buffer_desc.width);
+  ASSERT_EQ(kBufferHeight, buffer_desc.height);
+  AHardwareBuffer_release(ahb1);
+
+  // Resize the queue. We are testing with blob format, keep height to be 1.
+  constexpr int w2 = 20;
+  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+  ASSERT_EQ(0, ret);
+
+  // The next buffer we dequeued should have new width.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+  ALOGD_IF(TRACE, "TestResiveBuffer, gain buffer %p, fence_fd=%d", wb2,
+           fence_fd);
+  pdx::LocalHandle release_fence2(fence_fd);
+
+  // Check the buffer dimension, should be new width
+  ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+  ASSERT_EQ(0, ret);
+  AHardwareBuffer_describe(ahb2, &buffer_desc);
+  ASSERT_EQ(w2, buffer_desc.width);
+  AHardwareBuffer_release(ahb2);
+
+  // Resize the queue for the third time.
+  constexpr int w3 = 30;
+  ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+  ASSERT_EQ(0, ret);
+
+  // The next buffer we dequeued should have new width.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+  ALOGD_IF(TRACE, "TestResiveBuffer, gain buffer %p, fence_fd=%d", wb3,
+           fence_fd);
+  pdx::LocalHandle release_fence3(fence_fd);
+
+  // Check the buffer dimension, should be new width
+  ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+  ASSERT_EQ(0, ret);
+  AHardwareBuffer_describe(ahb3, &buffer_desc);
+  ASSERT_EQ(w3, buffer_desc.width);
+  AHardwareBuffer_release(ahb3);
+}
+
 }  // namespace
 
 }  // namespace dvr
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index babdc0e..d836fba 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -199,16 +199,14 @@
 }
 
 Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
-    Message& /*message*/, size_t meta_size_bytes) {
+    Message& /*message*/, const ProducerQueueConfig& config) {
   ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
   ALOGD_IF(TRACE,
            "ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
            "meta_size_bytes=%zu",
-           surface_id(), meta_size_bytes);
+           surface_id(), config.meta_size_bytes);
 
   std::lock_guard<std::mutex> autolock(lock_);
-  auto config =
-      ProducerQueueConfigBuilder().SetMetadataSize(meta_size_bytes).Build();
   auto producer = ProducerQueue::Create(config, UsagePolicy{});
   if (!producer) {
     ALOGE(
@@ -261,19 +259,17 @@
 }
 
 Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
-    Message& /*message*/, size_t meta_size_bytes) {
+    Message& /*message*/, const ProducerQueueConfig& config) {
   ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
   ALOGD_IF(
       TRACE,
       "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
-      surface_id(), meta_size_bytes);
+      surface_id(), config.meta_size_bytes);
 
   std::lock_guard<std::mutex> autolock(lock_);
   if (!direct_queue_) {
     // Inject the hw composer usage flag to enable the display to read the
     // buffers.
-    auto config =
-        ProducerQueueConfigBuilder().SetMetadataSize(meta_size_bytes).Build();
     auto producer = ProducerQueue::Create(
         config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0});
     if (!producer) {
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index c456b10..5380062 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -66,7 +66,7 @@
   }
 
   virtual pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
-      pdx::Message& message, size_t meta_size_bytes) = 0;
+      pdx::Message& message, const ProducerQueueConfig& config) = 0;
 
   // Registers a consumer queue with the event dispatcher in DisplayService. The
   // OnQueueEvent callback below is called to handle queue events.
@@ -129,7 +129,7 @@
 
  private:
   pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
-      pdx::Message& message, size_t meta_size_bytes) override;
+      pdx::Message& message, const ProducerQueueConfig& config) override;
   void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
                     int events) override;
 
@@ -154,7 +154,7 @@
 
  private:
   pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
-      pdx::Message& message, size_t meta_size_bytes) override;
+      pdx::Message& message, const ProducerQueueConfig& config) override;
   void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
                     int events) override;