blob: 841554e92fc5cf3cddc6a655b4aead91f0a1c615 [file] [log] [blame]
#include <base/logging.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
#include <gtest/gtest.h>
#include <vector>
namespace android {
namespace dvr {
using pdx::LocalHandle;
namespace {
constexpr int kBufferWidth = 100;
constexpr int kBufferHeight = 1;
constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
constexpr int kBufferSliceCount = 1; // number of slices in each buffer
class BufferHubQueueTest : public ::testing::Test {
public:
template <typename Meta>
void CreateQueues(int usage_set_mask = 0, int usage_clear_mask = 0,
int usage_deny_set_mask = 0,
int usage_deny_clear_mask = 0) {
producer_queue_ =
ProducerQueue::Create<Meta>(usage_set_mask, usage_clear_mask,
usage_deny_set_mask, usage_deny_clear_mask);
ASSERT_NE(nullptr, producer_queue_);
consumer_queue_ = producer_queue_->CreateConsumerQueue();
ASSERT_NE(nullptr, consumer_queue_);
}
void AllocateBuffer() {
// Create producer buffer.
size_t slot;
int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
kBufferFormat, kBufferUsage,
kBufferSliceCount, &slot);
ASSERT_EQ(ret, 0);
}
protected:
std::unique_ptr<ProducerQueue> producer_queue_;
std::unique_ptr<ConsumerQueue> consumer_queue_;
};
TEST_F(BufferHubQueueTest, TestDequeue) {
const size_t nb_dequeue_times = 16;
CreateQueues<size_t>();
// Allocate only one buffer.
AllocateBuffer();
// But dequeue multiple times.
for (size_t i = 0; i < nb_dequeue_times; i++) {
size_t slot;
auto p1 = producer_queue_->Dequeue(0, &slot);
ASSERT_NE(nullptr, p1);
size_t mi = i;
ASSERT_EQ(p1->Post(LocalHandle(), &mi, sizeof(mi)), 0);
size_t mo;
auto c1 = consumer_queue_->Dequeue(100, &slot, &mo);
ASSERT_NE(nullptr, c1);
ASSERT_EQ(mi, mo);
c1->Release(LocalHandle());
}
}
TEST_F(BufferHubQueueTest, TestProducerConsumer) {
const size_t nb_buffer = 16;
size_t slot;
uint64_t seq;
CreateQueues<uint64_t>();
for (size_t i = 0; i < nb_buffer; i++) {
AllocateBuffer();
// Producer queue has all the available buffers on initialize.
ASSERT_EQ(producer_queue_->count(), i + 1);
ASSERT_EQ(producer_queue_->capacity(), i + 1);
// Consumer queue has no avaiable buffer on initialize.
ASSERT_EQ(consumer_queue_->count(), 0U);
// Consumer queue does not import buffers until a dequeue is issued.
ASSERT_EQ(consumer_queue_->capacity(), i);
// Dequeue returns nullptr since no buffer is ready to consumer, but
// this implicitly triggers buffer import and bump up |capacity|.
auto consumer_null = consumer_queue_->Dequeue(0, &slot, &seq);
ASSERT_EQ(nullptr, consumer_null);
ASSERT_EQ(consumer_queue_->capacity(), i + 1);
}
for (size_t i = 0; i < nb_buffer; i++) {
// First time, there is no buffer available to dequeue.
auto buffer_null = consumer_queue_->Dequeue(0, &slot, &seq);
ASSERT_EQ(nullptr, buffer_null);
// Make sure Producer buffer is Post()'ed so that it's ready to Accquire
// in the consumer's Dequeue() function.
auto producer = producer_queue_->Dequeue(0, &slot);
ASSERT_NE(nullptr, producer);
uint64_t seq_in = static_cast<uint64_t>(i);
ASSERT_EQ(producer->Post({}, &seq_in, sizeof(seq_in)), 0);
// Second time, the just |Post()|'ed buffer should be dequeued.
uint64_t seq_out = 0;
auto consumer = consumer_queue_->Dequeue(0, &slot, &seq_out);
ASSERT_NE(nullptr, consumer);
ASSERT_EQ(seq_in, seq_out);
}
}
struct TestMetadata {
char a;
int32_t b;
int64_t c;
};
TEST_F(BufferHubQueueTest, TestMetadata) {
CreateQueues<TestMetadata>();
AllocateBuffer();
std::vector<TestMetadata> ms = {
{'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}};
for (auto mi : ms) {
size_t slot;
auto p1 = producer_queue_->Dequeue(0, &slot);
ASSERT_NE(nullptr, p1);
ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
TestMetadata mo;
auto c1 = consumer_queue_->Dequeue(0, &slot, &mo);
ASSERT_EQ(mi.a, mo.a);
ASSERT_EQ(mi.b, mo.b);
ASSERT_EQ(mi.c, mo.c);
c1->Release(LocalHandle(-1));
}
}
TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
CreateQueues<int64_t>();
AllocateBuffer();
int64_t mi = 3;
size_t slot;
auto p1 = producer_queue_->Dequeue(0, &slot);
ASSERT_NE(nullptr, p1);
ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
int32_t mo;
// Acquire a buffer with mismatched metadata is not OK.
auto c1 = consumer_queue_->Dequeue(0, &slot, &mo);
ASSERT_EQ(nullptr, c1);
}
TEST_F(BufferHubQueueTest, TestEnqueue) {
CreateQueues<int64_t>();
AllocateBuffer();
size_t slot;
auto p1 = producer_queue_->Dequeue(0, &slot);
ASSERT_NE(nullptr, p1);
int64_t mo;
producer_queue_->Enqueue(p1, slot);
auto c1 = consumer_queue_->Dequeue(0, &slot, &mo);
ASSERT_EQ(nullptr, c1);
}
TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
CreateQueues<int64_t>();
size_t s1;
AllocateBuffer();
auto p1 = producer_queue_->Dequeue(0, &s1);
ASSERT_NE(nullptr, p1);
// producer queue is exhausted
size_t s2;
auto p2_null = producer_queue_->Dequeue(0, &s2);
ASSERT_EQ(nullptr, p2_null);
// dynamically add buffer.
AllocateBuffer();
ASSERT_EQ(producer_queue_->count(), 1U);
ASSERT_EQ(producer_queue_->capacity(), 2U);
// now we can dequeue again
auto p2 = producer_queue_->Dequeue(0, &s2);
ASSERT_NE(nullptr, p2);
ASSERT_EQ(producer_queue_->count(), 0U);
// p1 and p2 should have different slot number
ASSERT_NE(s1, s2);
// Consumer queue does not import buffers until |Dequeue| or |ImportBuffers|
// are called. So far consumer_queue_ should be empty.
ASSERT_EQ(consumer_queue_->count(), 0U);
int64_t seq = 1;
ASSERT_EQ(p1->Post(LocalHandle(), seq), 0);
size_t cs1, cs2;
auto c1 = consumer_queue_->Dequeue(0, &cs1, &seq);
ASSERT_NE(nullptr, c1);
ASSERT_EQ(consumer_queue_->count(), 0U);
ASSERT_EQ(consumer_queue_->capacity(), 2U);
ASSERT_EQ(cs1, s1);
ASSERT_EQ(p2->Post(LocalHandle(), seq), 0);
auto c2 = consumer_queue_->Dequeue(0, &cs2, &seq);
ASSERT_NE(nullptr, c2);
ASSERT_EQ(cs2, s2);
}
TEST_F(BufferHubQueueTest, TestUsageSetMask) {
const int set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
CreateQueues<int64_t>(set_mask, 0, 0, 0);
// When allocation, leave out |set_mask| from usage bits on purpose.
size_t slot;
int ret = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage & ~set_mask,
kBufferSliceCount, &slot);
ASSERT_EQ(ret, 0);
auto p1 = producer_queue_->Dequeue(0, &slot);
ASSERT_EQ(p1->usage() & set_mask, set_mask);
}
TEST_F(BufferHubQueueTest, TestUsageClearMask) {
const int clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
CreateQueues<int64_t>(0, clear_mask, 0, 0);
// When allocation, add |clear_mask| into usage bits on purpose.
size_t slot;
int ret = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage | clear_mask,
kBufferSliceCount, &slot);
ASSERT_EQ(ret, 0);
auto p1 = producer_queue_->Dequeue(0, &slot);
ASSERT_EQ(p1->usage() & clear_mask, 0);
}
TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
const int deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
CreateQueues<int64_t>(0, 0, deny_set_mask, 0);
// Now that |deny_set_mask| is illegal, allocation without those bits should
// be able to succeed.
size_t slot;
int ret = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage & ~deny_set_mask,
kBufferSliceCount, &slot);
ASSERT_EQ(ret, 0);
// While allocation with those bits should fail.
ret = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage | deny_set_mask,
kBufferSliceCount, &slot);
ASSERT_EQ(ret, -EINVAL);
}
TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) {
const int deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
CreateQueues<int64_t>(0, 0, 0, deny_clear_mask);
// Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
// mandatory), allocation with those bits should be able to succeed.
size_t slot;
int ret = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferFormat,
kBufferUsage | deny_clear_mask, kBufferSliceCount, &slot);
ASSERT_EQ(ret, 0);
// While allocation without those bits should fail.
ret = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferFormat,
kBufferUsage & ~deny_clear_mask, kBufferSliceCount, &slot);
ASSERT_EQ(ret, -EINVAL);
}
} // namespace
} // namespace dvr
} // namespace android