Android SurfaceFlinger3 申请Buffer
发布日期:2021-05-06 20:20:23 浏览次数:18 分类:技术文章

本文共 16082 字,大约阅读时间需要 53 分钟。

在这里插入图片描述

本章节思维导图如上。主要讲述了 surafce 测试程序 demo 的第3步中的获取 Buffer,锁定(最关键)并写入 Buffer 的过程。

一 概述

该部分代码是在上一章节中 Surface 测试程序源码的精简版,保存了最关键的流程,如下所示:

#include 
#include
#include
#include
#include
#include
#include
#include
using namespace android; int main(int argc, char** argv){ //1 创建surfaceflinger的客户端 sp
client = new SurfaceComposerClient(); //2 获取surface sp
surfaceControl = client->createSurface(String8("resize"), 160, 240, PIXEL_FORMAT_RGB_565, 0); sp
surface = surfaceControl->getSurface(); //设置layer,layer值越大,显示层越靠前 SurfaceComposerClient::openGlobalTransaction(); surfaceControl->setLayer(100000); SurfaceComposerClient::closeGlobalTransaction(); //3 获取buffer->锁定buffer->写入buffer->解锁并提交buffer //这里主要关注:申请Buff 和 提交Buff ANativeWindow_Buffer outBuffer; surface->lock(&outBuffer, NULL); ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height); surface->unlockAndPost(); //... return 0;}

主要的步骤为:

  • 获取 SurfaceFlinger(后简称 SF)的客户端,通过 SF 的客户端获取 SurfaceControl,进而获得 Surface
  • 通过 SurfaceControl 设置 Layer 层数值(忽略),通过 Surface 获取 Buffer,锁定 Buffer 并写入 Buffer
  • 最后提交 Buffer

本章节主要关注获取 Buffer,锁定(最关键)并写入 Buffer 的过程。而获取 Buffer 只是通过ANativeWindow_Buffer 来创建一个 outBuffer 并传递给 Surface 的 lock 方法,写入 Buffer 只是最终使用 memset 向 Buffer 中写入数据。因此最关键也最繁琐的部分是 Surface 的 lock 方法,主要分析整个方法,对应代码为:

status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds){
if (mLockedBuffer != 0) {
ALOGE("Surface::lock failed, already locked"); return INVALID_OPERATION; } //获取显示器一些信息 if (!mConnectedToCpu) {
int err = Surface::connect(NATIVE_WINDOW_API_CPU); if (err) {
return err; } // we're intending to do software rendering from this point setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); } ANativeWindowBuffer* out; int fenceFd = -1; //关键点1 status_t err = dequeueBuffer(&out, &fenceFd); ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); if (err == NO_ERROR) {
sp
backBuffer(GraphicBuffer::getSelf(out)); const Rect bounds(backBuffer->width, backBuffer->height); Region newDirtyRegion; if (inOutDirtyBounds) {
newDirtyRegion.set(static_cast
(*inOutDirtyBounds)); newDirtyRegion.andSelf(bounds); } else {
newDirtyRegion.set(bounds); } // figure out if we can copy the frontbuffer back const sp
& frontBuffer(mPostedBuffer); const bool canCopyBack = (frontBuffer != 0 && backBuffer->width == frontBuffer->width && backBuffer->height == frontBuffer->height && backBuffer->format == frontBuffer->format); if (canCopyBack) {
// copy the area that is invalid and not repainted this round const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); if (!copyback.isEmpty()) copyBlt(backBuffer, frontBuffer, copyback); } else {
// if we can't copy-back anything, modify the user's dirty // region to make sure they redraw the whole buffer newDirtyRegion.set(bounds); mDirtyRegion.clear(); Mutex::Autolock lock(mMutex); for (size_t i=0 ; i
= 0) {
Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); mDirtyRegion.subtract(dirtyRegion); dirtyRegion = newDirtyRegion; } } mDirtyRegion.orSelf(newDirtyRegion); if (inOutDirtyBounds) {
*inOutDirtyBounds = newDirtyRegion.getBounds(); } void* vaddr; //关键点2 status_t res = backBuffer->lockAsync( GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd); if (res != 0) {
err = INVALID_OPERATION; } else {
mLockedBuffer = backBuffer; //构造 outbuffer 变量 outBuffer->width = backBuffer->width; outBuffer->height = backBuffer->height; outBuffer->stride = backBuffer->stride; outBuffer->format = backBuffer->format; outBuffer->bits = vaddr;//mmap映射地址 } } return err;}

二 Surface.dequeueBuffer

Surface 的 dequeueBuffer 方法,代码实现如下:

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
//... int buf = -1; sp
fence; //生产者,向SurfaceFlinger发出Buffer申请,得到 buffer,一个mslots数组的元素 status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, swapIntervalZero, reqW, reqH, reqFormat, reqUsage); //... if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
//向SF请求并返回fd,然后在APP这边mmap result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) {
mGraphicBufferProducer->cancelBuffer(buf, fence); return result; } } //... *buffer = gbuf.get(); return OK;}

