淺談 Google Skia 圖形處理引擎
2008 年九月,Google 宣佈以改良過的 WebKit 為核心的網路瀏覽器 Chrome,揭露了眾多新特徵,比方說嶄新的 [ V8] JavaScript (ECMAscript) 執行引擎,或許因為太亮眼,掩蔽了所使用另一個開放原始碼專案 [ skia],後者是個 2D 向量圖形處理函式庫,包含字型、座標轉換,以及點陣圖都有高效能且簡潔的表現。不僅用於 Google Chrome 瀏覽器,新興的 Android 開放手機平台也採用 skia 作為繪圖處理,搭配 OpenGL/ES 與特定的硬體特徵,強化顯示的效果,本文簡介 Google Skia 的歷史背景、應用層面,並探討其程式設計模型。Google 為了搭建 Open Handset Alliance (OHA) 的 Android 平台,布局極久,背後的百人研發團隊部份來自之前的併購案,其中兩項具指標性意義:
- 2005 年八月 17 日,收購美國 Android 公司,業務是手機軟體開發,這當然就是現在開放源碼 Android 計畫的前身
- 2005 年十一月,收購美國 Skia 公司,業務是向量繪圖軟體
- "Skia’s first product, SGL, is a portable graphics engine capable of rendering state-of-the-art 2D graphics on low-end devices such as mobile phones, TVs, and handhelds,” the Web site said. “SGL is feature-set compatible with existing 2D standards, making it ideal to serve as a back-end for public formats such as SVG, PDF, and OpenVG. SGL is licensed as source or binary, and can be customized to match specific HW/framebuffer requirements.”
相較於 Firefox 1.x,後繼的 Firefox 2.x/3.x 在圖形顯示方面有相當大的進展,很大層面歸功於引入 Cario 向量圖形程式庫來處理網頁繪製,而 Skia 就相當於扮演 Cairo 的角色,不過更輕量些。快速發展的 WebKit 儼然是從桌面應用跨足移動裝置之網頁引擎解決方案的首選,Apple 與 Google 都有為數可觀的全職工程師投入,拜網際網路的威力,也有其他廠商與團體個人積極投入開發,目前 WebKit 支持的圖形函式庫計有 Cairo, Gtk+, Qt4, WxWidgets, Cg (Mac 的非開放原始碼函式庫), Skia 等等,並以 WebKit 中 class GraphicsContext 處理前述圖形函式庫的實做,可針對不同平台的特性,規範不同平台所需的巨集與成員,詳情可參考程式碼 WebCore/platform/graphics/GraphicsContext.{h,cpp}。
Skia 以 C++ 實做,程式碼約八萬行,基本某些未知的因素,可參考的文件相當有限,但 Chromium 的 SVN log 與程式碼則是現在最完整的文件,以下是其特徵:
- 高度優化的軟體 rasteriser (module sgl/)
- 選擇性透過 OpenGL/ES,加速特定操作,如 shader 與 textures (module gl/)
- 動畫處理能力(module animator/)
- 內建 SVG 支援 (module (svg/)
- 內建若干 image codec,如 PNG, JPEG, GIF, BMP (modules images/)
- 內建文字處理,但缺乏泰文、藏文一類複雜文字處理的能力
- 效能特性:
- 對 image 與特定資料型態的 Copy-on-write
- 內部記憶體管理,謹慎地被免 fragmentation
- Thread-safety
- 字型: FreeType (值得注意的是,FreeType 的維護者 David Turner 目前任職於 Google), Windows GDI
- 多執行緒模型: pthread, Windows threads
- XML: expat, tinyxml
# svn co http://skia.googlecode.com/svn/trunk skia-trunk乍看這「清爽」的目錄架構,很難想像過去這是商業軟體,或許 Google 有些「不能說的秘密」,除了 samplecode/ 目錄若干的程式碼之外,就幾乎沒有充分的文檔了。用 svn log 可瀏覽 Skia 開發的紀錄,"reed@android.com" 就是 Mike Reed 本人,至今仍相當活躍地改良 Skia 的實做。編譯方式很單純,先看看說明:(本文對應於 svn r130)
# cd skia-trunk # make help可得到以下說明:
Targets: : out/libskia.a bench: out/bench/bench tests: out/tests/tests clean: removes entire out/ directory help: this text Options: (after make, or in bash shell) SKIA_DEBUG=true for debug build SKIA_SCALAR=fixed for fixed-point build SKIA_BUILD_FOR=mac for mac build (e.g. CG for image decoding)期望的編譯輸出就是靜態函式庫 out/libskia.a,而 Skia 的內部運算可選擇浮點數與定點 (fixed-point),不過筆者發現,目前尙未能透地選擇,但這不影響我們理解 Skia 的使用與體驗其威力。以筆者使用的 GNU/Linux 來說,可下達以下指令要求編譯:
# make SKIA_BUILD_FOR=linux沒意外的話,系統就會乖乖的編譯:
compiling out/src/core/Sk64.o compiling out/src/core/SkAlphaRuns.o compiling out/src/core/SkBitmap.o ...至於編譯 benchmark 程式,則可透過以下指令:
# make SKIA_BUILD_FOR=linux benchbenchmark 程式算是除了 Chromium 之外,最佳的「文件」了,不過 SKia API 本來就簡潔強大,這也不妨礙。執行 benchmark 程式:
./out/bench/bench -o `pwd`陸續會有類似以下的輸出:
running bench polygon running bench lines running bench points running bench rrects3 running bench rrects1 running bench ovals3 running bench ovals1 running bench rects3 running bench rects1 running bench bitmap_index8 running bench bitmap_4444 running bench bitmap_565 running bench bitmap_8888可大概窺知 Skia 涵蓋的範疇,接著筆者就寫個小程式,使用 Skia C++ API: [ test-skia.c]
/* Simple vector graphics demo utilizing Skia toolkit. * Authored by Jim Huang <jserv.tw@gmail.com> */ #include "SkBitmap.h" #include "SkDevice.h" #include "SkPaint.h" #include "SkRect.h" #include "SkImageEncoder.h" int main() { // Declare a raster bitmap, which has an integer width and height, // and a format (config), and a pointer to the actual pixels. // Bitmaps can be drawn into a SkCanvas, but they are also used to // specify the target of a SkCanvas' drawing operations. SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, 200, 200); bitmap.allocPixels(); // A Canvas encapsulates all of the state about drawing into a // device (bitmap). This includes a reference to the device itself, // and a stack of matrix/clip values. For any given draw call (e.g. // drawRect), the geometry of the object being drawn is transformed // by the concatenation of all the matrices in the stack. The // transformed geometry is clipped by the intersection of all of the // clips in the stack. SkCanvas canvas(new SkDevice(bitmap)); // SkPaint class holds the style and color information about how to // draw geometries, text and bitmaps. SkPaint paint; // SkIRect holds four 32 bit integer coordinates for a rectangle. SkRect r; paint.setARGB(255, 255, 0, 0); r.set(25, 25, 145, 145); canvas.drawRect(r, paint); /** Draw the specified rectangle using the specified paint. The rectangle will be filled or stroked based on the Style in the paint. */ paint.setARGB(255, 0, 255, 0); r.offset(20, 20); canvas.drawRect(r, paint); paint.setARGB(255, 0, 0, 255); r.offset(20, 20); canvas.drawRect(r, paint); // SkImageEncoder is the base class for encoding compressed images // from a specific SkBitmap. SkImageEncoder::EncodeFile("snapshot.png", bitmap, SkImageEncoder::kPNG_Type, /* Quality ranges from 0..100 */ 100); return 0; }編譯方式:
g++ / -I./include / -I./include/core / -I./include/images / -Wall -o test-skia test-skia.c / out/src/images/SkImageDecoder_libpng.o out/libskia.a / -lpng -lpthread -g筆者做了簡要的註解,大概可知曉 Sk 開頭的這些 API 的功用,而上述的範例程式一開始就要求 Skia 配置畫布 (SkCanvas),接著透過一份 SkRect 物件 r,給定 ARGB 的描述,使其有著不同的顏色,再來就是調整向量物件的位移並繪製。正如前文提及,Skia 僅是繪圖引擎,並未如 Cairo 一般廣泛對應到 PDF, X11, GDI 等等底層繪圖裝置,所以為了方便觀察繪圖結果,我們透過 Skia 內建的 image codec 來輸出 PNG 圖檔,所以執行前述編譯後的執行檔 "test-skia",應該會得到以下圖檔:(本無外框與底色,但為了清楚於文章呈現,額外用繪圖軟體追加)
疊合的三個不同色的矩形物件,就是透過以下 API 呼叫達成:
paint.setARGB(255, 0, 255, 0); r.offset(20, 20); canvas.drawRect(r, paint);由於 Skia 與 Cairo 的同質性相當高,也可參照 [ Cairo :: documentation] 建立所需的背景知識。
由 jserv 發表於 March 21, 2009 07:42 PM
原文地址 :
http://blog.linux.org.tw/~jserv/archives/002095.html
开源项目位置:
http://code.google.com/p/skia/