rsRand() 显着减慢了 RenderScript
rsRand() significantly slows down RenderScript
我一直在摸不着头脑,我唯一可以得出的结论是 rsRand()
没有在通常用于 运行 脚本的处理器上实现(例如 GPU 或 CPU) 或者它不能 运行 并行。
谁能证实这一点?如果是这样,是否有参考资料列出哪些功能可以安全使用与性能相关?
有没有其他不使用rsRand()
获取随机数的方法?
这是我的渲染脚本文件:
#pragma version(1)
#pragma rs java_package_name(com.example.app)
#pragma rs_fp_relaxed
float width;
float height;
float3 p0, p1, p2, p3;
uchar4 __attribute__((kernel)) gradGen(uint32_t x, uint32_t y)
{
float3 result;
float hd = x / width;
float vd = y / height;
float noise = rsRand((float) 1 / 256) - ((float) 1 / 512); // CULPRIT
hd = 3 * hd * hd - 2 * hd * hd * hd;
vd = 3 * vd * vd - 2 * vd * vd * vd;
result.r = (1 - vd) * ((1 - hd) * p0.r + hd * p1.r) + vd * ((1 - hd) * p3.r + hd * p2.r) + noise;
result.g = (1 - vd) * ((1 - hd) * p0.g + hd * p1.g) + vd * ((1 - hd) * p3.g + hd * p2.g) + noise;
result.b = (1 - vd) * ((1 - hd) * p0.b + hd * p1.b) + vd * ((1 - hd) * p3.b + hd * p2.b) + noise;
return rsPackColorTo8888(result);
}
与其疑惑,我决定做些蠢事,自己写 rsRand()
。 Xorshift was simple enough and here is extra code for implementing a PRNG:
uint32_t r0 = 0x6635e5ce, r1 = 0x13bf026f, r2 = 0x43225b59, r3 = 0x3b0314d0;
uchar4 __attribute__((kernel)) gradGen(uint32_t x, uint32_t y)
{
...
// Generate a random number between 0-1
uint32_t t = r0 ^ (r0 << 11);
r0 = r1; r1 = r2; r2 = r3;
r3 = r3 ^ (r3 >> 19) ^ t ^ (t >> 8);
float rnd = (float) r3 / 0xffffffff;
...
}
上面的速度很快,而且随机数的质量对我的应用来说已经足够好了。我仍然有兴趣了解 rsRand()
减速背后的细节。
rsRand()
在大多数实现中调用平台 rand()
(这就是它在 CPU 后端中的实现方式,我不知道任何 RS GPU 驱动程序实际上在他们的驱动程序),因此它将比简单的移位和 XOR 之类的东西更重量级和更慢。
是的,看看 rand()
的仿生实现,你是对的,它是序列化的。也许我会找人移植梅森扭曲器。
我一直在摸不着头脑,我唯一可以得出的结论是 rsRand()
没有在通常用于 运行 脚本的处理器上实现(例如 GPU 或 CPU) 或者它不能 运行 并行。
谁能证实这一点?如果是这样,是否有参考资料列出哪些功能可以安全使用与性能相关?
有没有其他不使用rsRand()
获取随机数的方法?
这是我的渲染脚本文件:
#pragma version(1)
#pragma rs java_package_name(com.example.app)
#pragma rs_fp_relaxed
float width;
float height;
float3 p0, p1, p2, p3;
uchar4 __attribute__((kernel)) gradGen(uint32_t x, uint32_t y)
{
float3 result;
float hd = x / width;
float vd = y / height;
float noise = rsRand((float) 1 / 256) - ((float) 1 / 512); // CULPRIT
hd = 3 * hd * hd - 2 * hd * hd * hd;
vd = 3 * vd * vd - 2 * vd * vd * vd;
result.r = (1 - vd) * ((1 - hd) * p0.r + hd * p1.r) + vd * ((1 - hd) * p3.r + hd * p2.r) + noise;
result.g = (1 - vd) * ((1 - hd) * p0.g + hd * p1.g) + vd * ((1 - hd) * p3.g + hd * p2.g) + noise;
result.b = (1 - vd) * ((1 - hd) * p0.b + hd * p1.b) + vd * ((1 - hd) * p3.b + hd * p2.b) + noise;
return rsPackColorTo8888(result);
}
与其疑惑,我决定做些蠢事,自己写 rsRand()
。 Xorshift was simple enough and here is extra code for implementing a PRNG:
uint32_t r0 = 0x6635e5ce, r1 = 0x13bf026f, r2 = 0x43225b59, r3 = 0x3b0314d0;
uchar4 __attribute__((kernel)) gradGen(uint32_t x, uint32_t y)
{
...
// Generate a random number between 0-1
uint32_t t = r0 ^ (r0 << 11);
r0 = r1; r1 = r2; r2 = r3;
r3 = r3 ^ (r3 >> 19) ^ t ^ (t >> 8);
float rnd = (float) r3 / 0xffffffff;
...
}
上面的速度很快,而且随机数的质量对我的应用来说已经足够好了。我仍然有兴趣了解 rsRand()
减速背后的细节。
rsRand()
在大多数实现中调用平台 rand()
(这就是它在 CPU 后端中的实现方式,我不知道任何 RS GPU 驱动程序实际上在他们的驱动程序),因此它将比简单的移位和 XOR 之类的东西更重量级和更慢。
是的,看看 rand()
的仿生实现,你是对的,它是序列化的。也许我会找人移植梅森扭曲器。