== GLSL'de dallanmaya neden olur mu?


27

Neyin dallanmaya neden olduğunu ve GLSL'de neyin olmadığını anlamaya çalışmak.

Gölgelendiricimde bunu çok yapıyorum:

float(a==b)

İfadeleri koşullu dallanma olmadan simüle etmek için kullanırım ... ama etkili mi? Şimdi programımın hiçbir yerinde if ifadeleri yok, döngülerim de yok.

EDIT: Netleştirmek için kodumda böyle şeyler yapıyorum:

float isTint = float((renderflags & GK_TINT) > uint(0)); // 1 if true, 0 if false
    float isNotTint = 1-isTint;//swaps with the other value
    float isDarken = float((renderflags & GK_DARKEN) > uint(0));
    float isNotDarken = 1-isDarken;
    float isAverage = float((renderflags & GK_AVERAGE) > uint(0));
    float isNotAverage = 1-isAverage;
    //it is none of those if:
    //* More than one of them is true
    //* All of them are false
    float isNoneofThose = isTint * isDarken * isAverage + isNotTint * isAverage * isDarken + isTint * isNotAverage * isDarken + isTint * isAverage * isNotDarken + isNotTint * isNotAverage * isNotDarken;
    float isNotNoneofThose = 1-isNoneofThose;

    //Calc finalcolor;
    finalcolor = (primary_color + secondary_color) * isTint * isNotNoneofThose + (primary_color - secondary_color) * isDarken * isNotNoneofThose + vec3((primary_color.x + secondary_color.x)/2.0,(primary_color.y + secondary_color.y)/2.0,(primary_color.z + secondary_color.z)/2.0) * isAverage * isNotNoneofThose + primary_color * isNoneofThose;

