Parça gölgelendiricimdeki bu koşullu neden bu kadar yavaş?


19

WebGL'de bazı FPS ölçüm kodları ayarladım ( bu SO cevabına dayanarak ) ve fragman gölgelendiricimin performansı ile bazı tuhaflıklar keşfettim. Kod, 1024x1024 tuval üzerinde tek bir dörtlü (veya iki üçgen) oluşturur, böylece tüm sihir parça gölgelendiricide gerçekleşir.

Bu basit gölgelendiriciyi düşünün (GLSL; tepe gölgelendirici sadece bir geçiştir):

// some definitions

void main() {
    float seed = uSeed;
    float x = vPos.x;
    float y = vPos.y;

    float value = 1.0;

    // Nothing to see here...

    gl_FragColor = vec4(value, value, value, 1.0);
}

Yani bu sadece beyaz bir tuval oluşturuyor. Makinemde ortalama 30 fps civarında.

Şimdi sayı çatırtısını artıralım ve her bir parçayı konuma bağlı gürültünün birkaç oktavına göre hesaplayalım:

void main() {
    float seed = uSeed;
    float x = vPos.x;
    float y = vPos.y;

    float value = 1.0;

      float noise;
      for ( int j=0; j<10; ++j)
      {
        noise = 0.0;
        for ( int i=4; i>0; i-- )
        {
            float oct = pow(2.0,float(i));
            noise += snoise(vec2(mod(seed,13.0)+x*oct,mod(seed*seed,11.0)+y*oct))/oct*4.0;
        }
      }

      value = noise/2.0+0.5;

    gl_FragColor = vec4(value, value, value, 1.0);
}

Yukarıdaki kodu çalıştırmak istiyorsanız, ben bu uygulamasınısnoise kullanıyorum .

Bu, fps'yi 7 gibi bir şeye indirir.

Şimdi garip kısım ... her 16 parçadan sadece birini gürültü olarak hesaplayalım ve aşağıdaki koşulda gürültü hesaplamasını sararak diğerlerini beyaz bırakalım:

if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
    // same noise computation
}

Bunun çok daha hızlı olmasını beklersiniz, ancak yine de sadece 7 fps.

Bir test daha yapmak için, pikselleri aşağıdaki koşulla filtreleyelim:

if (x > 0.5 && y > 0.5) {
    // same noise computation
}

Bu, öncekiyle aynı sayıda gürültü pikseli verir, ancak şimdi neredeyse 30 fps'ye kadar geri dönüyoruz.

Burada neler oluyor? Piksellerin 16'sını filtrelemenin iki yolu tam olarak aynı sayıda döngü sağlamamalı mı? Ve neden yavaş olan tüm pikselleri gürültü kadar yavaş yapıyor ?

Bonus soru: Bu konuda ne yapabilirim? Aslında eğer korkunç performansı etrafında çalışmalarına herhangi bir yolu var mı yok sadece birkaç pahalı parçaları ile benim tuval speckle ister misin?

(Sadece emin olmak için, gerçek modulo hesaplamasının beyaz yerine her 16. pikseli siyaha dönüştürerek kare hızını hiç etkilemediğini doğruladım.)

Yanıtlar:


22

Pikseller küçük kareler halinde gruplanır (donanıma ne kadar büyük olur) ve tek bir SIMD boru hattında birlikte hesaplanır . (SIMD dizisi türü)

Bu boru hattı (satıcıya bağlı olarak birkaç farklı isme sahiptir: çözgü, dalga önleri) kilit adımındaki her piksel / parça için işlemleri yürütür. Bu, 1 pikselin bir hesaplamaya ihtiyacı varsa, tüm piksellerin onu hesaplayacağı ve sonuca ihtiyaç duymayanların onu atacağı anlamına gelir.

Tüm parçalar bir gölgelendiriciden aynı yolu izlerse, diğer dallar yürütülmez.

Bu, her 16. pikseli hesaplama yönteminizin en kötü durumda dallanma olacağı anlamına gelir.

Görüntünüzü hala küçültmek istiyorsanız, daha küçük bir dokuya dönüştürün ve sonra görüntüyü yükseltin.


5
Daha küçük bir dokuya ve örneklemeye dönüştürmek bunu yapmanın iyi bir yoludur. Ancak, herhangi bir nedenden dolayı, büyük dokunun her 16. pikseline gerçekten yazmanız gerekiyorsa, yazma işlemlerini oluşturma hedefine dağıtmak için her 16. piksel için bir çağrı gölgeleme artı görüntü yükleme / depolama ile bir hesaplama gölgelendirici kullanmak iyi bir seçenek olabilir.
Nathan Reed
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.