IMGとCANVASでdrawImageを使用するとパフォーマンスが大幅に異なる


8

画像をキャンバスにレンダリングする簡単なテストをいくつか組み合わせました。1つはIMGからレンダリングし、もう1つはオフスクリーンCANVASからレンダリングします。あなたはここでコードと結果を見ることができます:http : //jsperf.com/canvas-rendering/2

ほとんどのブラウザでは、状況が逆転するChromeを除いて、画像からのレンダリングはキャンバスからのレンダリングよりもはるかに高速です。違いの理由を誰かが説明できますか?結局のところ、同じピクセルデータを同じ宛先にレンダリングしています。


2
これが質問なのか、少なくとも答えられる質問なのか、よくわかりません。それを除けば、テストを見ると、Chromeが画像のレンダリングを遅くするのが普通ではないのではなく、他の人だけがキャンバスオブジェクトのレンダリングが本当に遅いように見えます。
Matt Kemp

しかし、どちらの場合も同じデータをレンダリングしているのに、なぜまったく違いがあるのでしょうか。そして、少なくとも1つの主要なブラウザが反対のパフォーマンス特性を持っているという事実は、レンダラーに2つのコードパスを実装する必要があることを意味します。
alekop

buffercanvasとimgタグを使わずにテストレンダリングに追加できますか?見ていて面白いでしょう。
justanotherhobbyist 2012

@hustlerinc:キャンバスからそれ自体にレンダリングするという意味ですか?それは何を証明しますか?ゲームのグラフィックはすべて画像から読み込まれるため、プロセスのある時点で画像を使用する必要があります。
alekop

@alekopいいえ、オフスクリーンキャンバスをスキップして、1つのキャンバスだけを使用します。Webではレンダリングを高速化する必要があると思いますが、その証拠はありません。そして、自分でテストするのが面倒で経験が浅い。
justanotherhobbyist 2012

回答:


9

わかりました。ほとんど。それは実際にはかなり明白であり、私はこれにすぐに気づかないので少しばかげたことを感じます。drawImage(src, 0, 0)幅/高さを指定せずに呼び出すと、src領域全体が描画されます。この場合、これははるかに大きくなります(キャンバスは185x70のimgに対して320x420です)。したがって、キャンバスの場合、ブラウザはより多くの作業を行っており、パフォーマンスの低下を説明しています。Chromeのスコアが高く、srcが大きいことにまだ戸惑っています。

dest.drawImage(src, x, y) // bad
dest.drawImage(src, x, y, w, h, destX, destY, w, h) // good

同じリージョンを使用する更新バージョンを投稿しましたが、違いははるかに近いです。http://jsperf.com/canvas-rendering/5

なぜ違いがあるのか​​はまだ説明できませんが、今は十分に小さいので、あまり気にしません。


Windows 8とIntel Graphics HDを搭載したChrome 43では、最初のテストを実行するとクラッシュします。テストが終了すると、drawImage(img)が明らかに勝者となり、drawImage(canvas)は94%遅くなります。
Șerban 2015年

Firefox 38はスムーズに実行され、まったく問題はなく、両方のテストは終了しています。
Șerban、2015年

画像をスケーリングすると、@ alekop(developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/…)のパフォーマンスも低下ます
Jersh

4

Chromeはハードウェアアクセラレーションを使用する可能性があります。

キャンバス240x240を作成し、Chromeで実験を実行してから、キャンバス300x300を作成して、もう一度実行します。256x256以降はハードウェアアクセラレーションが作動し、サイズが小さい場合はchromeがソフトウェアを使用するため、より大きなキャンバスが高速になると予想します。

また、-webkit-transform:translateZ(0)がハードウェアアクセラレーションをオフにすることも指摘する価値があります。

上記のいずれもテストしていません。私がこれを知っているのは、キャンバスを256x256境界よりも大きいサイズから小さいサイズに動的にサイズ変更して、ハードウェアとソフトウェアのしきい値を超えたときに、クロムで報告したバグについてChromeエンジニアの1人がコメントしたという事実のためです。このバグの解決策は、前述のように、translateZを使用して加速をオフにすることでした。

私の場合、ユーザーに256x256未満のサイズ変更を許可しませんでした。


ターンオフハードウェアアクセラレーション?オンにしませんか?
gilbert-v

1

場合によっては、画像がGPUメモリとキャンバスのホストメモリに読み込まれることがあります。その場合、画像からキャンバスに描画するときに、画像データを最初にホストメモリにコピーしてから、キャンバスにコピーする必要があります。

1億ピクセルを超える画像を読み込んで、その一部を小さな256x256キャンバスに読み込むプロジェクトを作成しているときに、Chromeでこのような動作に気づきました(http://elhigu.github.io/canvas-image-tiles/)。

そのプロジェクトで、イメージタグからChromeのキャンバスに直接描画した場合、描画が開始されるとメモリが常に1.5GBにジャンプし、描画が終了するとメモリが再び解放されました。そのページに250メガピクセルのソース画像が常に表示されていたとしても。

画像を大きなキャンバス(画像と同じサイズ)に1回書き込み、そこから小さなキャンバスを描画することで問題を修正しました(キャンバスに変換した後、画像も捨てました)。


0

違いを説明することはできませんが、私は同意しません

また、少なくとも1つの主要なブラウザが反対のパフォーマンス特性を持っているという事実は、レンダラーに2つのコードパスを実装する必要があることを意味します。-アレコップ

js.prefの結果を見ると、クロムの違いはかなり微妙です。可能な場合は、画像からのレンダリングのみを使用します。


問題は、複雑な画像を構成するためにオフスクリーンキャンバスに依存していることです。たとえば、キャラクターのアニメーションフレームをオフスクリーンバッファーにレンダリングしてから、衣服/鎧/武器などを上にレンダリングしています。次に、ゲームは複合キャンバスからレンダリングします。各キャラクター、各フレームのこれらすべての詳細を再レンダリングするのではありません。Chrome以外のブラウザではキャンバス間のパフォーマンスが非常に低いため、コンポジットをレンダリングして画像に戻す必要があります。それは世界の終わりではありませんが、回避策があることを望んでいました。
alekop

0

画像のサイズは185 * 70ですが、サイズを指定してキャンバスを作成します。これによりパフォーマンスが低下するので、オフスクリーンキャンバスのサイズを画像と同じに設定します。そして、違いはより近いです。

var g_offscreenCanvas = createCanvas(185, 70);

http://jsperf.com/canvas-rendering/60

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.