EDIT: Neden dallanmak istemediğimi biliyorum. Dalların ne olduğunu biliyorum. Çocuklara dallanma dersi verdiğinize sevindim ama kendimi boolean operatörleri hakkında tanımak istiyorum (ve bitsel op'lar ama bunların iyi olduğundan eminim)

Yanıtlar:


42

GLSL'de dallanmaya neden olan şey GPU modeline ve OpenGL sürücü sürümüne bağlıdır.

Çoğu GPU, dallanma maliyeti olmayan bir "iki değerden birini seçme" işlemi şeklinde görünmektedir:

n = (a==b) ? x : y;

ve bazen bile böyle şeyler:

if(a==b) { 
   n = x;
   m = y;
} else {
   n = y;
   m = x;
}

Dallanma cezası olmadan birkaç seçme değeri işlemine indirgenir.

Bazı GPU / Sürücüler karşılaştırma operatörü üzerinde iki değer arasında bir miktar ceza almış (?) Ve sıfıra kıyasla daha hızlı bir işlem yapmıştır.

Bunu yapmak daha hızlı nerede olabilir:

gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;

(tmp1 != tmp2)doğrudan karşılaştırmak yerine bu çok GPU'ya ve sürücüye bağlıdır, bu yüzden çok özel bir GPU hedeflemiyorsanız ve başkaları yoksa karşılaştırma işlemini kullanmanızı öneririm ve bu optimizasyon işini OpenGL sürücüsüne başka bir sürücünün daha uzun formla ilgili bir sorunu olabilir ve daha basit, daha okunaklı bir şekilde daha hızlı olun.

"Şubeler" de her zaman kötü bir şey değildir. Örneğin, OpenPandora'da kullanılan SGX530 GPU’da, bu scale2x gölgelendiricisi (30ms):

    lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
    lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
    lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
    lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
    lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
    if ((D - F) * (H - B) == vec3(0.0)) {
            gl_FragColor.xyz = E;
    } else {
            lowp vec2 p = fract(pos);
            lowp vec3 tmp1 = p.x < 0.5 ? D : F;
            lowp vec3 tmp2 = p.y < 0.5 ? H : B;
            gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
    }

Bu eşdeğer gölgelendiriciden (80ms) çok daha hızlı sona erdi:

    lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
    lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
    lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
    lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
    lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
    lowp vec2 p = fract(pos);

    lowp vec3 tmp1 = p.x < 0.5 ? D : F;
    lowp vec3 tmp2 = p.y < 0.5 ? H : B;
    lowp vec3 tmp3 = D == F || H == B ? E : tmp1;
    gl_FragColor.xyz = tmp1 == tmp2 ? tmp3 : E;

Belirli bir GLSL derleyicisinin veya belirli bir GPU'nun, kıyaslama yapana kadar nasıl bir performans göstereceğini önceden asla bilemezsiniz.


Noktaya eklemek için (bu kısım için size sunacak gerçek zamanlama numaralarım ve gölgelendirici kodum olmasa bile) şu anda normal test donanımım olarak kullanıyorum:

  • Intel HD Graphics 3000
  • Intel HD 405 Grafik
  • nVidia GTX 560M
  • nVidia GTX 960
  • AMD Radeon R7 260X
  • nVidia GTX 1050

Test etmek için çok çeşitli, yaygın, GPU modelleri olarak.

Her birini Windows, Linux tescilli ve Linux açık kaynaklı OpenGL & OpenCL sürücüleri ile test etmek.

Ve her zaman belirli bir GPU / Sürücü combo için GLSL gölgelendiricisini (yukarıdaki SGX530 örneğinde olduğu gibi) veya OpenCL işlemlerini mikro-optimize etmeye çalıştığımda , diğer GPU'ların / Sürücülerin birden fazlasında performansı eşit derecede incitiyorum.

Açıkça yüksek seviye matematiksel karmaşıklığı azaltmaktan (ör: 5 aynı bölümü tek bir karşılıklı ve 5 çarpıma dönüştürmek) ve doku aramalarını / bant genişliğini azaltmak dışında, büyük olasılıkla zamanınızı boşa harcarsınız.

Her GPU diğerlerinden çok farklı.

Özellikle (a) belirli bir GPU'lu oyun konsolu / konsollarında çalışıyor olsaydınız, bu farklı bir hikaye olurdu.

Bunun (küçük oyun geliştiricileri için daha az önemli ama yine de dikkat çeken) yönü, bilgisayar GPU sürücülerinin, gölgelerinizi ( oyununuz yeterince popüler hale gelirse ) bir gün sessizce belirli GPU için optimize edilmiş özel yeniden yazılmış yazılımlarla değiştirebilecekleridir. Bunu yapmak senin için işe yarıyor.

Bunu, sık sık kıyaslama olarak kullanılan popüler oyunlar için yapacaklar.

Veya oyuncularınıza gölgelendiricilere erişim izni verirseniz, onları kolayca düzenleyebilirler, bazıları kendi yararları için birkaç FPS daha sıkabilir.

Örneğin, Oblivion için, aksi halde zar zor oynanabilen donanımlarda kare hızını çarpıcı şekilde artıracak fan yapımı gölgelendirici ve doku paketleri var.

Ve son olarak, gölgelendiriciniz yeterince karmaşık hale geldiğinde, oyununuz neredeyse bitti ve farklı donanımlar üzerinde test yapmaya başladığınızda, gölgeleyicilerinizi, istemeyeceğiniz çeşitli hatalar nedeniyle, çeşitli GPU'larda çalışacak şekilde sabitlemeye yetecek kadar meşgul olacaksınız. onları bu dereceye kadar optimize etmek için zamana sahip.


“Veya oyuncularınıza gölgelendiricilere erişim izni verirseniz, onları kolayca düzenleyebilirler…” Bundan bahsettiğinizden beri, duvar kepçeleri ve benzeri şeylere yaklaşımınız ne olabilir? Onur sistemi, doğrulandı, raporlar ...? Ne olursa olsun, aynı gölgelendiriciler / varlıklar ile sınırlı lobiler fikrini seviyorum, çünkü maksimum / dak / ölçeklenebilir gerçekçilik, istismarlar ve benzerleriyle ilgili tavırlar, gözden geçirme, işbirliği vb. Bunun Gary'nin Modunun çalıştığı şekli olduğunu hatırlamak için, ama ben çok iyiyim.
John P,

1
@JohnP Security, müşterinin riske atılmadığını varsayarsak hiçbir şeyin işe yaramadığını akıllıca yapar. Elbette, insanların gölgelendiricilerini düzenlemelerini istemiyorsanız, onları açığa vurmanın bir anlamı yoktur, ancak bu gerçekten güvenlik konusunda pek yardımcı olmuyor. Duvar kepçeleri gibi şeyleri tespit etme stratejiniz, müşteri tarafındaki karışıklıklarla ilk bariyer gibi davranmaya çalışmalı ve oyuncu için tespit edilebilir haksız bir avantaja yol açmazsa, bu modda olduğu gibi hafif modlamaya izin vermenin daha büyük bir yararı olabilir. .
Kübik

8
@JohnP Oyuncuların duvarlardan çok fazla görünmesini istemiyorsanız, sunucunun duvarın arkasında ne olduğu hakkında hiçbir bilgi göndermesine izin vermeyin.
Polygnome

1
İşte bu - Her ne sebeple olursa olsun beğenen oyuncular arasında duvar korsanlığına karşı değilim. Bir oyuncu olarak, birçok AAA başlığını bıraktım, çünkü - diğer nedenlerin yanı sıra - para / XP / vb. bilgisayar korsanları (hiç ödeme yapacak kadar hayal kırıklığına uğrayanların gerçek parasını kazandılar) yaramazlık yaptılar, raporlarını ve temyiz sistemlerini anlamadılar ve otomatikleştirdiler ve hayatta kalmaları için baktıkları sunucuların sayısı ile yaşadıklarından ve öldüklerinden emin oldular. Bir dev ve oyuncu olarak daha merkezi olmayan bir yaklaşım olabileceğini umuyordum.
John P,

Hayır, herhangi bir yerde satır içi yapmam. Sadece
yüzerim

7

@Stephane Hockenhull'un cevabı, bilmeniz gerekenleri size tamamen veriyor, tamamen donanıma bağlı.

Ama sana bazı örnekler verelim nasıl donanım bağımlı olabilir ve neden dallanma hatta dallanma zaman GPU perde arkasında yapar neyi hiç bir sorun olduğunu mu take place.

Benim odak öncelikle Nvidia ile, ben düşük seviyeli CUDA programlama ile biraz tecrübe var ve ne olduğunu görmek ise PTX ( IR CUDA çekirdekleri gibi, SPIR-V oluşturulan ve bazı değişiklikler yapma kriterleri mi göreceğiz ama sadece Nvidia için).

GPU Mimarisinde Dallanma Neden Bu Kadar Önemli?

Neden her şeyden önce dallanmak kötü? GPU'lar neden ilk sırada şube olmaktan kaçınmaya çalışıyor? Çünkü GPU'lar genellikle, iş parçacıklarının aynı komut işaretçisini paylaştığı bir şema kullanır . GPU'lar bir SIMD mimarisini takip ediyortipik olarak ve bunun granülerliği değişebilirken (yani Nvidia için 32 iplik, AMD ve diğerleri için 64 iplik), bir seviyede bir iplik grubu aynı komut göstergesini paylaşır. Bu, aynı sorun üzerinde birlikte çalışmak için bu iş parçacıklarının aynı kod satırına bakması gerektiği anlamına gelir. Aynı kod satırlarını nasıl kullanabileceklerini ve farklı şeyler yapabileceklerini sorabilirsiniz. Kayıtlarda farklı değerler kullanırlar, ancak bu kayıtlar hala tüm grup boyunca aynı kod satırlarında kullanılmaktadır. Durum durduğunda ne olur? (IE bir dal mı?) Program gerçekten etrafında bir yolu yoksa, grubu böler (Nvidia'ya 32 ipliğin bu tür demetleri, Çözgü olarak adlandırılır , AMD ve paralel hesaplama akademisi için dalga kenarı denir)) iki veya daha fazla farklı gruba.

