Android 12(S) 影像顯示系統 - SurfaceFlinger GPU合成/CLIENT合成方式 - 隨筆1

二的次方發表於2022-05-10

必讀:

Android 12(S) 影像顯示系統 - 開篇


 

一、前言

SurfaceFlinger中的圖層選擇GPU合成(CLIENT合成方式)時,會把待合成的圖層Layers通過renderengine(SkiaGLRenderEngine)繪製到一塊GraphicBuffer中,然後把這塊GraphicBuffer圖形快取通過呼叫setClientTarget傳遞給HWC模組,HWC進一步處理後把這個GraphicBuffer中的影像呈現到螢幕上。

本篇文章,我們先聚焦一點做介紹:用於儲存GPU合成後的圖形資料的GraphicBuffer是從哪裡來的?下面的講解會圍繞這個問題展開。

 

二、從dumpsys SurfaceFlinger中的資訊談起

如果你檢視過dumpsys SurfaceFlinger的資訊,也許你注意過一些GraphicBufferAllocator/GraphicBufferMapper列印出的一些資訊,這些資訊記錄了所有通過Gralloc模組allocate和import的圖形快取的資訊。

如下是在我的平臺下擷取的dumpsys SurfaceFlinger部分資訊:

GraphicBufferAllocator buffers:
    Handle |        Size |     W (Stride) x H | Layers |   Format |      Usage | Requestor
0xf3042b90 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xf3042f30 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xf3046020 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
Total allocated by GraphicBufferAllocator (estimate): 24300.00 KB
Imported gralloc buffers:
+ name:FramebufferSurface, id:e100000000, size:8.3e+03KiB, w/h:780x438, usage: 0x40001b00, req fmt:5, fourcc/mod:875713089/576460752303423505, dataspace: 0x0, compressed: true
	planes: B/G/R/A:	 w/h:780x440, stride:1e00 bytes, size:818000
+ name:FramebufferSurface, id:e100000001, size:8.3e+03KiB, w/h:780x438, usage: 0x40001b00, req fmt:5, fourcc/mod:875713089/576460752303423505, dataspace: 0x0, compressed: true
	planes: B/G/R/A:	 w/h:780x440, stride:1e00 bytes, size:818000
+ name:FramebufferSurface, id:e100000002, size:8.3e+03KiB, w/h:780x438, usage: 0x40001b00, req fmt:5, fourcc/mod:875713089/576460752303423505, dataspace: 0x0, compressed: true
	planes: B/G/R/A:	 w/h:780x440, stride:1e00 bytes, size:818000
Total imported by gralloc: 5e+04KiB

上面的資訊中可以看到一些兒冥冥之中貌似、似乎、好像很有意思的字眼:FramebufferSurface

作為Requestor的FramebufferSurface去請求分配了三塊圖形快取,還規定了width、height、format、usage等資訊。


 

如上你看到的這3塊GraphicBuffer,就是用來儲存CPU合成後的圖形資料的。

 


 

三、建立與初始化FramebufferSurface的流程

FramebufferSurface的初始化邏輯需要從SurfaceFlinger的初始化談起,在文章Android 12(S) 影像顯示系統 - SurfaceFlinger的啟動和訊息佇列處理機制(四)

中,曾分析過,SurfaceFlinger::init()中會去註冊HWC的回撥函式mCompositionEngine->getHwComposer().setCallback(this),當第一次註冊callback時,onComposerHalHotplug()會立即在呼叫registerCallback()的執行緒中被呼叫,並跨程式回撥到SurfaceFlinger::onComposerHalHotplug。然後一路飛奔:

SurfaceFlinger::processDisplayAdded這個方法中去建立了BufferQueue和FramebufferSurface,簡單理解為連線上了顯示螢幕(Display),那就要給準備一個BufferQueue,以便GPU合成UI等圖層時,可以向這個BufferQueue索要GraphicBuffer來儲存合成後的圖形資料,再呈現到螢幕上去(我的傻瓜式理解)

