HWC 합성 보이 기 (hwc display contents 1 t, hwc layer 1 t 데이터 구조 관계)

이전 블 로그 에 서 는 Surface Flinger 의 절차 와 hwc 와 Gralloc 모듈 의 대체적인 기능 을 분 석 했 으 나 그 중의 일부 데이터 구조 에 대해 서 는 잘 알 지 못 했 습 니 다. 이 블 로 그 는 주로 hwc 를 만 들 었 습 니 다.display_contents_1_t 데이터 구조 에 착안 하여 hal 층 hwc 의 일부 데이터 구 조 를 분석 하기 시작 했다.
hwc 생 성display_contents_1_t
setUpHWComposer 함수 에서 다음 코드 를 살 펴 보 겠 습 니 다. 각 display (디 스 플레이 장치 마다) 를 옮 겨 다 니 고 HWComposer 의 createWorkList 함 수 를 호출 하 며 현재 layer 의 수량 count 를 매개 변수 로 합 니 다.뒤에 hwc 의 prepare 함 수 를 호출 할 것 입 니 다.
    ......
    HWComposer& hwc(getHwComposer());
    if (hwc.initCheck() == NO_ERROR) {
        // build the h/w work list
        if (CC_UNLIKELY(mHwWorkListDirty)) {
            mHwWorkListDirty = false;
            for (size_t dpy=0 ; dpy hw(mDisplays[dpy]);
                const int32_t id = hw->getHwcDisplayId();
                if (id >= 0) {
                    const Vector< sp >& currentLayers(
                        hw->getVisibleLayersSortedByZ());
                    const size_t count = currentLayers.size();
                    if (hwc.createWorkList(id, count) == NO_ERROR) {
                        ......
                    }
                }
            }
        }
    ......
    status_t err = hwc.prepare();
    ......

디 스 플레이 데이터 구 조 를 먼저 살 펴 보면 디 스 플레이 장치 의 데 이 터 를 대표 합 니 다.그 중에서 list 변수 (hwc display contents 1 t 형식) 는 이 디 스 플레이 장치 의 모든 layer 데 이 터 를 포함 하고 layer 데 이 터 는 hwLayers 에 놓 습 니 다.이 list 의 마지막 은 framebufferTarget (gpu 합성 후의 layer) 입 니 다. 그리고 DisplayData 데이터 구조 에서 변 수 를 따로 주 었 습 니 다. framebufferTarget.
    struct DisplayData {
        DisplayData();
        ~DisplayData();
        Vector configs;
        size_t currentConfig;
        uint32_t format;    // pixel format from FB hal, for pre-hwc-1.1
        bool connected;
        bool hasFbComp;
        bool hasOvComp;
        size_t capacity;
        hwc_display_contents_1* list;//  layer
        hwc_layer_1* framebufferTarget;//gpu     layer
        buffer_handle_t fbTargetHandle;
        sp lastRetireFence;  // signals when the last set op retires
        sp lastDisplayFence; // signals when the last set op takes
                                    // effect on screen
        buffer_handle_t outbufHandle;
        sp outbufAcquireFence;

        // protected by mEventControlLock
        int32_t events;
    };

createWorkList 함 수 는 레이 어 를 신청 할 메모리 크기 를 계산 한 다음 malloc 를 통 해 메모 리 를 신청 하고 주 소 를 disp. list 에 부여 합 니 다. 그 다음 에 disp. list -> hwLayers 의 마지막 하 나 는 gpu 합성 후의 layer framebufferTarget 입 니 다.물론 우리 도 이 hwclayer_1. disp. framebuffer Target 에 부여 되 었 습 니 다.
status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
        return BAD_INDEX;
    }

    if (mHwc) {
        DisplayData& disp(mDisplayData[id]);
        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
            // we need space for the HWC_FRAMEBUFFER_TARGET
            numLayers++;
        }
        if (disp.capacity < numLayers || disp.list == NULL) {
            size_t size = sizeof(hwc_display_contents_1_t)
                    + numLayers * sizeof(hwc_layer_1_t);//       
            free(disp.list);
            disp.list = (hwc_display_contents_1_t*)malloc(size);//malloc  
            disp.capacity = numLayers;
        }
        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
            disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];//list hwLayers      framebufferTarget
            memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
            const DisplayConfig& currentConfig =
                    disp.configs[disp.currentConfig];
            const hwc_rect_t r = { 0, 0,
                    (int) currentConfig.width, (int) currentConfig.height };
            disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;//    target 
            disp.framebufferTarget->hints = 0;
            disp.framebufferTarget->flags = 0;
            disp.framebufferTarget->handle = disp.fbTargetHandle;
            disp.framebufferTarget->transform = 0;
            disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
                disp.framebufferTarget->sourceCropf.left = 0;
                disp.framebufferTarget->sourceCropf.top = 0;
                disp.framebufferTarget->sourceCropf.right =
                        currentConfig.width;
                disp.framebufferTarget->sourceCropf.bottom =
                        currentConfig.height;
            } else {
                disp.framebufferTarget->sourceCrop = r;
            }
            disp.framebufferTarget->displayFrame = r;
            disp.framebufferTarget->visibleRegionScreen.numRects = 1;
            disp.framebufferTarget->visibleRegionScreen.rects =
                &disp.framebufferTarget->displayFrame;
            disp.framebufferTarget->acquireFenceFd = -1;
            disp.framebufferTarget->releaseFenceFd = -1;
            disp.framebufferTarget->planeAlpha = 0xFF;
        }
        disp.list->retireFenceFd = -1;
        disp.list->flags = HWC_GEOMETRY_CHANGED;
        disp.list->numHwLayers = numLayers;
    }
    return NO_ERROR;
}
hwc_display_contents_1 의 데이터 구 조 는 다음 과 같 고 한 장치 의 데 이 터 를 대표 한다.
typedef struct hwc_display_contents_1 {
    /* File descriptor referring to a Sync HAL fence object which will signal
     * when this composition is retired. For a physical display, a composition
     * is retired when it has been replaced on-screen by a subsequent set. For
     * a virtual display, the composition is retired when the writes to
     * outputBuffer are complete and can be read. The fence object is created
     * and returned by the set call; this field will be -1 on entry to prepare
     * and set. SurfaceFlinger will close the returned file descriptor.
     */
    int retireFenceFd;

    union {
        /* Fields only relevant for HWC_DEVICE_VERSION_1_0. */
        struct {
            /* (dpy, sur) is the target of SurfaceFlinger's OpenGL ES
             * composition for HWC_DEVICE_VERSION_1_0. They aren't relevant to
             * prepare. The set call should commit this surface atomically to
             * the display along with any overlay layers.
             */
            hwc_display_t dpy;
            hwc_surface_t sur;
        };

        /* These fields are used for virtual displays when the h/w composer
         * version is at least HWC_DEVICE_VERSION_1_3. */
        struct {
            /* outbuf is the buffer that receives the composed image for
             * virtual displays. Writes to the outbuf must wait until
             * outbufAcquireFenceFd signals. A fence that will signal when
             * writes to outbuf are complete should be returned in
             * retireFenceFd.
             *
             * This field is set before prepare(), so properties of the buffer
             * can be used to decide which layers can be handled by h/w
             * composer.
             *
             * If prepare() sets all layers to FRAMEBUFFER, then GLES
             * composition will happen directly to the output buffer. In this
             * case, both outbuf and the FRAMEBUFFER_TARGET layer's buffer will
             * be the same, and set() has no work to do besides managing fences.
             *
             * If the TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS board config
             * variable is defined (not the default), then this behavior is
             * changed: if all layers are marked for FRAMEBUFFER, GLES
             * composition will take place to a scratch framebuffer, and
             * h/w composer must copy it to the output buffer. This allows the
             * h/w composer to do format conversion if there are cases where
             * that is more desirable than doing it in the GLES driver or at the
             * virtual display consumer.
             *
             * If some or all layers are marked OVERLAY, then the framebuffer
             * and output buffer will be different. As with physical displays,
             * the framebuffer handle will not change between frames if all
             * layers are marked for OVERLAY.
             */
            buffer_handle_t outbuf;

            /* File descriptor for a fence that will signal when outbuf is
             * ready to be written. The h/w composer is responsible for closing
             * this when no longer needed.
             *
             * Will be -1 whenever outbuf is NULL, or when the outbuf can be
             * written immediately.
             */
            int outbufAcquireFenceFd;
        };
    };

    /* List of layers that will be composed on the display. The buffer handles
     * in the list will be unique. If numHwLayers is 0, all composition will be
     * performed by SurfaceFlinger.
     */
    uint32_t flags;
    size_t numHwLayers;//layer   
    hwc_layer_1_t hwLayers[0];//  layer     

} hwc_display_contents_1_t;

