webdino / gecko-embedded

Main (meta) repository for Project GEM (Gecko Embedded)
https://gecko-embedded.org
22 stars 2 forks source link

Gecko 68 on RZ/G2 で WebGL の FPS が低い #91

Closed dynamis closed 4 years ago

dynamis commented 5 years ago

現状の Firefox 68 on RZ/G2M WIP ビルドで WebGL コンテンツを再生したときの FPS が (60 ではなく) 25 で頭打ちになってしまっている。2D Canvas などの処理は 60fps でているので、WebGL の場合のみの制限。BSP や OpenGL ドライバ周りか Gecko エンジン側かどちらの問題かなど未確認。

OpenGL ES3 周りで何か制約の生じるビルドになってしまっている?

FSP 表示のある軽量 WebGL サンプル:

anyakichi commented 5 years ago

Extension の違い

about:support の WebGL 1 Extensions において、Firefox 68 では EXT_frag_depth と WEBGL_draw_buffers が減っている。これは下記で修正されていて、意図したものである模様。

https://bugzilla.mozilla.org/show_bug.cgi?id=1524804

一応上記修正を外して Extension を有効に戻してみたが、Extensions の一覧には出るようになったもののパフォーマンス面では改善しなかった。

gfx の default provider

Firefox 60 ではビルド時に gl provider として EGL を明示的に指定していた。Firefox 68 では現状は指定なし(デフォルト)になっている。

gfx/gl/GLContextProvider.h の実装では、Firefox 68 では EGL ではなく Wayland が default provider として使用されるようになっている。これを試しに EGL に変更してみたが効果なし。

なお、Firefox のビルドオプションで Firefox 60 のときと同様に --with-gl-provider=EGL を指定すると、gfx/gl/moz.build の作りの都合で GLContextProviderGLX.cpp などがビルド対象から外されコンパイルに失敗するようになる。

gfx.blacklist.layers.opengl

Firefox 68 では、

gfx.blacklist.layers.opengl = 4
gfx.blacklist.layers.opengl.failureid = FEATURE_FAILURE_SOFTWARE_GL

が出ている。Firefox 60 から GfxInfoX11.cpp の実装の違いから出るようになっているようだが、ソフトウェア的にエラーが報告されないようにしても特に効果はなし。

anyakichi commented 5 years ago

現状で動作させている Firefox 60 と Firefox 68 では、Firefox のソースコードだけでなく、ビルド環境もかなり変わってしまっている。一旦「ビルド環境は関係ない」ことを確定させるために、Firefox 68 向けのビルド環境(rust や clang)などを使って、Firefox 60 をビルドし動作確認を行った。結論としてはビルド環境は特に関係なく、新しい rust や clang で構築した Firefox 60 で 60fps 出ることを確認した。

ただし、新しい環境で Firefox 60 のビルドのためにはいくつか調整が必要になる。

60 と 68 ではかなり差分も多く、現時点ではソースコード上のあたりはほぼついていない。

範囲を効率的に狭めるのであれば、61 〜 67 の動作確認を行って動作が遅くなってしまったバージョンを特定するのが部分的には良いと思うが、実際にコンパイルするための調整の手間がどれくらいかかるかが想定できておらず、本当にこれが効率的かどうかは不明(とはいえ rust, clang などの環境が Firefox 68 向けのままで良さそうではあるので、そんなに大変じゃないかもしれない)。

dynamis commented 5 years ago

あまり意味の無い報告: バージョン二分探索チェックも大変そうだなと思って先日少し Bugzilla なんかも見てみた のですが

といったくらいでこれといって怪しい bug は見つけられませんでした。怪しい挙動が見つからないと影響範囲特定を進めるしかなさそうですね。

anyakichi commented 5 years ago

1010527 は私も先日見ていたのですが、60 では良かったのに 68 でダメになった話とは全然合致しないので関係なさそうだなと思っていました。

それはそれとして、よく考えると WebGL2 対応で glxtest を XWayland を入れて通してあげるという話が実はちょっと変じゃないかというか、glxtest はビルドの内部的には MOZ_GL_DEFAULT_PROVIDER が GLX のときにしかビルドされないのですが、Firefox 60 のときには MOZ_GL_DEFAULT_PROVIDER は EGL になっているはずなのですよね(configure で指定していたので)。

