HWC 합성 보이 기 (hwc display contents 1 t, hwc layer 1 t 데이터 구조 관계)
24742 단어 안 드 로 이 드 디 스 플레이 시스템
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;
}