Sonuna kadar koyacağınız sadece iki farklı kod satırı varsa, çalışma başlıkları iki gruba bölünür (buradan bir tanesine çözgü diyeceğim). Hadi, çözgü büyüklüğünün 32 olduğu Nvidia mimarisini varsayalım, bu dişlerin yarısı birbirinden ayrılırsa , 32 aktif iş parçacığı tarafından işgal edilen 2 çözgü elde edersiniz, bu da işleri hesaplamadan başlayarak sonuna kadar verimli yapar. Birçok mimarileri üzerinde GPU bu sorunu çalışacağım yakınlaşan konuları aynı talimat postaneyle ulaştıktan sonra tek çözgü haline geri veya derleyici açıkça geri yakınsama dişlerine GPU söyleyen bir senkronizasyon noktasını koymak veya dener.

Örneğin:

if(a)
    x += z * w;
    q >>= p;
else if(c)
    y -= 3;
r += t;

İplik ayrılma potansiyeline sahiptir (farklı talimat yolları) bu nedenle böyle bir durumda r += t;, işaretçilerin tekrar aynı olacağı yerde birleşme olabilir . Ayrışma ikiden fazla dalda da olabilir, bu da daha düşük çözgü kullanımıyla sonuçlanır, dört dal, 32 ipliğin 4 çözgü,% 25 verim kullanımı şeklinde ayrılması anlamına gelir. Bununla birlikte, yakınsama bu sorunların bazılarını gizleyebilir, çünkü% 25'i programın tamamında üretimde kalmıyor.