hwclayer_1 의 데이터 구조
typedef struct hwc_layer_1 {
    /*
     * compositionType is used to specify this layer's type and is set by either
     * the hardware composer implementation, or by the caller (see below).
     *
     *  This field is always reset to HWC_BACKGROUND or HWC_FRAMEBUFFER
     *  before (*prepare)() is called when the HWC_GEOMETRY_CHANGED flag is
     *  also set, otherwise, this field is preserved between (*prepare)()
     *  calls.
     *
     * HWC_BACKGROUND
     *   Always set by the caller before calling (*prepare)(), this value
     *   indicates this is a special "background" layer. The only valid field
     *   is backgroundColor.
     *   The HWC can toggle this value to HWC_FRAMEBUFFER to indicate it CANNOT
     *   handle the background color.
     *
     *
     * HWC_FRAMEBUFFER_TARGET
     *   Always set by the caller before calling (*prepare)(), this value
     *   indicates this layer is the framebuffer surface used as the target of
     *   OpenGL ES composition. If the HWC sets all other layers to HWC_OVERLAY
     *   or HWC_BACKGROUND, then no OpenGL ES composition will be done, and
     *   this layer should be ignored during set().
     *
     *   This flag (and the framebuffer surface layer) will only be used if the
     *   HWC version is HWC_DEVICE_API_VERSION_1_1 or higher. In older versions,
     *   the OpenGL ES target surface is communicated by the (dpy, sur) fields
     *   in hwc_compositor_device_1_t.
     *
     *   This value cannot be set by the HWC implementation.
     *
     *
     * HWC_FRAMEBUFFER
     *   Set by the caller before calling (*prepare)() ONLY when the
     *   HWC_GEOMETRY_CHANGED flag is also set.
     *
     *   Set by the HWC implementation during (*prepare)(), this indicates
     *   that the layer will be drawn into the framebuffer using OpenGL ES.
     *   The HWC can toggle this value to HWC_OVERLAY to indicate it will
     *   handle the layer.
     *
     *
     * HWC_OVERLAY
     *   Set by the HWC implementation during (*prepare)(), this indicates
     *   that the layer will be handled by the HWC (ie: it must not be
     *   composited with OpenGL ES).
     *
     *
     * HWC_SIDEBAND
     *   Set by the caller before calling (*prepare)(), this value indicates
     *   the contents of this layer come from a sideband video stream.
     *
     *   The h/w composer is responsible for receiving new image buffers from
     *   the stream at the appropriate time (e.g. synchronized to a separate
     *   audio stream), compositing them with the current contents of other
     *   layers, and displaying the resulting image. This happens
     *   independently of the normal prepare/set cycle. The prepare/set calls
     *   only happen when other layers change, or when properties of the
     *   sideband layer such as position or size change.
     *
     *   If the h/w composer can't handle the layer as a sideband stream for
     *   some reason (e.g. unsupported scaling/blending/rotation, or too many
     *   sideband layers) it can set compositionType to HWC_FRAMEBUFFER in
     *   (*prepare)(). However, doing so will result in the layer being shown
     *   as a solid color since the platform is not currently able to composite
     *   sideband layers with the GPU. This may be improved in future
     *   versions of the platform.
     *
     *
     * HWC_CURSOR_OVERLAY
     *   Set by the HWC implementation during (*prepare)(), this value
     *   indicates the layer's composition will now be handled by the HWC.
     *   Additionally, the client can now asynchronously update the on-screen
     *   position of this layer using the setCursorPositionAsync() api.
     */
    int32_t compositionType;//      

    /*
     * hints is bit mask set by the HWC implementation during (*prepare)().
     * It is preserved between (*prepare)() calls, unless the
     * HWC_GEOMETRY_CHANGED flag is set, in which case it is reset to 0.
     *
     * see hwc_layer_t::hints
     */
    uint32_t hints;

    /* see hwc_layer_t::flags */
    uint32_t flags;

    union {
        /* color of the background.  hwc_color_t.a is ignored */
        hwc_color_t backgroundColor;

        struct {
            union {
                /* When compositionType is HWC_FRAMEBUFFER, HWC_OVERLAY,
                 * HWC_FRAMEBUFFER_TARGET, this is the handle of the buffer to
                 * compose. This handle is guaranteed to have been allocated
                 * from gralloc using the GRALLOC_USAGE_HW_COMPOSER usage flag.
                 * If the layer's handle is unchanged across two consecutive
                 * prepare calls and the HWC_GEOMETRY_CHANGED flag is not set
                 * for the second call then the HWComposer implementation may
                 * assume that the contents of the buffer have not changed. */
                buffer_handle_t handle;//      ,      

                /* When compositionType is HWC_SIDEBAND, this is the handle
                 * of the sideband video stream to compose. */
                const native_handle_t* sidebandStream;
            };

            /* transformation to apply to the buffer during composition */
            uint32_t transform;

            /* blending to apply during composition */
            int32_t blending;

            ......

            /* where to composite the sourceCrop onto the display. The sourceCrop
             * is scaled using linear filtering to the displayFrame. The origin is the
             * top-left corner of the screen.
             */
            hwc_rect_t displayFrame;

            /* visible region in screen space. The origin is the
             * top-left corner of the screen.
             * The visible region INCLUDES areas overlapped by a translucent layer.
             */
            hwc_region_t visibleRegionScreen;

            /* Sync fence object that will be signaled when the buffer's
             * contents are available. May be -1 if the contents are already
             * available. This field is only valid during set(), and should be
             * ignored during prepare(). The set() call must not wait for the
             * fence to be signaled before returning, but the HWC must wait for
             * all buffers to be signaled before reading from them.
             *
             * HWC_FRAMEBUFFER layers will never have an acquire fence, since
             * reads from them are complete before the framebuffer is ready for
             * display.
             *
             * HWC_SIDEBAND layers will never have an acquire fence, since
             * synchronization is handled through implementation-defined
             * sideband mechanisms.
             *
             * The HWC takes ownership of the acquireFenceFd and is responsible
             * for closing it when no longer needed.
             */
            int acquireFenceFd;

            /* During set() the HWC must set this field to a file descriptor for
             * a sync fence object that will signal after the HWC has finished
             * reading from the buffer. The field is ignored by prepare(). Each
             * layer should have a unique file descriptor, even if more than one
             * refer to the same underlying fence object; this allows each to be
             * closed independently.
             *
             * If buffer reads can complete at significantly different times,
             * then using independent fences is preferred. For example, if the
             * HWC handles some layers with a blit engine and others with
             * overlays, then the blit layers can be reused immediately after
             * the blit completes, but the overlay layers can't be reused until
             * a subsequent frame has been displayed.
             *
             * Since HWC doesn't read from HWC_FRAMEBUFFER layers, it shouldn't
             * produce a release fence for them. The releaseFenceFd will be -1
             * for these layers when set() is called.
             *
             * Since HWC_SIDEBAND buffers don't pass through the HWC client,
             * the HWC shouldn't produce a release fence for them. The
             * releaseFenceFd will be -1 for these layers when set() is called.
             *
             * The HWC client taks ownership of the releaseFenceFd and is
             * responsible for closing it when no longer needed.
             */
            int releaseFenceFd;

            ......

            /*
             * Availability: HWC_DEVICE_API_VERSION_1_5
             *
             * This defines the region of the source buffer that has been
             * modified since the last frame.
             *
             * If surfaceDamage.numRects > 0, then it may be assumed that any
             * portion of the source buffer not covered by one of the rects has
             * not been modified this frame. If surfaceDamage.numRects == 0,
             * then the whole source buffer must be treated as if it had been
             * modified.
             *
             * If the layer's contents are not modified relative to the prior
             * prepare/set cycle, surfaceDamage will contain exactly one empty
             * rect ([0, 0, 0, 0]).
             *
             * The damage rects are relative to the pre-transformed buffer, and
             * their origin is the top-left corner.
             */
            hwc_region_t surfaceDamage;
        };
    };

......

} hwc_layer_1_t;

