फ़्रेम पेसिंग लाइब्रेरी Android Game Development Kit का हिस्सा है.
Android फ़्रेम पेसिंग लाइब्रेरी, जिसे Swappy भी कहा जाता है, AGDK लाइब्रेरी का हिस्सा है. इससे OpenGL और Vulkan गेम को Android पर आसानी से रेंडर करने और सही फ़्रेम पेसिंग में मदद मिलती है. इस दस्तावेज़ में फ़्रेम पेसिंग के बारे में बताया गया है. साथ ही, उन स्थितियों के बारे में बताया गया है जहां फ़्रेम पेसिंग की ज़रूरत होती है. साथ ही, यह भी बताया गया है कि लाइब्रेरी इन स्थितियों को कैसे हल करती है. अगर आपको सीधे अपने गेम में फ़्रेम पेसिंग लागू करनी है, तो अगला चरण देखें.
बैकग्राउंड
फ़्रेम पेसिंग, किसी गेम के लॉजिक और रेंडरिंग लूप को ऑपरेटिंग सिस्टम के डिसप्ले सबसिस्टम और डिसप्ले हार्डवेयर के साथ सिंक करने की प्रोसेस है. Android डिसप्ले सबसिस्टम को इस तरह से डिज़ाइन किया गया है कि डिसप्ले हार्डवेयर के अपडेट के दौरान, टियरिंग जैसी गड़बड़ियां न हों. इन आर्टफ़ैक्ट से बचने के लिए, डिसप्ले सबसिस्टम ये काम करता है:
- पिछले फ़्रेम को अंदरूनी तौर पर बफ़र करता है
- देर से सबमिट किए गए फ़्रेम का पता लगाता है
- देर से आने वाले फ़्रेम का पता चलने पर, पिछले फ़्रेम को दोबारा दिखाता है
कोई गेम, डिसप्ले सबसिस्टम में मौजूद कंपोजिटर SurfaceFlinger को बताता है कि उसने eglSwapBuffers
या vkQueuePresentKHR
को कॉल करके, फ़्रेम के लिए ज़रूरी सभी ड्रॉ कॉल सबमिट कर दिए हैं. SurfaceFlinger, लैच का इस्तेमाल करके डिसप्ले हार्डवेयर को फ़्रेम की उपलब्धता का सिग्नल देता है. इसके बाद, डिसप्ले हार्डवेयर उस फ़्रेम को दिखाता है. डिसप्ले हार्डवेयर एक तय दर पर काम करता है, जैसे कि 60 हर्ट्ज़. अगर हार्डवेयर को नए फ़्रेम की ज़रूरत पड़ने पर कोई नया फ़्रेम नहीं मिलता है, तो हार्डवेयर पिछले फ़्रेम को फिर से दिखाता है.
फ़्रेम के बीच का समय अलग-अलग होने की समस्या अक्सर तब होती है, जब गेम रेंडर लूप, नेटिव डिसप्ले हार्डवेयर से अलग दर पर रेंडर करता है. अगर 30 FPS पर चलने वाला गेम, ऐसे डिवाइस पर रेंडर करने की कोशिश करता है जो नेटिव तौर पर 60 FPS पर काम करता है, तो गेम रेंडर करने वाले लूप को पता नहीं चलता कि दोहराया गया फ़्रेम, स्क्रीन पर 16 मिलीसेकंड तक दिखता है. आम तौर पर, इस डिसकनेक्ट की वजह से फ़्रेम के समय में काफ़ी अंतर होता है. जैसे: 49 मिलीसेकंड, 16 मिलीसेकंड, 33 मिलीसेकंड. ज़्यादा मुश्किल सीन होने पर, यह समस्या और भी बढ़ जाती है, क्योंकि इनमें फ़्रेम छूटने की समस्या आती है.
गलत समाधान
फ़्रेम पेसिंग के लिए, नीचे दिए गए समाधानों का इस्तेमाल पहले गेम में किया गया था. आम तौर पर, इनसे फ़्रेम के बीच का समय अलग-अलग होता है और इनपुट में लगने वाला समय बढ़ जाता है.
रेंडरिंग एपीआई की अनुमति के मुताबिक, फ़्रेम को जल्द से जल्द सबमिट करना
इस तरीके से, गेम को वैरिएबल SurfaceFlinger गतिविधि से जोड़ा जाता है और इसमें अतिरिक्त फ़्रेम के इंतज़ार का समय शामिल होता है. डिसप्ले पाइपलाइन में फ़्रेम की एक सूची होती है, आम तौर पर जिसका साइज़ दो होता है. अगर गेम फ़्रेम को बहुत तेज़ी से दिखाने की कोशिश करता है, तो यह सूची भर जाती है. सूची में जगह न होने पर, OpenGL या Vulkan कॉल से गेम लूप (या कम से कम रेंडरिंग थ्रेड) ब्लॉक हो जाता है. इसके बाद, गेम को डिसप्ले हार्डवेयर के फ़्रेम दिखाने का इंतज़ार करना पड़ता है. इस बैक-प्रेशर से, दोनों कॉम्पोनेंट सिंक हो जाते हैं. इस स्थिति को बफ़र-स्टफ़िंग या क्यू-स्टफ़िंग कहा जाता है. रेंडर करने की प्रोसेस को पता नहीं चलता कि क्या हो रहा है. इसलिए, फ़्रेम रेट में उतार-चढ़ाव की समस्या और भी बढ़ जाती है. अगर गेम, फ़्रेम से पहले इनपुट सैंपल करता है, तो इनपुट में लगने वाला समय बढ़ जाता है.
Android Choreographer का अपने-आप इस्तेमाल होना
गेम भी सिंक करने के लिए, Android Choreographer का इस्तेमाल करते हैं. यह कॉम्पोनेंट, एपीआई 16 से Java में और एपीआई 24 से C++ में उपलब्ध है. यह डिसप्ले सबसिस्टम की उसी फ़्रीक्वेंसी पर नियमित टिक डिलीवर करता है. हालांकि, इस बात में अब भी कुछ बारीकियां हैं कि यह टिक, असल हार्डवेयर VSYNC के हिसाब से कब डिलीवर की जाती है. साथ ही, ये ऑफ़सेट डिवाइस के हिसाब से अलग-अलग होते हैं. लंबे फ़्रेम के लिए, बफ़र-स्टफ़िंग अब भी हो सकती है.
फ़्रेम पेसिंग लाइब्रेरी के फ़ायदे
फ़्रेम पेसिंग लाइब्रेरी, सिंक करने के लिए Android Choreographer का इस्तेमाल करती है. साथ ही, टिक डिलीवरी में होने वाली बदलावों को मैनेज करती है. यह प्रज़ेंटेशन के टाइमस्टैंप का इस्तेमाल करके, यह पक्का करता है कि फ़्रेम सही समय पर दिखाए जाएं. साथ ही, बफ़र स्टफ़िंग से बचने के लिए, फ़ेंस सिंक करता है. अगर NDK Choreographer उपलब्ध है, तो लाइब्रेरी उसका इस्तेमाल करती है. अगर यह उपलब्ध नहीं है, तो Java Choreographer का इस्तेमाल किया जाता है.
अगर डिवाइस पर एक से ज़्यादा रीफ़्रेश रेट काम करते हैं, तो लाइब्रेरी उनका इस्तेमाल करती है. इससे गेम को फ़्रेम दिखाने में ज़्यादा आसानी होती है. उदाहरण के लिए, अगर किसी डिवाइस पर 60 हर्ट्ज़ और 90 हर्ट्ज़, दोनों रीफ़्रेश रेट काम करते हैं, तो ऐसा गेम जो 60 फ़्रेम प्रति सेकंड नहीं दिखा सकता है वह 30 के बजाय 45 फ़्रेम प्रति सेकंड पर चल सकता है, ताकि गेमिंग अनुभव बेहतर बना रहे. लाइब्रेरी, गेम के अनुमानित फ़्रेम रेट का पता लगाती है और इसके हिसाब से फ़्रेम के प्रज़ेंटेशन के समय में अपने-आप बदलाव करती है. फ़्रेम पेसिंग लाइब्रेरी से बैटरी लाइफ़ भी बेहतर होती है, क्योंकि इससे डिसप्ले के ग़ैर-ज़रूरी अपडेट से बचा जा सकता है. उदाहरण के लिए, अगर कोई गेम 60 एफ़पीएस पर रेंडर हो रहा है, लेकिन डिसप्ले 120 हर्ट्ज़ पर अपडेट हो रहा है, तो हर फ़्रेम के लिए स्क्रीन दो बार अपडेट होती है. फ़्रेम पेसिंग लाइब्रेरी, रीफ़्रेश रेट को डिवाइस के लिए काम करने वाली वैल्यू पर सेट करके, इस समस्या से बचती है. यह वैल्यू, टारगेट फ़्रेम रेट के सबसे करीब होती है.
यह कैसे काम करता है
यहां दिए गए सेक्शन में बताया गया है कि फ़्रेम पेसिंग लाइब्रेरी, सही फ़्रेम पेसिंग पाने के लिए, गेम के लंबे और छोटे फ़्रेम को कैसे मैनेज करती है.
30 हर्ट्ज़ पर फ़्रेम पेसिंग को ठीक करना
60 हर्ट्ज़ वाले डिवाइस पर 30 हर्ट्ज़ पर रेंडर करने पर, Android पर सबसे सही स्थिति, पहले चित्र में दिखाई गई है. अगर मौजूद हैं, तो SurfaceFlinger नए ग्राफ़िक बफ़र को लॉच करता है (डायग्राम में NB, "कोई बफ़र नहीं" मौजूद है और पिछले बफ़र को दोहराया गया है).
पहली इमेज. 60 हर्ट्ज़ वाले डिवाइस पर, 30 हर्ट्ज़ पर फ़्रेम पेसिंग का सबसे सही विकल्प.
गेम के फ़्रेम कम होने की वजह से, गेम में रुकावट आना
ज़्यादातर आधुनिक डिवाइसों पर, गेम इंजन, फ़्रेम सबमिट करने के लिए, प्लैटफ़ॉर्म को निर्देश देने वाले प्रोग्राम पर निर्भर होते हैं. हालांकि, छोटे फ़्रेम की वजह से, फ़्रेम की पेसिंग खराब हो सकती है. इसकी जानकारी दूसरे फ़ोटो में दी गई है. वीडियो में छोटे फ़्रेम के बाद लंबे फ़्रेम दिखने पर, प्लेयर को वीडियो रुक-रुककर चलने जैसा महसूस होता है.
दूसरी इमेज. गेम का छोटा फ़्रेम C, फ़्रेम B में सिर्फ़ एक फ़्रेम दिखाता है. इसके बाद, कई C फ़्रेम दिखते हैं.
फ़्रेम पेसिंग लाइब्रेरी, प्रज़ेंटेशन के टाइमस्टैंप का इस्तेमाल करके इस समस्या को हल करती है. लाइब्रेरी, प्रज़ेंटेशन टाइमस्टैंप एक्सटेंशन EGL_ANDROID_presentation_time
और VK_GOOGLE_display_timing
का इस्तेमाल करती है, ताकि फ़्रेम जल्दी न दिखाए जाएं. इस बारे में तीसरे चित्र में बताया गया है.
तीसरी इमेज. गेम फ़्रेम B को ज़्यादा स्मूद डिसप्ले के लिए दो बार दिखाया गया है.
लंबे फ़्रेम की वजह से वीडियो में रुकावट आती है और उसे लोड होने में ज़्यादा समय लगता है
जब डिसप्ले वर्कलोड, ऐप्लिकेशन वर्कलोड से ज़्यादा समय लेता है, तो अतिरिक्त फ़्रेम को सूची में जोड़ दिया जाता है. इससे, वीडियो में रुकावट आती है. साथ ही, बफ़र-स्टफ़िंग की वजह से, फ़्रेम में देरी भी हो सकती है (चित्र 4 देखें). लाइब्रेरी, वीडियो में रुकावट और लैटेंसी के अतिरिक्त फ़्रेम को हटा देती है.
चौथी इमेज. लंबा फ़्रेम B, दो फ़्रेम—A और B के लिए गलत पेसिंग देता है
लाइब्रेरी, सिंक फ़ेंस (EGL_KHR_fence_sync
और VkFence
) का इस्तेमाल करके, ऐप्लिकेशन में इंतज़ार का समय जोड़ती है. इससे डिसप्ले पाइपलाइन को बैक प्रेशर बढ़ने से बचाने के बजाय, उसे अप-टू-डेट रखने में मदद मिलती है. फ़्रेम A में अब भी एक अतिरिक्त फ़्रेम दिख रहा है, लेकिन फ़्रेम B अब सही तरीके से दिख रहा है, जैसा कि पांचवीं इमेज में दिखाया गया है.
पांचवीं इमेज. फ़्रेम C और D, दिखाए जाने का इंतज़ार करते हैं.
काम करने के मोड
फ़्रेम पेसिंग लाइब्रेरी को इन तीन में से किसी एक मोड में काम करने के लिए कॉन्फ़िगर किया जा सकता है:
- ऑटो मोड बंद है + पाइपलाइन
- ऑटो मोड चालू है + पाइपलाइन
- ऑटो मोड चालू है + ऑटो पाइपलाइन मोड (पाइपलाइन/नॉन-पाइपलाइन)
सुझाया गया मोड
ऑटो-मोड और पाइपलाइन मोड को आज़माया जा सकता है. हालांकि, इसके लिए आपको पहले इन्हें बंद करना होगा. इसके बाद, Swappy को शुरू करने के बाद ये शामिल करें:
swappyAutoSwapInterval(false);
swappyAutoPipelineMode(false);
swappyEnableStats(false);
swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);
पाइपलाइन मोड
इंजन के वर्कलोड को मैनेज करने के लिए, लाइब्रेरी आम तौर पर पाइपलाइन मॉडल का इस्तेमाल करती है. यह मॉडल, VSYNC सीमाओं के हिसाब से सीपीयू और GPU के वर्कलोड को अलग करता है.
छठी इमेज. पाइपलाइन मोड.
नॉन-पाइपलाइन मोड
आम तौर पर, इस तरीके से इनपुट-स्क्रीन के रिस्पॉन्स में कम समय लगता है और यह अनुमान लगाना आसान हो जाता है कि स्क्रीन पर कितनी देर में जानकारी दिखेगी. जिन मामलों में किसी गेम का फ़्रेम टाइम बहुत कम होता है उनमें सीपीयू और जीपीयू, दोनों का वर्कलोड एक ही स्वैप इंटरवल में फ़िट हो सकता है. इस मामले में, बिना पाइपलाइन वाले तरीकों से, इनपुट-स्क्रीन के इंतज़ार का समय कम होगा.
सातवीं इमेज. नॉन-पाइपलाइन मोड.
ऑटो मोड
ज़्यादातर गेम, स्वैप इंटरवल चुनने का तरीका नहीं जानते. यह वह अवधि होती है जिसके लिए हर फ़्रेम दिखाया जाता है. उदाहरण के लिए, 30 हर्ट्ज़ के लिए 33.3 मिलीसेकंड. कुछ डिवाइसों पर, गेम 60 FPS पर रेंडर हो सकता है, जबकि किसी दूसरे डिवाइस पर उसे कम फ़्रेम रेट पर रेंडर करना पड़ सकता है. ऑटो मोड, सीपीयू और जीपीयू के इस्तेमाल के समय को मेज़र करता है, ताकि ये काम किए जा सकें:
- स्वाप इंटरवल अपने-आप चुनना: कुछ सीन में 30 हर्ट्ज़ और कुछ में 60 हर्ट्ज़ पर चलने वाले गेम के लिए, लाइब्रेरी इस इंटरवल को डाइनैमिक तौर पर अडजस्ट कर सकती है.
- ज़्यादा तेज़ फ़्रेम के लिए, पाइपलाइनिंग की सुविधा बंद करना: इससे सभी मामलों में इनपुट-स्क्रीन लेटेंसी को ऑप्टिमाइज़ किया जाता है.
रीफ़्रेश रेट के कई विकल्प
एक से ज़्यादा रीफ़्रेश रेट वाले डिवाइसों पर, स्क्रीन स्विच करने के लिए बेहतर इंटरवल चुना जा सकता है:
- 60 हर्ट्ज़ वाले डिवाइसों पर: 60 FPS / 30 FPS / 20FPS
- 60 हर्ट्ज़ और 90 हर्ट्ज़ वाले डिवाइसों पर: 90 FPS / 60 FPS / 45 FPS / 30 FPS
- 60 हर्ट्ज़ + 90 हर्ट्ज़ + 120 हर्ट्ज़ वाले डिवाइसों पर: 120 FPS / 90 FPS / 60 FPS / 45 FPS / 40 FPS / 30 FPS
लाइब्रेरी, रीफ़्रेश रेट को इस तरह से चुनती है कि वह गेम के फ़्रेम के रींडर होने में लगने वाले समय से मेल खाता हो. इससे बेहतर विज़ुअल अनुभव मिलता है.
अलग-अलग रीफ़्रेश रेट के फ़्रेम पेसिंग के बारे में ज़्यादा जानने के लिए, Android पर ज़्यादा रीफ़्रेश रेट रेंडरिंग ब्लॉग पोस्ट देखें.
फ़्रेम के आंकड़े
फ़्रेम पेसिंग लाइब्रेरी, डीबग करने और प्रोफ़ाइल करने के लिए ये आंकड़े उपलब्ध कराती है:
- रेंडरिंग पूरी होने के बाद, कंपोजिटर की सूची में इंतज़ार कर रहे फ़्रेम की स्क्रीन रीफ़्रेश की संख्या का हिस्टोग्राम.
- अनुरोध किए गए प्रज़ेंटेशन के समय और मौजूदा समय के बीच, स्क्रीन रीफ़्रेश की संख्या का हिस्टोग्राम.
- लगातार दो फ़्रेम के बीच, स्क्रीन रीफ़्रेश की संख्या का हिस्टोग्राम.
- इस फ़्रेम के लिए सीपीयू के काम शुरू होने और मौजूदा समय के बीच, स्क्रीन रीफ़्रेश की संख्या का हिस्टोग्राम.
अगला चरण
अपने गेम में Android फ़्रेम पेसिंग लाइब्रेरी को इंटिग्रेट करने के लिए, इनमें से कोई एक गाइड देखें:
- अपने OpenGL रेंडरर में Android फ़्रेम पेसिंग को इंटिग्रेट करना
- अपने Vulkan रेंडरर में Android फ़्रेम पेसिंग को इंटिग्रेट करना
अन्य संसाधन
- Mir 2, Swappy का इस्तेमाल करके रेंडरिंग की परफ़ॉर्मेंस को बेहतर बनाता है. साथ ही, यह धीमे सेशन रेट को 40% से घटाकर 10% कर देता है.