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
9 namespace android {
10 namespace dvr {
11
12 using pdx::LocalHandle;
13
14 namespace {
15
16 constexpr int kBufferWidth = 100;
17 constexpr int kBufferHeight = 1;
18 constexpr int kBufferLayerCount = 1;
19 constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
20 constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
21
22 class BufferHubQueueTest : public ::testing::Test {
23 public:
24 template <typename Meta>
CreateProducerQueue(uint64_t usage_set_mask=0,uint64_t usage_clear_mask=0,uint64_t usage_deny_set_mask=0,uint64_t usage_deny_clear_mask=0)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
CreateConsumerQueue()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>
CreateQueues(int usage_set_mask=0,int usage_clear_mask=0,int usage_deny_set_mask=0,int usage_deny_clear_mask=0)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
AllocateBuffer()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
TEST_F(BufferHubQueueTest,TestDequeue)68 TEST_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
TEST_F(BufferHubQueueTest,TestProducerConsumer)96 TEST_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
TEST_F(BufferHubQueueTest,TestMultipleConsumers)150 TEST_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
222 struct TestMetadata {
223 char a;
224 int32_t b;
225 int64_t c;
226 };
227
TEST_F(BufferHubQueueTest,TestMetadata)228 TEST_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
TEST_F(BufferHubQueueTest,TestMetadataMismatch)254 TEST_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
TEST_F(BufferHubQueueTest,TestEnqueue)273 TEST_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
TEST_F(BufferHubQueueTest,TestAllocateBuffer)290 TEST_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
TEST_F(BufferHubQueueTest,TestUsageSetMask)344 TEST_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
TEST_F(BufferHubQueueTest,TestUsageClearMask)362 TEST_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
TEST_F(BufferHubQueueTest,TestUsageDenySetMask)380 TEST_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
TEST_F(BufferHubQueueTest,TestUsageDenyClearMask)399 TEST_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