Opengl 通过将代码移到main(){}之外来优化着色器

Opengl 通过将代码移到main(){}之外来优化着色器,opengl,canvas,webgl,gpu,Opengl,Canvas,Webgl,Gpu,在编写着色器时,代码是针对每个(顶点/片段)执行的主函数之外的代码,还是每次绘制调用只执行一次,从而通过在绘制开始时预先计算许多值来提供好处 例如,以下顶点着色器的性能是否会比下面的更好 #attribute vec4 position; #attribute vec2 texcoord; // desc. Sprite description array items in order // startCoord, endCoord, ununsed , textScale,(unused,s

在编写着色器时,代码是针对每个(顶点/片段)执行的主函数之外的代码,还是每次绘制调用只执行一次,从而通过在绘制开始时预先计算许多值来提供好处

例如,以下顶点着色器的性能是否会比下面的更好

#attribute vec4 position;
#attribute vec2 texcoord;
// desc. Sprite description array items in order
// startCoord, endCoord, ununsed  , textScale,(unused,screenAspect),(alpha,scale),unused,tile
#uniform vec2 desc[8];   
varying vec2 v_texcoord;
varying float alpha;
const vec2 proj = vec2(-0.5, 0.5);

//---------------------------------------------------------------------
// Does the following code only run once per draw code.
// code common to all verts
float aspect = desc[4].y;
vec2 aspectV = vec2(1.0,aspect);
vec2 line   =  desc[1] - desc[0]; 
vec2 lineI  =  normalize(line / aspectV);
float len   =  length(line / aspectV) *2.0;
vec2 lineJ  =  lineI * desc[3].y * desc[5].y;
vec2 textX  =  vec2(len / desc[5].y / desc[3].x / 2.0, 1.0);
mat4 tMat   =  mat4(1);  // if I change this to include assigning the 
                         // vectors lineI and lineJ will this provide a 
                         // performance benefit.
//---------------------------------------------------------------------

void main() {
   tMat[0][0] = lineI.x ;
   tMat[0][1] = lineI.y * aspect;
   tMat[1][0] = lineJ.y;
   tMat[1][1] = -lineJ.x * aspect;
   gl_Position  = (tMat * vec4(position.xy * vec2(len,2.0), position.zw)) +  vec4((desc[0] + proj) * 2.0, 0.0, 0.0);
   v_texcoord = texcoord * textX;
   alpha = desc[5].x;
} 
main中的所有代码都很慢吗

#attribute vec4 position;
#attribute vec2 texcoord;
// desc. Sprite description array items in order
// startCoord, endCoord, ununsed  , textScale,(unused,screenAspect),(alpha,scale),unused,tile
#uniform vec2 desc[8];   
varying vec2 v_texcoord;
varying float alpha;
const vec2 proj = vec2(-0.5, 0.5);

void main() {
   float aspect = desc[4].y;
   vec2 aspectV =   vec2(1.0,aspect);
   vec2 line  = desc[1] - desc[0]; 
   vec2 lineI = normalize(line / aspectV);
   float len  = length(line / aspectV) *2.0;
   vec2 lineJ = lineI * desc[3].y * desc[5].y;
   vec2 textX = vec2(len / desc[5].y / desc[3].x / 2.0, 1.0);
   mat4 tMat  = mat4(1);  
   tMat[0][0] = lineI.x ;
   tMat[0][1] = lineI.y * aspect;
   tMat[1][0] = lineJ.y;
   tMat[1][1] = -lineJ.x * aspect;
   gl_Position  = (tMat * vec4(position.xy * vec2(len,2.0), position.zw)) +  vec4((desc[0] + proj) * 2.0, 0.0, 0.0) ;
   v_texcoord = texcoord * textX;
   alpha = desc[5].x;
}` 

我将忽略一个事实,
#attribute
#uniform
不是合法的GLSL构造。我会假装你用的是真正合法的GLSL

本质上,您的问题是,您是否期望调用
glUniform
来实际更新所有这些全局变量的值

我不希望实现中出现这样的优化。这类优化很难实现,因为它们涉及到隐式统一值的创建。这会增加着色器使用的有效制服数量,可能会超过法定制服数量


如果要确保每次绘制调用都完成这些预计算,则应执行这些操作,并使结果显式地提供给着色器。

我不确定您使用的是什么语言/框架,但这绝对不是标准的glsl着色器。这样做没有好处,@LJ谢谢你的链接,但它没有回答我的问题。我只想知道main之外的代码是在每次绘制调用中执行一次,还是在每个顶点/片段中执行一次(取决于类型),它在着色器的每次迭代中执行一次。换句话说,
gl.drawArrays(…,6)
在内部或外部执行6次。对于webGL,在ECMAScript中计算着色器外部的值是一种降低速度的方法。很遗憾,我不能从着色器中写入制服,因为这将提供显著的改进,尤其是对于片段着色器。#只是一个预编译指令,生成用于设置制服、属性等的代码。它不编译
***错误编译着色器:错误:0:1:“属性”:无效的指令名
,如果它是为您编译的,或者您正在进行字符串替换,或者您正在使用不符合WebGL规范的浏览器。@Blindman67“在ECMAScript中,计算着色器外部的值是一种降低速度的方法“嗯,什么?特别是在现代javascript引擎中,算术运算的速度非常接近本机速度,如果这几项运算以任何方式阻碍了您的应用程序,您可能希望阅读有关编写performant javascript的内容,或者就性能问题提出问题。@Blindman67:“我更喜欢尽可能地将所有东西卸载到GPU,而不是“非常接近本机”,这显然是实现高性能代码的糟糕方法。GPU的速度并不是因为它是GPU。如果要在网格中渲染100000个顶点,在CPU上进行一次性计算并将结果上载到GPU,比让GPU计算100000次完全相同的结果更快。用C++编写的引擎可以做到这一点;这就是为什么他们主要处理矩阵和简单的数据结构。为什么JavaScript会有任何不同?@Blindman67:“我正在渲染100000多个顶点,每6个顶点代表一个唯一的平移、旋转、缩放、表引用、FXed、sprite。”然而,您将这些8个32位浮点作为制服传递,而不是逐顶点数据。这意味着您实际上发出了成千上万个单独的绘制命令。这就是你所有表演的方向。不是在数学计算中,而是在发出绘图命令时。“普通”解决方案是重新调整数据,以便在一次绘制中渲染所有精灵。