最好網(wǎng)站建設(shè)公司排名寧波優(yōu)化網(wǎng)頁(yè)基本流程
一、Surface 概述
OpenGL ES/Skia定義了一組繪制接口的規(guī)范,為什么能夠跨平臺(tái)? 本質(zhì)上需要與對(duì)應(yīng)平臺(tái)上的本地窗口建立連接。也就是說(shuō)OpenGL ES負(fù)責(zé)輸入了繪制的命令,但是需要一個(gè) “畫(huà)布” 來(lái)承載輸出結(jié)果,最終展示到屏幕。這個(gè)畫(huà)布就是本地窗口。
因此,每個(gè)平臺(tái)的有著不一樣的本地窗口的實(shí)現(xiàn)。Android平臺(tái)上是 ANativeWindow。
疑問(wèn):
- 那么如何將OpenGL本地化? 通過(guò) EGL來(lái)對(duì)OpenGL ES來(lái)進(jìn)行配置。關(guān)鍵點(diǎn)就是提供本地化窗口。
- 本地化窗口的作用是什么? 本地窗口是OpenGL ES和 物理屏幕之間的橋梁。
1.1 Android本地窗口簡(jiǎn)述
Android圖形系統(tǒng)提供的本地窗口,可以分為兩類(lèi):
- FrameBufferNativeWindow
面對(duì)SF(SurfaceFlinger)。它通過(guò)HAL層的Gralloc系統(tǒng)調(diào)用(alloc/free)來(lái)分配內(nèi)核中的FrameBuffer幀緩沖區(qū)。 這個(gè)幀緩沖區(qū)就代表了物理屏幕(fb驅(qū)動(dòng)節(jié)點(diǎn),表示屏幕數(shù)。如fb0主屏幕、fb1等)。 FrameBuffer的數(shù)量一般情況下是2,也就是雙緩沖。當(dāng)然還有三倍緩沖。
- Surface
面向應(yīng)用程序。對(duì)應(yīng)的是內(nèi)存中一塊緩沖區(qū),稱(chēng)為:GraphicBuffer。是由SF來(lái)進(jìn)行分配。app從SF中獲取一塊GraphicBuffer, 通過(guò)OpenGL/Skia將圖形數(shù)據(jù)繪制(軟件/硬件)到GraphicBuffer上。最終SF會(huì)把各個(gè)應(yīng)用的GraphicBuffer數(shù)據(jù)進(jìn)行合成,最終 通過(guò) FrameBufferNativeWindow 輸出到屏幕上。
有了一個(gè)整體的概念,接下來(lái)就好理解很多。
二、引出SurfaceSession
2.1 從WindowManagerImpl的addView()說(shuō)起
app:
WindowManagerImpl.addView()WindowManagerGlobal.addView()ViewRootImpl的setView()IWindowSession.addToDisplay()
?
WMS:new WindowStateWindowState.attach()session.windowAddedLocked()new SurfaceSession()
復(fù)制代碼
view添加到window的過(guò)程中, 從WindowManagerImpl 的 addView(),到WindowManagerGlobal(構(gòu)造方法中會(huì)在system server 進(jìn)程中創(chuàng)建一個(gè)Session對(duì)象)的addView()。最后會(huì)調(diào)用 ViewRootImpl的setView()方法。 內(nèi)部會(huì)調(diào)用 IWindowSession 的addToDisplay() 方法。IWindowSession是WMS提供的一個(gè)binder服務(wù)(實(shí)現(xiàn)類(lèi)就是Session)。
2.2 IWindowSession.windowAddedLocked()
內(nèi)部會(huì)創(chuàng)建一個(gè)WindowState 對(duì)象。 調(diào)用 WindowState的 attach()方法。最終調(diào)到Session中的windowAddedLocked(),會(huì)創(chuàng)建 一個(gè)SurfaceSession對(duì)象。這就是我們要找的的跟SurfaceFlinger建立聯(lián)系的地方。
SurfaceSession mSurfaceSession;
void windowAddedLocked(String packageName) {mPackageName = packageName;mRelayoutTag = "relayoutWindow: " + mPackageName;if (mSurfaceSession == null) {// 一個(gè)進(jìn)程只有一個(gè)session,因此也只創(chuàng)建一次 SurfaceSession 對(duì)象
?// 創(chuàng)建 SurfaceSession 對(duì)象mSurfaceSession = new SurfaceSession();
?// 每個(gè)session 都存入WMS中的mService.mSessions.add(this);
?if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {mService.dispatchNewAnimatorScaleLocked(this);}}mNumWindow++; // 進(jìn)程中所有窗口的數(shù)量+1
}
復(fù)制代碼
一個(gè)應(yīng)用進(jìn)程對(duì)應(yīng)一個(gè)Session對(duì)象,一個(gè)Session對(duì)象對(duì)應(yīng)一個(gè)SurfaceSession。 WMS會(huì)把 這個(gè)Session 存儲(chǔ)起來(lái)。也就是說(shuō)WMS 會(huì)把所有跟SurfaceFlinger保持連接狀態(tài)的應(yīng)用Session存儲(chǔ)起來(lái)。
2.3 SurfaceSession 創(chuàng)建過(guò)程
這個(gè)類(lèi)的實(shí)例代表了和SurfaceFlinger的一個(gè)連接。我們可以通過(guò)它 創(chuàng)建一個(gè)或多個(gè) Surface 對(duì)象。
2.3.1 構(gòu)造方法
> SurfaceSession.java
private long mNativeClient; // SurfaceComposerClient*
?
public SurfaceSession() {//native 方法mNativeClient = nativeCreate();
}
?
> frameworks/base/core/jni/android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz) {// 新建一個(gè) SurfaceComposerClient 對(duì)象SurfaceComposerClient* client = new SurfaceComposerClient();client->incStrong((void*)nativeCreate);//返回SurfaceComposerClient對(duì)象的引用到j(luò)ava層。return reinterpret_cast<jlong>(client);
}
復(fù)制代碼
SurfaceComposerClient 是什么呢?
2.3.2 SurfaceComposerClient
在 SurfaceComposerClient第一次被引用的時(shí)候會(huì)走onFirstRef()方法。
> frameworks/native/libs/gui/SurfaceComposerClient.cpp
void SurfaceComposerClient::onFirstRef() {//創(chuàng)建sf代理binder對(duì)象sf,類(lèi)型為 ISurfaceComposersp<ISurfaceComposer> sf(ComposerService::getComposerService());if (sf != nullptr && mStatus == NO_INIT) {sp<ISurfaceComposerClient> conn;//創(chuàng)建一個(gè) ISurfaceComposerClient 對(duì)象,用來(lái)跨進(jìn)程調(diào)用conn = sf->createConnection();if (conn != nullptr) {mClient = conn;mStatus = NO_ERROR;}}
}
復(fù)制代碼
- ISurfaceComposer 實(shí)現(xiàn)類(lèi)就是 SurfaceFlinger對(duì)象。在server進(jìn)程的代理對(duì)象是 ComposerService。This class defines the Binder IPC interface for accessing various SurfaceFlinger features.
- 通過(guò)SF.createConnection(),創(chuàng)建一個(gè) ISurfaceComposerClient 對(duì)象 mClient,用來(lái)跨進(jìn)程調(diào)用。
那么 ISurfaceComposerClient的實(shí)現(xiàn)類(lèi)是哪個(gè)呢? 繼續(xù)看看 SF.createConnection()。
2.3.3 SurfaceFlinger.createConnection()
注意,此時(shí)是在SF進(jìn)程。
> frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {// new client對(duì)象。return initClient(new Client(this));
}
static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {status_t err = client->initCheck();if (err == NO_ERROR) {// 返回該對(duì)象return client;}return nullptr;
}
> frameworks/native/services/surfaceflinger/Client.h
class Client : public BnSurfaceComposerClient{...class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {...
復(fù)制代碼
原來(lái),ISurfaceComposerClient的實(shí)現(xiàn)類(lèi)就是 SF中定義的 Client。也是一個(gè)binder服務(wù)。 我們回到 SurfaceComposerClient 類(lèi),它持有 ISurfaceComposerClient的binder引用 mClient。通過(guò) mClient實(shí)現(xiàn)與SF通信。
2.3 小結(jié)
- Session 類(lèi)中,創(chuàng)建了一個(gè) SurfaceSession 對(duì)象,內(nèi)部引用c++層的 SurfaceComposerClient 對(duì)象。
- SurfaceComposerClient 對(duì)象是通過(guò)SF創(chuàng)建的另一個(gè)binder服務(wù)。減輕SF的工作量。
- SurfaceComposerClient 對(duì)象則通過(guò) mClient成員(ISurfaceComposerClient)代理binder,后續(xù)用來(lái)創(chuàng)建 Surface。
Surface繪制原理
Surface的Buffer是從哪里來(lái)的?
源碼:frameworks/base/core/java/android/view/ViewRootImpl.java View觸發(fā)繪制是通過(guò)requestLayout()函數(shù)或者setLayoutParms()函數(shù):
performTravsersals()函數(shù)實(shí)現(xiàn):
private void performTraversals() {……performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);performLayout(lp, mWidth, mHeight);performDraw();……
}
perfomrDraw()函數(shù)調(diào)用draw()函數(shù)開(kāi)始繪制:
private void performDraw() {……boolean canUseAsync = draw(fullRedrawNeeded);……
}
ViewRootImpl.draw()函數(shù)實(shí)現(xiàn):
private boolean draw(boolean fullRedrawNeeded) {Surface surface = mSurface;……if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty, surfaceInsets)) {return false;}……return useAsyncReport;
}
drawSoftware()軟件繪制,默認(rèn)是軟件繪制。
drawSoftware()函數(shù)軟件繪制流程:
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
?// Draw with software renderer.final Canvas canvas;……canvas = mSurface.lockCanvas(dirty);……mView.draw(canvas);……surface.unlockCanvasAndPost(canvas);
?
}
獲取:通過(guò)lockCanvas函數(shù)獲取Canvas對(duì)象,
繪制:再通過(guò)mView.draw(canvas)函數(shù)向在canvas上繪制,
提交:最后通過(guò)surface.unlockCanvasAndPost(canvas)函數(shù)提交Canvas。
通過(guò)lockCanvas()函數(shù)獲取Canvas對(duì)象,lockCanvas()函數(shù)如何獲取Canvas對(duì)象。
lockCanvas()函數(shù)實(shí)現(xiàn):
/*** Gets a {@link Canvas} for drawing into this surface.** After drawing into the provided {@link Canvas}, the caller must* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.** @param inOutDirty A rectangle that represents the dirty region that the caller wants* to redraw. This function may choose to expand the dirty rectangle if for example* the surface has been resized or if the previous contents of the surface were* not available. The caller must redraw the entire dirty region as represented* by the contents of the inOutDirty rectangle upon return from this function.* The caller may also pass <code>null</code> instead, in the case where the* entire surface should be redrawn.* @return A canvas for drawing into the surface.** @throws IllegalArgumentException If the inOutDirty rectangle is not valid.* @throws OutOfResourcesException If the canvas cannot be locked.*/
public Canvas lockCanvas(Rect inOutDirty)throws Surface.OutOfResourcesException, IllegalArgumentException {synchronized (mLock) {checkNotReleasedLocked();if (mLockedObject != 0) {// Ideally, nativeLockCanvas() would throw in this situation and prevent the// double-lock, but that won't happen if mNativeObject was updated. We can't// abandon the old mLockedObject because it might still be in use, so instead// we just refuse to re-lock the Surface.throw new IllegalArgumentException("Surface was already locked");}mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);return mCanvas;}
}
通過(guò)Native層android_view_Surface.cpp的nativeLockCanvas(mNativeObject, mCanvas, inOutDirty)函數(shù)獲取,mNativeOjbect參數(shù)是Java層的Surface在Native層對(duì)應(yīng)的Surface對(duì)象的指針。mCanvas是Surface的變量,在lockCanvas()函數(shù)調(diào)用時(shí)mCanvas是空的。
在調(diào)用nativeLockCanvas()函數(shù)后mCanvas就有值了,最后返回mCanvas對(duì)象。
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {// (1)sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));……// (2)ANativeWindow_Buffer buffer;status_t err = surface->lock(&buffer, dirtyRectPtr);……// (3)graphics::Canvas canvas(env, canvasObj);canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));……// (4)// Create another reference to the surface and return it. This reference// should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,// because the latter could be replaced while the surface is locked.sp<Surface> lockedSurface(surface);lockedSurface->incStrong(&sRefBaseOwner);return (jlong) lockedSurface.get();
}
(1) 獲取Native層的Surface對(duì)象。
(2) 獲取Native層的Surface對(duì)象的Buffer。
(3) 將Buffer設(shè)置給Canvas,這里Canvas就有一個(gè)Buffer了。在每次都申請(qǐng)一個(gè)新的Buffer給Canvas對(duì)象。
(4) 向Java層返回Native的Surface對(duì)象,這里返回的是一個(gè)Long型數(shù)據(jù),這個(gè)Long型數(shù)據(jù)是Surface指針。
獲取Buffer實(shí)現(xiàn),surface -> lock(&buffer, ),這里傳入Buffer地址:
源碼:frameworks/native/libs/gui/Surface.cpp
status_t Surface::lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{……// (1)ANativeWindowBuffer* out;status_t err = dequeueBuffer(&out, &fenceFd);……// (2)sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));……// (3)void* vaddr;status_t res = backBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, newDirtyRegion.bounds(), &vaddr, fenceFd);……// (4)mLockedBuffer = backBuffer;// (5)outBuffer->bits = vaddr;……
}
(1) 獲取dequeueBuffer()函數(shù)在SurfaceFlinger的Buffer隊(duì)列中獲取Buffer。
(2) 創(chuàng)建GraphicBuffer對(duì)象backBuffer。在SharedBufferStack中有雙緩沖機(jī)制,分別為FontBuffer和BackBuffer。
FontBuffer:代表當(dāng)前將顯示在屏幕的Buffer數(shù)據(jù)。屬于前臺(tái)Buffer。 BackBuffer:代表繪制的Buffer數(shù)據(jù),是準(zhǔn)備渲染的數(shù)據(jù)Buffer。屬于后臺(tái)Buffer。 (3) 鎖定Buffer,并將Buffer地址返回,將返回的Buffer地址給Canvas的Buffer。
(4) 切換Buffer,將后臺(tái)BackBuffer切換到前臺(tái),交給mLockedBuffer。FontBuffer的變量就是mLockedBuffer。
(5) 將vaddr賦值給outBuffer->bits,bits最后賦值給Canvas的Buffer,就是BkBitmap,作為Canvas的緩沖區(qū)。
dequeteBuffer()是如何獲取Buffer的,dequeteBuffer()函數(shù)實(shí)現(xiàn):
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {……int buf = -1;// (1)status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,reqFormat, reqUsage, &mBufferAge,enableFrameTimestamps ? &frameTimestamps: nullptr);……// (2)sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);……// (3)if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {if (mReportRemovedBuffers && (gbuf != nullptr)) {mRemovedBuffers.push_back(gbuf);}result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);if (result != NO_ERROR) {ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);mGraphicBufferProducer->cancelBuffer(buf, fence);return result;}}……// (4)*buffer = gbuf.get();
}
(1) 通過(guò)mGaphicBufferProducer->dequeteBuffer()函數(shù)在遠(yuǎn)端的Buffer slots中獲得一個(gè)空閑的Buffer,返回遠(yuǎn)端Buffer地址指針。
(2) 通過(guò)gbp從本地Buffer Slots里獲取Buffer,在(1)中從遠(yuǎn)端,在(2)中從本地,這里涉及遠(yuǎn)端Buffer queue與本地Buffer queue同步問(wèn)題。
(3) 負(fù)責(zé)本地Buffer與遠(yuǎn)端Buffer同步,遠(yuǎn)端返回的Buffer的result是BUFFER_NEEDS_REALLOCATION或者本地的gbp是null,通過(guò)gbp的requestBuffer()獲取新的遠(yuǎn)端Buffer指針地址。mGaphicBufferProducer->requestBuffer()函數(shù)。
(4) 獲取Buffer。
Surface的Buffer是如何提交的?
通過(guò)surface.unlockCanvasAndPost(canvas)向遠(yuǎn)端提交更新的Buffer,unlockCanvasAndPost()函數(shù)實(shí)現(xiàn):
/*** Posts the new contents of the {@link Canvas} to the surface and* releases the {@link Canvas}.** @param canvas The canvas previously obtained from {@link #lockCanvas}.*/
public void unlockCanvasAndPost(Canvas canvas) {synchronized (mLock) {unlockSwCanvasAndPost(canvas);}
}
?
private void unlockSwCanvasAndPost(Canvas canvas) {try {nativeUnlockCanvasAndPost(mLockedObject, canvas);} finally {nativeRelease(mLockedObject);mLockedObject = 0;}
}
最后調(diào)用到Native層的nativeUnlockCanvasAndPost(mLockedObject, canvas)。
Native層,nativeUnlockCanvasAndPost()函數(shù)實(shí)現(xiàn):
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,jlong nativeObject, jobject canvasObj) {// (1)sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
?// (2)// detach the canvas from the surfacegraphics::Canvas canvas(env, canvasObj);canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);// (3)// unlock surfacestatus_t err = surface->unlockAndPost();
}
(1) 獲取對(duì)應(yīng)Java層的Native層的Surface對(duì)象。
(2) 獲取對(duì)應(yīng)Java層的Native層的Canvas對(duì)象。
(3) 將本地Buffer更新到遠(yuǎn)端的Buffer queue中。
Native層更新遠(yuǎn)端Buffer queue,surface->unlockAndPost()函數(shù)實(shí)現(xiàn):
源碼:frameworks/native/libs/gui/Surface.cpp
status_t Surface::unlockAndPost()
{if (mLockedBuffer == nullptr) {ALOGE("Surface::unlockAndPost failed, no locked buffer");return INVALID_OPERATION;}
?int fd = -1;status_t err = mLockedBuffer->unlockAsync(&fd);ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);err = queueBuffer(mLockedBuffer.get(), fd);ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",mLockedBuffer->handle, strerror(-err));mPostedBuffer = mLockedBuffer;mLockedBuffer = nullptr;return err;
}
通過(guò)函數(shù)queueBuffer(mLockedBuffer.get(), )函數(shù)實(shí)現(xiàn)更新:
int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {……// (1)int i = getSlotFromBufferLocked(buffer);……// (2)status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);……return err;
}
(1) 獲取Buffer的index。
(2) 通過(guò)mGraphicBufferProducer->queueBuffer(i, )函數(shù),將本地的Buffer同步到遠(yuǎn)端Buffer queue中。
以上為車(chē)載技術(shù)中Window Display板塊的surface的繪制過(guò)程與原理;更多車(chē)載技術(shù)參考,可點(diǎn)擊《車(chē)載技術(shù)手冊(cè)》查看類(lèi)目學(xué)習(xí)。
Android車(chē)載學(xué)習(xí)手冊(cè)?docs.qq.com/doc/DUldvclB5d0JZSVFn