BufferQueue笔记

作者: yangweigbh | 来源:发表于2018-01-13 18:17 被阅读425次

    应用程序的一个窗口通过ViewRootImpl的relayout来向SurfaceFlinger请求创建Surface时,会在SurfaceFlinger这边创建一个Layer对象。Layer对象创建时会创建一个Buffer队列。因为是triple buffer,所以MaxDequeuedBufferCount被设置为2。

    void Layer::onFirstRef() {
        // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
        sp<IGraphicBufferProducer> producer;
        sp<IGraphicBufferConsumer> consumer;
        BufferQueue::createBufferQueue(&producer, &consumer);
        mProducer = new MonitoredProducer(producer, mFlinger);
        mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
    
    #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
    #warning "disabling triple buffering"
    #else
        mProducer->setMaxDequeuedBufferCount(2);
    #endif
    
        const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
        updateTransformHint(hw);
    }
    
    void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
            sp<IGraphicBufferConsumer>* outConsumer,
            const sp<IGraphicBufferAlloc>& allocator) {
        ....
        sp<BufferQueueCore> core(new BufferQueueCore(allocator));
        LOG_ALWAYS_FATAL_IF(core == NULL,
                "BufferQueue: failed to create BufferQueueCore");
    
        sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
        LOG_ALWAYS_FATAL_IF(producer == NULL,
                "BufferQueue: failed to create BufferQueueProducer");
    
        sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
        LOG_ALWAYS_FATAL_IF(consumer == NULL,
                "BufferQueue: failed to create BufferQueueConsumer");
    
        *outProducer = producer;
        *outConsumer = consumer;
    }
    
    };
    

    BufferQueueCore的构造函数请求SurfaceFlinger创建一个GraphicBufferAlloc

    BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
        mAllocator(allocator),
    ......
        mMaxAcquiredBufferCount(1),
        mMaxDequeuedBufferCount(1),
    .....
    {
        if (allocator == NULL) {
            sp<ISurfaceComposer> composer(ComposerService::getComposerService());
            mAllocator = composer->createGraphicBufferAlloc();
            if (mAllocator == NULL) {
                BQ_LOGE("createGraphicBufferAlloc failed");
            }
        }
    
        int numStartingBuffers = getMaxBufferCountLocked(); //
        for (int s = 0; s < numStartingBuffers; s++) {
            mFreeSlots.insert(s);
        }
        for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
                s++) {
            mUnusedSlots.push_front(s);
        }
    }
    
    int BufferQueueCore::getMaxBufferCountLocked() const {
        int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
                ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
    
        // limit maxBufferCount by mMaxBufferCount always
        maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
    
        return maxBufferCount;
    }
    
    sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
    {
        sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
        return gba;
    }
    

    BufferQueueCore里面有个SlotsType的变量mSlots,其实是一个BufferSlot数组。一个BufferSlot包含了一块buffer所对应GraphicBuffer,还有buffer的状态。

    SlotsType BufferQueueCore.mSlots: 
    
    enum { NUM_BUFFER_SLOTS = 64 };
    
    typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
    
    struct BufferSlot {
    
        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
        // if no buffer has been allocated.
        sp<GraphicBuffer> mGraphicBuffer;
    
        // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects.
        EGLDisplay mEglDisplay;
    
        // mBufferState is the current state of this buffer slot.
        BufferState mBufferState;
    
        // mRequestBufferCalled is used for validating that the producer did
        // call requestBuffer() when told to do so. Technically this is not
        // needed but useful for debugging and catching producer bugs.
        bool mRequestBufferCalled;
    
        // mFrameNumber is the number of the queued frame for this slot.  This
        // is used to dequeue buffers in LRU order (useful because buffers
        // may be released before their release fence is signaled).
        uint64_t mFrameNumber;
    
        // mEglFence is the EGL sync object that must signal before the buffer
        // associated with this buffer slot may be dequeued. It is initialized
        // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
        // new sync object in releaseBuffer.  (This is deprecated in favor of
        // mFence, below.)
        EGLSyncKHR mEglFence;
    
        // mFence is a fence which will signal when work initiated by the
        // previous owner of the buffer is finished. When the buffer is FREE,
        // the fence indicates when the consumer has finished reading
        // from the buffer, or when the producer has finished writing if it
        // called cancelBuffer after queueing some writes. When the buffer is
        // QUEUED, it indicates when the producer has finished filling the
        // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
        // passed to the consumer or producer along with ownership of the
        // buffer, and mFence is set to NO_FENCE.
        sp<Fence> mFence;
    
        // Indicates whether this buffer has been seen by a consumer yet
        bool mAcquireCalled;
    
        // Indicates whether the buffer was re-allocated without notifying the
        // producer. If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when
        // dequeued to prevent the producer from using a stale cached buffer.
        bool mNeedsReallocation;
    };
    
    struct BufferState {
    
        uint32_t mDequeueCount;
        uint32_t mQueueCount;
        uint32_t mAcquireCount;
        bool mShared;
    
        // A buffer can be in one of five states, represented as below:
        //
        //         | mShared | mDequeueCount | mQueueCount | mAcquireCount |
        // --------|---------|---------------|-------------|---------------|
        // FREE    |  false  |       0       |      0      |       0       |
        // DEQUEUED|  false  |       1       |      0      |       0       |
        // QUEUED  |  false  |       0       |      1      |       0       |
        // ACQUIRED|  false  |       0       |      0      |       1       |
        // SHARED  |  true   |      any      |     any     |      any      |
    }
    

    一块Buffer状态转移:绘制图像时,Surface会从BufferQueue中dequeue中一块buffer出来进行绘制,最多可以dequeue两块,绘制完成后queue到bufferQueue中,然后BufferConsumer(SurfaceFlinger)可以从BufferQueue中acquire一块buffer进行多个窗口layer的合成渲染,然后显示到屏幕上。

    buffer_state.png

    以硬件渲染UI为例,分析一下BufferQueue的使用过程

    ViewRootImpl.performTraversal会用Surface初始化ThreadedRenderer

    hwInitialized = mAttachInfo.mHardwareRenderer.initialize(mSurface);
    

    initialize方法内部调用native方法。

    static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
            jlong proxyPtr, jobject jsurface) {
        RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
        sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
        proxy->initialize(surface);
    }
    

    最后调用CanvasContext.initialize

    void CanvasContext::initialize(Surface* surface) {
        setSurface(surface);
    }
    
    void CanvasContext::setSurface(Surface* surface) {
        mNativeSurface = surface;
    
        if (surface) {
            mEglSurface = mEglManager.createSurface(surface);
        }
    
    EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
        EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, nullptr);
    
        return surface;
    }
    

    /frameworks/native/opengl/libs/EGL/eglApi.cpp

    EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                        NativeWindowType window,
                                        const EGLint *attrib_list)
    {
        int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
        
        EGLSurface surface = cnx->egl.eglCreateWindowSurface(
                iDpy, config, window, attrib_list);
        if (surface != EGL_NO_SURFACE) {
            egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
                    surface, cnx);
            return s;
        }
        return EGL_NO_SURFACE;
    }
    

    其中native_window_api_connect会调用到Surface::connect,api=NATIVE_WINDOW_API_EGL

    int Surface::connect(int api, const sp<IProducerListener>& listener) {
    
        int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
    
        return err;
    }
    

    BufferQueueProducer::connect里设置了BufferQueueCore里的一些参数。

    status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
            int api, bool producerControlledByApp, QueueBufferOutput *output) {
    
        int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode,
                mDequeueTimeout < 0 ?
                mCore->mConsumerControlledByApp && producerControlledByApp : false,
                mCore->mMaxBufferCount) -
                mCore->getMaxBufferCountLocked();
        if (!mCore->adjustAvailableSlotsLocked(delta)) {
            BQ_LOGE("connect: BufferQueue failed to adjust the number of available "
                    "slots. Delta = %d", delta);
            return BAD_VALUE;
        }
    
        mCore->mBufferHasBeenQueued = false;
        mCore->mDequeueBufferCannotBlock = false;
        if (mDequeueTimeout < 0) {
            mCore->mDequeueBufferCannotBlock =
                    mCore->mConsumerControlledByApp && producerControlledByApp;
        }
    
        mCore->mAllowAllocation = true;
    
    }
    

    /frameworks/native/opengl/libagl/egl.cpp

    EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                        NativeWindowType window,
                                        const EGLint *attrib_list)
    {
        return createWindowSurface(dpy, config, window, attrib_list);
    }
    
    EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
        initialize();
        EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, nullptr);
        .....
        return surface;
    }
    
    static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
            NativeWindowType window, const EGLint* /*attrib_list*/)
    {
    
        egl_surface_t* surface;
        surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
                static_cast<ANativeWindow*>(window));
    
        return surface;
    }
    

    到此为止创建了一个EglSurface保存在CanvasContext中

    当使用ThreadedRenderer去draw一帧displaylist时,会调用nSyncAndDrawFrame

    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
        updateRootDisplayList(view, callbacks);
       
        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
    }
    

    最终会调用到CanvasContext的draw方法:

    void DrawFrameTask::run() {
        if (CC_LIKELY(canDrawThisFrame)) {
            context->draw();
        }
    }
    
    void CanvasContext::draw() {
    
        Frame frame = mEglManager.beginFrame(mEglSurface);
        ....
        if (drew || mEglManager.damageRequiresSwap()) {
            if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
                setSurface(nullptr);
            }
        }
    }
    

    CanvasContext的draw方法会先调用mEglManager.beginFrame,然后调用mEglManager.swapBuffers

    Frame EglManager::beginFrame(EGLSurface surface) {
        .....
        makeCurrent(surface);
        ....
    }
    bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
    
        if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
            ....
        }
        .....
    }
    
    EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
                                EGLSurface read, EGLContext ctx)
    {
    
        if (ctx == EGL_NO_CONTEXT) {
            // if we're detaching, we need the current context
            current_ctx = (EGLContext)getGlThreadSpecific();
        } else {
           
            egl_surface_t* d = (egl_surface_t*)draw;
        }
    
        if (d) {
            if (d->connect() == EGL_FALSE) {
                return EGL_FALSE;
            }
        }
        return setError(EGL_BAD_ACCESS, EGL_FALSE);
    }
    
    EGLBoolean egl_window_surface_v2_t::connect()
    {
    
        // dequeue a buffer
        int fenceFd = -1;
        if (nativeWindow->dequeueBuffer(nativeWindow, &buffer,
                &fenceFd) != NO_ERROR) {
            return setError(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        // wait for the buffer
        sp<Fence> fence(new Fence(fenceFd));
        if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) {
            nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
            return setError(EGL_BAD_ALLOC, EGL_FALSE);
        }
    
        return EGL_TRUE;
    }
    

    beginFrame其实就是调用ANativeWindow的dequeueBuffer来获取一个buffer。最终调用到Surface的dequeueBuffer

    int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
        ....
        int buf = -1;
        sp<Fence> fence;
        status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
                reqWidth, reqHeight, reqFormat, reqUsage);
    
        if (result < 0) {
            ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer"
                    "(%d, %d, %d, %d) failed: %d", reqWidth, reqHeight, reqFormat,
                    reqUsage, result);
            return result;
        }
    
        Mutex::Autolock lock(mMutex);
    
        sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
    
        // this should never happen
        ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
    
        if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
            freeAllBuffers();
        }
    
        if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
            result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
            if (result != NO_ERROR) {
                ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
                mGraphicBufferProducer->cancelBuffer(buf, fence);
                return result;
            }
        }
    
        if (fence->isValid()) {
            *fenceFd = fence->dup();
            if (*fenceFd == -1) {
                ALOGE("dequeueBuffer: error duping fence: %d", errno);
                // dup() should never fail; something is badly wrong. Soldier on
                // and hope for the best; the worst that should happen is some
                // visible corruption that lasts until the next frame.
            }
        } else {
            *fenceFd = -1;
        }
    
        *buffer = gbuf.get();
    
        return OK;
    }
    

    GraphicBufferProducer::dequeueBuffer

    status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
            sp<android::Fence> *outFence, uint32_t width, uint32_t height,
            PixelFormat format, uint32_t usage) {
    
        { // Autolock scope
            Mutex::Autolock lock(mCore->mMutex);
            mCore->waitWhileAllocatingLocked();
    
            if (format == 0) {
                format = mCore->mDefaultBufferFormat;
            }
    
            // Enable the usage bits the consumer requested
            usage |= mCore->mConsumerUsageBits;
    
            const bool useDefaultSize = !width && !height;
            if (useDefaultSize) {
                width = mCore->mDefaultWidth;
                height = mCore->mDefaultHeight;
            }
    
            int found = BufferItem::INVALID_BUFFER_SLOT;
            while (found == BufferItem::INVALID_BUFFER_SLOT) {
                status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
                        &found);
                if (status != NO_ERROR) {
                    return status;
                }
            }
    
            if (mCore->mSharedBufferSlot != found) {
                mCore->mActiveBuffers.insert(found);
            }
            *outSlot = found;
            ATRACE_BUFFER_INDEX(found);
    
            attachedByConsumer = mSlots[found].mNeedsReallocation;
            mSlots[found].mNeedsReallocation = false;
    
            mSlots[found].mBufferState.dequeue();
    
            if ((buffer == NULL) ||
                    buffer->needsReallocation(width, height, format, usage))
            {
                mSlots[found].mAcquireCalled = false;
                mSlots[found].mGraphicBuffer = NULL;
                mSlots[found].mRequestBufferCalled = false;
                mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
                mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
                mSlots[found].mFence = Fence::NO_FENCE;
                mCore->mBufferAge = 0;
                mCore->mIsAllocating = true;
    
                returnFlags |= BUFFER_NEEDS_REALLOCATION;
            } 
        } // Autolock scope
    
        if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
            status_t error;
            BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
            sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
                    width, height, format, usage, &error));
            { // Autolock scope
                Mutex::Autolock lock(mCore->mMutex);
    
                if (graphicBuffer != NULL && !mCore->mIsAbandoned) {
                    graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
                    mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
                }
    
                mCore->mIsAllocating = false;
                mCore->mIsAllocatingCondition.broadcast();
            }
        }
    
    
        return returnFlags;
    }
    

    GraphicBufferProducer::dequeueBuffer中会从BufferQueueCore中分配一个free slot,然后这个slot对应的mSlots[found]的mGraphicBuffer是空的,这时会走到

     sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(width, height, format, usage, &error));
    

    会调用GraphicBufferAlloc.createGraphicBuffer去从SurfaceFlinger分配一块GraphicBufferGraphicBufferAlloc继承自BnGraphicBufferAlloc

    class GraphicBufferAlloc : public BnGraphicBufferAlloc
    
    sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
            uint32_t height, PixelFormat format, uint32_t usage, status_t* error) {
        sp<GraphicBuffer> graphicBuffer(
                new GraphicBuffer(width, height, 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",
                    width, height, strerror(-err), graphicBuffer->handle);
            return 0;
        }
        return graphicBuffer;
    }
    

    GraphicBuffer实现了Flattenable接口来进行序列化,同时实现了ANativeWindowBuffer接口来供ANativeWindow来进行绘制图像:

    class GraphicBuffer
        : public ANativeObjectBase< ANativeWindowBuffer, GraphicBuffer, RefBase >,
          public Flattenable<GraphicBuffer>
    

    GraphicBuffer的构造函数里请求gralloc来分配缓存。这块缓存应该是SurfaceFlinger和App共享的。

    GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
            PixelFormat inFormat, uint32_t inUsage)
        : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
          mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
    {
        width  =
        height =
        stride =
        format =
        usage  = 0;
        handle = NULL;
        mInitCheck = initSize(inWidth, inHeight, inFormat, inUsage);
    }
    
    status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
            PixelFormat inFormat, uint32_t inUsage)
    {
        GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
        status_t err = allocator.alloc(inWidth, inHeight, inFormat, inUsage,
                &handle, &outStride); //通过GraphicBufferAllocator来分配缓存
        return err;
    }
    
    status_t GraphicBufferAllocator::alloc(uint32_t width, uint32_t height,
            PixelFormat format, uint32_t usage, buffer_handle_t* handle,
            uint32_t* stride)
    {
    
        err = mAllocDev->alloc(mAllocDev, static_cast<int>(width),
                static_cast<int>(height), format, static_cast<int>(usage), handle,
                &outStride);
        *stride = static_cast<uint32_t>(outStride);
    
        return err;
    }
    
    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);
        }
    }
    

    mAllocDev应该是通过gralloc_open赋值的。

    相关文章

      网友评论

        本文标题:BufferQueue笔记

        本文链接:https://www.haomeiwen.com/subject/pgrfoxtx.html