You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
6.6 KiB
207 lines
6.6 KiB
4 months ago
|
/*
|
||
|
* Copyright (C) 2017 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
#define LOG_TAG "BufferItemConsumer_test"
|
||
|
//#define LOG_NDEBUG 0
|
||
|
|
||
|
#include <gtest/gtest.h>
|
||
|
#include <gui/BufferItemConsumer.h>
|
||
|
#include <gui/IProducerListener.h>
|
||
|
#include <gui/Surface.h>
|
||
|
|
||
|
namespace android {
|
||
|
|
||
|
static constexpr int kWidth = 100;
|
||
|
static constexpr int kHeight = 100;
|
||
|
static constexpr int kMaxLockedBuffers = 3;
|
||
|
static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
|
||
|
static constexpr int kFrameSleepUs = 30 * 1000;
|
||
|
|
||
|
class BufferItemConsumerTest : public ::testing::Test {
|
||
|
protected:
|
||
|
struct BufferFreedListener
|
||
|
: public BufferItemConsumer::BufferFreedListener {
|
||
|
explicit BufferFreedListener(BufferItemConsumerTest* test)
|
||
|
: mTest(test) {}
|
||
|
void onBufferFreed(const wp<GraphicBuffer>& /* gBuffer */) override {
|
||
|
mTest->HandleBufferFreed();
|
||
|
}
|
||
|
BufferItemConsumerTest* mTest;
|
||
|
};
|
||
|
|
||
|
void SetUp() override {
|
||
|
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
|
||
|
mBIC =
|
||
|
new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true);
|
||
|
String8 name("BufferItemConsumer_Under_Test");
|
||
|
mBIC->setName(name);
|
||
|
mBFL = new BufferFreedListener(this);
|
||
|
mBIC->setBufferFreedListener(mBFL);
|
||
|
|
||
|
sp<IProducerListener> producerListener = new StubProducerListener();
|
||
|
IGraphicBufferProducer::QueueBufferOutput bufferOutput;
|
||
|
ASSERT_EQ(NO_ERROR,
|
||
|
mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
|
||
|
true, &bufferOutput));
|
||
|
ASSERT_EQ(NO_ERROR,
|
||
|
mProducer->setMaxDequeuedBufferCount(kMaxLockedBuffers));
|
||
|
}
|
||
|
|
||
|
int GetFreedBufferCount() {
|
||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
return mFreedBufferCount;
|
||
|
}
|
||
|
|
||
|
void HandleBufferFreed() {
|
||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
mFreedBufferCount++;
|
||
|
ALOGV("HandleBufferFreed, mFreedBufferCount=%d", mFreedBufferCount);
|
||
|
}
|
||
|
|
||
|
void DequeueBuffer(int* outSlot) {
|
||
|
ASSERT_NE(outSlot, nullptr);
|
||
|
|
||
|
int slot;
|
||
|
sp<Fence> outFence;
|
||
|
status_t ret = mProducer->dequeueBuffer(&slot, &outFence, kWidth, kHeight, 0, 0,
|
||
|
nullptr, nullptr);
|
||
|
ASSERT_GE(ret, 0);
|
||
|
|
||
|
ALOGV("dequeueBuffer: slot=%d", slot);
|
||
|
if (ret & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
|
||
|
ret = mProducer->requestBuffer(slot, &mBuffers[slot]);
|
||
|
ASSERT_EQ(NO_ERROR, ret);
|
||
|
}
|
||
|
*outSlot = slot;
|
||
|
}
|
||
|
|
||
|
void QueueBuffer(int slot) {
|
||
|
ALOGV("enqueueBuffer: slot=%d", slot);
|
||
|
IGraphicBufferProducer::QueueBufferInput bufferInput(
|
||
|
0ULL, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT,
|
||
|
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
|
||
|
IGraphicBufferProducer::QueueBufferOutput bufferOutput;
|
||
|
status_t ret = mProducer->queueBuffer(slot, bufferInput, &bufferOutput);
|
||
|
ASSERT_EQ(NO_ERROR, ret);
|
||
|
}
|
||
|
|
||
|
void AcquireBuffer(int* outSlot) {
|
||
|
ASSERT_NE(outSlot, nullptr);
|
||
|
BufferItem buffer;
|
||
|
status_t ret = mBIC->acquireBuffer(&buffer, 0, false);
|
||
|
ASSERT_EQ(NO_ERROR, ret);
|
||
|
|
||
|
ALOGV("acquireBuffer: slot=%d", buffer.mSlot);
|
||
|
*outSlot = buffer.mSlot;
|
||
|
}
|
||
|
|
||
|
void ReleaseBuffer(int slot) {
|
||
|
ALOGV("releaseBuffer: slot=%d", slot);
|
||
|
BufferItem buffer;
|
||
|
buffer.mSlot = slot;
|
||
|
buffer.mGraphicBuffer = mBuffers[slot];
|
||
|
status_t ret = mBIC->releaseBuffer(buffer, Fence::NO_FENCE);
|
||
|
ASSERT_EQ(NO_ERROR, ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
std::mutex mMutex;
|
||
|
int mFreedBufferCount{0};
|
||
|
|
||
|
sp<BufferItemConsumer> mBIC;
|
||
|
sp<BufferFreedListener> mBFL;
|
||
|
sp<IGraphicBufferProducer> mProducer;
|
||
|
sp<IGraphicBufferConsumer> mConsumer;
|
||
|
sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
|
||
|
};
|
||
|
|
||
|
// Test that detaching buffer from consumer side triggers onBufferFreed.
|
||
|
TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) {
|
||
|
int slot;
|
||
|
// Producer: generate a placeholder buffer.
|
||
|
DequeueBuffer(&slot);
|
||
|
QueueBuffer(slot);
|
||
|
|
||
|
ASSERT_EQ(0, GetFreedBufferCount());
|
||
|
// Consumer: acquire the buffer and then detach it.
|
||
|
AcquireBuffer(&slot);
|
||
|
status_t ret = mBIC->detachBuffer(slot);
|
||
|
ASSERT_EQ(NO_ERROR, ret);
|
||
|
|
||
|
// Sleep to give some time for callbacks to happen.
|
||
|
usleep(kFrameSleepUs);
|
||
|
ASSERT_EQ(1, GetFreedBufferCount());
|
||
|
}
|
||
|
|
||
|
// Test that detaching buffer from producer side triggers onBufferFreed.
|
||
|
TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromProducer) {
|
||
|
int slot;
|
||
|
// Let buffer go through the cycle at least once.
|
||
|
DequeueBuffer(&slot);
|
||
|
QueueBuffer(slot);
|
||
|
AcquireBuffer(&slot);
|
||
|
ReleaseBuffer(slot);
|
||
|
|
||
|
ASSERT_EQ(0, GetFreedBufferCount());
|
||
|
|
||
|
// Producer: generate the buffer again.
|
||
|
DequeueBuffer(&slot);
|
||
|
|
||
|
// Producer: detach the buffer.
|
||
|
status_t ret = mProducer->detachBuffer(slot);
|
||
|
ASSERT_EQ(NO_ERROR, ret);
|
||
|
|
||
|
// Sleep to give some time for callbacks to happen.
|
||
|
usleep(kFrameSleepUs);
|
||
|
ASSERT_EQ(1, GetFreedBufferCount());
|
||
|
}
|
||
|
|
||
|
// Test that abandoning BufferItemConsumer triggers onBufferFreed.
|
||
|
TEST_F(BufferItemConsumerTest, TriggerBufferFreed_AbandonBufferItemConsumer) {
|
||
|
int slot;
|
||
|
// Let buffer go through the cycle at least once.
|
||
|
DequeueBuffer(&slot);
|
||
|
QueueBuffer(slot);
|
||
|
AcquireBuffer(&slot);
|
||
|
ReleaseBuffer(slot);
|
||
|
|
||
|
// Abandon the BufferItemConsumer.
|
||
|
mBIC->abandon();
|
||
|
|
||
|
// Sleep to give some time for callbacks to happen.
|
||
|
usleep(kFrameSleepUs);
|
||
|
ASSERT_EQ(1, GetFreedBufferCount());
|
||
|
}
|
||
|
|
||
|
// Test that delete BufferItemConsumer triggers onBufferFreed.
|
||
|
TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) {
|
||
|
int slot;
|
||
|
// Let buffer go through the cycle at least once.
|
||
|
DequeueBuffer(&slot);
|
||
|
QueueBuffer(slot);
|
||
|
AcquireBuffer(&slot);
|
||
|
ReleaseBuffer(slot);
|
||
|
|
||
|
// Delete the BufferItemConsumer.
|
||
|
mBIC.clear();
|
||
|
|
||
|
// Sleep to give some time for callbacks to happen.
|
||
|
usleep(kFrameSleepUs);
|
||
|
ASSERT_EQ(1, GetFreedBufferCount());
|
||
|
}
|
||
|
|
||
|
} // namespace android
|