1#include <base/logging.h>
2#include <private/dvr/buffer_hub_client.h>
3#include <private/dvr/buffer_hub_queue_client.h>
4
5#include <gtest/gtest.h>
6
7#include <vector>
8
9namespace android {
10namespace dvr {
11
12using pdx::LocalHandle;
13
14namespace {
15
16constexpr int kBufferWidth = 100;
17constexpr int kBufferHeight = 1;
18constexpr int kBufferLayerCount = 1;
19constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
20constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
21
22class BufferHubQueueTest : public ::testing::Test {
23 public:
24  template <typename Meta>
25  bool CreateProducerQueue(uint64_t usage_set_mask = 0,
26                           uint64_t usage_clear_mask = 0,
27                           uint64_t usage_deny_set_mask = 0,
28                           uint64_t usage_deny_clear_mask = 0) {
29    producer_queue_ =
30        ProducerQueue::Create<Meta>(usage_set_mask, usage_clear_mask,
31                                    usage_deny_set_mask, usage_deny_clear_mask);
32    return producer_queue_ != nullptr;
33  }
34
35  bool CreateConsumerQueue() {
36    if (producer_queue_) {
37      consumer_queue_ = producer_queue_->CreateConsumerQueue();
38      return consumer_queue_ != nullptr;
39    } else {
40      return false;
41    }
42  }
43
44  template <typename Meta>
45  bool CreateQueues(int usage_set_mask = 0, int usage_clear_mask = 0,
46                    int usage_deny_set_mask = 0,
47                    int usage_deny_clear_mask = 0) {
48    return CreateProducerQueue<Meta>(usage_set_mask, usage_clear_mask,
49                                     usage_deny_set_mask,
50                                     usage_deny_clear_mask) &&
51           CreateConsumerQueue();
52  }
53
54  void AllocateBuffer() {
55    // Create producer buffer.
56    size_t slot;
57    int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
58                                              kBufferLayerCount, kBufferFormat,
59                                              kBufferUsage, &slot);
60    ASSERT_EQ(ret, 0);
61  }
62
63 protected:
64  std::unique_ptr<ProducerQueue> producer_queue_;
65  std::unique_ptr<ConsumerQueue> consumer_queue_;
66};
67
68TEST_F(BufferHubQueueTest, TestDequeue) {
69  const size_t nb_dequeue_times = 16;
70
71  ASSERT_TRUE(CreateQueues<size_t>());
72
73  // Allocate only one buffer.
74  AllocateBuffer();
75
76  // But dequeue multiple times.
77  for (size_t i = 0; i < nb_dequeue_times; i++) {
78    size_t slot;
79    LocalHandle fence;
80    auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
81    ASSERT_TRUE(p1_status.ok());
82    auto p1 = p1_status.take();
83    ASSERT_NE(nullptr, p1);
84    size_t mi = i;
85    ASSERT_EQ(p1->Post(LocalHandle(), &mi, sizeof(mi)), 0);
86    size_t mo;
87    auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
88    ASSERT_TRUE(c1_status.ok());
89    auto c1 = c1_status.take();
90    ASSERT_NE(nullptr, c1);
91    ASSERT_EQ(mi, mo);
92    c1->Release(LocalHandle());
93  }
94}
95
96TEST_F(BufferHubQueueTest, TestProducerConsumer) {
97  const size_t nb_buffer = 16;
98  size_t slot;
99  uint64_t seq;
100
101  ASSERT_TRUE(CreateQueues<uint64_t>());
102
103  for (size_t i = 0; i < nb_buffer; i++) {
104    AllocateBuffer();
105
106    // Producer queue has all the available buffers on initialize.
107    ASSERT_EQ(producer_queue_->count(), i + 1);
108    ASSERT_EQ(producer_queue_->capacity(), i + 1);
109
110    // Consumer queue has no avaiable buffer on initialize.
111    ASSERT_EQ(consumer_queue_->count(), 0U);
112    // Consumer queue does not import buffers until a dequeue is issued.
113    ASSERT_EQ(consumer_queue_->capacity(), i);
114    // Dequeue returns timeout since no buffer is ready to consumer, but
115    // this implicitly triggers buffer import and bump up |capacity|.
116    LocalHandle fence;
117    auto status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
118    ASSERT_FALSE(status.ok());
119    ASSERT_EQ(ETIMEDOUT, status.error());
120    ASSERT_EQ(consumer_queue_->capacity(), i + 1);
121  }
122
123  for (size_t i = 0; i < nb_buffer; i++) {
124    LocalHandle fence;
125    // First time, there is no buffer available to dequeue.
126    auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
127    ASSERT_FALSE(consumer_status.ok());
128    ASSERT_EQ(ETIMEDOUT, consumer_status.error());
129
130    // Make sure Producer buffer is Post()'ed so that it's ready to Accquire
131    // in the consumer's Dequeue() function.
132    auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
133    ASSERT_TRUE(producer_status.ok());
134    auto producer = producer_status.take();
135    ASSERT_NE(nullptr, producer);
136
137    uint64_t seq_in = static_cast<uint64_t>(i);
138    ASSERT_EQ(producer->Post({}, &seq_in, sizeof(seq_in)), 0);
139
140    // Second time, the just |Post()|'ed buffer should be dequeued.
141    uint64_t seq_out = 0;
142    consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence);
143    ASSERT_TRUE(consumer_status.ok());
144    auto consumer = consumer_status.take();
145    ASSERT_NE(nullptr, consumer);
146    ASSERT_EQ(seq_in, seq_out);
147  }
148}
149
150TEST_F(BufferHubQueueTest, TestMultipleConsumers) {
151  ASSERT_TRUE(CreateProducerQueue<void>());
152
153  // Allocate buffers.
154  const size_t kBufferCount = 4u;
155  for (size_t i = 0; i < kBufferCount; i++) {
156    AllocateBuffer();
157  }
158  ASSERT_EQ(kBufferCount, producer_queue_->count());
159
160  // Build a silent consumer queue to test multi-consumer queue features.
161  auto silent_queue = producer_queue_->CreateSilentConsumerQueue();
162  ASSERT_NE(nullptr, silent_queue);
163
164  // Check that buffers are correctly imported on construction.
165  EXPECT_EQ(kBufferCount, silent_queue->capacity());
166
167  // Dequeue and post a buffer.
168  size_t slot;
169  LocalHandle fence;
170  auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
171  ASSERT_TRUE(producer_status.ok());
172  auto producer_buffer = producer_status.take();
173  ASSERT_NE(nullptr, producer_buffer);
174  ASSERT_EQ(0, producer_buffer->Post<void>({}));
175
176  // Currently we expect no buffer to be available prior to calling
177  // WaitForBuffers/HandleQueueEvents.
178  // TODO(eieio): Note this behavior may change in the future.
179  EXPECT_EQ(0u, silent_queue->count());
180  EXPECT_FALSE(silent_queue->HandleQueueEvents());
181  EXPECT_EQ(0u, silent_queue->count());
182
183  // Build a new consumer queue to test multi-consumer queue features.
184  consumer_queue_ = silent_queue->CreateConsumerQueue();
185  ASSERT_NE(nullptr, consumer_queue_);
186
187  // Check that buffers are correctly imported on construction.
188  EXPECT_EQ(kBufferCount, consumer_queue_->capacity());
189  EXPECT_EQ(1u, consumer_queue_->count());
190
191  // Reclaim released/ignored buffers.
192  producer_queue_->HandleQueueEvents();
193  ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
194
195  // Post another buffer.
196  producer_status = producer_queue_->Dequeue(0, &slot, &fence);
197  ASSERT_TRUE(producer_status.ok());
198  producer_buffer = producer_status.take();
199  ASSERT_NE(nullptr, producer_buffer);
200  ASSERT_EQ(0, producer_buffer->Post<void>({}));
201
202  // Verify that the consumer queue receives it.
203  EXPECT_EQ(1u, consumer_queue_->count());
204  EXPECT_TRUE(consumer_queue_->HandleQueueEvents());
205  EXPECT_EQ(2u, consumer_queue_->count());
206
207  // Dequeue and acquire/release (discard) buffers on the consumer end.
208  auto consumer_status = consumer_queue_->Dequeue(0, &slot, &fence);
209  ASSERT_TRUE(consumer_status.ok());
210  auto consumer_buffer = consumer_status.take();
211  ASSERT_NE(nullptr, consumer_buffer);
212  consumer_buffer->Discard();
213
214  // Buffer should be returned to the producer queue without being handled by
215  // the silent consumer queue.
216  EXPECT_EQ(1u, consumer_queue_->count());
217  EXPECT_EQ(kBufferCount - 2, producer_queue_->count());
218  EXPECT_TRUE(producer_queue_->HandleQueueEvents());
219  EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
220}
221
222struct TestMetadata {
223  char a;
224  int32_t b;
225  int64_t c;
226};
227
228TEST_F(BufferHubQueueTest, TestMetadata) {
229  ASSERT_TRUE(CreateQueues<TestMetadata>());
230  AllocateBuffer();
231
232  std::vector<TestMetadata> ms = {
233      {'0', 0, 0}, {'1', 10, 3333}, {'@', 123, 1000000000}};
234
235  for (auto mi : ms) {
236    size_t slot;
237    LocalHandle fence;
238    auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
239    ASSERT_TRUE(p1_status.ok());
240    auto p1 = p1_status.take();
241    ASSERT_NE(nullptr, p1);
242    ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
243    TestMetadata mo;
244    auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
245    ASSERT_TRUE(c1_status.ok());
246    auto c1 = c1_status.take();
247    ASSERT_EQ(mi.a, mo.a);
248    ASSERT_EQ(mi.b, mo.b);
249    ASSERT_EQ(mi.c, mo.c);
250    c1->Release(LocalHandle(-1));
251  }
252}
253
254TEST_F(BufferHubQueueTest, TestMetadataMismatch) {
255  ASSERT_TRUE(CreateQueues<int64_t>());
256  AllocateBuffer();
257
258  int64_t mi = 3;
259  size_t slot;
260  LocalHandle fence;
261  auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
262  ASSERT_TRUE(p1_status.ok());
263  auto p1 = p1_status.take();
264  ASSERT_NE(nullptr, p1);
265  ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
266
267  int32_t mo;
268  // Acquire a buffer with mismatched metadata is not OK.
269  auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
270  ASSERT_FALSE(c1_status.ok());
271}
272
273TEST_F(BufferHubQueueTest, TestEnqueue) {
274  ASSERT_TRUE(CreateQueues<int64_t>());
275  AllocateBuffer();
276
277  size_t slot;
278  LocalHandle fence;
279  auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
280  ASSERT_TRUE(p1_status.ok());
281  auto p1 = p1_status.take();
282  ASSERT_NE(nullptr, p1);
283
284  int64_t mo;
285  producer_queue_->Enqueue(p1, slot);
286  auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
287  ASSERT_FALSE(c1_status.ok());
288}
289
290TEST_F(BufferHubQueueTest, TestAllocateBuffer) {
291  ASSERT_TRUE(CreateQueues<int64_t>());
292
293  size_t s1;
294  AllocateBuffer();
295  LocalHandle fence;
296  auto p1_status = producer_queue_->Dequeue(0, &s1, &fence);
297  ASSERT_TRUE(p1_status.ok());
298  auto p1 = p1_status.take();
299  ASSERT_NE(nullptr, p1);
300
301  // producer queue is exhausted
302  size_t s2;
303  auto p2_status = producer_queue_->Dequeue(0, &s2, &fence);
304  ASSERT_FALSE(p2_status.ok());
305  ASSERT_EQ(ETIMEDOUT, p2_status.error());
306
307  // dynamically add buffer.
308  AllocateBuffer();
309  ASSERT_EQ(producer_queue_->count(), 1U);
310  ASSERT_EQ(producer_queue_->capacity(), 2U);
311
312  // now we can dequeue again
313  p2_status = producer_queue_->Dequeue(0, &s2, &fence);
314  ASSERT_TRUE(p2_status.ok());
315  auto p2 = p2_status.take();
316  ASSERT_NE(nullptr, p2);
317  ASSERT_EQ(producer_queue_->count(), 0U);
318  // p1 and p2 should have different slot number
319  ASSERT_NE(s1, s2);
320
321  // Consumer queue does not import buffers until |Dequeue| or |ImportBuffers|
322  // are called. So far consumer_queue_ should be empty.
323  ASSERT_EQ(consumer_queue_->count(), 0U);
324
325  int64_t seq = 1;
326  ASSERT_EQ(p1->Post(LocalHandle(), seq), 0);
327  size_t cs1, cs2;
328  auto c1_status = consumer_queue_->Dequeue(0, &cs1, &seq, &fence);
329  ASSERT_TRUE(c1_status.ok());
330  auto c1 = c1_status.take();
331  ASSERT_NE(nullptr, c1);
332  ASSERT_EQ(consumer_queue_->count(), 0U);
333  ASSERT_EQ(consumer_queue_->capacity(), 2U);
334  ASSERT_EQ(cs1, s1);
335
336  ASSERT_EQ(p2->Post(LocalHandle(), seq), 0);
337  auto c2_status = consumer_queue_->Dequeue(0, &cs2, &seq, &fence);
338  ASSERT_TRUE(c2_status.ok());
339  auto c2 = c2_status.take();
340  ASSERT_NE(nullptr, c2);
341  ASSERT_EQ(cs2, s2);
342}
343
344TEST_F(BufferHubQueueTest, TestUsageSetMask) {
345  const uint32_t set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
346  ASSERT_TRUE(CreateQueues<int64_t>(set_mask, 0, 0, 0));
347
348  // When allocation, leave out |set_mask| from usage bits on purpose.
349  size_t slot;
350  int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
351                                            kBufferFormat, kBufferLayerCount,
352                                            kBufferUsage & ~set_mask, &slot);
353  ASSERT_EQ(0, ret);
354
355  LocalHandle fence;
356  auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
357  ASSERT_TRUE(p1_status.ok());
358  auto p1 = p1_status.take();
359  ASSERT_EQ(p1->usage() & set_mask, set_mask);
360}
361
362TEST_F(BufferHubQueueTest, TestUsageClearMask) {
363  const uint32_t clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
364  ASSERT_TRUE(CreateQueues<int64_t>(0, clear_mask, 0, 0));
365
366  // When allocation, add |clear_mask| into usage bits on purpose.
367  size_t slot;
368  int ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
369                                            kBufferLayerCount, kBufferFormat,
370                                            kBufferUsage | clear_mask, &slot);
371  ASSERT_EQ(0, ret);
372
373  LocalHandle fence;
374  auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
375  ASSERT_TRUE(p1_status.ok());
376  auto p1 = p1_status.take();
377  ASSERT_EQ(0u, p1->usage() & clear_mask);
378}
379
380TEST_F(BufferHubQueueTest, TestUsageDenySetMask) {
381  const uint32_t deny_set_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
382  ASSERT_TRUE(CreateQueues<int64_t>(0, 0, deny_set_mask, 0));
383
384  // Now that |deny_set_mask| is illegal, allocation without those bits should
385  // be able to succeed.
386  size_t slot;
387  int ret = producer_queue_->AllocateBuffer(
388      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
389      kBufferUsage & ~deny_set_mask, &slot);
390  ASSERT_EQ(ret, 0);
391
392  // While allocation with those bits should fail.
393  ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
394                                        kBufferLayerCount, kBufferFormat,
395                                        kBufferUsage | deny_set_mask, &slot);
396  ASSERT_EQ(ret, -EINVAL);
397}
398
399TEST_F(BufferHubQueueTest, TestUsageDenyClearMask) {
400  const uint32_t deny_clear_mask = GRALLOC_USAGE_SW_WRITE_OFTEN;
401  ASSERT_TRUE(CreateQueues<int64_t>(0, 0, 0, deny_clear_mask));
402
403  // Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
404  // mandatory), allocation with those bits should be able to succeed.
405  size_t slot;
406  int ret = producer_queue_->AllocateBuffer(
407      kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
408      kBufferUsage | deny_clear_mask, &slot);
409  ASSERT_EQ(ret, 0);
410
411  // While allocation without those bits should fail.
412  ret = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
413                                        kBufferLayerCount, kBufferFormat,
414                                        kBufferUsage & ~deny_clear_mask, &slot);
415  ASSERT_EQ(ret, -EINVAL);
416}
417
418}  // namespace
419
420}  // namespace dvr
421}  // namespace android
422