【ARM-Linux開發】wayland和weston的介紹

簡單地說,Wayland是一套display server(Wayland compositor)與client間的通訊協議,而Weston是Wayland compositor的參考實現。其官網爲http://wayland.freedesktop.org/。它們定位於在Linux上替換X圖形系統。X圖形系統經歷了30年左右的發展,其設計在今天看來已略顯陳舊。在X系統中,X Server做爲中心服務,鏈接clien和硬件以及compositor。但時至今日,本來在X Server中作的事不少已被移到kernel或者單獨的庫中,所以X Server就顯得比較累贅了。Wayland在架構上去掉了這個中間層,將compositor做爲display server,使client與compositor直接通訊,從而在靈活性和性能等方面上可以比前輩更加出色。css


Wayland既能夠用於傳統的桌面又適用於移動設備,已經被用於Tizen,Sailfish OS等商業操做系統,同時愈來愈多的窗口和圖形系統開始兼容Wayland協議。Wayland基於domain socket實現了一套display server與client間通訊的庫(簡單的基於例子的介紹能夠參見http://blog.csdn.NET/jinzhuojun/article/details/40264449),而且以XML形式定義了一套可擴展通訊協議。這個協議分爲Wayland核心協議和擴展協議(位於Weston中)。Weston做爲Wayland compositor的參考實現,通常和Wayland同步發佈。其它Wayland compositor實現還有如mutter, Kwin, Lipstick, Enlightenment, Clayland等。html

下面分別從架構,源碼及模塊結構,渲染流水線,窗口和輸入管理幾個方面介紹下Wayland/Weston的實現。java

架構

Wayland的系統體系架構能夠參見官方文檔,再也不累述。Weston從內部體系結構來看,主要分爲窗口管理(shell),合成器(compositor)和輸入管理幾個部分。可見,若是拿Android做類比,從功能上看它約等同於InputManagerService,WindowManagerService和SurfaceFlinger。從大致的流程上來看,輸入管理模塊接受用戶輸入,而後一方面shell做出相應的窗口管理操做(如窗口堆棧的改變,focus的變化等),另外一方面將該input event傳給以前註冊了相應輸入事件的client。client收到後會在handler中作相應動做,如調整視圖而後重繪。若有重繪發生,新buffer渲染完成後client將其handle傳給server,接着server端生成z-order序的窗口列表,以後compositor用renderer進行合成,最後輸出(好比到framebuffer)。linux

\

Weston是主要服務進程,它的事件處理模型採用的是典型的Reactor模式。根據Linux中萬物皆文件的原則,主循環經過epoll機制等待在一系列的文件fd上。這種模型與基於線程的binder不一樣,是一種串行的事件處理模型。在此模型上的過程調用在不加額外同步機制的狀況下是異步的。好處是不會有競爭問題,數據同步開銷較小。缺點是當有一個事件處理比較耗時或者在等待IO,則有可能使整個系統性能降低或響應不及時。android

\

主循環上等待的幾個核心fd包括:
• Server/Client通訊:listener fd在Weston啓動時創建,並一直監聽新的client鏈接。一個client鏈接後會與Weston創建一對domain socket,Wayland就是基於它來通訊的。
• 輸入處理:一方面經過udev monitor監聽設備的添加刪除事件。另外一方面若有新設備添加時會將該設備打開並監聽該fd來獲得輸入事件。
• 其它:監聽如timer(用於如睡眠鎖屏等場景)和signal(如收到SIGINT, SIGTERM, SIGQUIT時退出主循環)等事件。timer和signal能夠分別用timerfd和signalfd來用fd來表示。另外還有logind的dbus鏈接等。
除這些外,在event loop中還會維護一個idle list。Weston中須要異步處理的操做能夠放在其中。每輪循環都會檢查其中是否有任務,有的話拿出來執行。

下面看下Weston的運行時進程模型。Weston設計時是能夠以通常用戶運行的,但就須要用weston-launch來啓動。當須要進行一些須要root權限的工做,好比關於DRM, TTY, input device的相關操做,就交由weston-launch去作。

Weston會在啓動時或按需起一些子進程,它們本質上是Weston的client,它們會經過專用的協議作一些系統應用的工做。如系統應用weston-desktop-shell負責一些系統全局的界面,好比panel, background, cursor, app launcher, lock screen等。它不做爲Weston服務自己的一部分,而是做爲一個client。其做用有點相似於Android中的SystemUI。這樣即可方便地替換成定製的界面。weston-keyboard是軟鍵盤面板。weston-screenshooter和weston-screensaver分別用於截屏和屏保,它們都是按需才由Weston啓動的。前者在截屏快捷鍵按下時啓動,後者在須要鎖屏時啓動。git

\

另外,Weston啓動時會讀取weston.ini這個配置文件,其中能夠配置桌面,動畫和後端等等信息。詳細配置見http://manpages.ubuntu.com/manpages/raring/man5/weston.ini.5.html。web

源碼與模塊結構

wayland/weston/libinput等項目源碼位於http://cgit.freedesktop.org/wayland下。算法

Wayland的協議定義在protocol目錄,通訊協議實如今src目錄。它主要編譯出三個庫,libwayland-client,libwayland-server和libwayland-cursor。第一個爲協議的client端實現,第二個爲協議的server端實現。第三個是協議中鼠標相關處理實現。編譯時會首先編譯出wayland-scanner這個可執行文件,它利用expat這個庫來解析xml文件,將wayland.xml生成相應的wayland-protocol.c,wayland-client-protocol.h和wayland-server-protocol.h。它們會被Wayland的client和server在編譯時用到。同時wayland-scanner也須要在生成Weston中的Wayland擴展協議中起一樣做用。shell

\

Wayland主要依賴於兩個庫,一個上面提到的expat協議,另外一個libffi用於在跨進程過程調用中根據函數描述生成相應calling convention的跳板代碼。ubuntu

Weston的主要實如今src目錄下。與Wayland相似,protocol目錄下放着Wayland協議定義。在clients目錄下是一些client的例子,也包括了desktop-shell和keyboard等核心client的例子,也包含了如simple-egl, simple-shm, simple-touch等針對性的簡單用例。Weston啓動過程當中會分別加載幾個backend:shell backend, render backend和compositor backend。它們分別用於窗口管理,合成渲染和合成內容輸出。

\

因爲這些後端均可有不一樣的實現,爲了邏輯上的獨立性和結構上的靈活性,他們都編譯成動態連接庫從而能夠在Weston初始化時被加載進來。這種方式在Weston中被普遍採用,一些功能好比屏幕共享等都是以這種形式加載的。

舉例來講,compositor backend主要決定了compositor合成完後的結果怎麼處置。從數據結構上,weston_output是output設備的抽象,而下面的backend會實現具體的output設備。
• fbdev:直接輸出至linux的framebuffer設備。接口通用。
• headless:和noop-renderer配合使用,能夠在沒有窗口系統的機子(好比server上)測試邏輯。
• RPI:用於Raspberry Pi平臺。
• RDP:合成後經過RDP傳輸到RDP peer顯示,用於遠程桌面。
• DRM:Direct redering manager,桌面上通常用這個。
• x11:Wayland compositor做爲X server的client。它可讓Wayland client運行在X11上。
• wayland:Wayland composiotr做爲server同時,也做爲另外一個Wayland compositor的client。用於nested compositor。

Renderer backend主要用於compositor的合成之用,除去noop-renderer外,有gl-renderer和pixman-renderer兩種。前者爲GPU硬件渲染,後者爲軟件渲染。shell backend用於實現具體的窗口管理。相應的實現分別在desktop-shell,fullscreen-shell和ivi-shell目錄中。

Wayland/Weston運行時依賴的庫主要有下面幾個,其相互關係大致以下。

\

• libEGL, libGLES:本地窗口系統與圖形driver的glue layer,mesa提供了開源版本的實現。
• libdrm:封裝KMS,GEM等圖形相關接口。平臺相關。
• libffi:用於在運行時根據調用接口描述生成函數跳板並調用。
• pixman:用於像素操做的庫,包括region, box等計算。用了許多平臺相關的優化。
• cairo:軟件渲染庫,相似於skia。也有OpenGL後端。
• libinput:輸入處理,依賴於mtdev, libudev, libevdev等庫。
• libxkbcommon:主要用於鍵盤處理。
• libjpeg, libpng, libwebp:用於加載各類圖片文件,像壁紙,面板和鼠標等都須要。

渲染流水線

一個Wayland client要將內存渲染到屏幕上,首先要申請一個graphic buffer,繪製完後傳給Wayland compositor並通知其重繪。Wayland compositor收集全部Wayland client的請求,而後以必定週期把全部提交的graphic buffer進行合成。合成完後進行輸出。本質上,client須要將窗口內容繪製到一個和compositor共享的buffer上。這個buffer能夠是普通共享內存,也能夠是DRM中的GBM或是gralloc提供的可供硬件(如GPU)操做的graphic buffer。在大多數移動平臺上,沒有專門的顯存,所以它們最終都來自系統內存,區別在於圖形加速硬件通常會要求物理連續且符合對齊要求的內存。若是是普通共享內存,通常是物理不連續的,多數狀況用於軟件渲染。有些圖形驅動也支持用物理不連續內存作硬件加速,但效率相對會低一些。根據buffer類型的不一樣,client能夠選擇本身繪製,或是經過Cairo,OpenGL繪製,或是更高層的如Qt,GTK+這些widget庫等繪製。繪製完後client將buffer的handle傳給server,以及須要重繪的區域。在server端,compositor將該buffer轉爲紋理(若是是共享內存使用glTexImage2D上傳紋理,硬件加速buffer用GL_OES_EGL_image_external擴展生成外部紋理)。最後將其與其它的窗口內容進行合成。下面是抽象的流程圖。

\


注意Wayland設計中默認buffer是從client端分配的。這和Android中在server端分配buffer的策略是不一樣的。這樣,client能夠自行設計buffer的管理策略。理論上,client能夠始終只用一塊buffer,但由於這塊buffer在client和server同時訪問會產生競爭,因此通常client端都會實現buffer queue。流水線上比較關鍵的一環是buffer跨進程的傳輸,也就是client和server間的有效傳遞。buffer固然不可能經過拷貝傳輸,所以這裏只會傳handle,本質上是傳buffer的fd。咱們知道fd是per-process的。而能夠傳遞fd的主要IPC機制有binder, domain socket和pipe等。Wayland底層用的是domain socket,所以能夠用於傳fd。

在這條流水線上,能夠看到,client和server端都會發生繪製。client繪製本地的窗口內容,server端主要用於合成時渲染。注意兩邊均可獨立選擇用軟件或者硬件渲染。如今的商用設備上,可能是硬件加速渲染。和Android上的SurfaceFlinger和Ubuntu上的Mir同樣,Wayland一樣基於EGL接口。EGL用於將本地窗口系統與OpenGL關聯起來,與WGL, GLX等做用相似,只是它是用於Embedded platform的。在Wayland/Weston系統中,Wayland定義了用於EGL的窗口抽象,來做爲EGL stack(也就是廠商的圖形驅動)和Wayland協議的glue layer。它對EGL進行了擴展,增長了好比eglBindWaylandDisplayWL, eglUnbindWaylandDisplayWL, eglQueryWaylandBufferWL等接口,對Wayland友好的EGL庫應該提供它們的實現,也就是說要提供Wayland EGL platform,好比mesa(src/egl/main/eglapi.c中)。另外一種作法是像libhybris中eglplatform同樣經過EGL wrapper的方式加上這些支持(hybris/egl/platforms/common/eglplatformcommon.cpp)。同時,EGL stack須要提供廠商相關的協議擴展使client能與compositor共享buffer。wayland-egl庫提供了Wayland中surface和EGL粘合的做用。一個要用硬件加速的EGL window能夠基於Wayland的surface建立,即經過wayland-egl提供的接口建立wl_egl_window。wl_egl_window結構中包含了wl_surface,而後wl_egl_window就能夠被傳入EGL的eglCreateWindowSurface()接口。這樣就將Wayland surface與EGL stack聯繫在一塊兒了。

窗口管理

前面提到,buffer須要有surface爲載體,這個surface能夠理解爲一個窗口的繪製表面。若是一個Wayland client的窗口要被窗口管理器(Shell)所管理,則須要爲這個surface建立相應的shell surface。理一下這裏相關的幾個核心概念:surface,view,shell surface。首先,surface是Weston中的核心數據結構之一。Surface表明Wayland client的一個繪圖表面。Client經過將畫好的buffer attach到surface上來更新窗口,所以說surface是buffer的載體。在Weston中,shell是窗口管理器,所以一個surface要想被窗口管理器管理,須要建立相應的shell surface。同時shell surface對應的實際上是surface的一個view。view是surface的一個視圖。換句話說,同一個surface理論上能夠有多個view,所以weston_surface結構中有view的列表。這裏和咱們邏輯上的窗口的概念最近似的是view,由於它對應用戶所看到的一個窗口。而當surface與view是1:1關係時(絕大多數狀況下),surface也可近似等同於窗口。在server端它們的數據結構是相互關聯的。

\

若是從Server/Client角度,它們的相互對應關係以下:

\

 

另外subsurface能夠做爲surface的附屬繪圖表面,它與父surface保持關聯,但擁有獨立的繪圖surface,相似於Android中的SurfaceView,做用也是相似。主要用於Camera,Video等應用。

窗口管理不是直接管理view,而是分爲兩層進行管理。Layer是中間層,系統中的layer大致有下面幾個,按從上到下順序爲:
• Fade layer
• Lock layer
• Cursor layer
• Input panel layer
• Fullscreen layer
• Panel layer
• Workspace layers
• Background layer


其中的workspace layer是一個數組,默認是一個,也能夠有多個,其數量能夠在weston.ini中指定。大部分的普通應用窗口就是在這個layer中。這些layer被串成list。每次在要作合成時,會首先將這些layer的view按順序合併到一個view list中。這樣,在composition過程當中compositor只需訪問這個view list。

\

能夠看到,這是一個二層有序列表合成一個有序列表的過程。這和Android中的WMS經過爲每種類型的窗口定義一段z軸區域的原理相似。WMS中每一個類型的窗口對定一個基數(定義在WindowManager.Java),它會乘以乘數再加上偏移從而獲得z軸上的區域邊界。區別在於Weston中不是以數值而是有序列表表示z-order。結合具體的數據結構:

\



輸入管理

爲了提升輸入管理部分的重用性和模塊性。Weston將對輸入設備(鍵盤,鼠標,觸摸屏等)的處理分離到一個單獨的庫,也就是libinput中。這樣,其它的圖形處理系統也能夠共用這部分,好比X.Org Server和Mir。具體地,它提供了設備檢測,設備處理,輸入事件處理等基本功能,相似於Android中的EventHub。此外它還有pointer acceleration,touchpad support及gesture recognition等功能。libinput更像是一個框架,它將幾個更底層的庫的功能整合起來。它主要依賴於如下幾個庫:
• mtdev:Multi-touch設備處理,好比它會將不帶tracking ID的protocol A轉化爲protocol B。
• libevdev:處理kernel中evdev模塊對接。
• libudev:主要用於和udevd的通訊,從而獲取設備的增長刪除事件。也可從kernel獲取。

Weston中的輸入管理模塊與libinput對接,它實現了兩大部分的功能:一是對輸入設備的維護,二是對輸入事件的處理。對於輸入事件既會在Weston中作處理,也會傳給相應的client。從事件處理模型上來看,libinput的主循環監聽udev monitor fd,它主要用於監聽設備的添加刪除事件。若是有設備添加,會打開該設備並把fd加入到libinput的主循環上。另外一方面,Weston中會將libinput的epoll fd加入主循環。這樣造成級聯的epoll,不管是udev monitor仍是input device的fd有事件來,都會通知到Weston和libinput的主循環。這些事件經過libinput中的事件緩衝隊列存儲,而Weston會做爲消費者從中拿事件並根據事件類型進行處理。

\

Weston中支持三種輸入設備,分別是鍵盤,觸摸和鼠標。一套輸入設備屬於一個seat(嚴格來講,seat中包括一套輸入輸出設備)。所以,weston_seat中包含weston_keyboard,weston_pointer和weston_touch三個結構。系統中能夠有多個seat,它們的結構被串在weston_compositor的seat_list鏈表中。相應的數據結構以下。

\

能夠看到,對於焦點處理,每一個設備有本身的focus,它指向焦點窗口,用於拖拽和輸入等。成員focus_resource_list中包含了焦點窗口所在client中輸入設備proxy對應的resource對象。在這個list中意味着能夠接收到相應的事件。

最後,Wayland/Weston做爲正在活躍開發的項目,還有其它不少功能已被加入或正被加入進來。本文只是粗線條的介紹了Wayland/Weston主要結構及功能,具體細節以後再展開。

原文地址:http://blog.csdn.net/jinzhuojun/article/details/46794479   

                  http://www.it165.net/pro/html/201507/46537.html

相關文章
相關標籤/搜索