显示系统[4] APP申请创建Buffer分配Buffer的过程

这篇博客详细解析了Android系统中Surface如何通过dequeueBuffer申请和锁住buffer,以及内存分配的过程。从Surface的lock方法开始,经过IGraphicBufferProducer的跨进程通信,到BufferQueueProducer的内存分配,最后通过GrallocHAL模块完成实际的内存分配。整个流程涉及到的关键技术包括BufferQueue、 GraphicBuffer、Gralloc和Binder通信。
部署运行你感兴趣的模型镜像

  申请buffer 

ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);

  首先使用dequeueBuffer申请buffer然后把这个buffer包装成backBuffer

  最后调用backBuffer->lockAsync得到一个vaddr(虚拟地址) 

  然后把这个vaddr(虚拟地址)赋值给outBuffer->bits,这个就是最终把数据填充的地址

  路径  frameworks/native/libs/gui/Surface.cpp

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;
    //从队列中取出buffer
    status_t err = dequeueBuffer(&out, &fenceFd);
    if (err == NO_ERROR) {
        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
        const Rect bounds(backBuffer->width, backBuffer->height);
    ...
    void* vaddr;
    status_t res = backBuffer->lockAsync(
           GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
           newDirtyRegion.bounds(), &vaddr, fenceFd);

    ALOGW_IF(res, "failed locking buffer (handle = %p)",backBuffer->handle);
    if (res != 0) {
            err = INVALID_OPERATION;
        } else {
            mLockedBuffer = backBuffer;
            outBuffer->width  = backBuffer->width;
            outBuffer->height = backBuffer->height;
            outBuffer->stride = backBuffer->stride;
            outBuffer->format = backBuffer->format;
            outBuffer->bits   = vaddr;
        }
    ...
}

   SurfacedequeueBuffer 会跨进程调用

   远程的mGraphicBufferProducer消费者的dequeueBuffer

   mGraphicBufferProducer->dequeueBuffer

       surfaceflinger发出申请,surfaceflinger申请内存。得到bufint类型是数组mSlots下标。

       向surfaceflinger请求返回文件句柄fd,然后返回在app端mmap

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ATRACE_CALL();
    ALOGV("Surface::dequeueBuffer");
    ...
    int buf = -1;
    sp<Fence> fence;
    nsecs_t startTime = systemTime();

    FrameEventHistoryDelta frameTimestamps;
    status_t result = mGraphicBufferProducer->dequeueBuffer(
                      &buf, &fence, reqWidth, reqHeight,
                      reqFormat,reqUsage,&mBufferAge,
                      enableFrameTimestamps ? 
                                &frameTimestamps : nullptr);
    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
        if (mReportRemovedBuffers && (gbuf != nullptr)) {
            mRemovedBuffers.push_back(gbuf);
        }
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
        if (result != NO_ERROR) {
            ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
            mGraphicBufferProducer->cancelBuffer(buf, fence);
            return result;
        }
    }
}

        mGraphicBufferProducer->dequeueBuffer

       surfaceflinger发出申请,surfaceflinger申请内存。得到bufint类型是数组mSlots下标。

 由此可以看出IGraphicBufferProducer.cpp派生出两个binder通信接口

    BnGraphicBufferProducer  、 BpGraphicBufferProducer(也就是Surface使用的)

    而BnGraphicBufferProducer则派生出了BufferQueueProducer

        waitForFreeSlotThenRelock等待空闲的Slot得到后锁定

        分配buffer

路径  frameworks/native/libs/gui/BufferQueueProducer.cpp

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) {
    ...
    //找到空闲的Slot并锁定
     while (found == BufferItem::INVALID_BUFFER_SLOT) {
            status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
                    &found);
            if (status != NO_ERROR) {
                return status;
            }
    ...
    //判断是否需要分配 需要则分配
    if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
        BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                width, height, format, BQ_LAYER_COUNT, usage,
                {mConsumerName.string(), mConsumerName.size()});

allocator.allocate调用GrallocHAL模块来分配内存

GraphicBufferAllocator::get();构造函数打开HAL模块

  路径  frameworks/native/libs/ui/GraphicBuffer.cpp 

GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
    : GraphicBuffer()
{
    mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
            usage, std::move(requestorName));
}

status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight,
        PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
        std::string requestorName)
{
    //打开HAL模块
    GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
    uint32_t outStride = 0;
    //分配内存
    status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
            inUsage, &handle, &outStride, mId,
            std::move(requestorName));
    if (err == NO_ERROR) {
        width = static_cast<int>(inWidth);
        height = static_cast<int>(inHeight);
        format = inFormat;
        layerCount = inLayerCount;
        usage = inUsage;
        usage_deprecated = int(usage);
        stride = static_cast<int>(outStride);
    }
    return err;
}

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

BufferQueue 的状态机中,表示应用已申请并正在绘制的 Buffer 的状态是 **DEQUEUED**。该状态下,应用程序已经通过 `dequeueBuffer` 方法成功申请到了图形缓冲区,此时 Buffer 的控制权被移交给应用程序,允许其进行图形数据的绘制操作。 在此状态下,Buffer 既不处于空闲状态(FREE),也不处于等待消费的状态(QUEUED),更不是已经被图形消费者(如 SurfaceFlinger)获取用于合成的状态(ACQUIRED)。DEQUEUED 是一个中间状态,标志着 Buffer 正在被应用程序使用,尚未提交回 BufferQueue 等待后续的消费流程[^1]。 ### Buffer 状态流转简要说明 - **FREE → DEQUEUED**:当应用程序调用 `dequeueBuffer` 请求一个 Buffer 时,BufferQueue 会从空闲状态中选择一个 Buffer,并将其状态更改为 DEQUEUED。 - **DEQUEUED → QUEUED**:应用程序完成绘制后调用 `queueBuffer` 将 Buffer 提交回 BufferQueue,此时状态变为 QUEUED,等待图形消费者(如 SurfaceFlinger)进行消费。 - **QUEUED → ACQUIRED**:SurfaceFlinger 调用 `acquireBuffer` 获取该 Buffer 后,状态变为 ACQUIRED,表示正在被消费。 - **ACQUIRED → FREE**:消费完成后,Buffer 的状态重新变为空闲(FREE),可供下一次申请使用。 这种状态管理机制确保了图形数据的生产与消费之间的同步和高效协作。 ### 示例代码片段 以下是一个典型的 `dequeueBuffer` 和 `queueBuffer` 的调用示例: ```cpp // 应用端申请 Buffer int slot; status_t status = bufferQueue->dequeueBuffer(&slot, Fence::NO_FENCE, width, height, format, usage); if (status == OK) { // 使用 slot 对应的 GraphicBuffer 进行绘制 // ... // 绘制完成后将 Buffer 提交回 BufferQueue status = bufferQueue->queueBuffer(slot, queueing_fence); } ``` 上述代码展示了如何通过 `dequeueBuffer` 获取一个 Buffer 插槽索引,并在绘制完成后通过 `queueBuffer` 将其返回 BufferQueue 流程中[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值