¿Importa el orden de alineación y declaración de uniformes?

10

En la sección 6.4 Buffers constantes del libro Practical Rendering & Computation con Direct3D 11 (páginas 325, 326) se menciona:

Por defecto, el compilador HLSL intentará alinear constantes de modo que no abarquen múltiples registros float4. [...] El embalaje para un búfer constante HLSL también se puede especificar manualmente a través de la palabra clave packoffset.

Supongo que se aplicará una regla similar al equivalente de OpenGL, Uniform Buffer Objects, ya que se asignan a la misma característica de hardware.

Sin embargo, ¿qué pasa con los uniformes de vainilla? ¿Cuáles son las reglas que se aplican al declarar uniformes?

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?

Si el compilador puede hacer tales optimizaciones, ¿qué tan buenas son? ¿Podemos decirle explícitamente al compilador que empaque o no, y cuándo deberíamos?

Julien Guertault
fuente

Respuestas:

4

Busqué una respuesta, así que descargué el analizador de sombreadores de AMD para ver el ensamblaje producido cuando se compiló para GCN. En el conjunto a continuación, los registros vectoriales son v # y los registros escalares son s #.

Parece que los uniformes, incluso los uniformes vectoriales, se pasan al sombreador como escalares separados, por lo que un vec3 usaría 3 registros escalares. El bit que encontré confuso fue el v0 a v4, no estoy seguro de si v0 es un registro completo de 4 flotantes o un único flotante en un registro, con un registro vectorial completo que abarca v0 a v3. De una forma u otra, no pareció cambiar entre las dos versiones, por lo que puedo suponer que el orden de definición no afectó al ensamblaje.

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
Joshua Waring
fuente
2
El orden de definición afectó el diseño. La parte relevante aquí son las s_buffer_load_dwordinstrucciones: esas están leyendo los uniformes de entrada, y el último número en hexadecimal es el desplazamiento para leer. Se muestra en el primer caso xyen el desplazamiento 0 y zwen el desplazamiento 16. En el segundo caso, tiene xyen el desplazamiento 0, zen el desplazamiento 16 y zwen el desplazamiento 32. Parece que todos los uniformes están individualmente alineados con 16 bytes y no embalados juntos o reordenados.
Nathan Reed