当前位置: 首页 > article >正文

Android T(13) 源码分析 — BufferQueue 的分析

Android T(13) 源码分析 — BufferQueue 的分析


文章目录

  • Android T(13) 源码分析 — BufferQueue 的分析
  • 前言
  • 摘要
  • 一、Java 层的 BufferQueue 分析
  • 二、原生层的 BufferQueue 分析
    • 1、BLASTBufferQueue 的创建
    • 2、BLASTBufferQueue 的更新
    • 3、Surface 的创建
  • 总结


前言

该系列文章基于 Android T(13) 的源码进行分析,内容会逐渐丰富,欢迎大家点赞关注。


摘要

BufferQueue 是 Android 图形系统中的一个关键组件,它连接了生成图形数据缓冲区的组件(生产者)和接收这些数据以进行显示或进一步处理的组件(消费者)。几乎所有的图形数据缓冲区在系统中的传递都依赖于 BufferQueue。

当生产者需要一个缓冲区时,通过调用 dequeueBuffer() 从 BufferQueue 请求一个空闲缓冲区,指定缓冲区的宽度、高度、像素格式和使用标志。生产者填充缓冲区后,再调用 queueBuffer() 将缓冲区返回队列。消费者通过 acquireBuffer() 获取缓冲区,并在使用完毕后通过 releaseBuffer() 将缓冲区返回队列,本篇重点介绍一下 BufferQueue 的创建。


一、Java 层的 BufferQueue 分析

BufferQueue 是生产者和消费者的链接纽带,其依托于 SurfaceControl,与 Surface 联系紧密,之前我们分析过 Java 层 SurfaceControl 的创建,当 SurfaceControl 创建成功之后,接下来就进行 BufferQueue 创建。我们还是从 relayoutWindow 开始,看一下生产者端的 BufferQueue 是如何创建的:

//frameworks/base/core/java/android/view/ViewRootImpl.java
    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
    //...
        if (mSurfaceControl.isValid()) {
            if (!useBLAST()) {
                mSurface.copyFrom(mSurfaceControl);
            } else {
                updateBlastSurfaceIfNeeded();
            }
    //...

BLAST特性是 Android 12 新推出的,默认开启,具体看一下 updateBlastSurfaceIfNeeded 实现:

//frameworks/base/core/java/android/view/ViewRootImpl.java
    void updateBlastSurfaceIfNeeded() {
        if (!mSurfaceControl.isValid()) {
            return;
        }

        if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
            mBlastBufferQueue.update(mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y,
                mWindowAttributes.format);
            return;
        }

        // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
        // BBQ states.
        if (mBlastBufferQueue != null) {
            mBlastBufferQueue.destroy();
        }
        mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
        mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
        Surface blastSurface = mBlastBufferQueue.createSurface();
        // Only call transferFrom if the surface has changed to prevent inc the generation ID and
        // causing EGL resources to be recreated.
        mSurface.transferFrom(blastSurface);
    }

初始 mBlastBufferQueue 是空,会新建一个 BLASTBufferQueue 对象,我们看一下 BLASTBufferQueue 是如何定义的:

//frameworks/base/graphics/java/android/graphics/BLASTBufferQueue.java
    /** Create a new connection with the surface flinger. */
    public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
            @PixelFormat.Format int format) {
        this(name, true /* updateDestinationFrame */);
        update(sc, width, height, format);
    }

    public BLASTBufferQueue(String name, boolean updateDestinationFrame) {
        mNativeObject = nativeCreate(name, updateDestinationFrame);
    }

BLASTBufferQueue 会新建一个 mNativeObject 对象,继续看一下 nativeCreate 实现:

//frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
                          jboolean updateDestinationFrame) {
    ScopedUtfChars name(env, jName);
    sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str(), updateDestinationFrame);
    queue->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(queue.get());
}

这里通过JNI,新建了一个原生层的 BLASTBufferQueue 对象,我们稍后分析原生层的代码。在此之前,我们再看一下 BLASTBufferQueue 函数中 update 的实现:

//frameworks/base/graphics/java/android/graphics/BLASTBufferQueue.java
    public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
    }

这里 nativeUpdate 同样会转入 JNI,具体实现:

//frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp
static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
                         jlong height, jint format) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
}