摘取關鍵程式碼如下:

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
                                         const DisplayDeviceState& state) {
    ......
    sp<compositionengine::DisplaySurface> displaySurface; 
    sp<IGraphicBufferProducer> producer;
    // 建立BufferQueue,獲取到生產者和消費者,而且消費者不是SurfaceFlinger哦
    sp<IGraphicBufferProducer> bqProducer;
    sp<IGraphicBufferConsumer> bqConsumer;
    getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false);

    if (state.isVirtual()) { // 虛擬螢幕,不管它
        const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId());
        LOG_FATAL_IF(!displayId);
        auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *displayId, state.surface,
                                                       bqProducer, bqConsumer, state.displayName);
        displaySurface = surface;
        producer = std::move(surface);
    } else { // 看這個case
        ALOGE_IF(state.surface != nullptr,
                 "adding a supported display, but rendering "
                 "surface is provided (%p), ignoring it",
                 state.surface.get());
        const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId());
        LOG_FATAL_IF(!displayId);
        // 建立了FramebufferSurface物件,FramebufferSurface繼承自compositionengine::DisplaySurface
        // FramebufferSurface是作為消費者的角色工作的,消費SF GPU合成後的圖形資料
        displaySurface =
                sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer,
                                             state.physical->activeMode->getSize(),
                                             ui::Size(maxGraphicsWidth, maxGraphicsHeight));
        producer = bqProducer;
    }

    LOG_FATAL_IF(!displaySurface);
    // 建立DisplayDevice,其又去建立RenderSurface,作為生產者角色工作,displaySurface就是FramebufferSurface物件
    const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay),
                                                       state, displaySurface, producer);
    mDisplays.emplace(displayToken, display);
    ......   
}

瞅一瞅 FramebufferSuraface的建構函式,沒啥複雜的,就是一些設定,初始化一些成員

FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
                                       const sp<IGraphicBufferConsumer>& consumer,
                                       const ui::Size& size, const ui::Size& maxSize)
      : ConsumerBase(consumer),
        mDisplayId(displayId),
        mMaxSize(maxSize),
        mCurrentBufferSlot(-1),
        mCurrentBuffer(),
        mCurrentFence(Fence::NO_FENCE),
        mHwc(hwc),
        mHasPendingRelease(false),
        mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
        mPreviousBuffer() {
    ALOGV("Creating for display %s", to_string(displayId).c_str());

    mName = "FramebufferSurface";
    mConsumer->setConsumerName(mName); // 設定消費者的名字是 "FramebufferSurface"
    mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |  // 設定usage
                                       GRALLOC_USAGE_HW_RENDER |
                                       GRALLOC_USAGE_HW_COMPOSER);
    const auto limitedSize = limitSize(size);
    mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); // 設定buffer 大小
    mConsumer->setMaxAcquiredBufferCount( 
            SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
}

 

再進到SurfaceFlinger::setupNewDisplayDeviceInternal中看看相關的邏輯:

[/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
        const wp<IBinder>& displayToken,
        std::shared_ptr<compositionengine::Display> compositionDisplay,
        const DisplayDeviceState& state,
        const sp<compositionengine::DisplaySurface>& displaySurface, 
        const sp<IGraphicBufferProducer>& producer) {
    ......
    creationArgs.displaySurface = displaySurface;  // displaySurface就是FramebufferSurface物件   
    
    // producer是前面processDisplayAdded中建立的
    auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
    auto nativeWindow = nativeWindowSurface->getNativeWindow();
    creationArgs.nativeWindow = nativeWindow;

    ....
    // 前面一大坨程式碼是在初始話creationArgs,這些引數用來建立DisplayDevice
    // creationArgs.nativeWindow會把前面建立的producer關聯到了DisplayDevice
    sp<DisplayDevice> display = getFactory().createDisplayDevice(creationArgs);
    
    // 後面一大坨,對display進行了些設定
    if (!state.isVirtual()) {
        display->setActiveMode(state.physical->activeMode->getId());
        display->setDeviceProductInfo(state.physical->deviceProductInfo);
    }
    ....
}

 

接下來就是 DisplayDevice 的建構函式了,裡面主要是建立了RenderSurface物件,然後對其進行初始化

