मुझे " सीमा " के संदर्भ में प्रदर्शन के बारे में सोचना पसंद है । यह एक काफी जटिल, परस्पर प्रणाली को अवधारणा करने का एक आसान तरीका है। जब आपके पास प्रदर्शन की समस्या होती है, तो आप सवाल पूछते हैं: "मैं किस सीमा तक मार रहा हूं?" (या: "क्या मैं सीपीयू / जीपीयू बाध्य हूं?")
आप इसे कई स्तरों में तोड़ सकते हैं। उच्चतम स्तर पर आपके पास सीपीयू और जीपीयू है। आप सीपीयू बाउंड (जीपीयू सिटिंग आइडल सीपीयू के इंतजार में) हो सकते हैं, या जीपीयू बाउंड (सीपीयू जीपीयू पर इंतजार कर रहे हैं)। यहाँ विषय पर एक अच्छा ब्लॉग पोस्ट है ।
आप इसे और नीचे तोड़ सकते हैं। पर सीपीयू ओर, आप सीपीयू कैश में पहले से ही डेटा पर अपने सभी चक्रों का उपयोग कर हो सकता है। या हो सकता है कि आप मेमोरी सीमित हों , जिससे मुख्य मेमोरी से डेटा के आने के लिए सीपीयू बेकार हो जाए ( इसलिए अपने डेटा लेआउट को ऑप्टिमाइज़ करें )। आप इसे अभी और भी तोड़ सकते हैं।
(हालांकि मैं एक्सएनए के संबंध में प्रदर्शन का एक विस्तृत अवलोकन कर रहा हूं, मैं इंगित करूंगा कि एक संदर्भ प्रकार का आवंटन ( class
नहीं struct
), जबकि सामान्य रूप से सस्ता है, कचरा कलेक्टर को ट्रिगर कर सकता है, जो बहुत सारे चक्रों को जला देगा - विशेष रूप से Xbox 360 पर । यहाँ देखें जानकारी के लिए)।
पर GPU ओर, मैं करने के लिए आप इंगित कर बाहर शुरू करेंगे इस उत्कृष्ट ब्लॉग पोस्ट जो विवरण के बहुत सारे है। यदि आप पाइपलाइन पर विस्तार का एक पागल स्तर चाहते हैं , तो ब्लॉग पोस्ट की इस श्रृंखला को पढ़ें । ( यहाँ एक सरल है )।
इसे सीधे शब्दों में कहें, तो कुछ बड़े हैं: " भरण सीमा " (आप बैकबफ़र को कितने पिक्सेल लिख सकते हैं - अक्सर आपके पास कितना ओवरड्राइव हो सकता है), " शेडर लिमिट " (आपके शेड्स कितने जटिल हो सकते हैं) आप कितने डेटा को उनके माध्यम से धकेल सकते हैं), " टेक्सचर-फ़िच / टेक्सचर-बैंडविड्थ लिमिट " (बनावट का कितना डेटा आप एक्सेस कर सकते हैं)।
और, अब, हम बड़े पर आते हैं - जो कि आप वास्तव में पूछ रहे हैं - जहां सीपीयू और जीपीयू को (विभिन्न एपीआई और ड्राइवरों के माध्यम से) इंटरैक्ट करना पड़ता है। धीरे-धीरे " बैच सीमा " और " बैंडविड्थ " है। (ध्यान दें कि मेरे द्वारा पहले बताई गई श्रृंखला में से एक हिस्सा व्यापक विवरण में चला गया है ।)
लेकिन, मूल रूप से, एक बैच ( जैसा कि आप पहले से ही जानते हैं ) तब भी होता है जब आप किसी एक GraphicsDevice.Draw*
फ़ंक्शन (या एक्सएनए का हिस्सा, जैसे SpriteBatch
, आपके लिए ऐसा करता है) कहते हैं। जैसा कि आप कोई संदेह पहले से ही पढ़ चुके हैं, आपको प्रति फ्रेम कुछ हजार * मिलते हैं । यह एक सीपीयू सीमा है - इसलिए यह आपके अन्य सीपीयू उपयोग के साथ प्रतिस्पर्धा करता है। यह मूल रूप से ड्रायवर है जो आपने इसे तैयार करने, और इसे GPU पर भेजने के बारे में बताया है।
और फिर GPU के लिए बैंडविड्थ है। यह है कि आप कितना कच्चा डेटा वहां स्थानांतरित कर सकते हैं। इसमें सभी राज्य जानकारी शामिल है जो बैचों के साथ जाती है - DrawUser*
कार्यों का उपयोग करते समय लंबवत करने के लिए प्रतिपादन राज्य और shader स्थिरांक / पैरामीटर (जिसमें विश्व / दृश्य / प्रोजेक्ट मैट्रिस जैसी चीजें शामिल हैं) सेट करने से सब कुछ शामिल है । यह भी करने के लिए कोई कॉल भी शामिल SetData
और GetData
बनावट, शिखर बफ़र्स, आदि पर
इस बिंदु पर मुझे यह कहना चाहिए कि कुछ भी जिसे आप SetData
(बनावट, शीर्ष और सूचकांक बफ़र्स, आदि) पर कॉल कर सकते हैं , साथ ही साथ Effect
GPU मेमोरी में रहता है। इसे लगातार GPU में दोबारा नहीं भेजा जाता है। एक ड्रॉ कमांड जो उस डेटा को केवल एक पॉइंटर के साथ भेजा जाता है, उस संदर्भ को संदर्भित करता है।
(इसके अलावा, आप केवल मुख्य थ्रेड से ड्रॉ कमांड भेज सकते हैं, लेकिन आप SetData
किसी भी धागे पर कर सकते हैं ।)
XNA इसकी प्रस्तुत करना राज्य वर्गों (साथ कुछ हद तक बातें पेचीदा हो BlendState
, DepthStencilState
, आदि)। यह स्टेट डेटा प्रति ड्रा कॉल (प्रत्येक बैच में) भेजा जाता है । मुझे 100% यकीन नहीं है, लेकिन मैं इस धारणा के तहत हूं कि इसे आलसी (इसे केवल राज्य भेजता है जो बदलता है) भेजा जाता है। किसी भी तरह से, राज्य परिवर्तन एक बैच की लागत के सापेक्ष, मुफ्त के बिंदु पर सस्ते हैं।
अंत में, उल्लेख करने के लिए अंतिम बात आंतरिक GPU पाइपलाइन है । आप डेटा को लिखने के लिए इसे फ्लश करने के लिए मजबूर नहीं करना चाहते हैं कि इसे अभी भी पढ़ना है, या डेटा को पढ़ना है जिसे इसे अभी भी लिखना है। एक पाइपलाइन फ्लश का मतलब है कि यह ऑपरेशन खत्म होने का इंतजार करता है, ताकि डेटा एक्सेस होने पर सब कुछ एक सुसंगत स्थिति में हो।
दो विशेष मामलों को देखने के लिए: GetData
कुछ भी गतिशील पर कॉल करना - विशेष रूप से RenderTarget2D
उस पर जो GPU के लिए लिख रहा हो सकता है। यह प्रदर्शन के लिए बहुत बुरा है - ऐसा न करें।
अन्य मामला SetData
शीर्ष / सूचकांक बफ़र्स पर कॉल कर रहा है । यदि आपको अक्सर ऐसा करने की आवश्यकता होती है, तो DynamicVertexBuffer
(भी DynamicIndexBuffer
) का उपयोग करें । ये GPU को यह जानने की अनुमति देते हैं कि वे अक्सर बदलते रहेंगे, और पाइपलाइन फ्लश से बचने के लिए आंतरिक रूप से कुछ बफ़रिंग जादू करेंगे।
(यह भी ध्यान दें कि गतिशील बफ़र DrawUser*
विधियों की तुलना में तेज़ हैं - लेकिन उन्हें अधिकतम आवश्यक आकार पर पूर्व-आवंटित करना होगा।)
... और वह सब कुछ है जो मुझे XNA प्रदर्शन के बारे में पता है :)