안드로이드/안드로이드 프레임워크

안드로이드 미디어 프레임워크(SurfaceFlinger) 학습 3

냥냥냥냥냥냥 2024. 2. 27. 22:49

안드로이드 미디어 프레임워크(SurfaceFlinger) 학습 2 (tistory.com)

 

안드로이드 미디어 프레임워크(SurfaceFlinger) 학습 2

안드로이드 미디어 프레임워크(SurfaceFlinger) 학습 1 (tistory.com) 안드로이드 미디어 프레임워크(SurfaceFlinger) 학습 1 이번에 이 글을 작성하게 되는 이유는 위의 Android 공식 홈페이지의 기술되어 있는

nyaang.tistory.com

 

지난 번의 분석은 SurfaceFlinger의 createLayer와 역할에 대해서 봤는데
이번에 분석을 해볼 사항은, SurfaceFlinger의 sequence에 대해서 다시 한 번 알아보려고 합니다

SurfaceFlinger sequence diagram

이번에 알아볼 전체적인 sequence diagram입니다
사실 중요한 부분이 너무 많아서 ㅜㅜ 복잡해 보입니다 (실제로는 더 복잡하지만 꽤 많이 생략)
 
이전 분석에서 확인했듯 SurfaceFlinger는 layer단위로 관리를 하고 있으며, 실질적으로 composing 해야하는 경우 
HWComposer에게 compose 요청 하고, 이전에 봤던 queueBuffer를 해놓은 frameBuffer를 acquireBuffer를 통해 가져와서
(BufferItem에 담아서) Slot index를 통해서

mCurrentBufferSlot = item.mSlot;
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
mCurrentFence = item.mFence;

이런식으로 가져와서 buffer를 가져오게 됩니다
 
HwcComposition에서 쓰는 type은 아래와 같습니다
CLIENT가 GPU를 사용한 buffer, DEVICE가 hardware overlay인 것 같습니다

enum HwcCompositionType {
    // Invalid composition type
    INVALID = 0;
    // Layer was composited by the client into the client target buffer
    CLIENT = 1;
    // Layer was composited by the device through hardware overlays
    DEVICE = 2;
    // Layer was composited by the device using a color
    SOLID_COLOR = 3;
    // Similar to DEVICE, but the layer position may have been asynchronously set
    // through setCursorPosition
    CURSOR = 4;
    // Layer was composited by the device via a sideband stream.
    SIDEBAND = 5;
}

 

Output::prepare


// Output::rebuildLayerStacks
void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs,
                                LayerFESet& layerFESet) {
                                
    ...
    
    auto& outputState = editState();

    // Do nothing if this output is not enabled or there is no need to perform this update
    if (!outputState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) {
        return;
    }

    // Process the layers to determine visibility and coverage
    compositionengine::Output::CoverageState coverage{layerFESet};
    collectVisibleLayers(refreshArgs, coverage);



// Output::collectVisibleLayers
void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
                                  compositionengine::Output::CoverageState& coverage) {
    // Evaluate the layers from front to back to determine what is visible. This
    // also incrementally calculates the coverage information for each layer as
    // well as the entire output.
    for (auto layer : reversed(refreshArgs.layers)) {
        // Incrementally process the coverage for each layer
        ensureOutputLayerIfVisible(layer, coverage);

        // TODO(b/121291683): Stop early if the output is completely covered and
        // no more layers could even be visible underneath the ones on top.
    }

    setReleasedLayers(refreshArgs);

    finalizePendingOutputLayers();
}

prepare에서는 말 그대로 준비를 하는 곳인데, 실제적으로 visible한 layer만 그리는게 성능적으로 당연히 유리하기에
visible한지 체크하여 보여야하는 layer만 뽑아내는 작업을 합니다
자세한 로직은 ensureOutputLayerIfVislble에서 진행을 합니다 
 
 

Output::present


present는 선물이 아니라, 표현해주는 부분입니다

void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
    ATRACE_CALL();
    ALOGV(__FUNCTION__);

    updateColorProfile(refreshArgs);
    updateCompositionState(refreshArgs);
    planComposition();
    writeCompositionState(refreshArgs);
    setColorTransform(refreshArgs);
    beginFrame();
    prepareFrame();
    devOptRepaintFlash(refreshArgs);
    finishFrame(refreshArgs);
    postFramebuffer();
    renderCachedSets(refreshArgs);
}

각각이 다 중요한 함수겠지만 먼저 finishFrame을 보면
제일 처음 분석을 했던 queueBuffer부분 관련 된 부분과 연결이 됩니다
 

// 1. Output::FinishFrame
// swap buffers (presentation)
mRenderSurface->queueBuffer(std::move(*optReadyFence));

// 2. RenderSurface::queueBuffer
void RenderSurface::queueBuffer(base::unique_fd readyFence) {
    auto& state = mDisplay.getState();

    if (state.usesClientComposition || state.flipClientTarget) {
    
    ...
                status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
                                                         mTexture->getBuffer()->getNativeBuffer(),
                                                         dup(readyFence));
                                                         
    }

    status_t result = mDisplaySurface->advanceFrame();
    
 // 3. FrameBufferSurface::advanceFrame
 status_t FramebufferSurface::advanceFrame() {
    uint32_t slot = 0;
    sp<GraphicBuffer> buf;
    sp<Fence> acquireFence(Fence::NO_FENCE);
    Dataspace dataspace = Dataspace::UNKNOWN;
    status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
    
    
    
// 4. FrameBufferSurface::nextBuffer
status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
        sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
        Dataspace& outDataspace) {
        
    BufferItem item;
    status_t err = acquireBufferLocked(&item, 0);

    mCurrentBufferSlot = item.mSlot;
    mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
    mCurrentFence = item.mFence;

    outFence = item.mFence;
    mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
    outDataspace = static_cast<Dataspace>(item.mDataSpace);
    status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);

1,2,3,4 를 쭈욱 보시면
2번에서 clientComposition을 사용하거나 mTexture가 들어 있을 때에는 mNativeWindow의 queueBuffer를 요청합니다
4번을 보면 FrameBufferSurface의 nextBuffer 호출 시에, acquireBufferLocked가 불리고 이것이 결국 BufferQueueConsumer의 Buffer를 가져오게 됩니다
가져온 버퍼 들은 slot으로 구분을 하게 됩니다
 
그 이후 hardwareCompser에게 clientTarget을 set해줍니다
hwComposer의 경우 chip vendor (qc 퀄컴, slsi 삼성lsi) 에 따라 각각 구현되어 있는 부분이 있을 것으로 보입니다
 
 

SurfaceFlinger::postComposition


composition이 끝난 후에는 후처리 과정을 하기 위한 로직으로 보입니다
 
이렇게 전체적으로 
분석 1에서는 queueBuffer를 해주는 과정
분석 2에서는 createLayer를 통해 surfaceFlinger에서 관리하는 layer를 보고
분석 3(이장) 에서는 layer들을 통해 composition,  present를 어떻게 해주는 지 surfaceFlinger의 전체적인 과정에 대해서 쭉 확인을 해봤습니다
 
 4장에서는 surface <-> window의 관계를 좀 알아보려고 합니다
 
감사합니다!