nativeUpdate 函数中的 update 最后也会通过 JNI 链接到原生层,把 Buffer 的宽度,高度以及像素格式传递给原生层,进一步丰富 BLASTBufferQueue。最后,我们回到 updateBlastSurfaceIfNeeded 函数,看一下 blastSurface 的创建,具体 createSurface 实现 :

//frameworks/base/graphics/java/android/graphics/BLASTBufferQueue.java
    /**
     * @return a new Surface instance from the IGraphicsBufferProducer of the adapter.
     */
    public Surface createSurface() {
        return nativeGetSurface(mNativeObject, false /* includeSurfaceControlHandle */);
    }

可以看到,createSurface 同样调到了 JNI,函数 nativeGetSurface 实现:

//frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp
static jobject nativeGetSurface(JNIEnv* env, jclass clazz, jlong ptr,
                                jboolean includeSurfaceControlHandle) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    return android_view_Surface_createFromSurface(env,
                                                  queue->getSurface(includeSurfaceControlHandle));
}

queue 是一个 BLASTBufferQueue 对象,通过 android_view_Surface_createFromSurface 进行复制:

//frameworks/base/core/jni/android_view_Surface.cpp
jobject android_view_Surface_createFromSurface(JNIEnv* env, const sp<Surface>& surface) {
    jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz,
            gSurfaceClassInfo.ctor, (jlong)surface.get());
    if (surfaceObj == NULL) {
        if (env->ExceptionCheck()) {
            ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
            LOGE_EX(env);
            env->ExceptionClear();
        }
        return NULL;
    }
    surface->incStrong(&sRefBaseOwner);
    return surfaceObj;
}

总结下来,relayoutWindow 会在 Java 层创建一个 BLASTBufferQueue 对象,通过 JNI 同步在原生层同步创建一个 BLASTBufferQueue 对象;并且把具体的宽度,高度和像素格式也通过 JNI 传递给原生层,并且从原生层返回一个 blastSurface(Surface) 对象,函数时序图:
在这里插入图片描述


二、原生层的 BufferQueue 分析

上一章节我们分析过,Java 层通过调用 JNI 的 nativeCreate 在原生层创建 BufferQueue 对象,然后通过 nativeUpdate 更新 Buffer 的宽度,高度以及像素格式,最后通过 nativeGetSurface 来获取创建的 blastSurface,本节我们按照这个顺序逐一分析原生层的 BufferQueue 创建过程。

1、BLASTBufferQueue 的创建

先看一下,原生层 BLASTBufferQueue 的定义:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
      : mSurfaceControl(nullptr),
        mSize(1, 1),
        mRequestedSize(mSize),
        mFormat(PIXEL_FORMAT_RGBA_8888),
        mTransactionReadyCallback(nullptr),
        mSyncTransaction(nullptr),
        mUpdateDestinationFrame(updateDestinationFrame) {
    createBufferQueue(&mProducer, &mConsumer);
    //...
    mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
                                                      GraphicBuffer::USAGE_HW_COMPOSER |
                                                              GraphicBuffer::USAGE_HW_TEXTURE,
                                                      1, false, this);
    //...                           
}

在 BLASTBufferQueue 函数中,createBufferQueue 创建了 BufferQueue 对象,并且定义了当前 Buffer 的生产者和消费者:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                         sp<IGraphicBufferConsumer>* outConsumer) {
    //...
    sp<BufferQueueCore> core(new BufferQueueCore());
    //...
    sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core));
    //...
    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
    consumer->setAllowExtraAcquire(true);
    //...
    *outProducer = producer;
    *outConsumer = consumer;
}

在 createBufferQueue 函数中,新建了一个 BufferQueueCore 对象,IGraphicBufferProducer 对象和 BufferQueueConsumer 对象。其中 core(BufferQueueCore) 是 BufferQueue 的核心部分,是生产者和消费者的纽带,主要负责 BufferQueue 的状态管理, 从定义上也能看出,它涵盖了 BufferQueue 的诸多状态:

