2

この関数は、clock_gettime を使用して時刻を double として取得します。

// 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 への変換が必要です。仮数がオーバーフローしており、シェーダーへの途中で切り捨てられています。

例:

double として = 1330579093642.441895

float として = 1330579111936.000000

切り捨てが原因で、浮動小数点値が長時間 1 つの数値でスタックします。

また、res.tv_sec の秒の値も float に対して大きすぎるようで、GPU への途中で切り捨てられています。

アプリケーションの起動からの時間を測定しようとすると、同じ問題にすぐに遭遇します。

では、実行時間の値をシェーダーに取得する最良の方法は何でしょうか? Linux の世界ではクロス プラットフォーム (つまり、IOS、Android、Linux) です。

4

1 に答える 1

4

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

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

ほとんどのシェーダーはミリ秒単位の実際の時間を必要としません。時間 (または時間のようなもの) を必要とするシェーダー プロセスの大部分は周期的です。その場合、特定のサイクルをどれだけ進んだかを示す値を単純に渡すことができます。[0, 1) の範囲のこの値は、サイクルの開始時に 0、中間で 0.5、最後に 1 に達します。

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

または、ハードウェアが GL 3.x+ をサポートしている場合は、32 ビットの符号なし整数で時間を送信できます。これにより、さらに数ビットの精度が得られるため、問題をより長く回避できます。10 分の 1 ミリ秒で時間を送信すると、オーバーフローするまでに約 5 日程度の時間を確保できるはずです。繰り返しますが、これは int から float への変換だけを行うことができないため、すべての GPU 計算を複雑にします。

于 2012-03-01T06:12:10.167 に答える