HWComposer介紹
HWComposer類的作用:
1:打開了Gralloc模塊FB設(shè)備室埋,負責將圖像緩沖區(qū)的內(nèi)容渲染到FB顯示緩沖區(qū)
Gralloc模塊可以打開兩種設(shè)備显沈,一種負責分配圖形緩沖區(qū)两芳,另一種打開FB設(shè)備驯鳖,負責渲染FB緩沖區(qū)。
2:負責管理硬件HWComposer設(shè)備
HWC(hwcomposer)是Android中進行窗口(Layer)合成和顯示的HAL層模塊袍祖,其實現(xiàn)是特定于設(shè)備的底瓣,而且通常由顯示設(shè)備制造商 (OEM)完成,為SurfaceFlinger服務(wù)提供硬件支持盲泛。
SurfaceFlinger可以使用OpenGL ES合成Layer,這需要占用并消耗GPU資源键耕。大多數(shù)GPU都沒有針對圖層合成進行優(yōu)化寺滚,當SurfaceFlinger通過GPU合成圖層時,應(yīng)用程序無法使用GPU進行自己的渲染屈雄。而HWC通過硬件設(shè)備進行圖層合成村视,可以減輕GPU的合成壓力。
3:硬件HWComposer負責產(chǎn)生硬件VSync信號
HWC也提供了VSync事件酒奶,用于管理渲染和圖層合成時機蚁孔。
HWComposer初始化過程
在SurfaceFlinger的init方法中會初始化HWComposer對象
// Initialize the H/W composer object. There may or may not be an
// actual hardware composer underneath.
mHwc = new HWComposer(this,
*static_cast<HWComposer::EventHandler *>(this));
init方法中直接創(chuàng)建了一個HWComposer對象奶赔,保存在SurfaceFlinger中。
HWComposer::HWComposer(
const sp<SurfaceFlinger>& flinger,
EventHandler& handler)
: mFlinger(flinger),
mFbDev(0), mHwc(0), mNumDisplays(1),
mCBContext(new cb_context),
mEventHandler(handler),
mDebugForceFakeVSync(false)
{
......
bool needVSyncThread = true;
// 加載Gralloc HAL模塊杠氢,并打開FB設(shè)備站刑,保存在mFbDev中
int fberr = loadFbHalModule();、
// 加載HWComposer HAL模塊鼻百,并打開HWC設(shè)備绞旅,保存在mHWC中
loadHwcModule();
......
// 保留前三個設(shè)備ID
for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
mAllocatedDisplayIDs.markBit(i);
}
//如果打開HWC成功,則向HWC HAL注冊回調(diào)函數(shù)
if (mHwc) {
if (mHwc->registerProcs) {
mCBContext->hwc = this;
//注冊HWC硬件強制刷新的回調(diào)函數(shù)
mCBContext->procs.invalidate = &hook_invalidate;
//注冊硬件Vsync回調(diào)函數(shù)
mCBContext->procs.vsync = &hook_vsync;
//注冊熱插拔回調(diào)函數(shù)
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
mCBContext->procs.hotplug = &hook_hotplug;
else
mCBContext->procs.hotplug = NULL;
memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
mHwc->registerProcs(mHwc, &mCBContext->procs);
}
// 是否需要軟件模擬VSYNC信號
needVSyncThread = false;
// 硬件HWC VSYNC 開始的時候默認關(guān)閉
eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
//根據(jù)HWC的版本好温艇,決定支持顯示設(shè)備的數(shù)量
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
// 1.3 adds support for virtual displays
mNumDisplays = MAX_HWC_DISPLAYS;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// 1.1 adds support for multiple displays
mNumDisplays = NUM_BUILTIN_DISPLAYS;
} else {
mNumDisplays = 1;
}
}
//如果FB設(shè)備打開成功因悲,則獲取FB顯示設(shè)備的基本信息,保存在對應(yīng)的DisplayData對象中.
if (mFbDev) {
DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
disp.connected = true;
disp.format = mFbDev->format;
DisplayConfig config = DisplayConfig();
config.width = mFbDev->width;
config.height = mFbDev->height;
config.xdpi = mFbDev->xdpi;
config.ydpi = mFbDev->ydpi;
config.refresh = nsecs_t(1e9 / mFbDev->fps);
disp.configs.push_back(config);
disp.currentConfig = 0;
} else if (mHwc) {
// here we're guaranteed to have at least HWC 1.1
for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
queryDisplayProperties(i);
}
}
//如果沒有HWC硬件勺爱,則需要創(chuàng)建一個VSyncThread軟件模擬VSYNC信號
if (needVSyncThread) {
mVSyncThread = new VSyncThread(*this);
}
}
HWComposer的初始化函數(shù)做了那些內(nèi)容晃琳?
1:加載Gralloc模塊,打開FB設(shè)備琐鲁,用于渲染顯示緩沖區(qū)
2:加載HWC HAL模塊卫旱,打開HWC設(shè)備,用于硬件合成Layer及產(chǎn)生Vsync信號
3:注冊HWC Vsync, 熱插拔绣否,強制刷新的回調(diào)函數(shù)
4:獲取FB顯示驅(qū)動相關(guān)的參數(shù)誊涯,存放到DisplayData中
HWComposer 的DisplayData
struct DisplayData {
DisplayData();
~DisplayData();
Vector<DisplayConfig> configs; //設(shè)備配置信息
size_t currentConfig;
uint32_t format; //FB Hal的數(shù)據(jù)格式
bool connected; //設(shè)備時候連接
bool hasFbComp; //是否需要GL合成
bool hasOvComp; //是否需要HWC河涌
size_t capacity; //列表的最大容量
hwc_display_contents_1* list; //要合成的Layer的列表,用于傳遞個HWC HAL
hwc_layer_1* framebufferTarget; //HWComposer將列表中的Layer合成后最終存放到這個Layer中
buffer_handle_t fbTargetHandle; //最終合成Layer對應(yīng)的圖像緩沖區(qū)
......
buffer_handle_t outbufHandle;
sp<Fence> outbufAcquireFence;
// protected by mEventControlLock
int32_t events;
};
SurfaceFlinger中有DisplayDevice來描述一個顯示設(shè)備蒜撮, HWComposer中DisplayData來描述一個顯示設(shè)備需要顯示的數(shù)據(jù)信息暴构。詳細注釋已經(jīng)在代碼中
HWComposer 硬件合成相關(guān)接口分析
SurfaceFlinger合成圖像的時候會調(diào)用setHWComposer函數(shù),來設(shè)置HWComposer硬件合成相關(guān)的參數(shù)
//創(chuàng)建HWComposer任務(wù)列表段磨,并初始化基本的屬性信息
HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) {
// 創(chuàng)建HWC 合成的工作列表
if (CC_UNLIKELY(mHwWorkListDirty)) {
mHwWorkListDirty = false;
//變量所有的顯示設(shè)備列表取逾,為每個顯示設(shè)備都創(chuàng)建工作任務(wù)列表
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
//獲取當前顯示設(shè)備需要顯示的Layer列表,存放在VisibleLayersSortedByZ列表中
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
//調(diào)用HWComposer的createWorkList創(chuàng)建工作列表苹支,指定顯示設(shè)備ID和Layer數(shù)量
if (hwc.createWorkList(id, count) == NO_ERROR) {
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
const sp<Layer>& layer(currentLayers[i]);
//遍歷通過SurfaceFlinger的Layer設(shè)置HWC Layer的混合模式砾隅,裁剪區(qū)域等屬性
layer->setGeometry(hw, *cur);
if (mDebugDisableHWC || mDebugRegion || mDaltonize || mHasColorMatrix) {
cur->setSkip(true);
}
}
}
}
}
}
// 為HWComposer的每個Layer設(shè)置圖形數(shù)據(jù)
// 遍歷所有的顯示設(shè)備,為每個設(shè)備的工作列表中的Layer設(shè)置數(shù)據(jù)
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
const int32_t id = hw->getHwcDisplayId();
if (id >= 0) {
//獲取當前顯示設(shè)備中需要顯示的Layer列表
const Vector< sp<Layer> >& currentLayers(
hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
HWComposer::LayerListIterator cur = hwc.begin(id);
const HWComposer::LayerListIterator end = hwc.end(id);
for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
//通過SF中Layer的setPerFrameData方法债蜜,設(shè)置HWC Layer的圖形數(shù)據(jù)晴埂,將Buffer指給HWC 的Layer
const sp<Layer>& layer(currentLayers[i]);
layer->setPerFrameData(hw, *cur);
}
}
}
//調(diào)用HWC的prepare,做硬件合成準備
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
SF設(shè)置HWComposer的順序如下:
1:調(diào)用HWComposer的createWorkList創(chuàng)建合成任務(wù)列表
2:遍歷所有的Layer為HWComposer的Layer設(shè)置圖形數(shù)據(jù)
3:調(diào)用HWComposer的prepare做合成準備
HWComposer創(chuàng)建任務(wù)列表
HWComposer用于合成Layer圖像數(shù)據(jù)寻定,HWComposer硬件合成第一步是創(chuàng)建HWComposer任務(wù)列表
//參數(shù)id 表示當前為哪個顯示設(shè)備創(chuàng)建任務(wù)列表儒洛, numLayers表示要創(chuàng)建多大的列表,也就是SurfaceFlinger中有多少個Layer要顯示在這個屏幕上狼速。
status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
return BAD_INDEX;
}
if (mHwc) {
//找到當前ID對應(yīng)的顯示設(shè)備的信息
DisplayData& disp(mDisplayData[id]);
//如果版本大于HWC_DEVICE_API_VERSION_1_1琅锻, 則需要多創(chuàng)建一個Layer, 這個Layer用來存放那些需要軟件合成的Layer GL合成后的圖像數(shù)據(jù),這些Layer合成后的數(shù)據(jù)會放到任務(wù)列表中和其他的Layer一起參與硬件合成
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
numLayers++;
}
//如果對應(yīng)顯示設(shè)備的列表還沒有分配內(nèi)存,或者容量較小恼蓬,則釋放掉原來的列表惊完,重新分配內(nèi)存
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);
disp.capacity = numLayers;
}
//如果版本大于HWC_DEVICE_API_VERSION_1_1
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
//將列表中最后一個Layer作為GL軟件合成最后的存放Layer
disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
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 };
//設(shè)置最后一個Layer的合成方式為HWC_FRAMEBUFFER_TARGET
disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
disp.framebufferTarget->hints = 0;
disp.framebufferTarget->flags = 0;
disp.framebufferTarget->handle = disp.fbTargetHandle;
disp.framebufferTarget->transform = 0;
disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
//設(shè)置最終GL合成的區(qū)域
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;
//設(shè)置列表中Layer的數(shù)量為numHwLayers
disp.list->numHwLayers = numLayers;
}
return NO_ERROR;
}
DisplayData描述了一個顯示設(shè)備要合成的數(shù)據(jù)信息,其中有一個Layer列表处硬,存放SufaceFlinger設(shè)置的該顯示設(shè)備即將參加合成的Layer列表小槐。
創(chuàng)建任務(wù)列表的時候首先需要判斷列表的容量是否足以容納當前設(shè)置的Layer數(shù)量,如果存放不了則需要重新分配列表的內(nèi)存空間郁油。
當我們把Layer列表交個硬件進行合成的時候本股,需要多指定一個Layer,該Layer用來存放桐腌,軟件GL合成Layer的最終圖像數(shù)據(jù)拄显,這些Layer被軟件合成的后放到任務(wù)列表最后一個Layer中,一起參與HWC硬件合成案站,最后一起顯示到屏幕上躬审,所以在申請列表空間的時候需要多申請一個Layer的空間。在列表中這個Layer的位置為列表最后一個蟆盐,最終輸出的這個Layer是需要openGL進行合成操作的承边,所以將最后的Layer的合成類型設(shè)置為HWC_FRAMEBUFFER_TARGET,表示這個Layer最終需要渲染到FB顯示緩沖區(qū)石挂。
HWComposer數(shù)據(jù)合成準備
status_t HWComposer::prepare() {
Mutex::Autolock _l(mDisplayLock);
......
//調(diào)用硬件HWC prepare 即將開始合成數(shù)據(jù)
int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
if (err == NO_ERROR) {
//遍歷每一個顯示設(shè)備博助,確定該顯示設(shè)備是否需要HWC和GL合成
for (size_t i=0 ; i<mNumDisplays ; i++) {
DisplayData& disp(mDisplayData[i]);
disp.hasFbComp = false;
disp.hasOvComp = false;
//遍歷該設(shè)備中的Layer
if (disp.list) {
for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
hwc_layer_1_t& l = disp.list->hwLayers[i];
//如果該Layer的flag為HWC_SKIP_LAYER, 則需要GL方式合成
if (l.flags & HWC_SKIP_LAYER) {
l.compositionType = HWC_FRAMEBUFFER;
}
//如果Layer合成方式為HWC_FRAMEBUFFER痹愚,設(shè)置該設(shè)備hasFbComp為true
if (l.compositionType == HWC_FRAMEBUFFER) {
disp.hasFbComp = true;
}
//如果Layer合成方式為HWC_OVERLAY富岳, 則設(shè)置該設(shè)備hasOvComp為true
if (l.compositionType == HWC_OVERLAY) {
disp.hasOvComp = true;
}
//如果Layer的合成凡是為HWC_CURSOR_OVERLAY, 也設(shè)置hasOvComp為ture
if (l.compositionType == HWC_CURSOR_OVERLAY) {
disp.hasOvComp = true;
}
}
//如果該Layer為openGL合成輸出的Layer則設(shè)置hasFbComp為true
if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
disp.hasFbComp = true;
}
} else {
//如果list為空拯腮,則默認為GL方式合成
disp.hasFbComp = true;
}
}
}
return (status_t)err;
}
HWComposer的prepare方法決定了該顯示設(shè)備支持那種合成方式窖式,合成方式主要分為兩種
HWC硬件合成和GL方式的軟件合成
有以下類型的Layer,該顯示設(shè)備需要支持HWC硬件合成
1:Layer的合成類型為 HWC_OVERLAY
2:Layer的合成類型為 HWC_CURSOR_OVERLAY 光標類型的Layer
什么情況下顯示設(shè)備需要支持軟件合成呢?
1:如果HWComposer的任務(wù)列表為空动壤,則默認該設(shè)備需要GL來進行軟件合成
2:如果有Layer的flag為HWC_SKIP_LAYER萝喘,則需要支持GL合成
3:如果該Layer是HWC指定的OpenGL軟件合成后輸出Layer,則需要支持GL軟件合成