Gecko Layer 除錯工具: LayerDump & LayerScope

在 Firefox 的 Rendering Pipeline 中,一路從 Layout 到 Layer tree,在 Layer tree 中的每一個 Layer 會依序的畫到螢幕上,所以通常畫面出現問題後(ex. 某個畫面下面剛好少了一個 pixel ),我們會先從 Layer 開始下手從下到上去檢查到底是那一個環節出了問題。

不過 Layer 這麼複雜,有什麼好用的工具可以幫助我們快速的檢查每一個 Layer 的屬性呢?這次就來介紹兩個好用的工具:LayerDump 和 LayerScope。

LayerDump

嚴格來說這個並不算是工具的一種,只是在程式碼中已經寫好了一段程式可以快速的把我們目前的Layer tree把他印出來,使用的方式如下:

  1. 要先將 Firefox OS 編成 debug build,只需將 b2g 目錄下的 .userconfig 檔案裡加入一行 export B2G_DEBUG=1
  2. 在 gfx/layers/ipc/CompositorParent.cpp 內,找到static bool gDumpCompositorTree = false
    將 gDumpCompositorTree 改成 true
  3. Dump 這個 function 的第二個參數可以在 log 中加上一個 prefix,建議加入會比較好 debug 喔!
  4. 改完的code差異如下
    #ifdef MOZ_DUMP_PAINTING
    -  static bool gDumpCompositorTree = false;
    +  static bool gDumpCompositorTree = true;
       if (gDumpCompositorTree) {
         printf_stderr("Painting --- compositing layer tree:\n");
    -    mLayerManager->Dump();
    +    mLayerManager->Dump(nullptr, "DumpTest");
       }
     #endif
  5. 請把 gecko 重編後就會出現囉
  6. 因為上面我們有加入 prefix,因此只要打入 adb logcat | grep “DumpTest” 就可以輕鬆的把 Layer 資訊抓出來囉!!

一起來看看有那些資訊吧!從下面的範例來看,至少有

  1. Layer 的型態
  2. Layer 間的階層關係
  3. Layer 的空間資訊,大小、位置等等

LayerManager (0x4802c980)
  ContainerLayerComposite (0x44a8b800) [shadow-visible=< (x=0, y=0, w=480, h=800); >] [visible=< (x=0, y=0, w=480, h=800); >] [opaqueContent] [metrics={ viewport=(x=0.000000, y=0.000000, w=320.000000, h=533.333313) viewportScroll=(x=0.000000, y=0.000000) displayport=(x=0.000000, y=0.000000, w=0.000000, h=0.000000) scrollId=0 }]
    ThebesLayerComposite (0x45651000) [shadow-clip=(x=0, y=0, w=0, h=0)] [clip=(x=0, y=0, w=0, h=0)] [not visible]
    ColorLayerComposite (0x45651600) [not visible] [opaqueContent] [color=rgba(0, 0, 0, 1)]
    ContainerLayerComposite (0x45622c00) [shadow-clip=(x=0, y=0, w=480, h=800)] [shadow-visible=< (x=0, y=0, w=480, h=800); >] [clip=(x=0, y=0, w=480, h=800)] [visible=< (x=0, y=0, w=480, h=800); >] [opaqueContent]
      ThebesLayerComposite (0x45651200) [shadow-visible=< (x=0, y=0, w=480, h=800); >] [visible=< (x=0, y=0, w=480, h=800); >] [opaqueContent] [valid=< (x=0, y=0, w=480, h=800); >]
        DeprecatedContentHostDoubleBuffered (0x456d8630) [buffer-rect=(x=0, y=0, w=480, h=800)] [buffer-rotation=(x=0, y=0)]
          GrallocDeprecatedTextureHostOGL (0x442e10c0) [size=(width=480, height=800)] [format=FORMAT_B8G8R8X8] [flags=TEXTURE_USE_NEAREST_FILTER]
          GrallocDeprecatedTextureHostOGL (0x442e1300) [size=(width=480, height=800)] [format=FORMAT_B8G8R8X8] [flags=TEXTURE_USE_NEAREST_FILTER]
      CanvasLayerComposite (0x46132200) [shadow-clip=(x=0, y=0, w=480, h=800)] [shadow-transform=[ 1 0; 0 1; 0 664.75; ]] [shadow-visible=< (x=0, y=0, w=480, h=120); >] [clip=(x=0, y=0, w=480, h=800)] [transform=[ 1 0; 0 1; 0 664.75; ]] [visible=< (x=0, y=0, w=480, h=120); >]
        ImageHost (0x461b0280) [picture-rect=(x=0, y=0, w=0, h=0)]
          MemoryTextureHost (0x47061830) [size=(width=0, height=0)] [format=FORMAT_B8G8R8A8] [flags=]

      ThebesLayerComposite (0x47042a00) [shadow-visible=< (x=382, y=702, w=46, h=8); (x=57, y=710, w=36, h=30); (x=382, y=710, w=46, h=30); (x=382, y=740, w=46, h=8); >] [visible=< (x=382, y=702, w=46, h=8); (x=57, y=710, w=36, h=30); (x=382, y=710, w=46, h=30); (x=382, y=740, w=46, h=8); >] [valid=< (x=382, y=702, w=46, h=8); (x=57, y=710, w=36, h=30); (x=382, y=710, w=46, h=30); (x=382, y=740, w=46, h=8); >]
        DeprecatedContentHostDoubleBuffered (0x483eeeb0) [buffer-rect=(x=57, y=702, w=371, h=46)] [buffer-rotation=(x=0, y=0)]
          GrallocDeprecatedTextureHostOGL (0x461d9940) [size=(width=371, height=46)] [format=FORMAT_B8G8R8A8] [flags=TEXTURE_USE_NEAREST_FILTER]
          GrallocDeprecatedTextureHostOGL (0x461d98c0) [size=(width=0, height=0)] [format=FORMAT_UNKNOWN] [flags=TEXTURE_USE_NEAREST_FILTER]

LayerScope

雖然 LayerDump 簡單好用,但是我們卻看不到每一個 Layer 的內容,這時候就可以使用另一個工具 – LayerScope,它的原理是透過 WebSocket 連接Device上的Socket 來接收資料,用途是顯示出每個畫在畫面上的 Layer 的內容,截圖如下:
Gecko Layer 除錯工具: LayerDump & LayerScope
使用的方式如下:

  1. 這個功能是最近才新加入的功能,所以請確定已經抓到最新版的 gecko 程式碼喔。另一個簡單可以分辨的方式是可以直接去檢查gfx/layers/LayerScope.cpp 這個檔案有沒有存在,有才表示可以使用 LayerScope。
  2. 在 b2g 目錄下,打 ./edit-prefs.sh 並且加入以下二個 prefs
    user_pref("gfx.layerscope.enabled", true);
    user_pref("network.gonk.manage-offline-status", false);
  3. 請打以下指令 adb forward tcp:23456 tcp:23456
  4. 請下載 websockify,下載後請打以下指令 python websockify.py localhost:23457 localhost:23456
  5. 打開工具的網址,在其中的網址列打入 ws://localhost:23457 並按下 Connect 即可

結論

二個工具目前各有各的優點,LayerDump 資訊豐富且設定簡單,LayerScope 可得到 Layer 的內容可以容易的用肉眼看出一些潛在的問題,建議在做 Debugging 的時候二個搭配一起用,更能事半功倍!