[/frameworks/native/services/surfaceflinger/DisplayDevice.cpp]
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args)
      : mFlinger(args.flinger),
        mHwComposer(args.hwComposer),
        mDisplayToken(args.displayToken),
        mSequenceId(args.sequenceId),
        mConnectionType(args.connectionType),
        mCompositionDisplay{args.compositionDisplay},
        mPhysicalOrientation(args.physicalOrientation),
        mSupportedModes(std::move(args.supportedModes)),
        mIsPrimary(args.isPrimary) {
    mCompositionDisplay->editState().isSecure = args.isSecure;
    // 建立RenderSurface,args.nativeWindow 即為producer,指向生產者
    mCompositionDisplay->createRenderSurface(
            compositionengine::RenderSurfaceCreationArgsBuilder()
                    .setDisplayWidth(ANativeWindow_getWidth(args.nativeWindow.get()))
                    .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get()))
                    .setNativeWindow(std::move(args.nativeWindow))
                    .setDisplaySurface(std::move(args.displaySurface)) // displaySurface就是FramebufferSurface物件
                    .setMaxTextureCacheSize(
                            static_cast<size_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers))
                    .build());

    if (!mFlinger->mDisableClientCompositionCache &&
        SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) {
        mCompositionDisplay->createClientCompositionCache(
                static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
    }

    mCompositionDisplay->createDisplayColorProfile(
            compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut,
                                                               std::move(args.hdrCapabilities),
                                                               args.supportedPerFrameMetadata,
                                                               args.hwcColorModes});

    if (!mCompositionDisplay->isValid()) {
        ALOGE("Composition Display did not validate!");
    }
    // 初始化RenderSurface
    mCompositionDisplay->getRenderSurface()->initialize();

    setPowerMode(args.initialPowerMode);

    // initialize the display orientation transform.
    setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
}

本文作者@二的次方  2022-05-10 釋出於部落格園

RenderSurface作為生產者的角色工作,建構函式如下,留意啟成員displaySurface就是SurfaceFlinger中建立的FramebufferSurface物件

也就是 作為生產者的RenderSurface中持有 消費者的引用 displaySurface,可以呼叫FramebufferSurface的方法

[ /frameworks/native/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp]
RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
                             const RenderSurfaceCreationArgs& args)
      : mCompositionEngine(compositionEngine),
        mDisplay(display),
        mNativeWindow(args.nativeWindow),
        mDisplaySurface(args.displaySurface),  // displaySurface就是FramebufferSurface物件
        mSize(args.displayWidth, args.displayHeight),
        mMaxTextureCacheSize(args.maxTextureCacheSize) {
    LOG_ALWAYS_FATAL_IF(!mNativeWindow);
}

 

我們看看他的RenderSurface::initialize()方法

[/frameworks/native/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp]
void RenderSurface::initialize() {
    ANativeWindow* const window = mNativeWindow.get();

    int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
    ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
    status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
    ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
    status = native_window_set_usage(window, DEFAULT_USAGE);
    ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
}

上述方法也很簡單,就是作為producer去和BufferQueue建立connect,並設定format為RGBA_8888,設定usage為GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE

 


為了驗證上述分析的流程是正確的,我在BufferQueueProducer::connect中加log來列印呼叫棧的資訊,如下,是不是和分析的一樣啊

