今まで
Hamanaのシェーダーは アセンブラ(?)で書いていたのだが、nVIDIAの高級言語
Cg も触っとかないとな!ってことで、暇をみてCgを触っている。うーん、仕事以外のプログラミングってなんでこんなに楽しいのだろう。
んが、しかし、Cgのコンパイラが効率の悪いコードを吐き出していて困っている。
具体的には以下のCgのコードだ。
void FragmentProgram(float4 color : COLOR0,
in float2 texCoord0 : TEXCOORD0,
out float4 colorO : COLOR0,
const uniform sampler2D Texture0,
const uniform sampler1D Texture1)
{
float4 texCol = tex2D(Texture0, texCoord0);
colorO.r = tex1D(Texture1, texCol.r).r;
colorO.g = tex1D(Texture1, texCol.g).r;
colorO.b = tex1D(Texture1, texCol.b).r;
colorO.a = texCol.a * color.a;
}
これはトーン補正を行うためのピクセルシェーダー
のコードで Texture0がソースの画像をもつ2Dテクスチャ、Texture1 が各RGB成分から実際に出力するトーン値へのマッピングを保持する1Dテクスチャである。
これをCgコンパイラでps2.0用のコードにコンパイルすると、以下のようなアセンブリコードを出力する。
ps_2_0
// cgc version 1.4.0000, build date Jun 9 2005 12:09:02
// command line args: -profile ps_2_0
// source file: FragmentProgram.cg
//vendor NVIDIA Corporation
//version 1.0.02
//profile ps_2_0
//program FragmentProgram
//semantic FragmentProgram.Texture0
//semantic FragmentProgram.Texture1
//var float4 color : $vin.COLOR0 : COL0 : 0 : 1
//var float2 texCoord0 : $vin.TEXCOORD0 : TEX0 : 1 : 1
//var float4 colorO : $vout.COLOR0 : COL : 2 : 1
//var sampler2D Texture0 : : texunit 0 : 3 : 1
//var sampler2D Texture1 : : texunit 1 : 4 : 1
//const c[0] = 0.5
dcl_2d s0
dcl_2d s1
def c0, 0.500000, 0.000000, 0.000000, 0.000000
dcl t0.xy
dcl v0.xyzw
texld r0, t0, s0
mov r1.x, r0.y
mov r0.y, c0.x
mov r1.y, c0.x
mov r2.x, r0.z
mov r2.y, c0.x
mul r0.w, r0, v0
texld r3, r2, s1
mov r2.x, r3
texld r3, r0, s1
mov r0.x, r3
texld r3, r1, s1
mov r1.x, r3
mov r0.z, r2.x
mov r0.y, r1.x
mov oC0, r0
なぜか謎の定数 c0 が定義されていて、意味もなく汎用レジスタにmovしたりしている。
以前の、Cgを使わないでアセンブラで記述していたコードは以下のようになっていて、Cgの吐き出すコードよりもだいぶ短い。
ps_2_0
dcl v0
dcl t0
dcl_2d s0
dcl_2d s1
texld r0, t0, s0 // r0 に2Dテクスチャのテクセルロード
texld r1, r0, s1 // 2DテクスチャのR成分のトーンをr1に読み込む
mov r0.r, r0.gggg // 2DテクスチャのG成分をr0のRにコピー
texld r2, r0, s1 // 2DテクスチャのG成分のトーンをr2に読み込む
mov r0.r, r0.bbbb // 2DテクスチャのB成分をr0のRにコピー
texld r0, r0, s1 // 2DテクスチャのB成分のトーンをr0に読み込む
mov r0.r, r1 // r1に保持しておいたR成分のトーンをr0.rにコピー
mov r0.g, r2 // r2に保持しておいたG成分のトーンをr0.gにコピー
mul r0, r0, v0 // r0を頂点の色(1,1,1,a) と混合
mov oC0, r0 // 出力レジスタに色を書き出す
実際、ベンチマークをとってみると Cgの吐き出したコードのほうが重くなっている。謎の定数c0がらみのコードがなくなるだけで効率は同等になるっぽいんだが・・・
最適化があまいとかそういうレベルじゃなくて、脈絡のない無駄なコードが挿入されてしまっている。不思議だ。それとも何か僕がとんでもないミスをしてるんだろうか?