这里关注两个关键方法,mGraphicBufferProducer 的 dequeueBuffer 方法和 mGraphicBufferProducer 的 requestBuffer 方法。

2.1 GraphicBufferProducer.dequeueBuffer

status_t BufferQueueProducer::dequeueBuffer(int *outSlot,        sp
*outFence, bool async, uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
//... {
// Autolock scope //... int found; //得到空闲的slots元素并锁定 status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, &found, &returnFlags); if (status != NO_ERROR) {
return status; } //... } // Autolock scope //如果需要则重新分配 if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error; BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); sp
graphicBuffer(mCore->mAllocator->createGraphicBuffer( width, height, format, usage, &error)); if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed"); return error; } {
// Autolock scope Mutex::Autolock lock(mCore->mMutex); if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned"); return NO_INIT; } mSlots[*outSlot].mFrameNumber = UINT32_MAX; mSlots[*outSlot].mGraphicBuffer = graphicBuffer; } // Autolock scope } if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION; } //... return returnFlags;}

这里专注两段代码:waitForFreeSlotThenRelock 方法和 graphicBuffer 的创建。

2.1.1 GraphicBufferProducer.waitForFreeSlotThenRelock

status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,        bool async, int* found, status_t* returnFlags) const {
bool tryAgain = true; while (tryAgain) {
if (mCore->mIsAbandoned) {
BQ_LOGE("%s: BufferQueue has been abandoned", caller); return NO_INIT; } //... // Look for a free buffer to give to the client *found = BufferQueueCore::INVALID_BUFFER_SLOT; int dequeuedCount = 0; int acquiredCount = 0; for (int s = 0; s < maxBufferCount; ++s) {
switch (mSlots[s].mBufferState) {
case BufferSlot::DEQUEUED: ++dequeuedCount; break; case BufferSlot::ACQUIRED: ++acquiredCount; break; case BufferSlot::FREE: // We return the oldest of the free buffers to avoid // stalling the producer if possible, since the consumer // may still have pending reads of in-flight buffers if (*found == BufferQueueCore::INVALID_BUFFER_SLOT || mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
*found = s; } break; default: break; } } //... } // while (tryAgain) return NO_ERROR;}

最为关键的就是上面这段,主要功能是在 mSlots 数组中找到已经 FREE 的空余 Buffer 并通过下标方式返回(下标为上段代码中的 found)

2.1.2 graphicBuffer的创建

在创建 graphicBuffer 时,这里传递了一个参数,是这样一句话:

mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error)

这里主要是调用了 BufferQueueCore 中的成员变量 mAllocator(IGraphicBufferAlloc类型)的 createGraphicBuffer 方法,这段代码比较简单,最终返回一个 GraphicBuffer 类型的变量,代码如下:

sp
GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, status_t* error) {
sp
graphicBuffer(new GraphicBuffer(w, h, format, usage)); status_t err = graphicBuffer->initCheck(); *error = err; if (err != 0 || graphicBuffer->handle == 0) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog(); } ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " "failed (%s), handle=%p", w, h, strerror(-err), graphicBuffer->handle); return 0; } return graphicBuffer;}

之后我们详细分析下这里 sp graphicBuffer(…) 对应的构造器,代码如下:

GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,         PixelFormat reqFormat, uint32_t reqUsage)    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),      mInitCheck(NO_ERROR), mId(getUniqueId()){
width = w; height = h; stride = inStride; format = inFormat; usage = 0; handle = NULL; mInitCheck = initSize(w, h, reqFormat, reqUsage);}

这里继续分析 initSize,代码如下:

status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,        uint32_t reqUsage){
//打开 Gralloc 模块 GraphicBufferAllocator& allocator = GraphicBufferAllocator::get(); //调用 HAL 模块的 alloc 函数 status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride); if (err == NO_ERROR) {
this->width = w; this->height = h; this->format = format; this->usage = reqUsage; } return err;}

这里主要是调用了 gralloc 模块,获取 allocator 的代码如下:

GraphicBufferAllocator::GraphicBufferAllocator()    : mAllocDev(0){
hw_module_t const* module; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID); if (err == 0) {
gralloc_open(module, &mAllocDev); }}

之后使用 allocator.alloc 来申请内存。代码如下:

status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,        int usage, buffer_handle_t* handle, int32_t* stride){
if (!w || !h) w = h = 1; // we have a h/w allocator and h/w buffer is requested status_t err; err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride); if (err == NO_ERROR) {
Mutex::Autolock _l(sLock); KeyedVector
& list(sAllocList); int bpp = bytesPerPixel(format); if (bpp < 0) {
// probably a HAL custom format. in any case, we don't know // what its pixel size is. bpp = 0; } alloc_rec_t rec; rec.w = w; rec.h = h; rec.s = *stride; rec.format = format; rec.usage = usage; rec.size = h * stride[0] * bpp; list.add(*handle, rec); } return err;}

这里调用了 mAllocDev->alloc 方法,再往下就是 HAL 层 Gralloc 模块的调用了,在 Gralloc 模块初始化的时候,代码如下:

int gralloc_device_open(const hw_module_t* module, const char* name,        hw_device_t** device){
int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
gralloc_context_t *dev; dev = (gralloc_context_t*)malloc(sizeof(*dev)); /* initialize our state here */ memset(dev, 0, sizeof(*dev)); /* initialize the procs */ dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.version = 0; dev->device.common.module = const_cast
(module); dev->device.common.close = gralloc_close; dev->device.alloc = gralloc_alloc; dev->device.free = gralloc_free; *device = &dev->device.common; status = 0; } else {
status = fb_device_open(module, name, device); } return status;}

所以这里的 mAllocDev->alloc 方法 就是 Gralloc 模块对应的 gralloc_alloc 方法,代码如下:

static int gralloc_alloc(alloc_device_t* dev,        int w, int h, int format, int usage,        buffer_handle_t* pHandle, int* pStride){
//... int err; if (usage & GRALLOC_USAGE_HW_FB) {
err = gralloc_alloc_framebuffer(dev, size, usage, pHandle); } else {
err = gralloc_alloc_buffer(dev, size, usage, pHandle); } //... *pStride = stride; return 0;}

因为是申请 buffer,所以这里选择的是 gralloc_alloc_buffer,继续分析代码,如下所示:

static int gralloc_alloc_buffer(alloc_device_t* dev,        size_t size, int /*usage*/, buffer_handle_t* pHandle){
//... fd = ashmem_create_region("gralloc-buffer", size); //... if (err == 0) {
private_handle_t* hnd = new private_handle_t(fd, size, 0); gralloc_module_t* module = reinterpret_cast
( dev->common.module); err = mapBuffer(module, hnd); if (err == 0) {
*pHandle = hnd; } } return err;}

