void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const {
ATRACE_CALL();
while (mIsAllocating) {
mIsAllocatingCondition.wait(lock);
}
}
status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* outFence,
uint32_t width, uint32_t height, PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
// If we don't have a free buffer, but we are currently allocating, we wait until allocation
// is finished such that we don't allocate in parallel.
if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
mDequeueWaitingForAllocation = true;
mCore->waitWhileAllocatingLocked(lock);
mDequeueWaitingForAllocation = false;
mDequeueWaitingForAllocationCondition.notify_all();
}
...
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
mCore->mIsAllocating = true;
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
} // Autolock scope
...
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error = graphicBuffer->initCheck();
{ // Autolock scope
std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
} // Autolock scope
}
}
void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
PixelFormat format, uint64_t usage) {
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked(lock);
...
mCore->mIsAllocating = true;
} // Autolock scope
status_t result = graphicBuffer->initCheck();
...
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.notify_all();
// 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
}