// Allocates buffers based on the given dimensions/format.
//
// This function will allocate up to the maximum number of buffers
// permitted by the current BufferQueue configuration. It will use the
// given format, dimensions, and usage bits, which are interpreted in the
// same way as for dequeueBuffer, and the async flag must be set the same
// way as for dequeueBuffer to ensure that the correct number of buffers are
// allocated. This is most useful to avoid an allocation delay during
// dequeueBuffer. If there are already the maximum number of buffers
// allocated, this function has no effect.
void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
PixelFormat format, uint64_t usage) {
根据参数分配 buffer,该函数会根据 BufferQueue 允许的最大数量分配 buffer。它的最大用处是避免分配延迟,但没看到哪里在使用。
还是简单把实现机制说明一下。
while (true) {
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked(lock);
if (!mCore->mAllowAllocation) {
BQ_LOGE("allocateBuffers: allocation is not allowed for this "
"BufferQueue");
return;
}
// Only allocate one buffer at a time to reduce risks of overlapping an allocation from
// both allocateBuffers and dequeueBuffer.
newBufferCount = mCore->mFreeSlots.empty() ? 0 : 1;
if (newBufferCount == 0) {
return;
}
mCore->mIsAllocating = true;
} // Autolock scope
mFreeSlots
为空。设置 mIsAllocating
为 true
,释放锁,开始分配 buffer。Vector<sp<GraphicBuffer>> buffers;
for (size_t i = 0; i < newBufferCount; ++i) {
sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
allocUsage, allocName);
status_t result = graphicBuffer->initCheck();
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
" %u, usage %#" PRIx64 ")", width, height, format, usage);
std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
return;
}
buffers.push_back(graphicBuffer);
}
mIsAllocating
为 false
,并通知 mIsAllocatingCondition
,否则加入到 buffers
。{ // Autolock scope
if (checkWidth != allocWidth || checkHeight != allocHeight ||
checkFormat != allocFormat || checkUsage != allocUsage) {
// Something changed while we released the lock. Retry.
BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
continue;
}
for (size_t i = 0; i < newBufferCount; ++i) {
if (mCore->mFreeSlots.empty()) {
BQ_LOGV("allocateBuffers: a slot was occupied while "
"allocating. Dropping allocated buffer.");
continue;
}
auto slot = mCore->mFreeSlots.begin();
mCore->clearBufferSlotLocked(*slot); // Clean up the slot first
mSlots[*slot].mGraphicBuffer = buffers[i];
mSlots[*slot].mFence = Fence::NO_FENCE;
// freeBufferLocked puts this slot on the free slots list. Since
// we then attached a buffer, move the slot to free buffer list.
mCore->mFreeBuffers.push_front(*slot);
BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d",
*slot);
// Make sure the erase is done after all uses of the slot
// iterator since it will be invalid after this point.
mCore->mFreeSlots.erase(slot);
}
mFreeSlots
空了说明其他线程占用了 slot,重新分配。mFreeSlots
中取一个 slot,清除相关的属性,设置 mGraphicBuffer
和 mFence
,然后加入到 mFreeBuffers
中,最后从 mFreeSlots
移除。 mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
VALIDATE_CONSISTENCY();
// If dequeue is waiting for to allocate a buffer, release the lock until it's not
// waiting anymore so it can use the buffer we just allocated.
while (mDequeueWaitingForAllocation) {
mDequeueWaitingForAllocationCondition.wait(lock);
}
} // Autolock scope
} // while