11-13 00:52:58.497   227   227 D BufferQueueProducer: connect[1303] /vendor/bin/hw/android.hardware.graphics.composer@2.4-service start
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#00 pc 0005e77f  /system/lib/libgui.so (android::BufferQueueProducer::connect(android::sp<android::IProducerListener> const&, int, bool, android::IGraphicBufferProducer::QueueBufferOutput*)+1282)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#01 pc 000a276b  /system/lib/libgui.so (android::Surface::connect(int, android::sp<android::IProducerListener> const&, bool)+138)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#02 pc 0009de41  /system/lib/libgui.so (android::Surface::hook_perform(ANativeWindow*, int, ...)+128)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#03 pc 00121b1d  /system/bin/surfaceflinger (android::compositionengine::impl::RenderSurface::initialize()+12)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#04 pc 00083cc5  /system/bin/surfaceflinger (android::DisplayDevice::DisplayDevice(android::DisplayDeviceCreationArgs&)+1168)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#05 pc 000d8bed  /system/bin/surfaceflinger (android::SurfaceFlinger::processDisplayAdded(android::wp<android::IBinder> const&, android::DisplayDeviceState const&)+4440)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#06 pc 000d0db5  /system/bin/surfaceflinger (android::SurfaceFlinger::processDisplayChangesLocked()+2436)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#07 pc 000cef6b  /system/bin/surfaceflinger (android::SurfaceFlinger::processDisplayHotplugEventsLocked()+6422)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#08 pc 000d2c7f  /system/bin/surfaceflinger (android::SurfaceFlinger::onComposerHalHotplug(unsigned long long, android::hardware::graphics::composer::V2_1::IComposerCallback::Connection)+334)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#09 pc 0009afab  /system/bin/surfaceflinger (_ZN7android12_GLOBAL__N_122ComposerCallbackBridge9onHotplugEyNS_8hardware8graphics8composer4V2_117IComposerCallback10ConnectionE$d689f7ac1c60e4abeed02ca92a51bdcd+20)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#10 pc 0001bb97  /system/lib/android.hardware.graphics.composer@2.1.so (android::hardware::graphics::composer::V2_1::BnHwComposerCallback::_hidl_onHotplug(android::hidl::base::V1_0::BnHwBase*, android::hardware::Parcel const&, android::hardware::Parcel*, std::__1::function<void (android::hardware::Parcel&)>)+166)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#11 pc 000275e9  /system/lib/android.hardware.graphics.composer@2.4.so (android::hardware::graphics::composer::V2_4::BnHwComposerCallback::onTransact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>)+228)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#12 pc 00054779  /system/lib/libhidlbase.so (android::hardware::BHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>)+96)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#13 pc 0004fc67  /system/lib/libhidlbase.so (android::hardware::IPCThreadState::transact(int, unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int)+2174)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#14 pc 0004f2e5  /system/lib/libhidlbase.so (android::hardware::BpHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>)+36)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#15 pc 0002bdf1  /system/lib/android.hardware.graphics.composer@2.4.so (android::hardware::graphics::composer::V2_4::BpHwComposerClient::_hidl_registerCallback_2_4(android::hardware::IInterface*, android::hardware::details::HidlInstrumentor*, android::sp<android::hardware::graphics::composer::V2_4::IComposerCallback> const&)+296)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#16 pc 0002ed8d  /system/lib/android.hardware.graphics.composer@2.4.so (android::hardware::graphics::composer::V2_4::BpHwComposerClient::registerCallback_2_4(android::sp<android::hardware::graphics::composer::V2_4::IComposerCallback> const&)+34)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#17 pc 00085627  /system/bin/surfaceflinger (android::Hwc2::impl::Composer::registerCallback(android::sp<android::hardware::graphics::composer::V2_4::IComposerCallback> const&)+98)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#18 pc 00092d63  /system/bin/surfaceflinger (android::impl::HWComposer::setCallback(android::HWC2::ComposerCallback*)+2206)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#19 pc 000cd35b  /system/bin/surfaceflinger (android::SurfaceFlinger::init()+438)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#20 pc 000feb03  /system/bin/surfaceflinger (main+862)
11-13 00:52:58.581   227   227 E BufferQueueProducer: stackdump:#21 pc 0003253b  /apex/com.android.runtime/lib/bionic/libc.so (__libc_init+54)
11-13 00:52:58.582   227   227 D BufferQueueProducer: connect[1307] /vendor/bin/hw/android.hardware.graphics.composer@2.4-service end

注意 本文作者@二的次方  2022-05-10 釋出於部落格園

注意 本文作者@二的次方  2022-05-10 釋出於部落格園

注意 本文作者@二的次方  2022-05-10 釋出於部落格園

這裡有一個小細節要留意下,因為SurfaceFlinger::onComposerHalHotplug是HWC回撥過來的,所以程式碼執行是在android.hardware.graphics.composer@2.4-service這個程式中的。

BufferQueueProducer::connect中記錄的mConnectedPid就是composer service的PID

[ /frameworks/native/libs/gui/BufferQueueProducer.cpp]
mCore->mConnectedPid = BufferQueueThreadState::getCallingPid();

在dump BufferQueue的資訊時,根據PID獲取的 producer name 也就是 android.hardware.graphics.composer@2.4-service

[/frameworks/native/libs/gui/BufferQueueCore.cpp]
void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
    ...
    getProcessName(mConnectedPid, producerProcName);
    getProcessName(pid, consumerProcName);
    ....
}

如下是我的平臺dumpsys SurfaceFlinger的資訊列印出來的Composition RenderSurface State的資訊,看看是不是和程式碼的設定都有對應起來:

