Direct3D and FPU

浮動小数点数と言えば,最近Tom Miller氏のblogに"Direct3D and the FPU.."というポストがありました.
http://blogs.msdn.com/tmiller/archive/2004/06/01/145596.aspx
議論をまとめると以下の2点に要約されます.

  • 3Dデバイス作成時に規定の動作としてFPUの設定が変更される.変更はCLR浮動小数点演算に影響する.
  • この影響を回避するにはデバイス作成時にCreateFlags.FpuPreserve (D3DCREATE_FPU_PRESERVE)を指定する.

状態変数が知らない間に書き換えられて困るというのは,何だかRenderStateの管理と同じ苦労をしてますね.
ひげねこさんの日記にあるように,FPUのコントロールレジスタプログラマが意図的に変更することが可能です.

PCだと通常、単精度(24bit)を使っていてもFPU内部では80bit精度に変換されて計算されるので、SSE(単精度)を使っているゲーム中のみで起きる問題でした。

ちなみに、FPU内部の精度は

#include <float.h>
_clearfp();
_controlfp( PC_24, MCW_PC );

と、して変える事ができ、簡単な高速化の1つとして使えます。もちろん精度は落ちるのでプログラム側で対処する必要はあります。

Miller氏のblogに寄せられていたコメントでは他のプロセスの計算結果まで変わることを心配している人がいますが,まあ普通に考えてコンテキストスイッチでFPU状態は退避されるでしょう*1.少し調べてみたところ,Linux 2.6のFPUレジスタの遅延切り替えについての記事を見つけました.
http://www.itmedia.co.jp/enterprise/articles/0406/10/news001.html

*1:timeBeginPeriodのように本当にシステムグローバルな影響を持つ設定にはもちろん注意が必要ですけどね