这里主要通过 ashmem 共享内存机制来分配内存 Buffer,得到 fd;同时使用 fd 和 mmap 生成的 Buffer 一同来构造一个 handle。这其中 mmap 生成的地址直接供 SF 使用。

2.2 GraphicBufferProducer.requestBuffer

此时 SF 已经得到了 handle(要申请的 Buffer 的句柄 fd 和 mmap 的首地址的集合)。接下来调用 requestBuffer 使用 binder 机制把 SF 的 handle 传递给 APP(这个分析过程中忽略了 Binder 通信部分的分析,Binder 通信部分详见系列文章链接:专题分纲目录 android 系统核心机制 binder)。BufferQueueProducer 的 requestBuffer 代码实现如下:

status_t BufferQueueProducer::requestBuffer(int slot, sp
* buf) {
Mutex::Autolock lock(mCore->mMutex); //... mSlots[slot].mRequestBufferCalled = true; *buf = mSlots[slot].mGraphicBuffer; return NO_ERROR;}

2.3 总结

APP 对应一个 client,一个 SurfaceControl 对应一个 Layer,每个 Surface 都对应一个 mslots 数组(mslots 数组中共有64个元素,每个元素中包含一个 GraphicBuffer 和一个 handle,包含 fd 和 mmap 的映射地址)。Surface 获得 Buffer 的过程如下:

  • 首先执行 dequeueBuffer。若 Surface 无 Buffer,则向生产者 producer(GraphicBufferProducer 类对象,最终通过 SF 操作)申请,查看 mslots 有无余项,若有直接返回,若无则向 Gralloc HAL 申请,得到一个 handle(要申请的 Buffer 的句柄 fd 和 mmap 的首地址的集合)
  • 其次执行 requestBuffer,APP(Client 端)通过该方法将 SF 获得的 handle 转移到 Client 端的 handle 中
  • APP 获得 fd,mmap 获得地址(通过 Gralloc HAL 来执行 mmap),接下来向 Buffer 中写入内容即可

三 GraphicBuffer.lockAsync

status_t GraphicBuffer::lockAsync(uint32_t usage, const Rect& rect, void** vaddr,     int fenceFd){
//... status_t res = getBufferMapper().lockAsync(handle, usage, rect, vaddr, fenceFd); return res;}

继续分析 GraphicBufferMapper 的 lockAsync 方法,代码实现如下:

status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,        int usage, const Rect& bounds, void** vaddr, int fenceFd){
status_t err; if (mAllocMod->common.module_api_version >= GRALLOC_MODULE_API_VERSION_0_3) {
err = mAllocMod->lockAsync(mAllocMod, handle, usage, bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr, fenceFd); } else {
sync_wait(fenceFd, -1); close(fenceFd); err = mAllocMod->lock(mAllocMod, handle, usage, bounds.left, bounds.top, bounds.width(), bounds.height(), vaddr); } return err;}

这里继续分析会进入到 HAL 层,对应的是 Gralloc 模块的 gralloc_lock 函数,代码实现如下:

int gralloc_lock(gralloc_module_t const* /*module*/,        buffer_handle_t handle, int /*usage*/,        int /*l*/, int /*t*/, int /*w*/, int /*h*/,        void** vaddr){
if (private_handle_t::validate(handle) < 0) return -EINVAL; private_handle_t* hnd = (private_handle_t*)handle; *vaddr = (void*)hnd->base; return 0;}

这里主要是将 handle->base 赋值给 backBuffer->lockAsync 的参数 vaddr,这个同样也是 APP 中使用 mmap 映射的地址。最后会通过 outBuffer->bits = vaddr 这个赋值操作用 backBuffer 的成员变量初始化 outBuffer。

上一篇:Android SurfaceFlinger4 提交Buffer
下一篇:理解PendingIntent

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年04月02日 08时58分01秒