あまり細かくは調べられていないのですが、Firefox 60 は XWayland を有効にしても WebGL2 が有効にならず、これはそもそも glxtest とは全然違う問題でダメになっているからじゃないかと推測しています。

でも仮にこれが正しかったとすると、Firefox 68 で EGL に戻してパフォーマンスが回復したとして、WebGL2 対応は別の方法でやり直しになる可能性が高そうには思います。

anyakichi commented 5 years ago

いやでも Firefox 68 までの間に GLX と EGL の両立ができるようになったから、と思えば変ではないですか。いずれにせよ現時点ではあまり状況を捉えきれてないですね。

https://github.com/mozilla/gecko-dev/commit/704838e243a064a008f10baddd5d0115cf95e492

ashie commented 5 years ago

関係ないかもしれませんが、63辺りからVSyncの実装が入ってるのがちょっと気になってます。

あと、こちらも関係ないかもしれませんが、昨日似たような?バグが立ってました

ashie commented 5 years ago

あと、これもたぶん関係ないと思うんですが、すぐに試せることとしてはe10sを切った場合どうなるかもちょっと気になります。68ではprefでは切れなくなっていて、環境変数MOZ_FORCE_DISABLE_E10S=1が必要です(レシピ作ったときにはそのことに気がついてなかったのでdisable-e10sというPACKAGECONFIG入れちゃってますけど)。

anyakichi commented 5 years ago

VSync の方については frame_callback_handler() で

gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(time);

としているのをやめれば mWaylandFrameDelay = 1000/60 で確実に描画が入るだろう…ということでやってみましたが効果なし。さらに mWaylandFrameDelay 自体を 1000/100 で 100fps 相当にしてみたりしても変化なしですね。

MOZ_FORCE_DISABLE_E10S=1 の方も有意な変化は見られずでした。

一応ウインドウサイズを狭めれば fps が上がってくることはわかっているので、描画のタイミング制御がおかしいわけではなく、ただ単に描画そのものが遅いから全体が遅いのかな、という気はします。

あと全然別の話なのですが、私の Thinkpad X1 Yoga 4th (ArchLinux, Firefox 70, X11) でも https://threejs.org/examples/#webgl_geometry_normals は 2560x1440 のフルスクリーンだと 30fps くらいしか出ず。Wayland で起動しようとすると画面がちらついてしまって操作できない感じです。Chromium は何ということなく安定して 60fps なのですが。

別のデスクトップ機では Firefox 70 で 60fps 出ていたりするので、何か相性的なものもありそうなような…。

anyakichi commented 5 years ago

apitrace 8.0 を入れてログを取ってみた。

GDK_BACKEND=wayland apitrace --api=egl --output=/tmp/firefox-dump.trace firefox https://threejs.org/examples/webgl_geometry_normals.html

ちなみに Firefox 68 で --api=gl であれば解析可能なログが取れるが、おそらくは glxtest の実行を行っただけの短いものしか取れていない。

anyakichi commented 5 years ago

Firefox 68 で apitrace がおかしいのは e10s が有効だと複数プロセスからログを書きに行って潰してしまうからのようで、MOZ_FORCE_DISABLE_E10S=1 だと dump 可能だった。

ただし Firefox 60 だと Wayland で描画しているウインドウが replay 可能な感じになるが、Firefox 68 だとほとんど何も replay できない。

anyakichi commented 4 years ago

Firefox 67, 66 でそれぞれ動作確認を行ったが、どちらも FPS は 35 前後で遅い。

https://github.com/webdino/meta-browser/tree/anyakichi/firefox-67-rzg2 https://github.com/webdino/meta-browser/tree/anyakichi/firefox-66-rzg2

手作業の手順については MEMO ファイルを参照のこと。

anyakichi commented 4 years ago

ということで遅くなったバージョンは Firefox 62 で確定。変更量はそれなりに多い。

$ hg diff -r FIREFOX_61_0_2_RELEASE -r FIREFOX_62_0_3_RELEASE | wc -l
3267154
$ hg diff -r FIREFOX_61_0_2_RELEASE -r FIREFOX_62_0_3_RELEASE gfx | wc -l
146173