Daha az karmaşık GPU'larda başka sorunlar ortaya çıkabilir. Daldırma yerine sadece tüm dalları hesaplarlar ve sonunda çıktıyı seçerler. Bu, farklılaşma ile aynı görünebilir (her ikisi de 1 / n verimlilik kullanımına sahip), ancak çoğaltma yaklaşımında birkaç ana sorun var.

Birincisi güç kullanımı, hiç dallanma olduğunda çok daha fazla güç kullanıyor olmanız, mobil gpus için kötü olacaktır. İkincisi, ayrılma sadece Nvidia gpus'ta, aynı çözgü ipliklerinin farklı yollar alması ve böylece farklı bir komut göstergesine sahip olması (paskal olarak paylaşılan) olmasıdır. Böylece, Nvidia GPU'larda, 32'nin katlarında meydana gelirlerse ya da sadece düzinelerce tek bir çözgüde meydana gelirlerse, verim sorunları olabilir. eğer bir dalın oluşması muhtemelse, daha az sayıda iş parçacığı birbirinden ayrılır ve yine de dallanma sorunu yaşamayacaksınızdır.

Başka bir küçük sorun ise, GPU'ları CPU'larla karşılaştırdığınızda, bu mekanizmaların ne kadar donanım kullandığı nedeniyle genellikle tahmin mekanizmalarına ve diğer sağlam dal mekanizmalarına sahip değillerdir , bu nedenle modern GPU'lar için genellikle no-op dolgusunu görebilirsiniz .

Pratik GPU Mimari Fark Örneği

Şimdi Stephanes örneğini ele alalım ve iki teorik mimaride meclisin şubesiz çözümler için nasıl görüneceğini görelim.

n = (a==b) ? x : y;

Stephane’in dediği gibi, cihaz derleyici bir dalla karşılaştığında, branş cezası olmayacak olan “seçim” elemanını kullanmaya karar verebilir. Bu, bazı cihazlarda bunun gibi bir şeye derleneceği anlamına gelir

cmpeq rega, regb
// implicit setting of comparison bit used in next part
choose regn, regx, regy

Seçim talimatı olmayan diğerlerinde ise derlenebilir.

n = ((a==b))* x + (!(a==b))* y

hangi gibi görünebilir:

cmpeq rega regb
// implicit setting of comparison bit used in next part
mul regn regcmp regx
xor regcmp regcmp 1
mul regresult regcmp regy
mul regn regn regresult

ki bu dalsız ve eşdeğerdir, ancak daha fazla talimat alır. Stephanes örneği muhtemelen kendi sistemlerinden birinde derleneceğinden, ilk mimarinin derleyicisi yerine ikinci forma derlemeye karar verebileceğinden dallanmayı kendimiz kaldırmak için matematiği elle bulmaya çalışmak mantıklı değildir. daha hızlı form.


5

@ Stephane Hockenhull'un cevabında söylenen her şey ile hemfikir. Son noktada genişletmek için:

Belirli bir GLSL derleyicisinin veya belirli bir GPU'nun, kıyaslama yapana kadar nasıl bir performans göstereceğini önceden asla bilemezsiniz.

Kesinlikle doğru. Ayrıca, bu tür bir sorunun oldukça sık ortaya çıktığını görüyorum. Fakat pratikte nadiren bir performans sorununun kaynağı olan bir parça gölgelendiricisi gördüm. Diğer faktörlerin GPU'dan çok fazla durum okuması, çok fazla arabellek takas etmek, tek bir beraberlik çağrısında çok fazla çalışmak, vb. Gibi sorunlara neden olması çok daha yaygındır.

Başka bir deyişle, bir gölgelendiricinin mikro optimizasyonundan endişe etmeden önce uygulamanızın tamamını görüntüleyin ve gölgelendiricinin yavaşlamanıza neden olan şey olduğundan emin olun.

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.