壁紙との合成から考えてみます。
この合成というのは、Windows2000 から実装された TransparentBlt() という API を呼んでいるだけだったりします。これは、転送元のデバイスコンテキストうち透明とみなす色を渡すことで、その色以外だけ転送ということができる。
この API ですが、そんなに速くないっぽい。カーソルキーを押しっぱなしにしてスクロールさせたりすると、CPU 使用率が簡単に 80 とか 100% いってしまいます。なんか CPU だけで処理しているような感じ(少なくともうちのマシンでは)。試しに Delphi で同じようなことをするコード(転送元矩形に対して、透明色以外なら転送)を書いてみても、あまり速度が変わらなかったりします。
どうでもいいですが、この TransparentBlt() とか AlphaBlend() って、msimg32.dll に入ってることになってますが、Windows2000 だと本体は gdi32.dll にあるっぽいような。msimg32.dll はたぶん Win9x 系でも使えるようにするためのラッパということなのかな。
で、これをどうやって速くするかなのですが。。。
速度を計ってみると、ビューのサイズが 764×440 のとき、合成がだいたい 6msec、合成後のスクリーンへの転送(BitBlt())が 7msec くらいかかってるみたいです。
うーんこんなものなのかな。なんか後者が、アクセラレータが効いてないっぽい感じがしますが。。。TBitmap で作った実体が、スクリーンにコンパチブルな DC やビットマップとみなされないからかなあ? と思って、TBitmap ではなく CreateCompatibleDC()/CreateCompatibleBitmap() で作った生のビットマップを使うようにしてみましたが。。。変わらない。
オフスクリーンバッファを DDB で作るようにしてみたりしましたが、変化なし(かえって遅くなる)。なんかスクリーンへの転送自体はこんなものっぽいのかな。ちょっと納得いかないけどな。。。
ということで、合成処理側を速くしたほうがよさそうです。
とりあえず壁紙を 32bpp や 24bpp で持つよりは、15bpp で持ったほうが気持ち速いので、これはすでにそうなっています。
TransparentBlt() を使わないやりかただと、モノクロのビットマップを用意して転送先に AND して転送元を OR する、という昔ながらの方法か、MaskBlt() ということになると思います。でも転送元となるオフスクリーンバッファの背景色が常に rgb(0,0,0) というわけでもないのでちょっと面倒だし、BitBlt() の速度から考えるに現状から劇的に速くなることはなさそうです。
あるいは DirectX に行っちゃうとかかな。。。
TransparentBlt() の対象となる幅はビューの横幅なのですが、上のように表示していたとき、折り返し幅を超えて描画されることはありえないのに、透過転送する必要のない領域まで透過判定しつつ転送しているわけで、無駄です。これを最小の幅で合成するようにしたらそこそこ速くならないかな。
ついでにいうと上の「<td>22</td>」なんかは相当短いので、こういう行を有効に利用できないか。つまり 1 回でどばっと TransparentBlt() するのではなくて、行ごとに必要な幅の分だけ TransparentBlt() を繰り返す感じ。