//frameworks/native/libs/gui/BufferQueueCore.cpp
BufferQueueCore::BufferQueueCore()
      : mMutex(),
        mIsAbandoned(false),
        mConsumerControlledByApp(false),
        mConsumerName(getUniqueName()),
        mConsumerListener(),
        mConsumerUsageBits(0),
        mConsumerIsProtected(false),
        mConnectedApi(NO_CONNECTED_API),
        mLinkedToDeath(),
        mConnectedProducerListener(),
        mBufferReleasedCbEnabled(false),
        mSlots(),
        mQueue(),
        mFreeSlots(),
        mFreeBuffers(),
        mUnusedSlots(),
        mActiveBuffers(),
        mDequeueCondition(),
        mDequeueBufferCannotBlock(false),
        mQueueBufferCanDrop(false),
        mLegacyBufferDrop(true),
        mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
        mDefaultWidth(1),
        mDefaultHeight(1),
        mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
        mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
        mMaxAcquiredBufferCount(1),
        mMaxDequeuedBufferCount(1),
        mBufferHasBeenQueued(false),
        mFrameCounter(0),
        mTransformHint(0),
        mIsAllocating(false),
        mIsAllocatingCondition(),
        mAllowAllocation(true),
        mBufferAge(0),
        mGenerationNumber(0),
        mAsyncMode(false),
        mSharedBufferMode(false),
        mAutoRefresh(false),
        mSharedBufferSlot(INVALID_BUFFER_SLOT),
        mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
                           HAL_DATASPACE_UNKNOWN),
        mLastQueuedSlot(INVALID_BUFFER_SLOT),
        mUniqueId(getUniqueId()),
        mAutoPrerotation(false),
        mTransformHintInUse(0) {
//...
}

producer(IGraphicBufferProducer)是 BufferQueue 的生产者,主要负责 Buffer 的申请,调用 dequeueBuffer() 获取一个空闲缓冲区,填充数据后通过 queueBuffer() 将其返回队列,producer 是一个 BBQBufferQueueProducer 对象:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
    BBQBufferQueueProducer(const sp<BufferQueueCore>& core)
          : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/) {}

而 BBQBufferQueueProducer 又指向了一个 BufferQueueProducer 对象:

//frameworks/native/libs/gui/BufferQueueProducer.cpp
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
        bool consumerIsSurfaceFlinger) :
    mCore(core),
    mSlots(core->mSlots),
    mConsumerName(),
    mStickyTransform(0),
    mConsumerIsSurfaceFlinger(consumerIsSurfaceFlinger),
    mLastQueueBufferFence(Fence::NO_FENCE),
    mLastQueuedTransform(0),
    mCallbackMutex(),
    mNextCallbackTicket(0),
    mCurrentCallbackTicket(0),
    mCallbackCondition(),
    mDequeueTimeout(-1),
    mDequeueWaitingForAllocation(false) {}

consumer(BufferQueueConsumer) 是 BufferQueue 的消费者,主要负责 Buffer 的使用,调用 acquireBuffer() 获取缓冲区,并在使用完毕后通过 releaseBuffer() 将其返回队列,BufferQueueConsumer 的初始化:

//frameworks/native/libs/gui/BufferQueueConsumer.cpp
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
    mCore(core),
    mSlots(core->mSlots),
    mConsumerName() {}

总结一下,core 是 BufferQueue 的核心,主要负责 Buffer 的状态管理,是生产者和消费者之间的重要纽带。producer 是生产者,主要负责 Buffer 空间的申请,consumer 是消费者,主要负责 Buffer 的使用。


2、BLASTBufferQueue 的更新

JNI 通过 nativeGetSurface 更新 Buffer 的宽度,高度以及像素格式,这一小节我们看一下,原生层的 update 函数实现:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
                              int32_t format) {
    //...
    if (mFormat != format) {
        mFormat = format;
        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
    }

    const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
    if (surfaceControlChanged && mSurfaceControl != nullptr) {
        BQA_LOGD("Updating SurfaceControl without recreating BBQ");
    }
    bool applyTransaction = false;

    // Always update the native object even though they might have the same layer handle, so we can
    // get the updated transform hint from WM.
    mSurfaceControl = surface;
    SurfaceComposerClient::Transaction t;
    if (surfaceControlChanged) {
        t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
                   layer_state_t::eEnableBackpressure);
        applyTransaction = true;
    }
    mTransformHint = mSurfaceControl->getTransformHint();
    mBufferItemConsumer->setTransformHint(mTransformHint);
    BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
             mTransformHint);

    ui::Size newSize(width, height);
    if (mRequestedSize != newSize) {
        mRequestedSize.set(newSize);
        mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
        if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
            // If the buffer supports scaling, update the frame immediately since the client may
            // want to scale the existing buffer to the new size.
            mSize = mRequestedSize;
            if (mUpdateDestinationFrame) {
                t.setDestinationFrame(mSurfaceControl, Rect(newSize));
                applyTransaction = true;
            }
        }
    }
    if (applyTransaction) {
        // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
        t.setApplyToken(mApplyToken).apply(false, true);
    }
}

