画外音:不知道我的6200A排在什么地方哈哈。
其实上图有偏颇,这张图节选自Siggraph2004,而现在ATi 1800XT的SIMD性能已经超过了6800好多,可不是游戏性能。不过可以看出,比CPU的浮点运算性能高好几倍是不真的事实,可是如何利用呢?
可编程硬件的到来为我们开了一个好头,也许未来计算机硬件的发展趋势就是,通用计算Generic Computing(GC,自造词汇,可不是垃圾收集)。显卡一直以来都是和Pixel打交道,读取Texel,处理Primitive,写入FrameBuffer,为SIMD的应用打下了坚实的基础。显卡芯片从开始就是并行设计的,这样从纹理单元读取Texel时才能发挥效力,当年大名鼎鼎的Riva TNT2的意思其实是TwiNs Textures双纹理,而不是黄色炸药。Geforce3依靠添加的几个昂贵的register实现了Vertex Programming。NV收购3dfx,推出NV30系列芯片,伴随着DX8为PC机引入Shader,开创PC机图像画质飞跃的先河,如今热门游戏大多数已经使用可编程着色技术用来实现以往在工作站上才能实现的效果,这就是为什么如今看游戏实时演算的画面都比当年Square动用sgi工作站集群渲染出来的FF8动画效果好的原因。其实高级CG图形理论在80年代就已经相当成熟,比如78年的Shadow mapping,White的Ray-tracing等等。那些技术以后我会慢慢给大家介绍,大家不妨去NVIDIA下载一个SDK研究一下,还有MS DX SDK也是必需的。
先说目前可编程硬件用作通用计算的局限,而且在我看来,这个局限在Vista与DX10流行后可能依旧得不到解决,那就是API的问题。显卡厂商提供的驱动,无一例外的都是彻底为显示服务的,而不是用来标榜自己是GPGPU的。虽然说都有了自己的本地编译器(主要是用于编译GLSL string codes,HLSL可以预先编译好,然后再由驱动载入执行),可是依旧不是为了计算非图形数据服务。于是找到了Sh。Sh是一个很有趣的东西,使用了metaprogramming技术,模拟图形语言的算法,编译的时候转化为对应的低等级ASM语句,很多Graphic Slide里面进行核心算法展示的时候都用的Sh。有兴趣地可以到
这里看一下。强烈建议显卡厂商推出可以直接进行计算的驱动,不要和FrameBuffer牵涉,可以直接通过Bus写入内存,技术上并不难,也许是个商业问题。关键时刻永远是商业左右技术的发展,而不是技术人员的一厢情愿就可以左右世界发展,如今已经不是工业革命时代了。
给大家介绍来自Starford University的
Brook(听起来好像广告,不过在Shading Language界可是有Starford Shading Language得一席之地的)。Brook可以理解为是一个C编译器,只不过它编译的不是Bin,而是C++ string codes,而且是着色计算语句数组。比如有这样一段Brook代码,简单的Alpha混合,不对,不像,反正就是它了:
kernel void saxpy(float alpha, float4 x<>, float4 y<>,
out float4 result<>) {
result = (alpha * x) + y;
}
编译成最终的C++代码变成,
static const char* __saxpy_fp30[] = {
"!!FP1.0\n"
"DECLARE alpha;\n"
"TEX R0, f[TEX0].xyxx, TEX0, RECT;\n"
"TEX R1, f[TEX1].xyxx, TEX1, RECT;\n"
"MADR o[COLR], alpha.x, R0, R1;\n"
"END \n"
"##!!BRCC\n"
"##narg:4\n"
"##c:1:alpha\n"
"##s:4:x\n"
"##s:4:y\n"
"##o:4:result\n"
"##workspace:1024\n"
"##!!multipleOutputInfo:0:1:\n"
"",NULL};
void saxpy (const float alpha,const ::brook::stream& x,const ::brook::stream& y,
::brook::stream& result) {
static const void *__saxpy_fp[] = {"fp30", __saxpy_fp30, "ps20", __saxpy_ps20,
"cpu", (void *) __saxpy_cpu, NULL, NULL };
static __BRTKernel k(__saxpy_fp);
k->PushConstant(alpha);
k->PushStream(x);
k->PushStream(y);
k->PushOutput(result);
k->Map();
}
这不就是纯粹的Shading Language么。不过值得注意的是,Brook通过运行库进行封装,把GPU当作Streaming Processor,由CPU进行控制,计算数据并输出。目前似乎只能进行图形的计算,比如FFT,Ray-Tracing等演示,还没有到达能够计算pi的程度。
思考了一下。精度问题需要解决,FP16刚刚开始广泛使用,FP32还不能够支持硬件过滤。FP32仅仅只是IEEE754 float的精度而已,更本谈不上double的精度,用在需要精度较高的地方可能还不是很适合。如我设想那样,进行pi的几百万位的计算,目前来说不太可能,首先,Shading Language从来就没有提供地址的操作,也就是无法选泽Pixel的位置,也就是无法对FrameBuffer进行准确定位。如果可以解决这个问题,那么就可以进行真正意义上的通用计算,那个时候FrameBuffer只是一个暂时的缓冲容器而已。
SIMD的物理计算可以相当的强悍。物理特性计算都是强调同时性的,而GPU可以同时并行计算,充分发挥了自己的优势,难怪NVIDIA要和Havok进行合作。记得以前看过博客园中一位先生写的物理引擎,着实震惊,我建议他不妨研究研究这一块。Stream的概念将在DX10上得到彻底的诠释,不妨看看我以前翻译的DX10文章,其中Geometry Shader很有意思。
我期待下一代API出现,一个崭新的软硬件组合方案,这样就可能为Display Adapter这个古老的东西带来真正的革命。值得注意的是,AMD已经收购了ATi,而Intel还在为100亿美元收购NV的价格评估的时候,也许下一代变革已经开始了,让我们拭目以待。
提到的东西可以在这里找到
Brook
http://sourceforge.net/projects/brook libSh
http://sourceforge.net/projects/libsh