Add dvr_buffer_queue C API

Bug: 36401767
Bug: 32213274
Bug: 36266201
Test: build and ran dvr_buffer_queue-test
Change-Id: Icd8d063bd8b7adb15bf67f7e543b87dad1c32a68
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
new file mode 100644
index 0000000..158d58f
--- /dev/null
+++ b/libs/vr/libdvr/tests/Android.mk
@@ -0,0 +1,29 @@
+LOCAL_PATH := $(call my-dir)
+
+shared_libraries := \
+    libbase \
+    libbinder \
+    libcutils \
+    libgui \
+    liblog \
+    libhardware \
+    libui \
+    libutils \
+
+static_libraries := \
+    libdvr \
+    libbufferhubqueue \
+    libbufferhub \
+    libchrome \
+    libdvrcommon \
+    libpdx_default_transport \
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
+LOCAL_STATIC_LIBRARIES := $(static_libraries)
+LOCAL_SHARED_LIBRARIES := $(shared_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := ${LOCAL_C_INCLUDES}
+LOCAL_CFLAGS := -DLOG_TAG=\"dvr_buffer_queue-test\" -DTRACE=0 -O0 -g
+LOCAL_MODULE := dvr_buffer_queue-test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
new file mode 100644
index 0000000..f344a24
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -0,0 +1,149 @@
+#include <dvr/dvr_buffer_queue.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+static constexpr int kBufferWidth = 100;
+static constexpr int kBufferHeight = 1;
+static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr int kBufferSliceCount = 1;  // number of slices in each buffer
+static constexpr size_t kQueueCapacity = 3;
+
+typedef uint64_t TestMeta;
+
+class DvrBufferQueueTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    write_queue_ = new DvrWriteBufferQueue;
+    write_queue_->producer_queue_ = ProducerQueue::Create<TestMeta>(0, 0, 0, 0);
+    ASSERT_NE(nullptr, write_queue_->producer_queue_);
+  }
+
+  void TearDown() override {
+    if (write_queue_ != nullptr) {
+      dvrWriteBufferQueueDestroy(write_queue_);
+      write_queue_ = nullptr;
+    }
+  }
+
+  void AllocateBuffers(size_t buffer_count) {
+    size_t out_slot;
+    for (size_t i = 0; i < buffer_count; i++) {
+      int ret = write_queue_->producer_queue_->AllocateBuffer(
+          kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage,
+          kBufferSliceCount, &out_slot);
+      ASSERT_EQ(0, ret);
+    }
+  }
+
+  DvrWriteBufferQueue* write_queue_{nullptr};
+};
+
+TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+  dvrWriteBufferQueueDestroy(write_queue_);
+  write_queue_ = nullptr;
+}
+
+TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
+  AllocateBuffers(kQueueCapacity);
+  size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
+
+  ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
+  ASSERT_EQ(kQueueCapacity, capacity);
+}
+
+TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+  DvrReadBufferQueue* read_queue = nullptr;
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue);
+
+  dvrReadBufferQueueDestroy(read_queue);
+}
+
+TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+  DvrReadBufferQueue* read_queue1 = nullptr;
+  DvrReadBufferQueue* read_queue2 = nullptr;
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue1);
+
+  ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue2);
+  ASSERT_NE(read_queue1, read_queue2);
+
+  dvrReadBufferQueueDestroy(read_queue1);
+  dvrReadBufferQueueDestroy(read_queue2);
+}
+
+TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+  static constexpr int kTimeout = 0;
+  DvrReadBufferQueue* read_queue = nullptr;
+  DvrReadBuffer* rb = nullptr;
+  DvrWriteBuffer* wb = nullptr;
+  int fence_fd = -1;
+
+  int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, read_queue);
+
+  AllocateBuffers(kQueueCapacity);
+
+  // Gain buffer for writing.
+  ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, &wb, &fence_fd);
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, wb);
+  ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
+           wb, fence_fd);
+  pdx::LocalHandle release_fence(fence_fd);
+
+  // Post buffer to the read_queue.
+  TestMeta seq = 42U;
+  ret = dvrWriteBufferPost(wb, /* fence */ -1, &seq, sizeof(seq));
+  ASSERT_EQ(0, ret);
+  dvrWriteBufferDestroy(wb);
+  wb = nullptr;
+
+  // Acquire buffer for reading.
+  TestMeta acquired_seq = 0U;
+  ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, &rb, &fence_fd,
+                                  &acquired_seq, sizeof(acquired_seq));
+  ASSERT_EQ(0, ret);
+  ASSERT_NE(nullptr, rb);
+  ASSERT_EQ(seq, acquired_seq);
+  ALOGD_IF(TRACE,
+           "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
+           fence_fd);
+  pdx::LocalHandle acquire_fence(fence_fd);
+
+  // Release buffer to the write_queue.
+  ret = dvrReadBufferRelease(rb, -1);
+  ASSERT_EQ(0, ret);
+  dvrReadBufferDestroy(rb);
+  rb = nullptr;
+
+  // TODO(b/34387835) Currently buffer allocation has to happen after all queues
+  // are initialized.
+  size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+
+  ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
+  ASSERT_EQ(kQueueCapacity, capacity);
+
+  dvrReadBufferQueueDestroy(read_queue);
+}
+
+}  // namespace
+
+}  // namespace dvr
+}  // namespace android