surface lock
主要用于锁定(获取)一个图像缓冲区,以便应用程序可以直接读取或写入该缓冲区的像素数据。
- 调用dequeueBuffer方法从队列中取出一个可用的缓冲区,并将其存储在out参数中
- 通过GraphicBuffer::getSelf方法获取到该缓冲区对应的GraphicBuffer对象backBuffer,并根据其宽度和高度构建一个矩形bounds。
- 根据传入的inOutDirtyBounds参数(表示脏区域的边界),创建一个新的脏区域newDirtyRegion。如果inOutDirtyBounds为空,则将脏区域设为整个缓冲区的范围。
- 调用backBuffer的lockAsync方法,异步地锁定(映射)缓冲区的内存,并将结果存储在vaddr指针中。同时,设置了GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN标志,表示应用程序将频繁地读取和写入缓冲区的像素数据。fenceFd参数用于同步访问缓冲区的操作。
- 将锁定的缓冲区信息保存在outBuffer结构体中,包括宽度、高度、步长、格式和像素数据的指针。
status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) {
status_t err = dequeueBuffer(&out, &fenceFd); // 从缓冲区队列中取出一个可用的缓冲区
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out)); // 获取该缓冲区对应的GraphicBuffer对象
const Rect bounds(backBuffer->width, backBuffer->height); // 构建矩形表示缓冲区的范围
Region newDirtyRegion;
if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds)); // 使用传入的脏区域边界创建新的脏区域
newDirtyRegion.andSelf(bounds); // 将新的脏区域与缓冲区范围取交集
} else {
newDirtyRegion.set(bounds); // 如果未指定脏区域边界,则将整个缓冲区设置为脏区域
}
mDirtyRegion.orSelf(newDirtyRegion); // 将新的脏区域合并到Surface的脏区域中
void* vaddr;
status_t res = backBuffer->lockAsync(
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
newDirtyRegion.bounds(), &vaddr, fenceFd); // 异步锁定(映射)缓冲区的内存
mLockedBuffer = backBuffer; // 将锁定的缓冲区设置为Surface的当前缓冲区
outBuffer->width = backBuffer->width; // 将缓冲区宽度保存在输出结构体中
outBuffer->height = backBuffer->height; // 将缓冲区高度保存在输出结构体中
outBuffer->stride = backBuffer->stride; // 将缓冲区步长保存在输出结构体中
outBuffer->format = backBuffer->format; // 将缓冲区格式保存在输出结构体中
outBuffer->bits = vaddr; // 将缓冲区像素数据的指针保存在输出结构体中
}
}
Surface dequeueBuffer
dequeueBuffer用于从缓冲区队列中取出一个可用的缓冲区,并返回该缓冲区对应的android_native_buffer_t对象和Fence对象的文件描述符。
- Surface设置了共享缓冲区模式、自动刷新且当前共享缓冲区不为空,则直接返回共享缓冲区。
- 调用mGraphicBufferProducer的dequeueBuffer方法从缓冲区队列中取出一个可用的缓冲区,并获取该缓冲区对应的GraphicBuffer对象。
- 该缓冲区需要重新分配或者对应的GraphicBuffer对象为空,调用mGraphicBufferProducer的requestBuffer方法重新请求该缓冲区,并获取新的GraphicBuffer对象。
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
// 如果Surface设置了共享缓冲区模式、自动刷新且当前共享缓冲区不为空
if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) {
sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer); // 获取共享缓冲区对应的GraphicBuffer对象
if (gbuf != nullptr) { // 如果GraphicBuffer对象不为空
*buffer = gbuf.get(); // 将android_native_buffer_t对象指针设置为该GraphicBuffer对象
*fenceFd = -1; // 设置文件描述符为-1,表示没有Fence对象
return OK; // 返回执行成功
}
}
// 从缓冲区队列中取出一个可用的缓冲区,并返回该缓冲区对应的android_native_buffer_t对象和Fence对象的文件描述符
status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width,
dqInput.height, dqInput.format,
dqInput.usage, &mBufferAge,
dqInput.getTimestamps ?
&frameTimestamps : nullptr);
// 获取该缓冲区对应的GraphicBuffer对象
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
// 如果该缓冲区需要重新分配或者对应的GraphicBuffer对象为空
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
// 如果需要记录移除的缓冲区,将该GraphicBuffer对象添加到列表中
if (mReportRemovedBuffers && (gbuf != nullptr)) {
mRemovedBuffers.push_back(gbuf);
}
// 重新请求该缓冲区,并获取新的GraphicBuffer对象
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
}
// 将android_native_buffer_t对象指针设置为该缓冲区对应的GraphicBuffer对象
*buffer = gbuf.get();
// 将Fence对象的文件描述符保存到输出参数中
*fenceFd = fence->dup();
// 将该缓冲区标记为已取出状态
mDequeuedSlots.insert(buf);
}
总结
总之,Surface::lock主要目的是获取一个可用的图像缓冲区,并锁定该缓冲区以进行读写操作。
还记录了脏区域的边界,并返回缓冲区的相关信息给调用者,以便用户对buffer进行操作。
创作不易,欢迎点赞收藏。