? mConsumerName=FramebufferSurface

? producer=[342:/vendor/bin/hw/android.hardware.graphics.composer@2.4-service]

? consumer=[223:/system/bin/surfaceflinger])

? format/size/usage也都可以對應到程式碼的設定

   Composition RenderSurface State:
   size=[1920 1080] ANativeWindow=0xef2c3278 (format 1) flips=605 
  FramebufferSurface: dataspace: Default(0)
   mAbandoned=0
   - BufferQueue mMaxAcquiredBufferCount=2 mMaxDequeuedBufferCount=1
     mDequeueBufferCannotBlock=0 mAsyncMode=0
     mQueueBufferCanDrop=0 mLegacyBufferDrop=1
     default-size=[1920x1080] default-format=1      transform-hint=00 frame-counter=580
     mTransformHintInUse=00 mAutoPrerotation=0
   FIFO(0):
   (mConsumerName=FramebufferSurface, mConnectedApi=1, mConsumerUsageBits=6656, mId=df00000000, producer=[342:/vendor/bin/hw/android.hardware.graphics.composer@2.4-service], consumer=[223:/system/bin/surfaceflinger])
   Slots:
    >[01:0xeec82110] state=ACQUIRED 0xef4429c0 frame=2 [1920x1080:1920,  1]
    >[02:0xeec806f0] state=ACQUIRED 0xef443100 frame=580 [1920x1080:1920,  1]
     [00:0xeec81f00] state=FREE     0xef440580 frame=579 [1920x1080:1920,  1]

 

四、對上述分析的一個小結和猜想

上述內容中出現的一些字眼,不禁令人”瞎想連篇“

SurfaceFlinger建立了BufferQueue ==> Producer & Consumer

建立了RenderSurface作為生產者,它持有Producer

建立了FramebufferSurface作為消費者,它持有Consumer

 

前面分析BufferQueue的工作原理時,有講過:

生產者不斷的dequeueBuffer & queueBuffer ; 而消費者不斷的acquireBuffer & releaseBuffer ,這樣影像快取就在 生產者 -- BufferQueue -- 消費者 間流轉起來了。

 

看看作為生產者的RenderSurface中方法:

[/frameworks/native/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h]
/**
 * Encapsulates everything for composing to a render surface with RenderEngine
 */
class RenderSurface {
    ....
    // Allocates a buffer as scratch space for GPU composition
    virtual std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer(
            base::unique_fd* bufferFence) = 0;

    // Queues the drawn buffer for consumption by HWC. readyFence is the fence
    // which will fire when the buffer is ready for consumption.
    virtual void queueBuffer(base::unique_fd readyFence) = 0;
    ...
};

熟悉的味道:

dequeueBuffer : 分配一個緩衝區作為GPU合成的暫存空間

queueBuffer :  入佇列已繪製好的圖形快取供HWC使用

同樣如果去檢視作為消費者的FramebufferSurface也會看到acquireBuffer & releaseBuffer的呼叫,如下:

[/frameworks/native/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp]
status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
        sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
        Dataspace& outDataspace) {
    Mutex::Autolock lock(mMutex);

    BufferItem item;
    status_t err = acquireBufferLocked(&item, 0); // 獲取待顯示的buffer

    ...
        
    status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace); // 傳遞給HWC進一步處理顯示

    return NO_ERROR;
}

 


 

大概會有這樣一種邏輯處理流程:

當需要GPU合成時,會通過生產者RenderSurface::dequeueBuffer請求一塊圖形快取,然後GPU就合成/繪圖,把資料儲存到這塊圖形快取中,通過RenderSurface::queueBuffer提交這塊快取

呼叫mDisplaySurface->advanceFrame()通知消費者來消費:

FramebufferSurface::advanceFrame ==>FramebufferSurface::nextBuffer ==> acquireBufferLocked

去請求可用的圖形快取,這個buffer中儲存有GPU合成的結果,然後通過setClientTarget把這個buffer傳遞給HWC做處理顯示。

 


 

 最開始我們提出的問題:用於儲存GPU合成後的圖形資料的GraphicBuffer是從哪裡來的?分析到這裡大概應該有講明白吧

本文作者@二的次方  2022-05-10 釋出於部落格園

五、補充知識點

5.1 用於GPU合成的GraphicBuffer的數量控制

