He escuchado que si las declaraciones deben evitarse en los sombreadores, porque ambas partes de las declaraciones se ejecutarán y luego se eliminará el error (lo que perjudica el rendimiento).
¿Sigue siendo un problema en DirectX 10? Alguien me dijo que en él solo se ejecutará la rama correcta.
Para la ilustración tengo el código:
float y1 = 5; float y2 = 6; float b1 = 2; float b2 = 3;
if(x>0.5){
x = 10 * y1 + b1;
}else{
x = 10 * y2 + b2;
}
¿Hay alguna otra forma de hacerlo más rápido?
Si es así, ¿cómo hacerlo?
Ambas ramas se ven similares, la única diferencia son los valores de "constantes" ( y1, y2, b1, b2
son los mismos para todos los píxeles en Pixel Shader).
Respuestas:
Muchas reglas para sombreadores de microoptimización son las mismas que para las CPU tradicionales con extensiones vectoriales. Aquí hay algunos consejos:
test
,lerp
/mix
)Es cierto que las sucursales son más baratas en hardware moderno de lo que solían ser, pero es mejor evitarlas si es posible. Mediante el uso de funciones de swizzling y prueba, puede volver a escribir su sombreador sin pruebas:
Usar
step
ylerp
es un idioma muy común para elegir entre dos valores.fuente
En general está bien. Los sombreadores se ejecutarán en grupos de vértices o píxeles (diferentes proveedores tienen una terminología diferente para estos, así que me mantengo alejado de eso) y si todos los vértices o píxeles en un grupo toman la misma ruta, el costo de ramificación es insignificante.
También debe confiar en el compilador de sombreadores. El código HLSL que escriba no debe verse como una representación directa del bytecode o incluso el ensamblaje en el que se compilará, y el compilador es perfectamente libre de convertirlo en algo equivalente pero que evita la ramificación (por ejemplo, un lerp a veces puede ser una conversión preferida) Por otro lado, si el compilador determina que realizar una rama es realmente la ruta más rápida, la compilará en una rama. Ver el ensamblaje generado en PIX o una herramienta similar puede ser muy útil aquí.
Finalmente, la vieja sabiduría aún se mantiene aquí: perfílela, determine si en realidad es un problema de rendimiento para usted, y enfréntela entonces, no antes. Asumir que algo puede ser un problema de rendimiento y actuar de acuerdo con esa suposición solo generará un gran riesgo de mayores problemas más adelante.
fuente
Cita del enlace / artículo publicado por Robert Rouhani:
Como sugirió mh01 ("Ver el ensamblado generado en PIX o una herramienta similar puede ser muy útil aquí"), debe usar una herramienta de compilación para examinar la salida. En mi experiencia, la herramienta Cg de nVidia (Cg todavía se usa ampliamente hoy en día debido a sus capacidades multiplataforma) dio una ilustración perfecta del comportamiento mencionado en el párrafo de códigos de condición (predicción) de gemas de GPU . Por lo tanto, independientemente del valor de activación, ambas ramas se evaluaron por fragmento y solo al final, la correcta se colocó en el registro de salida. Sin embargo, se perdió el tiempo de cálculo. En aquel entonces, pensé que la ramificación ayudaría al rendimiento, especialmente porque todosLos fragmentos en ese sombreador dependían de un valor uniforme para decidir la rama correcta, eso no sucedió como se esperaba. Entonces, una advertencia importante aquí (por ejemplo, evitar ubershaders, posiblemente la mayor fuente de infierno ramificado).
fuente
Si aún no tiene problemas de rendimiento, está bien. El costo de la comparación contra una constante sigue siendo extremadamente barato. Aquí hay una buena lectura sobre la ramificación de GPU: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter34.html
De todos modos, aquí hay un fragmento de código que va a ser mucho peor que la instrucción if (y es mucho menos legible / mantenible), pero aún así se deshace de él:
Tenga en cuenta que estoy asumiendo que x está limitado al rango
[0, 1]
. Esto no funcionará si x> = 2 o x <0.Lo que corta es convertir x en uno
0
o dos1
y multiplicar el incorrecto por 0 y el otro por 1.fuente
if(x<0.5)
el valor parafx
debería serround(x)
ofloor(x + 0.5)
.Hay múltiples instrucciones capaces de hacer condiciones sin ramificación;
Además de algunos operadores lógicos;
fuente: http://theorangeduck.com/page/avoiding-shader-conditionals
fuente