このバージョンから GLContextProviderWayland が導入されるなど、gfx/gl 以下の構成にいろいろと変更がある。また、これまで #ifdef GL_PROVIDER_GLX だったところが #ifdef MOZ_X11 に変更、もしくは #ifdef そのものが削除されている箇所も多数あり、EGL と GLX が共存するような形式に変更されている。

感覚的にはこのあたりが怪しいような気はするが…あまり確証はない。

暫定的に MOZ_X11 を無効にしてビルドするのは試してみたが、cairo 周りの依存関係でビルドを通すまでの調整が難しそうだった。

dynamis commented 4 years ago

関係ないだろう話が発端ですがこちらに共有:

別件で GDK_BACKEND 指定ミスったら WebGL1 は動くが WebGL2 だけ動かずに

WebGL creation failed:
tryNativeGL
Exhausted GL driver options

というメッセージがコンソールや about:support の WebGL2 欄に出ていた。 https://dxr.mozilla.org/mozilla-central/source/dom/canvas/WebGLContext.cpp#627 https://dxr.mozilla.org/mozilla-central/source/dom/canvas/WebGLContext.cpp#642

それで回り少し見たら https://dxr.mozilla.org/mozilla-central/source/dom/canvas/WebGLContext.cpp#570 const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL"); が false になっていて GLContextProviderEGL ではなく GLContextProvider を使っているケースは WebGL1 だけ動く状態になっていた様子。

GLContextProvider が一杯ある&変わってるけど Gecko ~61 と 62〜 で実際どれを使って描画しているのか (同じなのか違うのか)、ビルド設定や環境変数などに依存して切り替わる感じがするけど適切な GLContextProvider が使われているのか、強制的に切り替えてみたらどう変わるのかとか気になりました。

ashie commented 4 years ago

GLContextProvider が一杯ある&変わってるけど Gecko ~61 と 62〜 で実際どれを使って描画しているのか (同じなのか違うのか)、ビルド設定や環境変数などに依存して切り替わる感じがするけど適切な GLContextProvider が使われているのか、強制的に切り替えてみたらどう変わるのかとか気になりました。

最近自分ではあまり実機を触ってないので未だに本issueの現象自体確認できていないのですが、 GDK_BACKENDの指定を間違っていなければそこは大丈夫じゃないかなと思ってます。

GLContextProviderWayland

GLContext* GLContextProviderWayland::GetGlobalContext() {
  if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
    return sGLContextProviderGLX.GetGlobalContext();
  } else {
    return sGLContextProviderEGL.GetGlobalContext();
  }
}

こういうベタな方法でGLContextProviderをランタイムで切り替えるだけの存在なので、GDK_BACKENDの指定を間違えて無ければ、Wayland上でGLContextProviderGLXが使われることはまず無いはずです(といううかGDK_BACKENDを間違えてたらX11バックエンドでGLContextProviderGLXが動く)し、使われたとしてもWaylandバックエンドでは動かないと思います。

ashie commented 4 years ago

る。また、これまで #ifdef GL_PROVIDER_GLX だったところが #ifdef MOZ_X11 に変更、もしくは #ifdef そのものが削除されている箇所も多数あり、EGL と GLX が共存するような形式に変更されている。

感覚的にはこのあたりが怪しいような気はするが…あまり確証はない。

X11のコードが中途半端に動いて変なことになっていたのは今までにもよくあったので、たしかに怪しいなぁと思ってちょっと差分を眺めてみてます。

この辺とか怪しいです。

https://searchfox.org/mozilla-esr68/source/gfx/gl/GLScreenBuffer.cpp#84

もともとdefined(GL_PROVIDER_GLX)の条件でしかビルドされなかったのが、defined(MOZ_X11)に変わってビルドされるようになっています。一方で、その下のEGL用のコードがビルドされなくなっちゃってるように見えます(従来は上記の条件に引っかからなくてここがビルドされていたはず)。

https://searchfox.org/mozilla-esr68/source/gfx/gl/GLScreenBuffer.cpp#97

#else
    if (gl->GetContextType() == GLContextType::EGL) {
      if (XRE_IsParentProcess()) {
        factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
      }
    }
#endif
anyakichi commented 4 years ago

