プログラミングに関して私が気づいたことの 1 つは、個々のピクセルを描画したり、個々のピクセルからデータを取得したりするメソッドがある場合は常に、プリミティブや既製のグラフィックスを描画するメソッドよりもずっと遅いということです。なぜだろうと思っただけです。これらのメソッドを作成するには、(ある時点で) 単一ピクセルの描画メソッドを使用する必要がありますか? そして、それを行うためのより高速な方法がある場合、なぜ彼らは単一ピクセルの方法でもそのようにしないのでしょうか?
2 に答える
多くの隣接するピクセルに触れるプリミティブを描画するときに、通常は最適化できる GetPixel/SetPixel 操作のオーバーヘッドがあります。
GetPixel と SetPixel をどのように実装する必要があるかを検討してください。
- 各座標が範囲内にあるかどうかを判断します。
- そのピクセルのメモリ内の位置を計算します。
- ピクセル形式によっては、そのピクセルのデータを分離するためにアンパックが必要になる場合があります。
ここで、軸に沿った長方形プリミティブのようなものを考えてみましょう。これを実装する単純な方法は、x と y を 2 回ループして SetPixel を呼び出すことです。
void DrawRect(RGB color, int left, int top, int right, int bottom) {
for (int y = top; y < bottom; ++y) {
for (int x = left; x < right; ++x) {
SetPixel(x, y, color);
}
}
}
SetPixel は、呼び出しごとに両方の座標が境界内にあることを確認しますが、これは無駄です。y 座標が同じ行の前のピクセルで有効だった場合、次のピクセルでも有効になります。
さらに、ほとんどのラスター形式では、設定するピクセルのほとんどがメモリ内で隣接するため、汎用の数式 ( のような単純なものであってもaddress = base + (y * stride) + x
) は、同じ行の次のピクセルの最後のアドレスをインクリメントするだけではありません。
これは、SetPixel を使用した単純な実装よりもはるかに少ない境界チェックと計算で、いくつの (ほとんどの?) プリミティブを描画できるかを示しています。プリミティブ描画操作は非常に一般的であるため、最適化される傾向があります。
最新のマシンでは、最適化の機会がさらに増えています。一部のプリミティブは、CPU ではなく GPU によって実際に描画される場合があります。GPU はビデオ メモリに直接アクセスできるため、これは重要です。通常、CPU はビデオ メモリに間接的にアクセスし、ピクセル アクセスはグラフィックス バスを行き来する必要があります。一部のグラフィックス バスは非常に高速ですが、通常はローカル メモリへのアクセスほど高速ではありません。バスを介して GPU に単一の描画プリミティブ コマンド (わずか数バイト) を送信すると、多くの set-pixel コマンドを送信するよりもはるかに高速になります。
さらに、GPU はこの種の作業を並行して行うように設計されています。一般に、同時に動作できる多くの単純なコアがあります。したがって、長方形を描画している場合、GPU は (たとえば) 各スキャンラインを別々のコアに分配し、単一のコアが単一の水平線を描画できるのと同じ速さで長方形全体を描画します。
いくつかの考え:
最新のコンピューティング環境の多くには、グラフィックス プリミティブを描画するためのハードウェア アクセラレーションが含まれています。CPU が一度に 1 ピクセルずつビデオ メモリにアクセスする代わりに、グラフィックス アクセラレーション ハードウェアは一度に複数のピクセルに相当するビデオ メモリにアクセスします。描画プリミティブは、ソフトウェアのピクセル操作ではできない方法で、このような高速化を利用できます。 http://en.wikipedia.org/wiki/Hardware_accelerationには、役立つヒントがいくつかあります。
ソフトウェアで実行される描画プリミティブでさえ高度に最適化されており、多くの場合、高水準言語から (簡単に) アクセスできない方法で行われます。たとえば、最近の CPU のSIMD 命令では、一度に複数のピクセル位置に触れることができます。
最後に、インタープリター言語は、コンパイル済み言語と比較して、ピクセル間の遅延が大幅に発生する可能性があります。これは、最も多く試したプログラミング言語によって異なります。