当高度,宽度等有变化的时候,会更新 BufferQueue。注意,这里 mBufferItemConsumer 对应的是上一小节中创建的 consumer。


3、Surface 的创建

JNI 通过 nativeGetSurface 来获取一块 blastSurface,在 nativeGetSurface 函数中,Surface 是由 BLASTBufferQueue 类中的 getSurface 函数返回的:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::unique_lock _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
        scHandle = mSurfaceControl->getHandle();
    }
    return new BBQSurface(mProducer, true, scHandle, this);
}

在 Java 层,传入的 includeSurfaceControlHandle 是 false,所以这里直接新建一个 BBQSurface 对象:

//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
               const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
          : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}

BBQSurface 初始化了一个 Surface 对象,并将指针返回给 getSurface。这里 Surface 初始化并没有分配空间,还是一块空的 Buffer:

//frameworks/native/libs/gui/Surface.cpp
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
                 const sp<IBinder>& surfaceControlHandle)
      : mGraphicBufferProducer(bufferProducer),
        mCrop(Rect::EMPTY_RECT),
        mBufferAge(0),
        mGenerationNumber(0),
        mSharedBufferMode(false),
        mAutoRefresh(false),
        mAutoPrerotation(false),
        mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
        mSharedBufferHasBeenQueued(false),
        mQueriedSupportedTimestamps(false),
        mFrameTimestampsSupportsPresent(false),
        mEnableFrameTimestamps(false),
        mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
    ANativeWindow::queueBuffer      = hook_queueBuffer;
    ANativeWindow::query            = hook_query;
    ANativeWindow::perform          = hook_perform;

    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;

    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;

    mReqWidth = 0;
    mReqHeight = 0;
    mReqFormat = 0;
    mReqUsage = 0;
    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
    mDataSpace = Dataspace::UNKNOWN;
    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
    mTransform = 0;
    mStickyTransform = 0;
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;
    mTransformHint = 0;
    mConsumerRunningBehind = false;
    mConnectedToCpu = false;
    mProducerControlledByApp = controlledByApp;
    mSwapIntervalZero = false;
    mMaxBufferCount = NUM_BUFFER_SLOTS;
    mSurfaceControlHandle = surfaceControlHandle;
}

在文章第一部分,我们分析了 blastSurface 是一个 Surface 对象,这一小节通过原生层的代码分析,最后新建了一个原生层的 Surface 对象。函数时序图:
在这里插入图片描述


总结

至此,BufferQueue 的创建过程已经分析完成,后续我们会继续分析 BufferQueue 如何通过 dequeueBuffer(),queueBuffer(),acquireBuffer() ,releaseBuffer() 进行 Buffer 管理;以及如何通过 Gralloc 申请具体的 Buffer 空间。



http://www.kler.cn/a/538221.html

相关文章:

  • [LVGL] 在VC_MFC中移植LVGL
  • Oracle迁移到MySQL
  • STM32G474--Whetstone程序移植(单精度)笔记
  • idea整合deepseek实现AI辅助编程
  • Git的使用
  • xss闯关
  • 【无标题】堆
  • F - Building Roads S
  • 实验5 配置OSPFv2验证
  • Kafka中的KRaft算法
  • 探秘 C++ list:在复杂数据管理的编程世界里,它宛如灵动的魔法链条,高效实现元素频繁增删,有序维系数据秩序,无论是海量动态数据缓存、游戏角色属性集处理,还是复杂任务调度编排
  • 网络通信小白知识扫盲(五)
  • deepseek本地部署-linux
  • 设计模式实战运用之模板方法模式
  • 算法兵法全略
  • 链表专题-01
  • Delphi语言的云计算
  • 【免费】2011-2020年各省长途光缆线路长度数据
  • Linux 调用可执行程序
  • pytest-xdist 进行多进程并发测试
  • 网络安全 架构 网络安全架构师考试
  • Listener监听器和Filter过滤器
  • 【真一键部署脚本】——一键部署deepseek
  • 【练习】PAT 乙 1046 划拳
  • 【如何掌握CSP-J 信奥赛中的深搜算法】
  • 索引失效的14种常见场景