HWComposer 의 prepare 함 수 를 살 펴 보 겠 습 니 다. 이 함 수 는 주로 HWC 모듈 의 prepare 함 수 를 호출 한 다음 에 disp. list 의 각 layer 데이터 에 따라 disp 에 해당 하 는 변 수 를 수정 합 니 다. 예 를 들 어 hasOvComp 는 hwc 합성 이 필요 한 지, hasFbComp 는 gpu 합성 이 필요 한 지 여부 입 니 다.HWComposer 의 prepare 함 수 는 대응 하 는 그래 픽 의 유형 을 HWC 로 설정 합 니 다.FRAMEBUFPER 는 GPU 합성 이 필요 하 다 는 뜻 입 니 다.
그리고 HWComposer 의 mList 는 각 디 스 플레이 장치 에 대응 하고 DisplayData 의 list 변 수 는 hwc 입 니 다.display_contents_1
status_t HWComposer::prepare() {
    Mutex::Autolock _l(mDisplayLock);
    for (size_t i=0 ; icompositionType = HWC_FRAMEBUFFER_TARGET;// framebufferTarget     
        }
        if (!disp.connected && disp.list != NULL) {
            ALOGW("WARNING: disp %zu: connected, non-null list, layers=%zu",
                  i, disp.list->numHwLayers);
        }
        mLists[i] = disp.list;//mLists               hwc_display_contents_1
        if (mLists[i]) {
            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
                mLists[i]->outbuf = disp.outbufHandle;
                mLists[i]->outbufAcquireFenceFd = -1;
            } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
                // garbage data to catch improper use
                mLists[i]->dpy = (hwc_display_t)0xDEADBEEF;
                mLists[i]->sur = (hwc_surface_t)0xDEADBEEF;
            } else {
                mLists[i]->dpy = EGL_NO_DISPLAY;
                mLists[i]->sur = EGL_NO_SURFACE;
            }
        }
    }

    int err = mHwc->prepare(mHwc, mNumDisplays, mLists);//  hwc prepare  

    if (err == NO_ERROR) {
        for (size_t i=0 ; inumHwLayers ; i++) {
                    hwc_layer_1_t& l = disp.list->hwLayers[i];//    layer,  disp     

                    if (l.flags & HWC_SKIP_LAYER) {
                        l.compositionType = HWC_FRAMEBUFFER;
                    }
                    if (l.compositionType == HWC_FRAMEBUFFER) {
                        disp.hasFbComp = true;
                    }
                    if (l.compositionType == HWC_OVERLAY) {
                        disp.hasOvComp = true;
                    }
                    if (l.compositionType == HWC_CURSOR_OVERLAY) {
                        disp.hasOvComp = true;
                    }
                }
                if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
                    disp.hasFbComp = true;
                }
            } else {
                disp.hasFbComp = true;
            }
        }
    }
    return (status_t)err;
}

