Имеет ли значение порядок выравнивания и декларации униформы?

10

В разделе 6.4 Буферы констант книги Практический рендеринг и вычисления с Direct3D 11 (страницы 325, 326) упоминается:

По умолчанию компилятор HLSL пытается выровнять константы так, чтобы они не охватывали несколько регистров float4. [...] Упаковка для постоянного буфера HLSL также может быть указана вручную через ключевое слово packoffset.

Я предполагаю, что подобное правило будет применяться к эквивалентным OpenGL объектам Uniform Buffer, поскольку они отображаются на одну и ту же аппаратную функцию.

А как насчет ванильной формы? Какие правила применяются при объявлении униформы?

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?

Если компилятор может делать такие оптимизации, насколько они хороши? Можем ли мы явно указать компилятору упаковывать или нет, и когда мы должны?

Жюльен Геро
источник

Ответы:

4

Я искал ответ, поэтому я скачал шейдерный анализатор 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
Джошуа Варинг
источник
2
Порядок определения действительно влияет на макет. Соответствующей частью здесь являются s_buffer_load_dwordинструкции - они читают входную форму, а последнее число в шестнадцатеричном формате - это смещение, с которого нужно читать. Это показывает, что в первом случае xyэто смещение 0 и zwсмещение 16. Во втором случае вы имеете xyсмещение 0, zсмещение 16 и zwсмещение 32. Похоже, что все формы по отдельности выровнены по 16 байтов и не упакованы. вместе или переупорядочены.
Натан Рид