版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Android6.0 图像合成过程详解(二) doComposition函数一、doComposition合成图层doComposition这个函数就是合成所有层的图像cpp view plain copy 在CODE上查看代码片派生到我的代码片void SurfaceFlinger:doComposition() ATRACE_CALL(); const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpymDisplays.size() ; dpy+) con
2、st sp& hw(mDisplaysdpy); if (hw-isDisplayOn() / transform the dirty region into this screens coordinate space const Region dirtyRegion(hw-getDirtyRegion(repaintEverything); / repaint the framebuffer (if needed) doDisplayComposition(hw, dirtyRegion); hw-dirtyRegion.clear(); hw-flip(hw-swapRegion); hw
3、-swapRegion.clear(); / inform the h/w that were done compositing hw-compositionComplete(); postFramebuffer(); 上面函数遍历所有的DisplayDevice然后调用doDisplayComposition函数。然后我们再看看doDisplayComposition函数cpp view plain copy 在CODE上查看代码片派生到我的代码片void SurfaceFlinger:doDisplayComposition(const sp& hw, const Region& inDi
4、rtyRegion) bool isHwcDisplay = hw-getHwcDisplayId() = 0; if (!isHwcDisplay & inDirtyRegion.isEmpty() return; Region dirtyRegion(inDirtyRegion); /swapRegion设置为需要更新的区域 hw-swapRegion.orSelf(dirtyRegion); uint32_t flags = hw-getFlags();/获得显示设备支持的更新方式标志 if (flags & DisplayDevice:SWAP_RECTANGLE) /支持矩阵更新 d
5、irtyRegion.set(hw-swapRegion.bounds(); else if (flags & DisplayDevice:PARTIAL_UPDATES) /支持部分更新 dirtyRegion.set(hw-swapRegion.bounds(); else /将更新区域调整为整个窗口大小 dirtyRegion.set(hw-bounds(); hw-swapRegion = dirtyRegion; if (CC_LIKELY(!mDaltonize & !mHasColorMatrix) if (!doComposeSurfaces(hw, dirtyRegion)
6、return;/合成 else RenderEngine& engine(getRenderEngine(); mat4 colorMatrix = mColorMatrix; if (mDaltonize) colorMatrix = colorMatrix * mDaltonizer(); mat4 oldMatrix = engine.setupColorTransform(colorMatrix); doComposeSurfaces(hw, dirtyRegion);/合成 engine.setupColorTransform(oldMatrix); / update the swa
7、p region and clear the dirty region hw-swapRegion.orSelf(dirtyRegion); / swap buffers (presentation) hw-swapBuffers(getHwComposer();/使用egl将egl中的合成好的图像,输出到DisplayDevice的mSurface中 这个函数设置下需要更新的区域,后面调用doComposeSurfaces函数来合成图层,调用完doComposeSurfaces函数后,如果需要egl合成图像话,在这个函数中合成好。而最后调用swapBuffers只是将egl合成好的图像输出到
8、DisplayDevice的mSurface中。我们再来看看doComposeSurfaces函数,我们先来看一开始的代码,先判断是否有egl合成,然后再看是否有hwc合成(硬件合成)cpp view plain copy 在CODE上查看代码片派生到我的代码片bool SurfaceFlinger:doComposeSurfaces(const sp& hw, const Region& dirty) RenderEngine& engine(getRenderEngine(); const int32_t id = hw-getHwcDisplayId(); HWComposer& hwc
9、(getHwComposer(); HWComposer:LayerListIterator cur = hwc.begin(id); const HWComposer:LayerListIterator end = hwc.end(id); bool hasGlesComposition = hwc.hasGlesComposition(id); if (hasGlesComposition) /是否有egl合成 if (!hw-makeCurrent(mEGLDisplay, mEGLContext) ALOGW(DisplayDevice:makeCurrent failed. Abor
10、ting surface composition for display %s, hw-getDisplayName().string(); eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if(!getDefaultDisplayDevice()-makeCurrent(mEGLDisplay, mEGLContext) ALOGE(DisplayDevice:makeCurrent on default display failed. Aborting.); return false;
11、 / Never touch the framebuffer if we dont have any framebuffer layers const bool hasHwcComposition = hwc.hasHwcComposition(id); if (hasHwcComposition) /是否有hwc合成 / when using overlays, we assume a fully transparent framebuffer / NOTE: we could reduce how much we need to clear, for instance / remove w
12、here there are opaque FB layers. however, on some / GPUs doing a clean slate clear might be more efficient. / Well revisit later if needed. engine.clearWithColor(0, 0, 0, 0); else / we start with the whole screen area const Region bounds(hw-getBounds(); / we remove the scissor part / were left with
13、the letterbox region / (common case is that letterbox ends-up being empty) const Region letterbox(bounds.subtract(hw-getScissor(); / compute the area to clear Region region(hw-undefinedRegion.merge(letterbox); / but limit it to the dirty region region.andSelf(dirty); / screen is already cleared here
14、 if (!region.isEmpty() / can happen with SurfaceView drawWormhole(hw, region); if (hw-getDisplayType() != DisplayDevice:DISPLAY_PRIMARY) / just to be on the safe side, we dont set the / scissor on the main display. It should never be needed / anyways (though in theory it could since the API allows i
15、t). const Rect& bounds(hw-getBounds(); const Rect& scissor(hw-getScissor(); if (scissor != bounds) / scissor doesnt match the screens dimensions, so we / need to clear everything outside of it and enable / the GL scissor so we dont draw anything where we shouldnt / enable scissor for this frame cons
16、t uint32_t height = hw-getHeight(); engine.setScissor(scissor.left, height - scissor.bottom, scissor.getWidth(), scissor.getHeight(); . 我们来看hasGlesComposition函数和hasHwcComposition函数,就是看其对应的DisplayData中是否有hasFbComp和hasOvComp。cpp view plain copy 在CODE上查看代码片派生到我的代码片bool HWComposer:hasGlesComposition(int
17、32_t id) const if (!mHwc | uint32_t(id)31 | !mAllocatedDisplayIDs.hasBit(id) return true; return mDisplayDataid.hasFbComp; cpp view plain copy 在CODE上查看代码片派生到我的代码片bool HWComposer:hasHwcComposition(int32_t id) const if (!mHwc | uint32_t(id)31 | !mAllocatedDisplayIDs.hasBit(id) return false; return mDi
18、splayDataid.hasOvComp; 而这两个值是在prepare中调用Hwc的prepare函数之后赋值的cpp view plain copy 在CODE上查看代码片派生到我的代码片status_t HWComposer:prepare() . int err = mHwc-prepare(mHwc, mNumDisplays, mLists); ALOGE_IF(err, HWComposer: prepare failed (%s), strerror(-err); if (err = NO_ERROR) / here were just making sure that sk
19、ip layers are set / to HWC_FRAMEBUFFER and were also counting how many layers / we have of each type. / / If there are no window layers, we treat the display has having FB / composition, because SurfaceFlinger will use GLES to draw the / wormhole region. for (size_t i=0 ; imNumDisplays ; i+) Display
20、Data& disp(mDisplayDatai); disp.hasFbComp = false; disp.hasOvComp = false; if (disp.list) for (size_t i=0 ; inumHwLayers ; i+) hwc_layer_1_t& l = disp.list-hwLayersi; /ALOGD(prepare: %d, type=%d, handle=%p, / i, positionType, l.handle); if (l.flags & HWC_SKIP_LAYER) positionType = HWC_FRAMEBUFFER; i
21、f (positionType = HWC_FRAMEBUFFER) disp.hasFbComp = true;/只要有一个layer是HWC_FRAMEBUFFER if (positionType = HWC_OVERLAY) disp.hasOvComp = true;/有一个layer是HWC_OVERLAY if (positionType = HWC_CURSOR_OVERLAY) disp.hasOvComp = true;/有一个layer是HWC_CURSOR_OVERLAY if (disp.list-numHwLayers = (disp.framebufferTarg
22、et ? 1 : 0) /layer的数量 有framebufferTarget为1 没有为0 disp.hasFbComp = true; else disp.hasFbComp = true;/没有list return (status_t)err; 我们继续看doComposeSurfaces函数,下面这个函数当cur!=end代表起码有两个以上图层,然后遍历图层,当layer是HWC_FRAMEBUFFER代表是需要egl合成的,而HWC_FRAMEBUFFER_TARGET是egl合成后使用的直接就跳了,HWC_CURSOR_OVERLAY和HWC_OVERLAY是用HWC模块(硬件
23、合成)的,也就不用调用Layer的draw方法。而如果图层只要1个或者没有,那么直接使用egl合成。cpp view plain copy 在CODE上查看代码片派生到我的代码片 HWComposer:LayerListIterator cur = hwc.begin(id); const HWComposer:LayerListIterator end = hwc.end(id); . const Vector sp & layers(hw-getVisibleLayersSortedByZ(); const size_t count = layers.size(); const Trans
24、form& tr = hw-getTransform(); if (cur != end) /代表起码有两个以上图层 / were using h/w composer for (size_t i=0 ; icount & cur!=end ; +i, +cur) /遍历图层 const sp& layer(layersi); const Region clip(ersect(tr.transform(layer-visibleRegion); if (!clip.isEmpty() switch (cur-getCompositionType() case HWC_CURS
25、OR_OVERLAY: case HWC_OVERLAY: const Layer:State& state(layer-getDrawingState(); if (cur-getHints() & HWC_HINT_CLEAR_FB) & i & layer-isOpaque(state) & (state.alpha = 0xFF) & hasGlesComposition) / never clear the very first layer since were / guaranteed the FB is already cleared layer-clearWithOpenGL(
26、hw, clip); break; case HWC_FRAMEBUFFER: layer-draw(hw, clip);/只有是HWC_FRAMEBUFFER才会调用Layer的draw合成 break; case HWC_FRAMEBUFFER_TARGET: / this should not happen as the iterator shouldnt / let us get there. ALOGW(HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu), i); break; layer-setAcquireFence(hw,
27、*cur); else / were not using h/w composer for (size_t i=0 ; icount ; +i) /只有一个或者没有图层 就直接使用Layer的draw合成 const sp& layer(layersi); const Region clip(ersect( tr.transform(layer-visibleRegion); if (!clip.isEmpty() layer-draw(hw, clip); / disable scissor at the end of the frame engine.disableSci
28、ssor(); return true; Layer的draw我们就不看了主要是使用egl合成纹理,但是有一点疑问,我们从来没有把layer中的mActiveBuffer放到egl中去,那么egl又是怎么合成各个layer的呢,我想肯定客户进程在绘制各个layer的时候,也是用egl绘制的,所有后面合成的时候egl有各个layer的buffer。后面我们再来看下DisplayDevice:swapBuffers函数,是使用eglSwapBuffers来把egl合成的数据放到mSurface中去。cpp view plain copy 在CODE上查看代码片派生到我的代码片void Displa
29、yDevice:swapBuffers(HWComposer& hwc) const / We need to call eglSwapBuffers() if: / (1) we dont have a hardware composer, or / (2) we did GLES composition this frame, and either / (a) we have framebuffer target support (not present on legacy / devices, where HWComposer:commit() handles things); or /
30、 (b) this is a virtual display if (hwc.initCheck() != NO_ERROR | (hwc.hasGlesComposition(mHwcDisplayId) & (hwc.supportsFramebufferTarget() | mType = DISPLAY_VIRTUAL) EGLBoolean success = eglSwapBuffers(mDisplay, mSurface); if (!success) EGLint error = eglGetError(); if (error = EGL_CONTEXT_LOST | mT
31、ype = DisplayDevice:DISPLAY_PRIMARY) LOG_ALWAYS_FATAL(eglSwapBuffers(%p, %p) failed with 0x%08x, mDisplay, mSurface, error); else ALOGE(eglSwapBuffers(%p, %p) failed with 0x%08x, mDisplay, mSurface, error); else if(hwc.supportsFramebufferTarget() | mType = DISPLAY_VIRTUAL) EGLBoolean success = eglSw
32、apBuffersVIV(mDisplay, mSurface); if (!success) EGLint error = eglGetError(); ALOGE(eglSwapBuffersVIV(%p, %p) failed with 0x%08x, mDisplay, mSurface, error); status_t result = mDisplaySurface-advanceFrame(); if (result != NO_ERROR) ALOGE(%s failed pushing new frame to HWC: %d, mDisplayName.string(),
33、 result); 二、FramebufferSurface收到egl合成数据之前分析DisplayDevice时候,还分析了FramebufferSurface,我们这里再来看下。在SurfaceFlinger.cpp中的init函数,在创建DisplayDevice之前,我们先调用createBufferQueue来创建了一个buffer的生产者和消费者,然后把消费者放入了FramebufferSurface,生产者放入了DisplayDevice中。cpp view plain copy 在CODE上查看代码片派生到我的代码片sp producer; sp consumer; Buffe
34、rQueue:createBufferQueue(&producer, &consumer, new GraphicBufferAlloc(); sp fbs = new FramebufferSurface(*mHwc, i, consumer); int32_t hwcId = allocateHwcDisplayId(type); sp hw = new DisplayDevice(this, type, hwcId, mHwc-getFormat(hwcId), isSecure, token, fbs, producer, mRenderEngine-getEGLConfig();
35、我们先来看生产者,下面是DisplayDevice的构造函数,生产者作为参数直接新建了一个Surface,然后把这个Surface作为参数调用eglCreateWindowSurface返回的就是mSurface,之前我们分析最后egl合成的数据时调用eglSwapBuffers并且把数据放到mSurface,这样最后肯定就到消费者(FramebufferSurface)去了。cpp view plain copy 在CODE上查看代码片派生到我的代码片mNativeWindow = new Surface(producer, false); ANativeWindow* const wind
36、ow = mNativeWindow.get(); /* * Create our displays surface */ EGLSurface surface; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (config = EGL_NO_CONFIG) config = RenderEngine:chooseEglConfig(display, format); surface = eglCreateWindowSurface(display, config, window, NULL); 最后到消费者那端的onF
37、rameAvailable,也就是FramebufferSurface的onFrameAvailable中,我们现在来分析下这个过程,也就解答了一个onFrameAvailable的疑惑。FramebufferSurface的父类是ConsumerBase类,我们来看其构造函数。先是构造了mConsumer,这里其实就是BufferQueueConsumer类,后面调用了其consumerConnect方法。cpp view plain copy 在CODE上查看代码片派生到我的代码片ConsumerBase:ConsumerBase(const sp& bufferQueue, bool c
38、ontrolledByApp) : mAbandoned(false), mConsumer(bufferQueue) mName = String8:format(unnamed-%d-%d, getpid(), createProcessUniqueId(); wp listener = static_cast(this); sp proxy = new BufferQueue:ProxyConsumerListener(listener); status_t err = mConsumer-consumerConnect(proxy, controlledByApp); if (err
39、!= NO_ERROR) CB_LOGE(ConsumerBase: error connecting to BufferQueue: %s (%d), strerror(-err), err); else mConsumer-setConsumerName(mName); 我们来看下BufferQueueConsumer类的consumerConnect方法,就是调用了connect方法。cpp view plain copy 在CODE上查看代码片派生到我的代码片virtual status_t consumerConnect(const sp& consumer, bool contro
40、lledByApp) return connect(consumer, controlledByApp); 这个方法中将mCore-mConsumerListener = consumerListener,这个mCore就是BufferQueueCore类。我们再从ConsumerBase的构造函数看这个consumerListener参数其实就是FrameBufferSurface对象本身。cpp view plain copy 在CODE上查看代码片派生到我的代码片status_t BufferQueueConsumer:connect( const sp& consumerListene
41、r, bool controlledByApp) ATRACE_CALL(); if (consumerListener = NULL) BQ_LOGE(connect(C): consumerListener may not be NULL); return BAD_VALUE; BQ_LOGV(connect(C): controlledByApp=%s, controlledByApp ? true : false); Mutex:Autolock lock(mCore-mMutex); if (mCore-mIsAbandoned) BQ_LOGE(connect(C): Buffer
42、Queue has been abandoned); return NO_INIT; mCore-mConsumerListener = consumerListener;/设置回调 mCore-mConsumerControlledByApp = controlledByApp; return NO_ERROR; 我们再看BufferQueueProducer:queueBuffer函数,这个函数应该是生产者已经使用好buffer了,这个使用会调用如下代码这个listener就是BufferQueueCore的mConsumerListener,传输的数据时BufferItem。再传之前把BufferItem的mGraphicBuffer清了,因为消费者可以自己获取buffer,不用通过BufferItem传。cpp view plain copy 在CODE上查看代码片派生到我的代码片item.mGraphicBuffer.clear(); item.mSlot = BufferItem:INVALID_BUFFER_SLOT; / Call back without the main BufferQueue lock held, but with the callback / lock held so we can ensure that callbacks occur
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026湖北黄冈罗田县教育系统面向国内普通高校招聘教师41人备考题库及答案详解【全优】
- 广告投放效果评估与优化方案
- 2026年3月广西玉林市陆川县城镇公益性岗位人员招聘5人备考题库含完整答案详解(历年真题)
- 2026河南郑州市第一〇七高级中学招聘23人备考题库【典优】附答案详解
- 2026广西钦州市城市管理局招聘公益性岗位人员2人备考题库【满分必刷】附答案详解
- 2026广东深圳万润科技股份有限公司招聘1人备考题库含完整答案详解【考点梳理】
- 中国国际职业教育及培训展览会参展参会管理办法
- 2026湖南怀化市辰溪县残疾人联合会公益性岗位招聘1人备考题库带答案详解(综合题)
- 中国国际学前教育及装备展览会参展参会管理办法
- 2026广西河池大化瑶族自治县实验中学德育工作辅助人员招聘1人备考题库有答案详解
- 2025年江西建设职业技术学院单招综合素质考试题库及答案解析
- 抗菌药物临床应用指导原则试题含答案
- 2026黑龙江新高考:语文必背知识点归纳
- 金属非金属地下矿山人行梯子间设置细则
- 领导干部任前法律法规知识考试题库(2025年度)及答案
- 2025福建厦门航空有限公司招聘备考题库及答案详解(易错题)
- 村集体三资管理培训课件
- (正式版)DB61∕T 2115-2025 《中深层地热能开发钻完井技术规程》
- 年鉴编纂基本知识课件
- 2026年保安员证考试题库完整版
- 2026年四川单招语数英基础提升分层试卷含答案适配不同水平
评论
0/150
提交评论