2011-06-25 22 views
4

我想使用GLSL以隔行模式高效渲染。GLSL交错

我可以alrdy做到这一点,如:

vec4 background = texture2D(plane[5], gl_TexCoord[1].st); 
if(is_even_row(gl_TexCoord[1].t)) 
{ 
    vec4 foreground = get_my_color(); 
    gl_FragColor = vec4(fore.rgb * foreground .a + background .rgb * (1.0-foreground .a), background .a + fore.a); 
} 
else 
    gl_FragColor = background; 

然而,据我所理解GLSL分支的本质是两个分支实际上被执行,因为“even_row”被认为是运行 - 时间价值。

有什么技巧可以在这里使用,以避免不必要地调用相当沉重的函数“get_color”? is_even_row的行为非常静态。

或者还有其他方法可以做到这一点吗?

注意:glPolygonStipple将不起作用,因为我在我的GLSL代码中有自定义混合函数。

+1

除非你在软件渲染器上运行,否则我会强烈地阻止你以隔行模式渲染。它会变得更糟,但速度不会更快。事实上,它可能会更慢。隔行渲染会干扰GPU的自然2x2块着色,这是不好的。 – Damon

+0

我在合成和隔行扫描视频,后来在管道上显示1080i电视。它必须交错。 – ronag

+3

在这种情况下,如何处理Y分辨率为1/2的所有内容,然后绘制纹理全屏四边形作为最后一件事,并滥用模板缓冲区来屏蔽奇数行?这样,至少除了最后一次传递都是对GPU友好的。或者,如果模板不可用,则可以执行“明确的Z剔除”。 – Damon

回答

5

(发表评论我要回答,如要求)

问题,隔行是图形处理器在2x2的集群上运行的着色器,这意味着你从隔行一无所获(良好的软件实施有可能会只执行实际像素是是必要的,除非你要求部分衍生品)。

充其量,隔行扫描以相同的速度运行,最糟糕的是,由于交错的额外工作,其运行速度较慢。几年前,ShaderX4中有一篇文章提出了隔行渲染。我在6张图形卡(每个“两个大”制造商的硬件的3代)上尝试了这种方法,并且在每种情况下它运行速度较慢(有时略微,有时高达50%)。

你可以做的是在1/2垂直分辨率下进行所有昂贵的渲染,这将使像素着色器工作(和纹理带宽)减少1/2。然后可以放大纹理(GL_NEAREST),并放弃其他所有行。

在执行像素着色器之前,模板测试可用于丢弃像素。当然,硬件仍然在2x2组中运行着色器,所以在这个过程中你不会获得任何东西。但是,如果它只是最后一个通道,那么这并不重要,这是一个写出单个提取纹理的平凡着色器。成本更高的构图着色器(重要的)以半分辨率运行。
您会在这里找到详细的说明,包括代码:fake dynamic branching。此演示通过丢弃使用模板的光线范围外的照明来避免照明像素。

不需要模板缓冲区的另一种方法是使用“显式Z剔除”。事实上,这可能更容易,更快。
为此,请清除Z,禁用颜色写入(glColorMask),然后绘制一个全屏四元组,其顶点具有一些“接近”的Z坐标,并使着色器在每一个奇数行中杀死碎片(或者如果您想要使用弃用的alpha测试, 管他呢)。 gl_FragCoord.y是一种非常简单的方法,可以知道哪条线要杀死,使用环绕的另一个小纹理(如果您必须使用GLSL 1.0)。
现在在顶点绘制另一个全屏四边形,带有“远”Z值(当然还有深度测试)。只需获取半分辨率纹理(GL_NEAREST过滤),然后将其写出。由于深度缓冲区的值在每隔一行都“接近”,因此会丢弃这些像素。

glPolygonStipple和这个比较?多边形点画是一个不推荐的功能,因为它不直接受硬件支持,必须由驱动程序模拟,或者“暗中”重写着色器以包含额外的逻辑或退回到软件。

3

这可能不是交错的正确方法。如果你真的需要达到这个效果,不要在这样的片段着色器中做。相反,您可以执行以下操作:

  1. 初始化全屏1位模板缓冲区,其中每个位存储其对应行的奇偶校验位。

  2. 将场景像往常一样渲染到具有1/2垂直分辨率的临时FBO。

  3. 打开模板测试,并根据要绘制哪组扫描线切换模板func。

  4. 将上述fbo(包含帧的内容)的重新缩放版本切换到模板缓冲区。

请注意,您可以跳过屏幕外FBO步骤,并且使用模板缓存直接绘制,但这会浪费一些填充率测试那些刚刚不管怎样都是修剪这些像素。如果你的程序着色较重,我刚刚提到的解决方案将是最佳的。如果不是这样,你最终可能会在屏幕上直接绘制更好的。