blob: 474e9684c28725ec19a4ef7dc40bb317cdb75404 [file] [log] [blame]
#include <dvr/dvr_api.h>
#include <dvr/dvr_buffer_queue.h>
#include <gui/Surface.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <base/logging.h>
#include <gtest/gtest.h>
#include "../dvr_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 size_t kQueueCapacity = 3;
typedef uint64_t TestMeta;
class DvrBufferQueueTest : public ::testing::Test {
protected:
void SetUp() override {
write_queue_ = CreateDvrWriteBufferQueueFromProducerQueue(
ProducerQueue::Create<TestMeta>(0, 0, 0, 0));
ASSERT_NE(nullptr, write_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 = GetProducerQueueFromDvrWriteBufferQueue(write_queue_)
->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount,
kBufferFormat, kBufferUsage, &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, CreateEmptyBuffer) {
AllocateBuffers(3);
DvrReadBuffer* read_buffer = nullptr;
DvrWriteBuffer* write_buffer = nullptr;
EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
dvrReadBufferCreateEmpty(&read_buffer);
ASSERT_NE(nullptr, read_buffer);
dvrWriteBufferCreateEmpty(&write_buffer);
ASSERT_NE(nullptr, write_buffer);
EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
DvrReadBufferQueue* read_queue = nullptr;
ASSERT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
const int kTimeoutMs = 0;
int fence_fd = -1;
ASSERT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, kTimeoutMs,
write_buffer, &fence_fd));
EXPECT_EQ(-1, fence_fd);
EXPECT_TRUE(dvrWriteBufferIsValid(write_buffer));
ASSERT_EQ(0, dvrWriteBufferClear(write_buffer));
EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
}
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);
dvrWriteBufferCreateEmpty(&wb);
ASSERT_NE(nullptr, wb);
dvrReadBufferCreateEmpty(&rb);
ASSERT_NE(nullptr, rb);
AllocateBuffers(kQueueCapacity);
// Gain buffer for writing.
ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(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_TRUE(dvrReadBufferIsValid(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);
}
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(
CreateDvrWriteBufferQueueFromProducerQueue(
ProducerQueue::Create<DvrNativeBufferMetadata>(0, 0, 0, 0)),
dvrWriteBufferQueueDestroy);
ASSERT_NE(nullptr, write_queue.get());
ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, window);
sp<Surface> surface = static_cast<Surface*>(window);
ASSERT_TRUE(Surface::isValid(surface));
}
} // namespace
} // namespace dvr
} // namespace android