應用程序中不同類型的Surface,在FrameWorks本地層的SurfaceFlinger中,分別對應着不同的Layer類,本文主要是討論這幾種Layer的實現和差異。
閱讀本文之前,最好對SurfaceFlinger這個系統服務有所瞭解,可以參閱我的以下兩篇文章:
- Android SurfaceFlinger中的SharedClient -- 客戶端(Surface)和服務端(Layer)之間的顯示緩衝區管理
- Android SurfaceFlinger中的工作線程:threadLoop()
視覺效果
下面幾張圖片分別表示了不同Layer產生的視覺效果:
- Layer對應普通的窗口
- LayerDim 會使他後面的窗口產生一個變暗的透明效果
- LayerBlur在LayerDim的基礎上,背景會產生模糊的效果
創建Layer
默認地,創建普通的窗口Surface,在SurfaceFlinger中會創建Layer類,如果想創建LayerDim或LayerBlur,應用程序需要在綁定View之前設置一下窗口的標誌位:
創建LayerDim效果:
- @Override
- protected void onCreate(Bundle icicle) {
- // Be sure to call the super class.
- super.onCreate(icicle);
- // Have the system blur any windows behind this one.
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
- WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- ......
- setContentView(......);
- }
創建LayerBlur效果:
- @Override
- protected void onCreate(Bundle icicle) {
- // Be sure to call the super class.
- super.onCreate(icicle);
- // Have the system blur any windows behind this one.
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
- WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
- ......
- setContentView(......);
- }
相應地,在SufaceFlinger中,會根據Java層傳入的標誌,創建不同的Layer:
- sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid,
- const String8& name, ISurfaceFlingerClient::surface_data_t* params,
- DisplayID d, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags)
- {
- sp<LayerBaseClient> layer;
- sp<LayerBaseClient::Surface> surfaceHandle;
- ......
- switch (flags & eFXSurfaceMask) {
- case eFXSurfaceNormal:
- if (UNLIKELY(flags & ePushBuffers)) {
- layer = createPushBuffersSurfaceLocked(client, d, id,
- w, h, flags);
- } else {
- layer = createNormalSurfaceLocked(client, d, id,
- w, h, flags, format);
- }
- break;
- case eFXSurfaceBlur:
- layer = createBlurSurfaceLocked(client, d, id, w, h, flags);
- break;
- case eFXSurfaceDim:
- layer = createDimSurfaceLocked(client, d, id, w, h, flags);
- break;
- }
- if (layer != 0) {
- layer->setName(name);
- setTransactionFlags(eTransactionNeeded);
- surfaceHandle = layer->getSurface();
- ........
- }
- return surfaceHandle;
- }
Layer類的靜態結構
下面的圖展示了Layer類之間的繼承關係:
- 所有的Layer都繼承了LayerBaseClient,SurfaceFlinger統一通過LayerBaseClient類訪問其他的派生Layer類
- LayerBaseClient的內嵌類Surface繼承了ISurface接口,ISurface用於和SurfaceFlinger的客戶端交互
- Layer和LayerBuffer都有各自的內嵌類:SurfaceLayer、SurfaceLayerBuffer,繼承了LayerBaseClient的內嵌類Surface
- LayerBuffer還有另外的內嵌類:Source,並且派生出另外兩個內嵌類:BufferSource、OverlaySource
ISurface接口
ISurface接口其實非常簡單,只有幾個函數:
- requestBuffer() // Layer類使用,用於申請frontbuffer、backbuffer,初始化或size變化時調用
- registerBuffers() // LayerBuffer類使用,用於註冊IMemoryHeap接口
- unregisterBuffers() // LayerBuffer類使用,用於註銷IMemoryHeap接口
- postBuffer() // post用於刷新的圖像數據
- createOverlay() // 用於創建Overlay表面
LayerBaseClient的派生類中,會有一個內嵌類,繼承LayerBaseClient::Surface,然後根據需要會實現該接口的相應函數。
Layer類
Layer類是使用最多的一個,普通的應用程序窗口都會對應一個Layer類,Layer類的內嵌類SurfaceLayer繼承了ISurface接口,創建Layer類時,將會返回一個ISurface接口給創建者。並且,Layer類在創建時會建立兩個GraphicBuffer對象,這兩個Buffer在不同的時刻分別被作爲frontbuffer和backbuffer,frontbuffer用於本窗口的畫圖操作,backbuffer用於所有窗口的混合操作。但是兩個GraphicBuffer對象在創建時並沒有真正地分配內存,而是在第一次lockBuffer時才正式通過ISurface接口的requestBuffer方法申請內存,當窗口的大小發生變化時,也要重新分配適合窗口大小的內存。Layer類的主要成員函數如下:
- createSurface() 返回ISurface接口
- setBuffers() 創建兩個GraphicBuffer對象,創建ISurface接口的實現類SurfaceLayer
- onDraw() 把frontbuffer中的圖像數據通過OpenGL混合到OpenGL的主表面中
- doTransaction() 檢測並處理窗口大小變化
- lockPageFlip() 獲取frontbuffer,並且生成frontbuffer的OpenGL貼圖
- finishPageFlip() unlock frontbuffer,此後該buffer會queue到空閒列表中,下次可以作爲backbuffer使用
LayerDim和LayerBlur
LayerDim和LayerBlur,他們的顯示內容是固定不變的(透明的黑色),所以不需要分配兩個GraphicBuffer對象,因此它們也沒有繼承自LayerBaseClient::Surface的內嵌類,而是直接使用LayerBaseClient::Surface類作爲它們的ISurface接口。以LayerDim爲例跟蹤一下它的Draw過程:
- 創建LayerDim時,在LayerDim.initDimmer()中生成純黑的OpenGL貼圖
- void LayerDim::initDimmer(SurfaceFlinger* flinger, uint32_t w, uint32_t h)
- {
- sTexId = -1;
- sImage = EGL_NO_IMAGE_KHR;
- ......
- if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
- /* 申請GraphicBuffer */
- sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
- GraphicBuffer::USAGE_SW_WRITE_OFTEN |
- GraphicBuffer::USAGE_HW_TEXTURE);
- android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
- /* 申請OpenGL貼圖 */
- glGenTextures(1, &sTexId);
- glBindTexture(GL_TEXTURE_2D, sTexId);
- EGLDisplay dpy = eglGetCurrentDisplay();
- sImage = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)clientBuf, 0);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)sImage);
- ......
- // initialize the texture with zeros
- GGLSurface t;
- buffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
- memset(t.data, 0, t.stride * t.height * 2);
- buffer->unlock();
- sUseTexture = true;
- }
- }
- 在OnDraw()中把第一步生成的貼圖混合到OpenGL的主表面中
- void LayerDim::onDraw(const Region& clip) const
- {
- const State& s(drawingState());
- Region::const_iterator it = clip.begin();
- Region::const_iterator const end = clip.end();
- if (s.alpha>0 && (it != end)) {
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- ......
- /* 設置透明值 */
- glColor4x(0, 0, 0, alpha);
- #if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
- if (sUseTexture) {
- glBindTexture(GL_TEXTURE_2D, sTexId);
- glEnable(GL_TEXTURE_2D);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- const GLshort texCoords[4][2] = {
- { 0, 0 },
- { 0, 1 },
- { 1, 1 },
- { 1, 0 }
- };
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_SHORT, 0, texCoords);
- } else
- #endif
- {
- glDisable(GL_TEXTURE_2D);
- }
- GLshort w = sWidth;
- GLshort h = sHeight;
- const GLshort vertices[4][2] = {
- { 0, 0 },
- { 0, h },
- { w, h },
- { w, 0 }
- };
- glVertexPointer(2, GL_SHORT, 0, vertices);
- while (it != end) {
- const Rect& r = *it++;
- const GLint sy = fbHeight - (r.top + r.height());
- glScissor(r.left, sy, r.width(), r.height());
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- }
- }
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }