blob: fa61c4a215a6ae5f3184e9d89c22a736f2067aad [file] [log] [blame]
#include <gtest/gtest.h>
#include <private/dvr/buffer_hub_client.h>
#include <mutex>
#include <thread>
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
decltype(fnc_call) result; \
do { \
result = (fnc_call); \
} while (result == -1 && errno == EINTR); \
return result; \
})()
using android::dvr::BufferProducer;
using android::dvr::BufferConsumer;
using android::pdx::LocalHandle;
const int kWidth = 640;
const int kHeight = 480;
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
const uint64_t kContext = 42;
using LibBufferHubTest = ::testing::Test;
TEST_F(LibBufferHubTest, TestBasicUsage) {
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
// Check that consumers can spawn other consumers.
std::unique_ptr<BufferConsumer> c2 =
BufferConsumer::Import(c->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
// Both consumers should be triggered.
EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
EXPECT_LT(0, RETRY_EINTR(c2->Poll(10)));
uint64_t context;
LocalHandle fence;
EXPECT_LE(0, c->Acquire(&fence, &context));
EXPECT_EQ(kContext, context);
EXPECT_GE(0, RETRY_EINTR(c->Poll(0)));
EXPECT_LE(0, c2->Acquire(&fence, &context));
EXPECT_EQ(kContext, context);
EXPECT_GE(0, RETRY_EINTR(c2->Poll(0)));
EXPECT_EQ(0, c->Release(LocalHandle()));
EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
EXPECT_EQ(0, c2->Discard());
EXPECT_LE(0, RETRY_EINTR(p->Poll(0)));
EXPECT_EQ(0, p->Gain(&fence));
EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
}
TEST_F(LibBufferHubTest, TestWithCustomMetadata) {
struct Metadata {
int64_t field1;
int64_t field2;
};
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
Metadata m = {1, 3};
EXPECT_EQ(0, p->Post(LocalHandle(), m));
EXPECT_LE(0, RETRY_EINTR(c->Poll(10)));
LocalHandle fence;
Metadata m2 = {};
EXPECT_EQ(0, c->Acquire(&fence, &m2));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
}
TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
struct Metadata {
int64_t field1;
int64_t field2;
};
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
int64_t sequence = 3;
EXPECT_NE(0, p->Post(LocalHandle(), sequence));
EXPECT_GE(0, RETRY_EINTR(c->Poll(10)));
}
TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
struct Metadata {
int64_t field1;
int64_t field2;
};
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
Metadata m = {1, 3};
EXPECT_EQ(0, p->Post(LocalHandle(), m));
LocalHandle fence;
int64_t sequence;
EXPECT_NE(0, c->Acquire(&fence, &sequence));
}
TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
int64_t sequence = 3;
EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
LocalHandle fence;
EXPECT_EQ(0, c->Acquire(&fence));
}
TEST_F(LibBufferHubTest, TestWithNoMeta) {
std::unique_ptr<BufferProducer> p =
BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
LocalHandle fence;
EXPECT_EQ(0, p->Post<void>(LocalHandle()));
EXPECT_EQ(0, c->Acquire(&fence));
}
TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
std::unique_ptr<BufferProducer> p =
BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
ASSERT_TRUE(p.get() != nullptr);
std::unique_ptr<BufferConsumer> c =
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
int64_t sequence = 3;
EXPECT_NE(0, p->Post(LocalHandle(), sequence));
}
TEST_F(LibBufferHubTest, TestPersistentBufferPersistence) {
auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
kHeight, kFormat, kUsage);
ASSERT_NE(nullptr, p);
// Record the original buffer id for later comparison.
const int buffer_id = p->id();
auto c = BufferConsumer::Import(p->CreateConsumer());
ASSERT_NE(nullptr, c);
EXPECT_EQ(0, p->Post<void>(LocalHandle()));
// Close the connection to the producer. This should not affect the consumer.
p = nullptr;
LocalHandle fence;
EXPECT_EQ(0, c->Acquire(&fence));
EXPECT_EQ(0, c->Release(LocalHandle()));
// Attempt to reconnect to the persistent buffer.
p = BufferProducer::Create("TestPersistentBuffer");
ASSERT_NE(nullptr, p);
EXPECT_EQ(buffer_id, p->id());
EXPECT_EQ(0, p->Gain(&fence));
}
TEST_F(LibBufferHubTest, TestPersistentBufferMismatchParams) {
auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
kHeight, kFormat, kUsage);
ASSERT_NE(nullptr, p);
// Close the connection to the producer.
p = nullptr;
// Mismatch the params.
p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth * 2,
kHeight, kFormat, kUsage);
ASSERT_EQ(nullptr, p);
}
TEST_F(LibBufferHubTest, TestRemovePersistentBuffer) {
auto p = BufferProducer::Create("TestPersistentBuffer", -1, -1, kWidth,
kHeight, kFormat, kUsage);
ASSERT_NE(nullptr, p);
LocalHandle fence;
auto c = BufferConsumer::Import(p->CreateConsumer());
ASSERT_NE(nullptr, c);
EXPECT_NE(-EPIPE, c->Acquire(&fence));
// Test that removing persistence and closing the producer orphans the
// consumer.
EXPECT_EQ(0, p->RemovePersistence());
p = nullptr;
EXPECT_EQ(-EPIPE, c->Release(LocalHandle()));
}