| #include <android/log.h> |
| #include <android/native_window.h> |
| #include <dvr/dvr_api.h> |
| #include <dvr/dvr_buffer_queue.h> |
| |
| #include <gtest/gtest.h> |
| |
| #include <array> |
| #include <unordered_map> |
| |
| #include "dvr_api_test.h" |
| |
| #define LOG_TAG "dvr_buffer_queue-test" |
| |
| #ifndef ALOGD |
| #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) |
| #endif |
| |
| #ifndef ALOGD_IF |
| #define ALOGD_IF(cond, ...) \ |
| ((__predict_false(cond)) ? ((void)ALOGD(__VA_ARGS__)) : (void)0) |
| #endif |
| |
| namespace { |
| |
| static constexpr uint32_t kBufferWidth = 100; |
| static constexpr uint32_t kBufferHeight = 1; |
| static constexpr uint32_t kLayerCount = 1; |
| static constexpr uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB; |
| static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN; |
| static constexpr size_t kQueueCapacity = 3; |
| |
| class DvrBufferQueueTest : public DvrApiTest { |
| public: |
| static void BufferAvailableCallback(void* context) { |
| DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context); |
| thiz->HandleBufferAvailable(); |
| } |
| |
| static void BufferRemovedCallback(DvrReadBuffer* buffer, void* context) { |
| DvrBufferQueueTest* thiz = static_cast<DvrBufferQueueTest*>(context); |
| thiz->HandleBufferRemoved(buffer); |
| } |
| |
| protected: |
| void TearDown() override { |
| if (write_queue_ != nullptr) { |
| api_.WriteBufferQueueDestroy(write_queue_); |
| write_queue_ = nullptr; |
| } |
| DvrApiTest::TearDown(); |
| } |
| |
| void HandleBufferAvailable() { |
| buffer_available_count_ += 1; |
| ALOGD_IF(TRACE, "Buffer avaiable, count=%d", buffer_available_count_); |
| } |
| |
| void HandleBufferRemoved(DvrReadBuffer* buffer) { |
| buffer_removed_count_ += 1; |
| ALOGD_IF(TRACE, "Buffer removed, buffer=%p, count=%d", buffer, |
| buffer_removed_count_); |
| } |
| |
| DvrWriteBufferQueue* write_queue_ = nullptr; |
| int buffer_available_count_{0}; |
| int buffer_removed_count_{0}; |
| }; |
| |
| TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| api_.WriteBufferQueueDestroy(write_queue_); |
| write_queue_ = nullptr; |
| } |
| |
| TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| size_t capacity = api_.WriteBufferQueueGetCapacity(write_queue_); |
| |
| ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity); |
| ASSERT_EQ(kQueueCapacity, capacity); |
| } |
| |
| TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| DvrReadBufferQueue* read_queue = nullptr; |
| ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); |
| |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, read_queue); |
| |
| api_.ReadBufferQueueDestroy(read_queue); |
| } |
| |
| TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| DvrReadBufferQueue* read_queue1 = nullptr; |
| DvrReadBufferQueue* read_queue2 = nullptr; |
| ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue1); |
| |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, read_queue1); |
| |
| ret = api_.ReadBufferQueueCreateReadQueue(read_queue1, &read_queue2); |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, read_queue2); |
| ASSERT_NE(read_queue1, read_queue2); |
| |
| api_.ReadBufferQueueDestroy(read_queue1); |
| api_.ReadBufferQueueDestroy(read_queue2); |
| } |
| |
| TEST_F(DvrBufferQueueTest, GainBuffer) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(ret, 0); |
| |
| DvrWriteBuffer* wb = nullptr; |
| EXPECT_FALSE(api_.WriteBufferIsValid(wb)); |
| |
| DvrNativeBufferMetadata meta; |
| int fence_fd = -1; |
| ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta, |
| &fence_fd); |
| ASSERT_EQ(ret, 0); |
| EXPECT_EQ(fence_fd, -1); |
| EXPECT_NE(wb, nullptr); |
| EXPECT_TRUE(api_.WriteBufferIsValid(wb)); |
| } |
| |
| TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(ret, 0); |
| |
| DvrReadBufferQueue* read_queue = nullptr; |
| DvrReadBuffer* rb = nullptr; |
| DvrWriteBuffer* wb = nullptr; |
| DvrNativeBufferMetadata meta1; |
| DvrNativeBufferMetadata meta2; |
| int fence_fd = -1; |
| |
| ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); |
| |
| ASSERT_EQ(ret, 0); |
| ASSERT_NE(read_queue, nullptr); |
| |
| api_.ReadBufferQueueSetBufferAvailableCallback( |
| read_queue, &BufferAvailableCallback, this); |
| |
| // Gain buffer for writing. |
| ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, |
| &meta1, &fence_fd); |
| ASSERT_EQ(ret, 0); |
| ASSERT_NE(wb, nullptr); |
| ASSERT_TRUE(api_.WriteBufferIsValid(wb)); |
| ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d", |
| wb, fence_fd); |
| close(fence_fd); |
| |
| // Post buffer to the read_queue. |
| meta1.timestamp = 42; |
| ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1); |
| ASSERT_EQ(ret, 0); |
| ASSERT_FALSE(api_.WriteBufferIsValid(wb)); |
| wb = nullptr; |
| |
| // Acquire buffer for reading. |
| ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, |
| &meta2, &fence_fd); |
| ASSERT_EQ(ret, 0); |
| ASSERT_NE(rb, nullptr); |
| |
| // Dequeue is successfully, BufferAvailableCallback should be fired once. |
| ASSERT_EQ(buffer_available_count_, 1); |
| ASSERT_TRUE(api_.ReadBufferIsValid(rb)); |
| |
| // Metadata should be passed along from producer to consumer properly. |
| ASSERT_EQ(meta1.timestamp, meta2.timestamp); |
| |
| ALOGD_IF(TRACE, |
| "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb, |
| fence_fd); |
| close(fence_fd); |
| |
| // Release buffer to the write_queue. |
| ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2, |
| /*release_fence_fd=*/-1); |
| ASSERT_EQ(ret, 0); |
| ASSERT_FALSE(api_.ReadBufferIsValid(rb)); |
| rb = nullptr; |
| |
| // TODO(b/34387835) Currently buffer allocation has to happen after all queues |
| // are initialized. |
| size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue); |
| |
| ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity); |
| ASSERT_EQ(kQueueCapacity, capacity); |
| |
| api_.ReadBufferQueueDestroy(read_queue); |
| } |
| |
| TEST_F(DvrBufferQueueTest, GetANativeWindow) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| /*capacity=*/0, /*user_metadata_size=*/0, &write_queue_); |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, write_queue_); |
| |
| ANativeWindow* window = nullptr; |
| ret = api_.WriteBufferQueueGetANativeWindow(write_queue_, &window); |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, window); |
| |
| uint32_t width = ANativeWindow_getWidth(window); |
| uint32_t height = ANativeWindow_getHeight(window); |
| uint32_t format = ANativeWindow_getFormat(window); |
| ASSERT_EQ(kBufferWidth, width); |
| ASSERT_EQ(kBufferHeight, height); |
| ASSERT_EQ(kBufferFormat, format); |
| } |
| |
| // Create buffer queue of three buffers and dequeue three buffers out of it. |
| // Before each dequeue operation, we resize the buffer queue and expect the |
| // queue always return buffer with desired dimension. |
| TEST_F(DvrBufferQueueTest, ResizeBuffer) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| int fence_fd = -1; |
| |
| DvrNativeBufferMetadata meta; |
| DvrReadBufferQueue* read_queue = nullptr; |
| DvrWriteBuffer* wb1 = nullptr; |
| DvrWriteBuffer* wb2 = nullptr; |
| DvrWriteBuffer* wb3 = nullptr; |
| AHardwareBuffer* ahb1 = nullptr; |
| AHardwareBuffer* ahb2 = nullptr; |
| AHardwareBuffer* ahb3 = nullptr; |
| AHardwareBuffer_Desc buffer_desc; |
| |
| ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); |
| |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, read_queue); |
| |
| api_.ReadBufferQueueSetBufferRemovedCallback(read_queue, |
| &BufferRemovedCallback, this); |
| |
| // Handle all pending events on the read queue. |
| ret = api_.ReadBufferQueueHandleEvents(read_queue); |
| ASSERT_EQ(0, ret); |
| |
| size_t capacity = api_.ReadBufferQueueGetCapacity(read_queue); |
| ALOGD_IF(TRACE, "TestResizeBuffer, capacity=%zu", capacity); |
| ASSERT_EQ(kQueueCapacity, capacity); |
| |
| // Resize before dequeuing. |
| constexpr uint32_t w1 = 10; |
| ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight); |
| ASSERT_EQ(0, ret); |
| |
| // Gain first buffer for writing. All buffers will be resized. |
| ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, |
| &meta, &fence_fd); |
| ASSERT_EQ(0, ret); |
| ASSERT_TRUE(api_.WriteBufferIsValid(wb1)); |
| ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1); |
| close(fence_fd); |
| |
| // Check the buffer dimension. |
| ret = api_.WriteBufferGetAHardwareBuffer(wb1, &ahb1); |
| ASSERT_EQ(0, ret); |
| AHardwareBuffer_describe(ahb1, &buffer_desc); |
| ASSERT_EQ(w1, buffer_desc.width); |
| ASSERT_EQ(kBufferHeight, buffer_desc.height); |
| AHardwareBuffer_release(ahb1); |
| |
| // For the first resize, all buffers are reallocated. |
| int expected_buffer_removed_count = kQueueCapacity; |
| ret = api_.ReadBufferQueueHandleEvents(read_queue); |
| ASSERT_EQ(0, ret); |
| ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_); |
| |
| // Resize the queue. We are testing with blob format, keep height to be 1. |
| constexpr uint32_t w2 = 20; |
| ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight); |
| ASSERT_EQ(0, ret); |
| |
| // The next buffer we dequeued should have new width. |
| ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, |
| &meta, &fence_fd); |
| ASSERT_EQ(0, ret); |
| ASSERT_TRUE(api_.WriteBufferIsValid(wb2)); |
| ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2, |
| fence_fd); |
| close(fence_fd); |
| |
| // Check the buffer dimension, should be new width |
| ret = api_.WriteBufferGetAHardwareBuffer(wb2, &ahb2); |
| ASSERT_EQ(0, ret); |
| AHardwareBuffer_describe(ahb2, &buffer_desc); |
| ASSERT_EQ(w2, buffer_desc.width); |
| AHardwareBuffer_release(ahb2); |
| |
| // For the second resize, all but one buffers are reallocated. |
| expected_buffer_removed_count += (kQueueCapacity - 1); |
| ret = api_.ReadBufferQueueHandleEvents(read_queue); |
| ASSERT_EQ(0, ret); |
| ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_); |
| |
| // Resize the queue for the third time. |
| constexpr uint32_t w3 = 30; |
| ret = api_.WriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight); |
| ASSERT_EQ(0, ret); |
| |
| // The next buffer we dequeued should have new width. |
| ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, |
| &meta, &fence_fd); |
| ASSERT_EQ(0, ret); |
| ASSERT_TRUE(api_.WriteBufferIsValid(wb3)); |
| ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3, |
| fence_fd); |
| close(fence_fd); |
| |
| // Check the buffer dimension, should be new width |
| ret = api_.WriteBufferGetAHardwareBuffer(wb3, &ahb3); |
| ASSERT_EQ(0, ret); |
| AHardwareBuffer_describe(ahb3, &buffer_desc); |
| ASSERT_EQ(w3, buffer_desc.width); |
| AHardwareBuffer_release(ahb3); |
| |
| // For the third resize, all but two buffers are reallocated. |
| expected_buffer_removed_count += (kQueueCapacity - 2); |
| ret = api_.ReadBufferQueueHandleEvents(read_queue); |
| ASSERT_EQ(0, ret); |
| ASSERT_EQ(expected_buffer_removed_count, buffer_removed_count_); |
| |
| api_.ReadBufferQueueDestroy(read_queue); |
| } |
| |
| TEST_F(DvrBufferQueueTest, ReadQueueEventFd) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| DvrReadBufferQueue* read_queue = nullptr; |
| ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); |
| |
| ASSERT_EQ(0, ret); |
| ASSERT_NE(nullptr, read_queue); |
| |
| int event_fd = api_.ReadBufferQueueGetEventFd(read_queue); |
| ASSERT_GT(event_fd, 0); |
| } |
| |
| // Verifies a Dvr{Read,Write}BufferQueue contains the same set of |
| // Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id, |
| // the corresponding AHardwareBuffer handle stays the same. |
| TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(0, ret); |
| |
| int fence_fd = -1; |
| DvrReadBufferQueue* read_queue = nullptr; |
| EXPECT_EQ(0, api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue)); |
| |
| // Read buffers. |
| std::array<DvrReadBuffer*, kQueueCapacity> rbs; |
| // Write buffers. |
| std::array<DvrWriteBuffer*, kQueueCapacity> wbs; |
| // Buffer metadata. |
| std::array<DvrNativeBufferMetadata, kQueueCapacity> metas; |
| // Hardware buffers for Read buffers. |
| std::unordered_map<int, AHardwareBuffer*> rhbs; |
| // Hardware buffers for Write buffers. |
| std::unordered_map<int, AHardwareBuffer*> whbs; |
| |
| constexpr int kNumTests = 100; |
| |
| // This test runs the following operations many many times. Thus we prefer to |
| // use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output. |
| std::function<void(size_t i)> Gain = [&](size_t i) { |
| int ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10, |
| &wbs[i], &metas[i], &fence_fd); |
| ASSERT_EQ(ret, 0); |
| ASSERT_LT(fence_fd, 0); // expect invalid fence. |
| ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i])); |
| int buffer_id = api_.WriteBufferGetId(wbs[i]); |
| ASSERT_GT(buffer_id, 0); |
| |
| AHardwareBuffer* hb = nullptr; |
| ASSERT_EQ(0, api_.WriteBufferGetAHardwareBuffer(wbs[i], &hb)); |
| |
| auto whb_it = whbs.find(buffer_id); |
| if (whb_it == whbs.end()) { |
| // If this is a new buffer id, check that total number of unique |
| // hardware buffers won't exceed queue capacity. |
| ASSERT_LT(whbs.size(), kQueueCapacity); |
| whbs.emplace(buffer_id, hb); |
| } else { |
| // If this is a buffer id we have seen before, check that the |
| // buffer_id maps to the same AHardwareBuffer handle. |
| ASSERT_EQ(hb, whb_it->second); |
| } |
| }; |
| |
| std::function<void(size_t i)> Post = [&](size_t i) { |
| ASSERT_TRUE(api_.WriteBufferIsValid(wbs[i])); |
| |
| metas[i].timestamp++; |
| int ret = api_.WriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i], |
| /*fence=*/-1); |
| ASSERT_EQ(ret, 0); |
| }; |
| |
| std::function<void(size_t i)> Acquire = [&](size_t i) { |
| int ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, |
| &rbs[i], &metas[i], &fence_fd); |
| ASSERT_EQ(ret, 0); |
| ASSERT_LT(fence_fd, 0); // expect invalid fence. |
| ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i])); |
| |
| int buffer_id = api_.ReadBufferGetId(rbs[i]); |
| ASSERT_GT(buffer_id, 0); |
| |
| AHardwareBuffer* hb = nullptr; |
| ASSERT_EQ(0, api_.ReadBufferGetAHardwareBuffer(rbs[i], &hb)); |
| |
| auto rhb_it = rhbs.find(buffer_id); |
| if (rhb_it == rhbs.end()) { |
| // If this is a new buffer id, check that total number of unique hardware |
| // buffers won't exceed queue capacity. |
| ASSERT_LT(rhbs.size(), kQueueCapacity); |
| rhbs.emplace(buffer_id, hb); |
| } else { |
| // If this is a buffer id we have seen before, check that the buffer_id |
| // maps to the same AHardwareBuffer handle. |
| ASSERT_EQ(hb, rhb_it->second); |
| } |
| }; |
| |
| std::function<void(size_t i)> Release = [&](size_t i) { |
| ASSERT_TRUE(api_.ReadBufferIsValid(rbs[i])); |
| |
| int ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i], |
| /*release_fence_fd=*/-1); |
| ASSERT_EQ(ret, 0); |
| }; |
| |
| // Scenario one: |
| for (int i = 0; i < kNumTests; i++) { |
| // Gain all write buffers. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Gain(i)); |
| } |
| // Post all write buffers. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Post(i)); |
| } |
| // Acquire all read buffers. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Acquire(i)); |
| } |
| // Release all read buffers. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Release(i)); |
| } |
| } |
| |
| // Scenario two: |
| for (int i = 0; i < kNumTests; i++) { |
| // Gain and post all write buffers. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Gain(i)); |
| ASSERT_NO_FATAL_FAILURE(Post(i)); |
| } |
| // Acquire and release all read buffers. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Acquire(i)); |
| ASSERT_NO_FATAL_FAILURE(Release(i)); |
| } |
| } |
| |
| // Scenario three: |
| for (int i = 0; i < kNumTests; i++) { |
| // Gain all write buffers then post them in reversed order. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Gain(i)); |
| } |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Post(kQueueCapacity - 1 - i)); |
| } |
| |
| // Acquire all write buffers then release them in reversed order. |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Acquire(i)); |
| } |
| for (size_t i = 0; i < kQueueCapacity; i++) { |
| ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i)); |
| } |
| } |
| } |
| |
| TEST_F(DvrBufferQueueTest, ConsumerReleaseAfterProducerDestroy) { |
| int ret = api_.WriteBufferQueueCreate( |
| kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage, |
| kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); |
| ASSERT_EQ(ret, 0); |
| |
| DvrReadBufferQueue* read_queue = nullptr; |
| DvrReadBuffer* rb = nullptr; |
| DvrWriteBuffer* wb = nullptr; |
| DvrNativeBufferMetadata meta1; |
| DvrNativeBufferMetadata meta2; |
| int fence_fd = -1; |
| |
| ret = api_.WriteBufferQueueCreateReadQueue(write_queue_, &read_queue); |
| ASSERT_EQ(ret, 0); |
| |
| api_.ReadBufferQueueSetBufferAvailableCallback( |
| read_queue, &BufferAvailableCallback, this); |
| |
| // Gain buffer for writing. |
| ret = api_.WriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, |
| &meta1, &fence_fd); |
| ASSERT_EQ(ret, 0); |
| close(fence_fd); |
| |
| // Post buffer to the read_queue. |
| ret = api_.WriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1); |
| ASSERT_EQ(ret, 0); |
| wb = nullptr; |
| |
| // Acquire buffer for reading. |
| ret = api_.ReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, |
| &meta2, &fence_fd); |
| ASSERT_EQ(ret, 0); |
| close(fence_fd); |
| |
| // Destroy the write buffer queue and make sure the reader queue is picking |
| // these events up. |
| api_.WriteBufferQueueDestroy(write_queue_); |
| ret = api_.ReadBufferQueueHandleEvents(read_queue); |
| ASSERT_EQ(0, ret); |
| |
| // Release buffer to the write_queue. |
| ret = api_.ReadBufferQueueReleaseBuffer(read_queue, rb, &meta2, |
| /*release_fence_fd=*/-1); |
| ASSERT_EQ(ret, 0); |
| rb = nullptr; |
| |
| api_.ReadBufferQueueDestroy(read_queue); |
| } |
| |
| } // namespace |