Transform Feedback是Shader Model 4.0带来的一个新特性,与其他特性不同的是,它带来了OpenGL/OpenGL ES渲染管线的改变。Transform Feedback在DirectX中被称为Stream-Output Stage,有兴趣的读者可以去自己翻一下DirectX的文档。在本篇的博客中着重要讲的是Transform Feedback在Khronos组织是怎么一步步发展过来的,这些扩展(extensions)和OpenGL ES有什么联系,以及各家厂商对于Transform Feedback有什么自己的开发和见解。至于Transform Feedback和OpenGL有什么联系,这里就不描述了。
让我们先来看一下最新的OpenGL ES3的渲染管线 (摘自OpenGL ES3.1官方spec),
很明显可以看到流水线为Transform Feedback新开了一条管道,它处于Vertex Shader管道之后,但是在光栅化管道之前。仔细想一下Vertex Shader要做的事情,不就是Transformation & Lighting嘛,所以很容易联想到Transform Feedback要操作的对象就是Vertex Shader变换后的顶点数据。这是Transform所要表达的意思,至于Feedback,在上面这张图中并没有画出来,事实上这个箭头应该重新指向Vertex Shader之前。就是说,Transform Feedback出来的顶点会存储在一个缓存里面,然后重新作为VBO进行Vertex Shader的绘制处理。
Transform Feedback能够很好地应用在在粒子系统中,在OpenGL ES中,每个粒子都可能是一个GL_Point,在GPU中就是一个顶点。如果没有Transform Feedback,在每一帧的绘制中,开发者可能需要为粒子准备不同的VBO,来描述粒子的变换,而VBO从客户端上传到服务器端需要消耗很大的时间。随着Transform feedback的到来,我们可以一次性的把顶点数据变换好然后输出到Transform Feedback缓存中,然后这个缓存就可以给后面的很多帧使用。这种2-pass的绘制解决方案能极大地提高应用程序的3D图形的效率。
下面是一个Transform Feedback应用在粒子系统中的demo,
如果各位有兴趣翻一下Khronos里面关于Transform Feedback的所有的扩展,估计会晕掉了,链接在OpenGL® Registry。大大小小一共有9个扩展,4个ARB,1个EXT,2个NV和2个AMD。这里先简述一下所有扩展之间的关系,这样读者就知道所有扩展之间的依赖关系,学习起来就会有的放矢。
下面用箭头来表示所有扩展之间的关系,首先Transform Feedback的始祖是NVidia公司,他们提出了GL_NV_transform_feedback和GL_NV_transform_feedback2这两个扩展,以后所有的扩展都是基于这两个扩展开发出来的。
其中GL_EXT_transform_feedback已经被GL_ARB_transform_feedback2和GL_ARB_transform_feedback3完全覆盖了。
在接下来的博客文章中我会分析一下GL_ARB_transform_feedback2和GL_ARB_transform_feedback3以及所有基于这两者的扩展。有些读者可能会有疑惑,GL_ARB_transform_feedback2和GL_ARB_transform_feedback3不是已经被OpenGL全盘吸收了吗,为什么需要分开讲?主要的原因是由OpenGL ES和OpenGL的不同造成的。在下一篇博客中会详细描述OpenGL ES对于这个新特性的兼容。
ARB_transform_feedback2这个扩展基本定义了Transform Feedback这个新特性的所有基本元素。我们可以用录音机的操作来形容所有Transform Feedback需要的操作。
另外其他的一些基本操作是和Transform Feedback也是作为一个面向对象的概念相关的,这个在OpenGL里面很常见,比如texture就是一个对象,
而要把一个任意的buffer指定为Transform Feedback的buffer,我们还需要以下API,
最后这个扩展还需要用到GL_EXT_transform_feedback的一个函数来指定哪些Vertex Shader Varying变量需要输出到Transform Feedback的buffer中去,这个函数在GL_ARB_transform_feedback3里面被转正了,拿掉了EXT的帽子。
这一套API非常容易理解,如果有很多个drawcall出现在开发者的应用程序中,开发者可以很灵活地调用上述API来获得期望的Vertex Shader的输出,比如
glBeginTransformFeedback draw1 glPauseTransformFeedback draw2 glResumeTransformFeedback draw3 glEndTransformFeedback
上面的例子的结果就是当前的Transform Feedback的buffer包括了draw1和draw3的指定的Vertex Shader的输出,而draw2就会被忽视掉。
值得注意的是,Transform Feedback接受的几何图元只包括
以上就是Transform Feedback的基本知识,就是这么简单。
ARB_transform_feedback3主要提供了以下新功能,
对于glTransformFeedbackVaryingsEXT这个函数的转正是必然的,其实这个函数非常的强大,它指定了要输出的varying变量可以用两种layout来存储
所谓的INTERLEAVED就是 (A, B, A, B,...)这种模式,而SEPARATE就是(A, A, ..., B, B, ...)这种模式。可以看到这个和VBO支持的layout是完全吻合的。这就可以给开发者带来很大的便利来优化他们的程序。
GL_RASTERIZER_DISCARD又是一个非常有意思的变量,如果这个变量被启用了,那么Transform Feedback就和上面的渲染管线描述地一模一样。如果这个变量被禁用了,那么Vertex Shader输出到Transform Feedback缓存后,还要继续进行光栅化的操作,从而绘制出来。这个更多的是对渲染管线的一种补充,提供了更多的功能和灵活性。从深的程度讲,这个和OpenGL一贯以来的海纳百川的精神是一致的,灵活性和可扩展性都很重要。
Transform Feedback用在Geometry Shader后面一点都不奇怪,因为Geometry Shader相当于扩展了Vertex Shader的一些功能,两者都是在光栅化之前做的。从原理上来讲Geometry Shader变换后的结果输出到Transform Feedback缓存中没什么好解释的,但是需要注意的是有一个限制,就是如果选择从Geometry Shader中输出的话几何图元类型只能是GL_POINTS。
对于新增加的query功能,下面用一个简单的例子来说明,
glBeginQuery(GL_PRIMITIVES_GENERATED0, 11); glBeginQuery(GL_PRIMITIVES_GENERATED1, 12); draw glEndQuery(GL_PRIMITIVES_GENERATED0); glEndQuery(GL_PRIMITIVES_GENERATED1);
这个例子是用来得到stream 11和stream 12产生的primitive个数。关于primitive和stream的概念,各位可以去查询下Geometry Shader的spec。
以上就是对Transform Feedback的一个简单基本介绍,在下一篇博客中我还会描述OpenGL ES和这个新特性的兼容性以及其他厂商对Transform Feedback的一些新的扩展。