2012-03-01 4 views
2

は、二重使用にclock_gettimeとしての時間を取得し、この機能を取る:シェーダにそれを送信するシェーダ時間の制服 - にclock_gettime切り捨てられている

// return current time in milliseconds 
static double time_get_ms(void) 
{ 
    struct timespec res; 

#ifdef ANDROID 
    clock_gettime(CLOCK_REALTIME_HR, &res); 
#else 
    clock_gettime(CLOCK_REALTIME, &res); 
#endif 
    return (double)(1000.0*res.tv_sec + res.tv_nsec/1e6); 
} 

はfloatに変換する必要があります。仮数はオーバーフローしており、シェーダへの途中で切り捨てられます。

例:floatとしてダブル= 1330579093642.441895

として

= 1330579111936.000000

フロート値による切り捨て長期間単一数で立ち往生。

また、res.tv_secの秒の値が浮動小数点数の場合でも、GPUへの途中で切り捨てられているようです。

アプリケーションが起動してから時間を測定しようとしていて、同じ問題がかなり早く発生します。

シェーダに実行時間の値を入力する最も良い方法は何ですか? Linuxの世界で何かがプラットフォームを超えています(IOS、Android、Linuxなど)。

答えて

4

仮数部で32ビットの浮動小数点精度を使い果たしました。 GL 4.xを倍精度サポートで使用していない限り、シェーダは32ビット浮動小数点も扱うことができないため、シェーダは精度の欠如に対処できません。

ミリ秒オーバーフロー浮動小数点精度(〜1ミリ秒、つまり約2.7時間を必要とする)がかかるようにアプリケーションを実行している場合、このアプリケーションを正常に処理する方法を見つける必要があります状況。正確には、どのようにシェイダーがこの時間値を使用しているかによって異なります。

ほとんどのシェーダは、実際の時間をミリ秒単位で必要としません。時間を必要とするシェーダプロセスの大半(または時間のようなもの)は周期的です。どのような場合には、特定のサイクルを通ってどれくらいの距離であるかを示す値を渡すことができます。この値は、[0,1]の範囲で、サイクルの開始時には0、途中では0.5、最後では1になります。

シェーダプロセスをパラメータ化できない場合、絶対時間が必要な場合は、の2つの浮動小数点パラメータを渡すことをお勧めします。基本的には、オーバーフロービットを維持する必要があります。これは、2つの値を使用して時間の更新を行うためにそれらを移植する方法を知っていなければならないので、GPUでの時間を含むすべての計算を複雑にします。繰り返しますが、どのようにこれを行うかは、シェーダで何をやっているかによって異なります。

ハードウェアがGL 3.x +をサポートしている場合は、32ビットの符号なし整数で時間を送信することもできます。これにより、精度のビット数が増えますので、問題が長く続くことはありません。ミリ秒の10分の1を送信すると、オーバーフローするまでに約5日かかります。繰り返しますが、これはint-to-float変換だけではできないので、GPUの計算をすべて複雑にします。