通過屬性值來控制數量 ro.surface_flinger.max_frame_buffer_acquired_buffers,如何控制的可以看SF的程式碼

[/frameworks/native/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop]
# Controls the number of buffers SurfaceFlinger will allocate for use in FramebufferSurface.
prop {
    api_name: "max_frame_buffer_acquired_buffers"
    type: Long
    scope: Public
    access: Readonly
    prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
}

這個屬性值。控制用於GPU合成的FramebufferSurface分配幾個GraphicBuffer,,一般是 3 個

 

5.2 一個疑問

為什麼在allocator出列印出來的Framebuffer的format=1 (PIXEL_FORMAT_RGBA_8888) , 而importer處列印出來的Framebuffer的format=5 (PIXEL_FORMAT_BGRA_8888)  ?

 

由於對整個體系架構瞭解還不是很深入,為了找到這個問題的原因,確實費了不少功夫。其實答案在 Gralloc HAL 中。

我的平臺採用的是 Mali GPU,Gralloc HAL使用的是 Open Source Mali GPUs Gralloc Module 為基礎的Source code。

在 Gralloc 的程式碼實現中有定義一個巨集開關 GRALLOC_HWC_FORCE_BGRA_8888 ,開啟這個巨集的時候,SurfaceFlinger中的 RenderSurface::initialize() 設定的RGBA_8888 會在Gralloc allocate/map時強轉為了BGRA_8888來處理。具體的可以開啟和關閉這個巨集看dumpsys SurfaceFlinger對比

# When enabled, forces format to BGRA_8888 for FB usage when HWC is in use
GRALLOC_HWC_FORCE_BGRA_8888?=0

我的平臺對比的資訊:

// 關閉GRALLOC_HWC_FORCE_BGRA_8888這個巨集定義,仍是framework設定的RGBA8888
+ name:FramebufferSurface, id:e400000000, size:8.1e+03KiB, w/h:780x438, usage: 0x1b00, req fmt:1, fourcc/mod:875708993/0, dataspace: 0x0, compressed: false
        planes: R/G/B/A:         w/h:780x438, stride:1e00 bytes, size:7e9000
            
// 開啟GRALLOC_HWC_FORCE_BGRA_8888這個巨集定義,強制轉為了BGRA8888
+ name:FramebufferSurface, id:e200000000, size:8.1e+03KiB, w/h:780x438, usage: 0x1b00, req fmt:1, fourcc/mod:875713089/0, dataspace: 0x0, compressed: false
        planes: B/G/R/A:         w/h:780x438, stride:1e00 bytes, size:7e9000

 

5.3 用於GPU合成的GraphicBuffer的size(width & height)是由什麼決定的?

答案是當前螢幕的解析度,也就是 Display的 active mode

比如我的Android TV平臺,設定不同的電視解析度

// 720 TV
GraphicBufferAllocator buffers:
    Handle |        Size |     W (Stride) x H | Layers |   Format |      Usage | Requestor
0xf2d8e0d0 | 3600.00 KiB | 1280 (1280) x  720 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xf2d937d0 | 3600.00 KiB | 1280 (1280) x  720 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xf2d98050 | 3600.00 KiB | 1280 (1280) x  720 |      1 |        1 | 0x    1b00 | FramebufferSurface

// 1080 TV
GraphicBufferAllocator buffers:
    Handle |        Size |     W (Stride) x H | Layers |   Format |      Usage | Requestor
0xf2d81d10 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xf2d83840 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xf2d85ab0 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface

// 4K TV(限制ro.surface_flinger.max_graphics_height/width)
GraphicBufferAllocator buffers:
    Handle |        Size |     W (Stride) x H | Layers |   Format |      Usage | Requestor
0xe8041b40 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xe8045c80 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface
0xe804fa30 | 8100.00 KiB | 1920 (1920) x 1080 |      1 |        1 | 0x    1b00 | FramebufferSurface

下面的屬性是受平臺限制,GPU最大可以支援的合成的size

console:/ $ getprop | grep max_graphics
[ro.surface_flinger.max_graphics_height]: [1080]
[ro.surface_flinger.max_graphics_width]: [1920]

 

本文作者@二的次方  2022-05-10 釋出於部落格園

大概就講這些吧,之後想到什麼問題再補充。

 

相關文章