egl 합성
... 에 있다http://blog.csdn.net/kc58236582/article/details/52868973#t1블 로그 에서 우 리 는 GPU 가 각 layer 를 합성 하 는 절 차 를 분석 한 적 이 있다.우 리 는 egl 에서 데 이 터 를 합성 한 후에 분석 을 시작 하면 Framebuffer Surface 의 onFrameAvailable 함수 에 도착 합 니 다.이 함 수 는 HWComposer 의 fbPost 함 수 를 직접 호출 하 였 습 니 다.
fbPost 함수
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
    sp buf;
    sp acquireFence;
    status_t err = nextBuffer(buf, acquireFence);
    if (err != NO_ERROR) {
        ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
                strerror(-err), err);
        return;
    }
    err = mHwc.fbPost(mDisplayType, acquireFence, buf);
    if (err != NO_ERROR) {
        ALOGE("error posting framebuffer: %d", err);
    }
}

setFramebufferTarget 함 수 는 주로 Target 의 handle 대상 을 Framework 층 의 DisplayData 에 주 는 fbTargetHandle 입 니 다.
int HWComposer::fbPost(int32_t id,
        const sp& acquireFence, const sp& buffer) {
    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
        return setFramebufferTarget(id, acquireFence, buffer);
    } else {
        acquireFence->waitForever("HWComposer::fbPost");
        return mFbDev->post(mFbDev, buffer->handle);
    }
}