もともとdefined(GL_PROVIDER_GLX)の条件でしかビルドされなかったのが、defined(MOZ_X11)に変わってビルドされるようになっています。一方で、その下のEGL用のコードがビルドされなくなっちゃってるように見えます(従来は上記の条件に引っかからなくてここがビルドされていたはず)。

おおおお、なるほど。手元に残っていた Firefox 62 のビルド環境でビルドしてみたところ、FPS 60 出るようになりました!どうやらこれでビンゴっぽいですね…。素晴らしい…。

また後日 Firefox 68 でも同様に改善するかは確認してみます。

あとは直し方として、if 文を MOZ_X11 の中に入れてしまうのが良いのか、違う条件で切るのかは考えないといけませんが(現在の #else で EGL というのもなんか違和感はありますが)。

ashie commented 4 years ago

一番簡単な直し方としてはMOZ_X11のところをそのまま#elseの中に移動してしまえば良さそうです。 Waylandの場合にはたぶんsGLXLibrary.UseTextureFromPixmap() == falseになると思うので。 もちろん、さらにGDK_IS_X11_DISPLAY(gdk_display_get_default())のチェックを入れた方がより確実だとは思います。

あと、この関数の最後の#ifdef MOZ_X11は不要そうなので削除しておいた方が良さそうです。

(現在の #else で EGL というのもなんか違和感はありますが)

昔は違ったような気がするのですが、今はGLContextProviderEGLが全てのプラットフォームでビルドされるようなので、そんなもんなのかなという気もします。

ashie commented 4 years ago

あと、この関数の最後の#ifdef MOZ_X11は不要そうなので削除しておいた方が良さそうです。

いや、必要らしい

https://bugzilla.mozilla.org/show_bug.cgi?id=1241486

ashie commented 4 years ago

PC上で以下のようなパッチを試してみたが、XRE_IsParentProcess()の条件があるので、e10sを無効化(環境変数MOZ_FORCE_DISABLE_E10S=1)しないとSharedSurface_EGLImageが有効にならない。 e10を切ると、e10s有効の場合より速くなった。この条件を外してe10s有効の場合は画面が真っ黒。

diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -25,16 +25,17 @@
 #  include "mozilla/gfx/DeviceManagerDx.h"
 #endif

 #ifdef XP_MACOSX
 #  include "SharedSurfaceIO.h"
 #endif

 #ifdef MOZ_X11
+#  include <gdk/gdkx.h>
 #  include "GLXLibrary.h"
 #  include "SharedSurfaceGLX.h"
 #endif

 namespace mozilla {
 namespace gl {

 using gfx::SurfaceFormat;
@@ -80,30 +81,32 @@ UniquePtr<SurfaceFactory> GLScreenBuffer
       !StaticPrefs::webgl_force_layers_readback() &&
       (backend == layers::LayersBackend::LAYERS_D3D11 ||
        (backend == layers::LayersBackend::LAYERS_WR && useANGLE));

   UniquePtr<SurfaceFactory> factory = nullptr;
   if (useGl) {
 #if defined(XP_MACOSX)
     factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
-#elif defined(MOZ_X11)
-    if (sGLXLibrary.UseTextureFromPixmap())
-      factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
 #elif defined(MOZ_WIDGET_UIKIT)
     factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel,
                                                    mFlags);
 #elif defined(MOZ_WIDGET_ANDROID)
     if (XRE_IsParentProcess() && !StaticPrefs::webgl_enable_surface_texture()) {
       factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
     } else {
       factory =
           SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
     }
 #else
+#  if defined(MOZ_X11)
+    if (gl->GetContextType() == GLContextType::GLX &&
+        sGLXLibrary.UseTextureFromPixmap())
+      factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
+#  endif
     if (gl->GetContextType() == GLContextType::EGL) {
       if (XRE_IsParentProcess()) {
         factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
       }
     }
 #endif
   } else if (useD3D) {
 #ifdef XP_WIN
@@ -127,17 +130,19 @@ UniquePtr<SurfaceFactory> GLScreenBuffer
     if (!factory && StaticPrefs::webgl_dxgl_enabled()) {
       factory =
           SurfaceFactory_D3D11Interop::Create(gl, caps, ipcChannel, flags);
     }
 #endif
   }

 #ifdef MOZ_X11
-  if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
+  // Bug 1241486: Use SharedSurface_GLX with XRender
+  if (!factory && GDK_IS_X11_DISPLAY(gdk_display_get_default()) &&
+      sGLXLibrary.UseTextureFromPixmap()) {
     factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
   }
 #endif

   return factory;
 }

 GLScreenBuffer::GLScreenBuffer(GLContext* gl, const SurfaceCaps& caps,
anyakichi commented 4 years ago

上記パッチで RZ/G2M + Firefox 68 試してみました。

ということで e10s 無効であれば状況が改善しました。どちらも描画そのものは適切にできているように見えます。

ただ、若干気になる点として FPS が 60 「前後」なので、なんとなく 62 で安定しつつ 40〜50 くらいに急に落ちてまた 62 に戻る…ような数値の見え方になっています。Firefox 62 のときには 60 できれいに張り付いていたのですが…。

dynamis commented 4 years ago

お二人とも調査・検証ありがとうございます。FPS 60 前後が (一応) 出るようになって良かったです! // 適切な条件分岐がされておらずテスト不足の環境では挙動が怪しいというのはなるほどというか確かに以前もそういう話をされていた気がしました。

e10s を有効化できないのは残念ですが仕方ない&Fx60 でも有効化できなかったので regression にはならないですし、今回も無効化を標準ビルドとする (WebGL 使わないから e10s 有効化するという選択は一応あり) のが妥当そうですね。

FPS 不安定になるというのはまだ何か問題が残っているので継続調査が必要そうですが...

ashie commented 4 years ago

68ではprefでのe10s無効化が出来なくなっているのでお気をつけ下さい。 PACKAGECONFIGdisable-e10sが意味を成さなくなっているので、OSSystems/meta-browserの方では削除しました。 https://github.com/OSSystems/meta-browser/pull/343

実行時にMOZ_FORCE_DISABLE_E10S=1を指定するか、新たなパッチが必要だと思います。

ashie commented 4 years ago

パッチについては後でBugzillaに報告しておきます。

ちなみにX11の場合はgfx.use-glx-texture-from-pixmapというオプションがデフォルトoffでこれをonにしないとSharedSurfaceGLXが使えないようです。また、こちらもe10sでは動作しないようです。

ashie commented 4 years ago

パッチについては後でBugzillaに報告しておきます。

既にdmabufで実装中でした。

https://bugzilla.mozilla.org/show_bug.cgi?id=1586696

dynamis commented 4 years ago

少し脱線になりますが:

68ではprefでのe10s無効化が出来なくなっているのでお気をつけ下さい。 PACKAGECONFIGのdisable-e10sが意味を成さなくなっているので、OSSystems/meta-browserの方では削除しました。

こちらでも検証をしてみたのですが現状の Fx68 ビルドはデフォルト e10s オンですが browser.tabs.remote.autostart=false にすると ps コマンドと about:support いずれで見ても e10s 無効にちゃんと切り替わりました (MOZ_FORCE_DISABLE_E10S=1 で起動するときと同じ)。以前入れていた 4 設定

pref("browser.tabs.remote.force-enable", false);
pref("browser.tabs.remote.force-disable", true);
pref("browser.tabs.remote.autostart", false);
pref("browser.tabs.remote.autostart.2", false);

の一部は使えなくなっているが少なくとも browser.tabs.remote.autostart はまだ e10s 無効化に使えるということはないでしょうか?

ashie commented 4 years ago

の一部は使えなくなっているが少なくとも browser.tabs.remote.autostart はまだ e10s 無効化に使えるということはないでしょうか?

もしかしたら、そういうことなのかもしれません。 (すみません、最近自分ではまったくいじれてないので、本件に関しては自分で確かめたことではなくて周りから聞いたことの受け売りに過ぎないです。)

dynamis commented 4 years ago

Gecko 68 時点では e10s の有効化と WebGL のパフォーマンス確保は排他的な関係にあるという制約は残るが、Gecko 60 と比べて遅くなっていた問題は解消したためクローズします。

(Gecko 60 ではそもそも e10s 有効化できていなかったので regression ではない)

Gecko 68 では何らかの特別な事情で e10s/webgl 両方を使いたいケースがでてこない限り終了としてクローズ、次は Gecko 78 ベースでどうなるのかを確認・検討していくこととしましょう。