अगर DirectX 10 शेड्स में बयान से बचें?


14

मैंने सुना है कि अगर बयानों को शादियों से बचना चाहिए, क्योंकि बयानों के दोनों हिस्सों को निष्पादित किया जाएगा, और गलत की तुलना में गिरा दिया जाएगा (जो प्रदर्शन को नुकसान पहुंचाता है)।

यह अभी भी DirectX 10 में एक समस्या है? किसी ने मुझे बताया, कि इसमें केवल सही शाखा निष्पादित होगी।

चित्रण के लिए मेरे पास कोड है:

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;
}

क्या इसे तेज करने का कोई और तरीका है?

यदि हां, तो यह कैसे होता है?

दोनों शाखाएं समान दिखती हैं, एकमात्र अंतर "स्थिरांक" के मूल्य y1, y2, b1, b2हैं ( पिक्सेल शैडर में सभी पिक्सेल के लिए समान हैं)।


1
ईमानदारी से, यह बहुत ही समयपूर्व अनुकूलन है, बस उन्हें तब तक न बदलें जब तक आप अपने कोड को बेंचमार्क नहीं करते हैं और यह 100% है कि shader एक अड़चन है।
pwny

जवाबों:


17

माइक्रो-ऑप्टिमाइज़िंग शेड के लिए कई नियम वेक्टर एक्सटेंशन के साथ पारंपरिक सीपीयू के लिए समान हैं। यहाँ कुछ संकेत दिए गए हैं:

  • अंतर्निहित परीक्षण कार्य ( test, lerp/ mix) हैं
  • दो फ़्लोटर्स को जोड़ने में दो फ़्लैट जोड़ने के समान लागत होती है
  • स्वाज़लिंग मुफ्त है

यह सच है कि शाखाएँ आधुनिक हार्डवेयर की तुलना में सस्ती होती हैं, जो पहले हुआ करती थीं, लेकिन यदि संभव हो तो उनसे बचना अभी भी बेहतर है। स्विज़लिंग और परीक्षण कार्यों का उपयोग करके आप परीक्षण के बिना अपने शेडर को फिर से लिख सकते हैं:

/* y1, y2, b1, b2 */
float4 constants = float4(5, 6, 2, 3);

float2 tmp = 10 * constants.xy + constants.zw;
x = lerp(tmp[1], tmp[0], step(x, 0.5));

का उपयोग करना stepऔर lerpदो मूल्यों के बीच चयन करने के लिए एक बहुत ही सामान्य मुहावरा है।


6

आम तौर पर यह ठीक है। शेड्स कोने या पिक्सेल के समूहों में निष्पादित होंगे (विभिन्न विक्रेताओं के पास इन के लिए अलग शब्दावली है इसलिए मैं इससे दूर रह रहा हूं) और यदि समूह में सभी कोने या पिक्सेल समान पथ लेते हैं तो ब्रांचिंग लागत नगण्य है।

आपको shader संकलक पर भरोसा करने की भी आवश्यकता है। आपके द्वारा लिखा गया एचएलएसएल कोड को बाईटेकोड या यहां तक ​​कि असेंबली के प्रत्यक्ष प्रतिनिधित्व के रूप में नहीं देखा जाना चाहिए जो इसे संकलित करेगा, और संकलक इसे किसी चीज़ के रूप में परिवर्तित करने के लिए पूरी तरह से स्वतंत्र है, लेकिन शाखा से बचता है (जैसे एक लार्प कभी-कभी शामिल हो सकता है) एक पसंदीदा रूपांतरण)। दूसरी ओर, यदि संकलक यह निर्धारित करता है कि एक शाखा का प्रदर्शन वास्तव में तेज़ पथ है, तो यह इसे एक शाखा के लिए संकलित करेगा। PIX या इसी तरह के उपकरण में उत्पन्न विधानसभा को देखना यहां बहुत मददगार हो सकता है।

अंत में, पुरानी बुद्धि अभी भी यहां है - इसे प्रोफाइल करें, यह निर्धारित करें कि क्या यह वास्तव में आपके लिए एक प्रदर्शन समस्या है, और इससे पहले निपटें, इससे पहले नहीं। यह मानते हुए कि कुछ प्रदर्शन की समस्या हो सकती है और उस धारणा के अनुसार काम करना बाद में बड़ी समस्याओं का एक बड़ा खतरा होगा।


4

रॉबर्ट रूहानी द्वारा पोस्ट किए गए लिंक / लेख से उद्धरण:

"स्थिति कोड (पूर्वानुमान) का उपयोग पुराने आर्किटेक्चर में सच्चे ब्रांचिंग का अनुकरण करने के लिए किया जाता है। यदि इन आर्किटेक्चर के लिए संकलित किए गए बयानों को सभी टुकड़ों पर शाखा निर्देशों को लिया और नहीं जाना चाहिए दोनों का मूल्यांकन करना होगा। शाखा की स्थिति का मूल्यांकन किया जाता है और एक शर्त कोड निर्धारित किया जाता है।" शाखा के प्रत्येक भाग के निर्देशों को रजिस्टर करने के लिए अपना परिणाम लिखने से पहले स्थिति कोड के मूल्य की जांच करनी चाहिए। नतीजतन, केवल ली गई शाखाओं में दिए गए निर्देश अपना आउटपुट लिखते हैं। इस प्रकार, इन आर्किटेक्चर में सभी शाखाओं की लागत दोनों भागों के बराबर होती है। शाखा, साथ ही शाखा की स्थिति का मूल्यांकन करने की लागत। ऐसे आर्किटेक्चर पर शाखाओं का उपयोग संयम से किया जाना चाहिए। NVIDIA GeForce FX सीरीज GPUs अपने खंड प्रोसेसर में स्थिति-कोड शाखा अनुकरण का उपयोग करते हैं। "

जैसा कि m0101 ने सुझाव दिया ("PIX में जनरेट किए गए असेंबली को देखना या एक समान टूल यहां बहुत उपयोगी हो सकता है।"), आपको आउटपुट की जांच करने के लिए एक कंपाइलर टूल का उपयोग करना चाहिए। मेरे अनुभव में, nVidia का Cg टूल (Cg अभी भी व्यापक रूप से इसकी क्रॉस प्लेटफ़ॉर्म क्षमताओं के कारण आज भी उपयोग किया जाता है) ने GPU शेप में उल्लिखित व्यवहार का एक सही चित्रण दिया स्थिति कोड (प्रिडिक्शन) पैराग्राफ । इस प्रकार, ट्रिगर मूल्य की परवाह किए बिना, दोनों शाखाओं का मूल्यांकन प्रति टुकड़े के आधार पर किया गया था, और केवल अंत में, सही को आउटपुट रजिस्ट्री में रखा गया था। फिर भी, गणना समय बर्बाद हो गया था। इसके बाद, मैंने सोचा कि ब्रांचिंग प्रदर्शन में मदद करेगी, खासकर क्योंकि सभीउस shader में टुकड़े सही शाखा पर निर्णय लेने के लिए एक समान मूल्य पर निर्भर करते थे - जैसा कि इरादा नहीं था। तो, यहाँ एक प्रमुख चेतावनी (जैसे ubershaders से बचें - संभवतः शाखा नरक का सबसे बड़ा स्रोत)।


2

यदि आप पहले से ही प्रदर्शन समस्याएँ नहीं हैं, तो यह ठीक है। एक निरंतर के खिलाफ तुलना के लिए लागत अभी भी बहुत सस्ती है। यहाँ GPU शाखाओं के बारे में एक अच्छा पढ़ा है: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter34.html

भले ही, यहाँ कोड का एक स्निपेट है जो कि यदि कथन से बहुत खराब है (और बहुत कम पठनीय / बनाए रखने योग्य है), लेकिन फिर भी इससे छुटकारा मिल जाता है:

int fx = floor(x);
int y = (fx * y2) + ((1- fx) * y1);
int b = (fx * b2) + ((1 -fx) * b1);

x = 10 * y + b;

ध्यान दें कि मैं यह धारणा बना रहा हूं कि x सीमा तक सीमित है [0, 1]। यह काम नहीं करेगा यदि x> = 2 या x <0।

जो छीनता है वह x को या तो परिवर्तित करता है 0या 1गलत को 0 से और दूसरे को 1 से गुणा करता है।


चूंकि मूल परीक्षण के if(x<0.5)लिए मूल्य fxहोना चाहिए round(x)या है floor(x + 0.5)
सैम होसेवर

1

ब्रांचिंग के बिना शर्तों को करने में सक्षम कई निर्देश हैं;

vec4 when_eq(vec4 x, vec4 y) {
  return 1.0 - abs(sign(x - y));
}

vec4 when_neq(vec4 x, vec4 y) {
  return abs(sign(x - y));
}

vec4 when_gt(vec4 x, vec4 y) {
  return max(sign(x - y), 0.0);
}

vec4 when_lt(vec4 x, vec4 y) {
  return max(sign(y - x), 0.0);
}

vec4 when_ge(vec4 x, vec4 y) {
  return 1.0 - when_lt(x, y);
}

vec4 when_le(vec4 x, vec4 y) {
  return 1.0 - when_gt(x, y);
}

प्लस कुछ तार्किक ऑपरेटरों;

vec4 and(vec4 a, vec4 b) {
  return a * b;
}

vec4 or(vec4 a, vec4 b) {
  return min(a + b, 1.0);
}

vec4 xor(vec4 a, vec4 b) {
  return (a + b) % 2.0;
}

vec4 not(vec4 a) {
  return 1.0 - a;
}

स्रोत: http://theorangeduck.com/page/avoiding-shader-conditionals

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.