在之前的博客中,分析了SurfaceFlinger的流程,以及hwc和Gralloc模块的大致功能,但是对其中一些数据结构不是很清楚. 这篇博客我们主要从创建hwc_display_contents_1_t数据结构入手开始对hal层 hwc的一些数据结构进行分析。
我们先来看看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();
......
我们先来看DisplayData数据结构,它就代表一个显示设备的数据。其中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函数先是计算我们要申请layer的内存大小,然后通过malloc申请内存,并且地址赋给disp.list.后面我们把disp.list->hwLayers的最后一个其实就是gpu合成之后的layer framebufferTarget。当然我们也就把这个hwc_layer_1赋给了disp.framebufferTarget.
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;
再来看看hwc_layer_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_FRAMEBUFFER代表就是需要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;
}
在http://blog.csdn.net/kc58236582/article/details/52868973#t1博客中,我们分析过GPU合成各个layer的流程。我们直接从egl合成好数据好之后开始分析,就到FramebufferSurface的onFrameAvailable函数。这个函数直接调用了HWComposer的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);
}
}
fbPost函数我们这里是调用了setFramebufferTarget函数。
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);
}
}
setFramebufferTarget函数主要是将Target的handle对象给Framework层的DisplayData的fbTargetHandle
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;
}
最后在SurfaceFlinger的doComposition函数中会调用postFramebuffer函数,这个函数主要是调用了HWComposer的commit函数,就到HWC模块来最后到显示设备上。
status_t HWComposer::commit() {
int err = NO_ERROR;
if (mHwc) {
if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// On version 1.0, the OpenGL ES target surface is communicated
// by the (dpy, sur) fields and we are guaranteed to have only
// a single display.
mLists[0]->dpy = eglGetCurrentDisplay();
mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
}
for (size_t i=VIRTUAL_DISPLAY_ID_BASE; ioutbuf = disp.outbufHandle;
mLists[i]->outbufAcquireFenceFd =
disp.outbufAcquireFence->dup();
}
}
err = mHwc->set(mHwc, mNumDisplays, mLists);//调用HWC的set函数,输出到显示设备
for (size_t i=0 ; iretireFenceFd != -1) {
disp.lastRetireFence = new Fence(disp.list->retireFenceFd);
disp.list->retireFenceFd = -1;
}
disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
}
}
}
return (status_t)err;
}