Performance 着色器中分支的效率

Performance 着色器中分支的效率,performance,branch,shader,Performance,Branch,Shader,我理解这个问题似乎有些不合理,但如果有人在这个问题上有理论知识/实践经验,你能分享一下就好了 我正在尝试优化我的一个旧着色器,它使用了大量纹理查找 我为三个可能的贴图平面中的每一个都提供了漫反射、法线和镜面反射贴图,对于靠近用户的一些面,我还必须应用贴图技术,这也带来了很多纹理查找(如视差遮挡贴图) 分析表明纹理查找是着色器的瓶颈,我愿意删除其中的一些。对于输入参数的某些情况,我已经知道部分纹理查找是不必要的,显而易见的解决方案是执行类似(伪代码)的操作: 现在,问题来了 我记不清了(这就是为什

我理解这个问题似乎有些不合理,但如果有人在这个问题上有理论知识/实践经验,你能分享一下就好了

我正在尝试优化我的一个旧着色器,它使用了大量纹理查找

我为三个可能的贴图平面中的每一个都提供了漫反射、法线和镜面反射贴图,对于靠近用户的一些面,我还必须应用贴图技术,这也带来了很多纹理查找(如
视差遮挡贴图

分析表明纹理查找是着色器的瓶颈,我愿意删除其中的一些。对于输入参数的某些情况,我已经知道部分纹理查找是不必要的,显而易见的解决方案是执行类似(伪代码)的操作:

现在,问题来了

我记不清了(这就是为什么我说这个问题可能是不确切的),但在我最近读到的一些论文中(不幸的是,我记不起名字),我说了一些类似于以下内容的东西:

介绍了该系统的性能 技术取决于效率 基于硬件的条件反射 执行分支

在我即将开始重构大量着色器并实现我所说的基于
的优化之前,我就记得这种说法

在我开始之前,有人知道着色器中分支的效率吗?为什么分支会在着色器中造成严重的性能损失

如果基于
的分支,我是否可能只会恶化
的实际性能?


你可能会说-试试看。是的,如果这里没有人帮助我,我会这么做:)

但是,对于新的GPU来说,
if
的情况可能是一场噩梦。这种问题很难预测,除非你有很多不同的GPU(这不是我的情况)

因此,如果有人知道这方面的一些事情,或者对这类着色器有基准测试经验,我将非常感谢您的帮助


剩下的几个实际工作的脑细胞一直告诉我,GPU上的分支可能远不如CPU上的分支有效(CPU通常有非常有效的分支预测和消除缓存未命中的方法),因为它是一个GPU(或者可能很难/不可能在GPU上实现)


不幸的是,我不确定这句话是否与实际情况有任何共同之处…

我不知道基于if的优化,但如何创建您认为需要的纹理查找的所有排列,每个都有自己的着色器,并针对正确的情况使用正确的着色器(取决于需要哪个纹理查找特定模型或模型的一部分)。我认为我们在Xbox 360的Bully上做了类似的操作。

如果条件是一致的(即整个过程中保持不变),那么分支基本上是自由的,因为框架基本上会编译着色器的两个版本(执行分支和不执行分支)然后根据输入变量为整个过程选择其中一个。在这种情况下,一定要使用
if
语句,因为它会使着色器更快


如果每个顶点/像素的条件不同,那么它确实会降低性能,而较旧的着色器模型甚至不支持动态分支。

不幸的是,我认为这里的真正答案是在目标硬件上使用特定情况下的性能分析器进行实际测试。特别是考虑到听起来您在项目优化阶段;这是考虑硬件频繁更改和特定着色器性质的唯一方法

在CPU上,如果出现预测失误的分支,则会导致管道刷新,而且由于CPU管道太深,实际上会丢失20个或更多周期的内容。在GPU上,情况稍有不同;管道可能要浅得多,但没有分支预测,所有着色器代码都将存储在快速内存中--但这并不是真正的区别

很难知道正在发生的一切的确切细节,因为nVidia和ATI是相对守口如瓶的,但关键是GPU是为大规模并行执行而设计的。有许多异步着色器内核,但每个内核又被设计为运行多个线程。我的理解是,每个内核都希望运行多个线程在任何给定周期的所有线程上都有相同的指令(nVidia将此线程集合称为“扭曲”)

在这种情况下,线程可能代表一个顶点、一个几何元素或一个像素/片段,而扭曲是其中大约32个的集合。对于像素,它们很可能是屏幕上彼此接近的像素。问题是,如果在一个扭曲内,不同的线程在条件跳转时做出不同的决定,那么扭曲已经发散,并且不再为每个线程运行相同的指令。硬件可以处理这个问题,但它并不完全清楚(至少对我来说)它是如何实现的。对于每一代连续的卡,处理方式也可能略有不同。最新、最通用的CUDA/compute shader友好型NVIDIA可能具有最好的实现;较旧的卡可能具有较差的实现。更糟糕的情况是,您可能会发现许多线程同时执行if/else语句

着色器的一个重要技巧是学习如何利用这种大规模并行范例。有时这意味着使用额外的过程、临时屏幕外缓冲区和模板缓冲区将逻辑从着色器推到CPU上。有时是优化
if (part_actually_needed) {
   perform lookups;
   perform other steps specific for THIS PART;
}

// All other parts.
lowp vec4 a = vec4(0.0, 0.0, 0.0, 0.0);
if (a.r == 0.0)
    gl_FragColor = texture2D ( texture1, TextureCoordOut );   
gl_FragColor = texture2D ( texture1, TextureCoordOut );