디 스 플레이 장치 에 HWC 출력
마지막 으로 Surface Flinger 의 doComposition 함수 에서 post Framebuffer 함 수 를 호출 합 니 다. 이 함 수 는 주로 HWComposer 의 commt 함 수 를 호출 하여 HWC 모듈 로 마지막 으로 디 스 플레이 장치 에 갑 니 다.
status_t HWComposer::setFramebufferTarget(int32_t id,
        const sp& acquireFence, const sp& buf) {
    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
        return BAD_INDEX;
    }
    DisplayData& disp(mDisplayData[id]);
    if (!disp.framebufferTarget) {
        // this should never happen, but apparently eglCreateWindowSurface()
        // triggers a Surface::queueBuffer()  on some
        // devices (!?) -- log and ignore.
        ALOGE("HWComposer: framebufferTarget is null");
        return NO_ERROR;
    }

    int acquireFenceFd = -1;
    if (acquireFence->isValid()) {
        acquireFenceFd = acquireFence->dup();
    }

    // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd);
    disp.fbTargetHandle = buf->handle;// target buffer handle DisplayData fbTargetHandle
    disp.framebufferTarget->handle = disp.fbTargetHandle;
    disp.framebufferTarget->acquireFenceFd = acquireFenceFd;
    return NO_ERROR;
}





좋은 웹페이지 즐겨찾기