2014-05-20 6 views
0

J'ai trouvé un shader bloom simple et magnifique sur Internet, mais il est relativement lent. En apparence, le coupable est la boucle imbriquée et une recherche de texture en son sein.Bloom Shader Performance

Comment est-ce que je pourrais faire courir ceci plus rapidement?

uniform sampler2D u_texture; 
varying vec2 v_texCoords; 
void main() { 
    vec4 sum = vec4(0); 
    vec2 texcoord = vec2(v_texCoords); 
    int j; 
    int i; 

    for (i = -2; i < 2; i++) { 
     for (j = -2; j < 2; j++) { 
      sum += texture2D(u_texture, texcoord + vec2(j, i)*0.004) * 0.25; 
     } 
    } 
    if (texture2D(u_texture, texcoord).r < 0.3) { 
     gl_FragColor = sum*sum*0.012 + texture2D(u_texture, texcoord); 
    } else { 
     if (texture2D(u_texture, texcoord).r < 0.5) { 
      gl_FragColor = sum*sum*0.009 + texture2D(u_texture, texcoord); 
     } else { 
      gl_FragColor = sum*sum*0.0075 + texture2D(u_texture, texcoord); 
     } 
    } 
} 
+0

qui est le problème avec la floraison, c'est lent car il interroge la texture 25 fois dans cette boucle imbriquée –

+0

Il s'agit d'un filtre séparable, parfois deux passes (horizontal et vertical) est plus rapide que 1 - en particulier lorsque vous commencez à utiliser des fenêtres d'échantillons plus grandes (c'est un noyau 5x5). Vous pouvez également tirer parti de la capacité intégrée du matériel à échantillonner et à calculer rapidement 4 texels à la fois (filtrage linéaire). –

+0

Err, maintenant que je regarde de plus près, c'est un noyau 4x4. Pourquoi fais-tu ça de façon déséquilibrée? Je pense que votre boucle devrait effectivement inclure *** I, j = 2 plutôt que * finissant * là. Idéalement, il serait divisé en deux passes, donc juste [-2,2] = 5 fetchs par passe. –

Répondre

0

Je ne suis pas sûr si 'manuellement optimisé' GLSL a un sens, mais vous pouvez essayer de:

  • boucles manuellement Déroulez (pour (i = -2; i < 2; i ++), pour (j = -2; j < 2; j ++)), il vous donnera 16 lignes au lieu de 5 mais le code 'optimisé' semble souvent 'pas élégant', normalement cette opération devrait être faite par le compilateur ...
  • magasin texture2D (u_texture, texcoord) dans un vecteur
  • ne pas répéter calculer sum * su m
  • résultat
  • devrait ressembler à: uniform sampler2D u_texture; varying vec2 v_texCoords; void main() { vec4 sum = vec4(0); vec4 col = vec4(0); vec2 texcoord = vec2(v_texCoords); sum += texture2D(u_texture, texcoord + vec2(-2, -2)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-2, -1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-2, 0)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-2, 1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-1, -2)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-1, -1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-1, 0)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(-1, 1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(0, -2)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(0, -1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(0, 0)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(0, 1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(1, -2)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(1, -1)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(1, 0)*0.004) * 0.25; sum += texture2D(u_texture, texcoord + vec2(1, 1)*0.004) * 0.25; sum *= sum; col = texture2D(u_texture, texcoord); if (col.r < 0.3) { gl_FragColor = 0.012 + col; } else { if (col.r < 0.5) { gl_FragColor = sum * 0.009 + col; } else { gl_FragColor = sum * 0.0075 + col; } } } Vous pouvez également envisager la recherche de quelques conseils d'optimisation GLSL plus spécifiques (texture fetch), outil d'optimisation, etc.
+0

vous pouvez également faire la multiplication à la fin de la somme –

+0

Dérouler la boucle manuellement semble discutable. Vous ne savez pas si la version déroulée sera plus rapide sur toutes les architectures. Le compilateur devrait être en mesure de prendre une décision beaucoup plus éclairée quant à savoir si le déroulement est bénéfique. Comme le souligne @ratchetfreak, vous pouvez éliminer certaines opérations. Et la recherche de texture pour le point central est toujours faite deux fois. Mais je soupçonne que ce sont toutes des améliorations mineures. Les 25 recherches de texture vont probablement dominer tout le reste. –

+0

Pourquoi 25? C'est fait pour i, j: {-2, -1, 0, 1} donc "juste" 16, ai-je tort? – jaroslawj

0

l'une des choses que je vois dans le shader est qu'il n'a pas besoin de fonctionner quand col.r < 0.3 Cela signifie qu'avec un stencil, vous pouvez exclure ces parties (donc le shader ne fonctionnera pas sur ces pixels) lors de l'exécution du bloom