※この記事ではgitのタグ「v2.74」から生成したブランチ上でコードリーディングしています。

頂点が頻繁に更新されるのはEditモードだよね

前回の記事の続きです。

前回はObjectモード時のレンダリングはGPUで行われている事を突き止めましたが、今回は頂点データが頻繁に更新されてメインメモリ<ー>GPUメモリ間のデータ転送コストが毎回発生するであろうEditモードのレンダリングについて調べてみます。Editモードのレンダリングに使われているのはCPUでしょうか?GPUでしょうか?

OB_MODE_EDITで探るもレンダリング命令まで行き着かず

Objectモードのときはdrawobject.cの中でObjectモードを示すenum値:OB_MODE_OBJECTの付近を探っていたら運良くレンダリング命令の部分を引き当てる事に成功しましたが、今回はEditモードを示すOB_MODE_EDITの付近を探ってみるも、レンダリング命令に行き着きませんでした。

しかしdrawobject.cの中に目的の部分がある可能性は捨てず、別の方法で探す事にしました。いろいろ検索条件を変えて絞り込んでいきましょう。

Objectモードのときと同じようにdrawFacesSolidが答えか?

ObjectモードのときはdrawFacesSolidという関数ポインタがドローコールにつながっていたので、Editモードのときも同じようにViewport ShadingがSolidの場合は関数ポインタdrawFacesSolidがドローコールにつながっているかもしれません。

drawobject.cの中で関数ポインタdrawFacesSolidがコールされている場所は8カ所。試しに8カ所全てコメントアウトしてみるも、Editモードの時のモデルの面が消える事はありませんでした。

drawFaces〜〜〜かな??

ついでに「drawFaces」でdrawobject.c内を検索してみましょう。

ヒットは11件で8件が先ほどのdrawFacesSolid。1件はenum値なのでこれは関係なし。残る2件はdrawFacesGLSL(GLSLはOpenGLのシェーダ言語)という関数ポインタで、EditモードはデフォルトでSolidシェーディングなのでGLSLが使われる事もなさそうだから違うだろうなと思いつつ2件ともコメントアウトしてみるもやはり該当しませんでした。

試行錯誤

「draw」ならどうか?ヒットは1311件。これは調べきれません。

Objectモードのときと同じように構造体内の関数ポインタになっていると予想できるので、「->draw」で検索してみると135件。まだ手探りで該当箇所を探るのはキツい件数ですね。

Xcodeはパターン検索が出来るので「->draw〜〜〜(」という形で検索して絞り込む。すると55件。もう少し絞りたい!この55件の〜〜〜の中には「Verts」(頂点)や「Edges」(辺)という文字列が含まれています。でも狙いは「Faces」(面)なので「->draw〜〜〜Faces」で検索。すると12件まで絞れました。これくらいの数であれば1つ1つ手で調べていけますね!この12件の中に答えがあるか!?

容疑者:drawMappedFaces

12件のうち1件は関数でも関数ポインタでもないので除外。そして10件は関数ポインタdrawMappedFaces、1件は関数ポインタdrawMappedFacesGLSLです。Objectモードのときもdraw〜〜〜という関数ポインタがレンダリング命令につながっていたので、この11件の中のどれかがEditモードの面のレンダリングにつながっているかもしれません。

どの関数がdrawMappedFacesまたはdrawMappedFacesGLSLを呼び出しているかを列挙してみると、

  • draw_dm_faces_sel() 1件
  • draw_em_fancy() 3件
  • draw_mesh_fancy() 1件
  • bbs_mesh_solid_EM() 2件
  • bbs_mesh_solid_verts() 1件
  • bbs_mesh_solid_faces() 2件
  • draw_object_mesh_instance() 1件

となっていました。

Objectモードのときはdraw_mesh_fancy()がdrawFacesSolid()を呼び出していてレンダリング命令につながっていましたね。試しにdraw_mesh_fancy()の中のdrawMappedFaces()をコメントアウトして実行してみましたが、Editモードの面のレンダリングには関係ないようです。

次はdraw_mesh_fancy()と同じように「fancy」の付くdraw_em_fancy()辺りが怪しいでしょうか?3件ともコメントアウトしてみます。
before
↓↓↓
after
Editモードの面が消えましたね!!結果、3つの関数ポインタdrawMappedFacesのうち最後が今回探している起動時のデフォルト状態からEditモードに切り替えた直後の面のレンダリング部分につながっているようです。

関数ポインタが指す関数本体は?

さて、狙いの関数ポインタdrawMappedFacesも見つかった事ですし、ステップ実行してこのdrawMappedFacesが指し示している関数本体を探してみましょう。するとdrawMappedFacesはeditderivedmesh.c内のemDM_drawMappedFaces()を指し示している事がわかります。

emDM_drawMappedFaces()の中ではやはりOpenGLのレンダリング命令が使われており、GPUレンダリングが行われているようです。CPUか?GPUか?答えが出ましたね!

おまけ

ObjectモードのときはglDrawArraysで頂点データの格納された配列の中身を一気にレンダリングしていました。

Editモードのときはこれと違い、for文の中で三角形を1つずつレンダリングしているようです。きっと頻繁な頂点の追加&削除の負荷に耐えるためでしょう。

試しにfor文のカウントの上限値から1を引いてみたら三角形が1つ欠けたりするんでしょうか?
before
三角形が1つ消えましたね^^


@fmystB