Open3

flutter_glの使い方

fastriverfastriver

Windowsでの挙動

  • FlutterGlPlugin.initialize()を呼ぶ
    • FlutterGlPlatform.initialize_interface()を呼ぶ
      • Web以外はMethodChannelFlutterGl.initialize_interface()
      • MethodChannel.invokeMethod("initialize")を呼ぶ
        • FlutterGlWindowsPlugin::HandleMethodCall()が呼ばれる
          • CustomRenderを作成
            • PixelBufferTextureを作成し、TextureRegistrarに登録
            • FlutterDesktopPixelBuffer構造体でデータ格納場所を確保
            • CustomRender::initEGL()を呼ぶ
              • EglEnvを3つ作成(shareEglEnv, eglEnv, dartEglEnv)
                • それぞれEglEnv::setupRender()を呼び出す(コンテキストは全て共有)
              • eglEnv.makeCurrent()を呼ぶ
                • glfwMakeContextCurrent()を呼んでコンテキストを有効化
              • gladLoadGLLoader()でOpenGL関数を読み込み
              • CustomRender::initGL()を呼ぶ
                • texture, framebuffer, renderbufferを作成してバインド
              • RenderWorkerを作成
              • RenderWorker::setup()を呼ぶ
                • OpenGLProgramを作成
                • RenderWorker::setupVBO()を呼ぶ
                  • 画面を覆う四角形を構成するVertexBufferObjectを作ってバインド
                • RenderWorker::setupVBO4FBO()
                  • 上に同じ(頂点の型が異なる)
          • textureIDを保存して返す
    • OpenGL.init()を呼ぶ
      • getInstance()を呼ぶ(Web以外は"OpenGL-ES.dart"内)
        • OpenGLESを作成
          • EGLとOpenGLのdllを読み込み
          • LibOpenGLESを作成
          • LibEGLを作成

その後

  • FlutterGlPlugin.prepareContext()を呼ぶ
    • FlutterGlPlatform.getEgl_interface()を呼ぶ
      • Web以外はMethodChannelFlutterGl.getEgl_interface()
      • MethodChannel.invokeMethod("getEgl")を呼ぶ
        • FlutterGlWindowsPlugin::HandleMethodCall()が呼ばれる
          • CustomRender::getEgls()を呼ぶ
            • なんかリストを作って返す
    • OpenGL.makeCurrent()を呼ぶ
      • OpenGLES.makeCurrent()を呼ぶ
        • egl.makeCurrent()を呼ぶ

Q. CustomRender内でもmakeCurrentを呼んでいるのになぜもう一度呼ぶの?

A. DartとC++両方のスレッドでOpenGLのオブジェクトを共有し、どちらからでも命令が使えるようにするため。OpenGLのcontextはmakeCurrentが呼ばれたスレッドでしか使えない。EglEnvはcontextを共有しているため、両方でmakeCurrentを呼べばどちらからでも利用できるようになる。
参考: https://sites.google.com/site/monshonosuana/openglの話/openglの話-第5回

適当なtextureを用意する

  • FlutterGlPlugin.updateTexture()を呼ぶ
    • FlutterGlPlatform.updateTexture_interface()を呼ぶ
      • Web以外はMethodChannelFlutterGl.updateTexture_interface()
      • MethodChannel.invokeMethod("updateTexture")を呼ぶ
        • FlutterGlWindowsPlugin::HandleMethodCall()が呼ばれる
          • CustomRender::updateTexture()を呼ぶ
            • frameBufferをバインド
            • RenderWorker.renderTexture()を呼ぶ
              • RenderWorker::drawTexture()を呼ぶ
                • RenderWorker::getProgram()を呼ぶ
                  • 初回だけOpenGLProgram::getProgram()を呼ぶ
                    • shaderのGLSLを用意
                    • OpenGLProgram::compileShaders()を呼ぶ
                      • OpenGLProgram::compileShader()でそれぞれのshaderをコンパイル
                      • programを作成
                • programを利用
                • 渡されたtextureをtexture8にバインド
                • vertexBufferをバインド
                • vaoを作成
                • positionとtextureのデータを送信
                • 描画
            • bufferにPixelを読み出す
            • TextureRegistrar::MarkTextureFrameAvailable()を呼ぶ
fastriverfastriver

そもそもOpenGLの登場人物

レンダリングコンテキスト

https://sonson.jp/blog/2006/04/04/opengl-5/

  • 描画のためのOpenGLの状態やオブジェクトを統括する存在
  • PixelFormatとOSのDeviceContextから作られる
  • 基本的にWindowと1対1対応
  • ディスプレイリスト・テクスチャ・フォントなどの情報が格納される
  • マルチウィンドウなら複数のレンダリングコンテキストを使うことになる
  • OpenGLの命令は全て暗黙的にカレントコンテキストに向けたもの
    • makeCurrent()などを呼び出すと現在のスレッドのカレントコンテキストが変わる
  • glfwMakeContextCurrent()などで作成できる

Framebuffer Object

https://www.khronos.org/opengl/wiki/Framebuffer_Object

https://qiita.com/edo_m18/items/95483cabf50494f53bb5

  • 複数のバッファを束ねたオブジェクト
    • Color Buffer, Depth Buffer, Stencil Bufferを持つ
    • これらはTexture BufferかRender Bufferである
  • 画面に表示するデータ構造と似たような形式になっている
  • オフスクリーンレンダリングなどに利用できる
  • glCreateFramebuffer()で作れる
  • glBindFramebuffer()で有効化

Texture Object

  • 画像を保持するオブジェクト
  • glCreateTextures()で作れる
  • glBindTexture()で有効化

Renderbuffer

https://stackoverflow.com/questions/41182154/deferred-rendering-renderbuffer-vs-texture

  • Textureと同様、画像状データを保持するオブジェクト
  • しかし、Textureとして読み出すことはできない
  • パフォーマンスはRenderbuffer >= Texture
  • colorbufferはTexture、depthbufferはRenderbufferにするなどが考えられる
  • glCreateRenderbuffer()で作れる
  • glBindRenderbuffer()で有効化

Shader

  • GPU上で頂点や色を計算するためのプログラム
  • 基本的にVertex ShaderとFragment Shaderの2つが存在
  • 頂点データ→Vertex Shader(頂点位置の計算)→Fragment Shader(ピクセルの色の計算)→画像
  • glCreateShader()で作成
  • GLSLで書いてプログラム中でコンパイル
  • glShaderSource()でシェーダプログラムを指定
  • glCompileShader()でコンパイル

Program Object

  • シェーダオブジェクトをまとめたオブジェクト
  • glCreateProgram()で作成
  • glAttachShader()でシェーダを追加
  • glLinkProgram()でリンク
  • glUseProgram()でカレントの状態として展開

Vertex Buffer Object (VBO)

  • 頂点情報をGPUメモリに格納するためのオブジェクト
  • glGenBuffers()で作成
  • glBindBuffer()で有効化
  • glBufferData()でデータを格納
  • glBufferSubData()でデータを更新
  • バインドした状態でglVertexAttribPointer()を呼ぶとシェーダのattributeと結びつけてくれる

Vertex Array Object (VAO)

  • VBOとattrの設定などを録画・保持できるオブジェクト
  • glBindVertexArray()で有効化