在《使用Direct3D 11进行实际渲染和计算》(第325、326页)的6.4常量缓冲区一节中,提到:


默认情况下,HLSL编译器将尝试对齐常量,例如他们没有跨越多个float4寄存器。 [...] HLSL常量缓冲区的打包也可以通过packoffset关键字手动指定。


我假设类似的规则将适用于OpenGL等效的统一缓冲区对象,因为它们映射到相同的硬件功能。

香草制服呢?声明制服时应遵循哪些规则?

uniform vec2 xy; // Can we expect the compiler to pack xy
uniform vec2 zw; // into a same four component register?

uniform vec2 rg;
uniform float foo; // Will this prevent from packing rg and ba?
uniform vec2 ba;   // If so, will foo eat up a full four components register?


如果编译器可以进行此类优化,它们的效果如何?我们可以明确地告诉编译器是否打包,什么时候应该打包?

#1 楼

我一直在寻找答案,所以我下载了AMD的着色器分析器,以查看为GCN编译时生成的程序集。在下面的汇编中,矢量寄存器是v#,标量寄存器是s#。

似乎均匀的矢量均匀矢量都作为单独的标量传递到着色器中,因此vec3将使用3个标量寄存器。我感到困惑的是v0到v4,我不确定v0是完整的4浮点寄存器还是寄存器中的单个浮点,而完整的向量寄存器跨越v0到v3。在两个版本之间似乎并没有改变一种方式,因此我可以假设定义顺序不影响程序集。

http://amd-dev.wpengine.netdna-cdn .com / wordpress / media / 2013/07 / AMD_GCN3_Instruction_Set_Architecture.pdf

#version 450

uniform vec2 xy; 
uniform vec2 zw;

out vec4 v;

void main(){ 
    v.xy = xy; 
    v.zw = zw; 
}

shader 
  asic(VI)
  type(VS)

  v_cndmask_b32  v0, s0, v0, vcc               
  v_mov_b32     v0, 0                          
  v_mov_b32     v1, 1.0                        
  exp           pos0, v0, v0, v0, v1 done      
  s_andn2_b32   s0, s5, 0x3fff0000             
  s_mov_b32     s1, s0                         
  s_mov_b32     s2, s6                         
  s_mov_b32     s3, s7                         
  s_mov_b32     s0, s4                         
  s_buffer_load_dwordx2  s[4:5], s[0:3], 0x00  
  s_buffer_load_dwordx2  s[0:1], s[0:3], 0x10  
  s_waitcnt     expcnt(0) & lgkmcnt(0)         
  v_mov_b32     v0, s4                         
  v_mov_b32     v1, s5                         
  v_mov_b32     v2, s0                         
  v_mov_b32     v3, s1                         
  exp           param0, v0, v1, v2, v3         
end

#version 450

uniform vec2 xy;
uniform float z;
uniform vec2 zw;

out vec4 v;

void main(){ 
    v.xy = xy; 
    v.zw = zw;
    v.w += z;
}

shader 
  asic(VI)
  type(VS)

  v_cndmask_b32  v0, s0, v0, vcc              
  v_mov_b32     v0, 0                         
  v_mov_b32     v1, 1.0                       
  s_andn2_b32   s0, s5, 0x3fff0000            
  exp           pos0, v0, v0, v0, v1 done     
  s_mov_b32     s1, s0                        
  s_mov_b32     s2, s6                        
  s_mov_b32     s3, s7                        
  s_mov_b32     s0, s4                        
  s_buffer_load_dword  s4, s[0:3], 0x10       
  s_buffer_load_dwordx2  s[6:7], s[0:3], 0x00 
  s_buffer_load_dwordx2  s[0:1], s[0:3], 0x20 
  s_waitcnt     expcnt(0) & lgkmcnt(0)        
  v_mov_b32     v0, s4                        
  v_add_f32     v0, s1, v0                    
  v_mov_b32     v1, s6                        
  v_mov_b32     v2, s7                        
  v_mov_b32     v3, s0                        
  exp           param0, v1, v2, v3, v0        
end


评论


$ \ begingroup $
定义顺序确实影响了布局。此处的相关部分是s_buffer_load_dword指令-那些正在读取输入制服,而十六进制的最后一个数字是要读取的偏移量。在第一种情况下,它显示xy在偏移量0处,而zw在偏移量16处。在第二种情况下,您在偏移量0处具有xy,在偏移量16处具有zy,在偏移量32处具有zw。看来所有统一都是16字节的对齐,没有包装在一起或重新排序。
$ \ endgroup $
–内森·里德(Nathan Reed)
2015年10月6日17:27