5CPUからComputeShaderにすると、非常に負荷が大きい局面では25%くらい速くなるかな?というくらいです。負荷が低い局面では差が小さくなってしまいます。2018年後半以降に登場した、低価格帯(3万円台以下)向けのチップです。ついでに、たまたまそこにあった高級機種を見てみましょう。S9+(SCV39)です。60高い機械は速いなあ、と思いますね。数字はfpsなので60で天井ですから、本当は100出るかもしれませんし、200出るかもしれません。最低でも、CPUからGPUに持っていけば4倍近くの性能になる、ということがわかります。2018でも同じ測定をしてみました。最低でも差が3倍近くある、ということです。いうのはちょっと疑わしいですね。数字は真に受けないようにおねがいいたします。今回の実装についての懸念点、改良すべき点については後にまとめます。測定方法GitHubにプロジェクトを置いておきました。これを32bitの整数とみなして乱数アルゴリズムであるXorShiftで変換します。RGBAに戻しています。こんな必要はないのですが、どの機械でも動くのかがわからないので、確実に動くRGBA32にしておきました。これを独立に更新していく、という計算になります。各要素間は完全に独立なので、GPU向きの計算と言えます。ちなみに、画面はこんなです。この例だと、解像度は64x64なのでツブツブ模様がよく見えますね。CPU計算時のスレッド数が3、Unityが返したプロセッサ数が4、という意味です。やってみないとわかりません。スライダーを用意しておきました。今回のComputeShaderは、先程のXorShiftの処理をGPUに移植しただけです。同じ計算をGPUを使って行います。今回はAndroidしか試しておらず、APIはVulkanのみです。iOSは試していませんが、たぶんiPhone5S以降であれば動くのでしょう。実装は後で紹介します。測定値の詳細もう一度データを載せます。CPUではフレームレートが15fps、ComputeShader使用時には17fpsだった、ということです。4096x4096にすれば計算量は4倍になりますので、性能が1/4に落ちることが想像されますが、そこまでは落ちません。これは測定方法に問題があることと、フレームごとに発生するそれ以外の処理によるオーバーヘッドがあるからです。行ったような手続きが必要でしょうが、今回は粗くわかれば良いとして、真面目な測定を作りませんでした。CPU側の解釈さて、このデータはsnapdragon430のデータでして、CPUは8コアです。解像度2048での測定です。同時に動いているのは4コアなのでしょう。いう設計なのだと思われます。1024x1024だともう少しスレッドが多い方が速かったりします。熱や電池のかねあいもあるのでしょう。いうことが言えるかと思います。少なくとも私は「スレッド数を倍にして性能が倍になった」というケースは見たことがありません。1.5倍でも良い方です。自作スレッドプールに比べて1/4くらいになってしまいました。今回はGPUが主役ですので、これ以上の検証はしていません。その度合いはかなり残念なレベルです。ComputeShaderの設定を変えたら倍速になる、なんてことはたぶんないでしょう。ここで根本的なことについて考えておきます。「CPUでもできることをGPUにやらせることは正義か?」という事です。描画処理、つまりシェーダの実行はGPUにしかできません。全体としては品質が上がるでしょう。こいつも描画に参加させた方が速い」という変態マシンもありましたが、たぶん例外です。GPUにはできるだけ描画をさせるべきでしょう。ゲームの種類によっては、CPUが忙しくてGPUが余っていることもありえます。群体シミュレーションが凄まじく重いゲーム、とかですね。積極的にGPUにやらせる方が良い可能性があります。この天秤は、GPUとCPUの性能比によって変わってくるわけです。いうのが正義になります。それによって空くCPU時間が大きいので、追加でいろいろやれるようになります。全体としては品質が上がるでしょう。いう判断になる率が上がってくるわけです。いう器用な奴もいます(AsyncComputeという奴です)。みたいなことができ、性能を有効活用できます。いうGPUが一般的になれば、よりComputeShaderを使いたくなってくるわけですね。これがUnityから使えるのはPlaystation4だけみたいです。偉そうに説明はできませんが、紹介だけはしておきます。c;}シェーダ側はこのようになっています。Destinationに流すだけのシェーダです。この時に注意が必要です。IEEE754な浮動小数点数は255で割ると誤差が出ます。みたいな感じになり、整数に切り捨てると254になってしまいます。ここでは0.5を足してから切り捨てています。Unityのやり方がわからなかったのでこのようにしました。次に問題になるのがインデクスです。ように添字でアクセスする時に、何を書けばいいか、ということですね。引数のxyをそのまま渡せば終わりです。SourceもDestinationも2Dテクスチャですので、添字の型は2次元整数型です。threadId.xyのように2次元ベクトルを書けます。結論から言えば、処理しているテクセルの座標になっています。(0,0)から(1023,1023)までの全ての組み合わせが一回づつ出てきます。全テクセルを処理できるわけです。なるためにはCPU側も合わせて見ないといけません。C#側初期化まず初期化です。renderTextures[1]);まずシェーダの入出力になるRenderTextureを作ります。フレームごとに役割を入れ換えます。次のフレームでは、1番を入力として、0番に出力するわけです。明示的にCreate()します。できない事情があるようですね。1番RenderTextureにコピーするものです。これ以降、一切CPUにはデータを返さず、2枚のRenderTextureの間でデータの往復が行われるだけになります。C#側毎フレームあとは毎フレームの処理です。ここではcomputeShaderという変数です。使う関数のIDを取ります。いくつかある場合もあるでしょうから、名前から番号に変換するのが良い作法でしょう。入力と出力のRenderTextureをセットします。「今どっちが出力か」を覚えていて、0か1が入っています。みたいな記述を取ってきます。sizeZ);ここではsizeXに8、sizeYに8、sizeZに1が帰ってきますね。これが実行の単位で、テクスチャの8x8の64画素分を1単位として実行する、という意味になります。ComputeShader用語では「1グループあたり8x8=64スレッド」ですね。次にいよいよ実行です。1);さっきの「実行単位」をいくつ実行するかを指定します。sizeYも8なので128になりますね。これで全テクセルをカヴァーできるわけです。ComputeShader用語では「128x128=16384スレッドグループを実行する」ですね。全テクセルを順番に見ていくことができます。凝ったことをやりたくなったら、その時はその時ですね。縦横1/2に縮小するなら、実行回数は元のテクセル数の1/4です。コードになるでしょう。関してはいろいろ詳しい記事がありますので、探してみてください。絞って考え、「何に使うか」は考えないことにしています。writeBufferIndexを0から1、あるいは1から0へと切り換えます。私はこの世界に入って3年以上気づきませんでした。他人のコードを見て知っただけです。その時の悔しさはひどいものでした。それまではインクリメントして2になったら0に戻していたのです。どんなに簡単なことでも、「思いつく」ということは難しいことなのです。何もかもを自力で作ることはできないのだ、ということを強く意識した出来事でした。考察もう一度さて、結果についてもう少し深く考えます。いうことを、どう捉えるかです。私の現状の結論は、「高性能機での品質を重視するか、今後の展望を考えればComputeShaderはアリ。S9+)を比べてみましょう。60CPUは4倍程度、GPUは小さく見積っても12倍は違います。慣れてしまえばCPUで書くよりGPUで書く方が楽、というケースもあります。計算の本体はアセットとして後からロードしたり配信したりできます。いうのも良いかもしれません。計算量を低価格機種と高価格機種で変えてあげれば良いのでしょう。マシですから、「今後GPUとCPUの性能差は開いていく。いえ、無理して今やらなくてもいいな、という感じはあるわけですね。APIについて「ComputeShader必須」としてしまうと動く機械を狭めてしまう、という問題もあります。Vulkanが動く機械が必要になり、OpenGLES3.0までの機械はダメです。3.0以下の機械がまだ半分くらいいます。「ComputeShader必須」と言ってしまった瞬間に、世界にあるAndroidの半分が対象外になるわけです。ちなみに、私が長らくお世話になった京セラS2も、vulkan非対応なので動きません。今ComputeShaderを使うならば、非対応機種向けのケアは必要でしょう。まとめ案外遅かったですね。スマホを買ったのですが、期待した結果にはなりませんでした。実装が悪くて良いデータが出なかった、という可能性はあります。フレームレートを評価値にしてしまったので、オーバーヘッドが大きい上に、60で天井になってしまう自作スレッドプールの実装が良くない可能性があるComputeShaderのスレッド/スレッドグループ設定に改良の余地があるかもしれない整数演算主体なので、GPUによっては不利があるのかもしれない計算が短いので、オーバーヘッドが多く出て本当の性能が見えにくいかもしれない。多数の可能性が考えられます。そんな改造をして多少改善したとしても、どうでも良いことです。1年は放っておいていいかな、という気分でおります。おまけ記事を書いた後に、測定に協力してくださった方が何人かいるので、そのデータも貼っておきます。高級品が多いので、解像度は全て4096です。S3の結果も並べておきます。5測定は非常な誤差が伴うので、参考程度と考えてください。XZで20fpsは低すぎる気がします。Nexus6PのCPU計算が低いのも何か事情がありそうです。それにしても、皆さん高級品ばかりですね。安い機械と高い機械のGPU性能の絶望的な差がよくわかります。思いを新たにいたしました。貧乏なわけじゃないのです。(1)月別アーカイブ検索スターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。