फ़्रेम पेसिंग लाइब्रेरी   Android Game Development Kit का हिस्सा.

Android Frame Pacing Library को Swappy के नाम से भी जाना जाता है. यह AGDK Libraries का हिस्सा है. इससे Android पर OpenGL और Vulkan गेम को आसानी से रेंडर करने और फ़्रेम पेसिंग को सही करने में मदद मिलती है. इस दस्तावेज़ में, फ़्रेम पेसिंग के बारे में बताया गया है. साथ ही, उन स्थितियों के बारे में बताया गया है जिनमें फ़्रेम पेसिंग की ज़रूरत होती है. इसमें यह भी बताया गया है कि लाइब्रेरी इन स्थितियों को कैसे हैंडल करती है. अगर आपको सीधे तौर पर अपने गेम में फ़्रेम पेसिंग लागू करनी है, तो अगला चरण देखें.

बैकग्राउंड

फ़्रेम पेसिंग, गेम के लॉजिक और रेंडरिंग लूप को ओएस के डिसप्ले सबसिस्टम और डिसप्ले हार्डवेयर के साथ सिंक करने की प्रोसेस है. Android के डिसप्ले सबसिस्टम को इस तरह से डिज़ाइन किया गया है कि डिसप्ले हार्डवेयर के अपडेट के दौरान, विज़ुअल आर्टफ़ैक्ट (टेयरिंग के तौर पर जाना जाता है) न दिखें. ऐसा तब हो सकता है, जब डिसप्ले हार्डवेयर अपडेट के दौरान किसी नए फ़्रेम पर स्विच करता है. इन आर्टफ़ैक्ट से बचने के लिए, डिसप्ले सबसिस्टम यह काम करता है:

  • यह पिछले फ़्रेम को अंदरूनी तौर पर बफ़र करता है
  • इससे देर से फ़्रेम सबमिट होने का पता चलता है
  • फ़्रेम के देर से लोड होने का पता चलने पर, पिछले फ़्रेम को फिर से दिखाता है

गेम, डिसप्ले सबसिस्टम में कंपोज़िटर SurfaceFlinger को यह सूचना देता है कि उसने किसी फ़्रेम के लिए ज़रूरी सभी ड्रॉ कॉल सबमिट कर दिए हैं. इसके लिए, वह eglSwapBuffers या vkQueuePresentKHR को कॉल करता है. SurfaceFlinger, लैच का इस्तेमाल करके डिसप्ले हार्डवेयर को फ़्रेम के उपलब्ध होने की सूचना देता है. इसके बाद, डिसप्ले हार्डवेयर दिए गए फ़्रेम को दिखाता है. डिस्प्ले हार्डवेयर एक तय दर पर काम करता है. उदाहरण के लिए, 60 हर्ट्ज़. अगर हार्डवेयर को नए फ़्रेम की ज़रूरत होती है, लेकिन उसे नया फ़्रेम नहीं मिलता है, तो वह पिछला फ़्रेम फिर से दिखाता है.

फ़्रेम के रेंडर होने में लगने वाले समय में अंतर तब आता है, जब गेम रेंडर लूप, नेटिव डिसप्ले हार्डवेयर की तुलना में अलग रेट पर रेंडर होता है. अगर 30 एफ़पीएस पर चल रहा कोई गेम, ऐसे डिवाइस पर रेंडर करने की कोशिश करता है जो मूल रूप से 60 एफ़पीएस के साथ काम करता है, तो गेम रेंडर लूप को यह पता नहीं चलता कि दोहराया गया फ़्रेम, स्क्रीन पर 16 मिलीसेकंड तक बना रहता है. इस वजह से, फ़्रेम के रेंडर होने में लगने वाले समय में काफ़ी अंतर आ जाता है. जैसे: 49 मिलीसेकंड, 16 मिलीसेकंड, 33 मिलीसेकंड. ज़्यादा जटिल सीन की वजह से यह समस्या और बढ़ जाती है, क्योंकि इससे फ़्रेम छूट जाते हैं.

बेहतर समाधान नहीं

गेम में फ़्रेम पेसिंग के लिए, यहां दिए गए समाधानों का इस्तेमाल किया गया है. हालांकि, इनसे फ़्रेम के समय में अंतर आता है और इनपुट में देरी होती है.

रेंडरिंग एपीआई की अनुमति के मुताबिक, फ़्रेम जल्द से जल्द सबमिट करें

इस तरीके से, गेम को SurfaceFlinger की अलग-अलग गतिविधियों से जोड़ा जाता है. साथ ही, इसमें एक अतिरिक्त फ़्रेम की लेटेन्सी भी शामिल होती है. डिसप्ले पाइपलाइन में फ़्रेम की एक कतार होती है. आम तौर पर, इसका साइज़ 2 होता है. अगर गेम बहुत तेज़ी से फ़्रेम दिखाने की कोशिश करता है, तो यह कतार भर जाती है. जब कतार में कोई जगह नहीं होती, तब गेम लूप (या कम से कम रेंडरिंग थ्रेड) को OpenGL या Vulkan कॉल से ब्लॉक कर दिया जाता है. इसके बाद, गेम को डिसप्ले हार्डवेयर के फ़्रेम दिखाने का इंतज़ार करना पड़ता है. इससे दोनों कॉम्पोनेंट सिंक हो जाते हैं. इस स्थिति को बफ़र-स्टफ़िंग या कतार-स्टफ़िंग कहा जाता है. रेंडरर प्रोसेस को यह पता नहीं चलता कि क्या हो रहा है. इसलिए, फ़्रेमरेट में अंतर और बढ़ जाता है. अगर गेम, फ़्रेम से पहले इनपुट का सैंपल लेता है, तो इनपुट में लगने वाला समय बढ़ जाता है.

Android Choreographer का इस्तेमाल अकेले करना

गेम भी सिंक्रनाइज़ेशन के लिए, Android Choreographer का इस्तेमाल करते हैं. यह कॉम्पोनेंट, एपीआई 16 से Java में और एपीआई 24 से C++ में उपलब्ध है. यह डिसप्ले सबसिस्टम की फ़्रीक्वेंसी के हिसाब से, नियमित अंतराल पर टिक डिलीवर करता है. हालांकि, अब भी यह तय करना मुश्किल है कि हार्डवेयर वीसिंक के हिसाब से यह टिक कब डिलीवर किया जाता है. साथ ही, ये ऑफ़सेट डिवाइस के हिसाब से अलग-अलग होते हैं. लंबे फ़्रेम के लिए, अब भी बफ़र स्टफ़िंग हो सकती है.

फ़्रेम पेसिंग लाइब्रेरी के फ़ायदे

फ़्रेम पेसिंग लाइब्रेरी, सिंक्रनाइज़ेशन के लिए Android Choreographer का इस्तेमाल करती है. साथ ही, यह आपके लिए टिक डिलीवरी में होने वाले बदलावों को मैनेज करती है. यह प्रज़ेंटेशन के टाइमस्टैंप का इस्तेमाल करता है, ताकि यह पक्का किया जा सके कि फ़्रेम सही समय पर दिखाए जाएं. साथ ही, बफ़र स्टफ़िंग से बचने के लिए, सिंक फ़ेंस का इस्तेमाल करता है. अगर NDK Choreographer उपलब्ध है, तो लाइब्रेरी इसका इस्तेमाल करती है. अगर यह उपलब्ध नहीं है, तो लाइब्रेरी Java Choreographer का इस्तेमाल करती है.

अगर डिवाइस पर कई रीफ़्रेश रेट काम करते हैं, तो लाइब्रेरी उन्हें मैनेज करती है. इससे गेम को फ़्रेम दिखाने में ज़्यादा आसानी होती है. उदाहरण के लिए, अगर किसी डिवाइस पर 60 हर्ट्ज़ और 90 हर्ट्ज़, दोनों की रीफ़्रेश दर काम करती है, तो 60 फ़्रेम प्रति सेकंड जनरेट न कर पाने वाला गेम, स्मूद तरीके से चलने के लिए 30 फ़्रेम प्रति सेकंड के बजाय 45 फ़्रेम प्रति सेकंड पर चल सकता है. लाइब्रेरी, गेम के अनुमानित फ़्रेम रेट का पता लगाती है. साथ ही, फ़्रेम दिखाने के समय को इसके हिसाब से अपने-आप अडजस्ट करती है. फ़्रेम पेसिंग लाइब्रेरी, बैटरी की लाइफ़ को भी बेहतर बनाती है. ऐसा इसलिए, क्योंकि यह डिसप्ले को गैर-ज़रूरी तौर पर अपडेट होने से रोकती है. उदाहरण के लिए, अगर कोई गेम 60 FPS पर रेंडर हो रहा है, लेकिन डिसप्ले 120 हर्ट्ज़ पर अपडेट हो रहा है, तो हर फ़्रेम के लिए स्क्रीन दो बार अपडेट होती है. फ़्रेम पेसिंग लाइब्रेरी, रीफ़्रेश रेट को उस वैल्यू पर सेट करती है जो टारगेट फ़्रेम रेट के सबसे करीब होती है. इससे इस समस्या से बचा जा सकता है.

यह कैसे काम करता है

यहां दिए गए सेक्शन में बताया गया है कि फ़्रेम पेसिंग लाइब्रेरी, गेम के लंबे और छोटे फ़्रेम को कैसे मैनेज करती है, ताकि सही फ़्रेम पेसिंग हासिल की जा सके.

30 हर्ट्ज़ पर फ़्रेम पेसिंग सही है

जब 60 हर्ट्ज़ वाले डिवाइस पर 30 हर्ट्ज़ पर रेंडर किया जाता है, तो Android पर सबसे सही स्थिति को पहले फ़िगर में दिखाया गया है. अगर नए ग्राफ़िक बफ़र मौजूद हैं, तो SurfaceFlinger उन्हें जोड़ता है. (डायग्राम में NB का मतलब है कि "कोई बफ़र नहीं" मौजूद है और पिछले बफ़र को दोहराया गया है).

60 हर्ट्ज़ वाले डिवाइस पर 30 हर्ट्ज़ पर फ़्रेम पेसिंग का सही उदाहरण

पहली इमेज. 60 हर्ट्ज़ वाले डिवाइस पर 30 हर्ट्ज़ पर फ़्रेम पेसिंग का सही उदाहरण.

गेम फ़्रेम कम होने की वजह से, गेम अटक-अटककर चलता है

ज़्यादातर नए डिवाइसों पर, गेम इंजन इस बात पर निर्भर करते हैं कि प्लैटफ़ॉर्म कोरियोग्राफ़र, फ़्रेम सबमिट करने के लिए टिक डिलीवर करे. हालांकि, छोटे फ़्रेम की वजह से फ़्रेम पेसिंग अब भी खराब हो सकती है. जैसा कि इमेज 2 में दिखाया गया है. प्लेयर को छोटे फ़्रेम के बाद बड़े फ़्रेम दिखने पर, वीडियो रुक-रुककर चलता हुआ दिखता है.

गेम के छोटे फ़्रेम

दूसरी इमेज. गेम के छोटे फ़्रेम C की वजह से, फ़्रेम B में सिर्फ़ एक फ़्रेम दिखता है. इसके बाद, कई C फ़्रेम दिखते हैं.

फ़्रेम पेसिंग लाइब्रेरी, प्रज़ेंटेशन टाइमस्टैंप का इस्तेमाल करके इस समस्या को हल करती है. लाइब्रेरी, प्रज़ेंटेशन टाइमस्टैंप एक्सटेंशन EGL_ANDROID_presentation_time और VK_GOOGLE_display_timing का इस्तेमाल करती है, ताकि फ़्रेम को समय से पहले न दिखाया जाए. जैसा कि तीसरी इमेज में दिखाया गया है.

प्रज़ेंटेशन के टाइमस्टैंप

तीसरी इमेज. गेम के फ़्रेम B को दो बार दिखाया गया है, ताकि डिसप्ले स्मूद हो.

बड़े फ़्रेम की वजह से, वीडियो रुक-रुककर चलता है और उसमें देरी होती है

जब डिसप्ले वर्कलोड में ऐप्लिकेशन वर्कलोड से ज़्यादा समय लगता है, तो अतिरिक्त फ़्रेम को एक कतार में जोड़ दिया जाता है. इस वजह से, वीडियो फिर से रुक-रुककर चलने लगता है. साथ ही, बफ़र में डेटा भरने की वजह से, लेटेन्सी का एक और फ़्रेम भी जुड़ सकता है (चौथी इमेज देखें). इस लाइब्रेरी की मदद से, वीडियो में होने वाली रुकावट और लेटेन्सी के अतिरिक्त फ़्रेम, दोनों को हटाया जा सकता है.

लंबे गेम के फ़्रेम

चौथी इमेज. लंबे फ़्रेम बी की वजह से, दो फ़्रेम—ए और बी की पेसिंग गलत हो जाती है

लाइब्रेरी इस समस्या को हल करने के लिए, सिंक फ़ेंस (EGL_KHR_fence_sync और VkFence) का इस्तेमाल करती है. इससे ऐप्लिकेशन में इंतज़ार के समय को शामिल किया जाता है, ताकि डिसप्ले पाइपलाइन को डेटा प्रोसेस करने के लिए ज़्यादा समय मिल सके. इससे बैक प्रेशर को बढ़ने से रोका जा सकता है. फ़्रेम A में अब भी एक अतिरिक्त फ़्रेम दिख रहा है. हालांकि, फ़्रेम B अब सही तरीके से दिख रहा है. इसे पांचवीं इमेज में देखा जा सकता है.

ऐप्लिकेशन लेयर में जोड़े गए इंतज़ार

पांचवीं इमेज. फ़्रेम C और D, प्रज़ेंट होने का इंतज़ार करते हैं.

ऑपरेटिंग मोड

फ़्रेम पेसिंग लाइब्रेरी को इन तीन मोड में से किसी एक में काम करने के लिए कॉन्फ़िगर किया जा सकता है:

  • ऑटो मोड बंद है + पाइपलाइन
  • ऑटो मोड चालू है + पाइपलाइन
  • ऑटो मोड चालू है + ऑटो पाइपलाइन मोड (पाइपलाइन/नॉन-पाइपलाइन)

ऑटो-मोड और पाइपलाइन मोड के साथ एक्सपेरिमेंट किया जा सकता है. हालांकि, आपको इन्हें बंद करके शुरू करना होगा. साथ ही, Swappy को शुरू करने के बाद, ये शामिल करने होंगे:

  swappyAutoSwapInterval(false);
  swappyAutoPipelineMode(false);
  swappyEnableStats(false);
  swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);

पाइपलाइन मोड

इंजन के वर्कलोड को मैनेज करने के लिए, लाइब्रेरी आम तौर पर पाइपलाइनिंग मॉडल का इस्तेमाल करती है. यह मॉडल, सीपीयू और जीपीयू के वर्कलोड को वीसिंक बाउंड्री के हिसाब से अलग करता है.

पाइपलाइन मोड

छठी इमेज. पाइपलाइन मोड.

नॉन-पाइपलाइन मोड

आम तौर पर, इस तरीके से इनपुट स्क्रीन की लेटेन्सी कम होती है और इसका अनुमान लगाना आसान होता है. अगर किसी गेम का फ़्रेम टाइम बहुत कम है, तो सीपीयू और जीपीयू, दोनों के वर्कलोड एक ही स्वैप इंटरवल में फ़िट हो सकते हैं. इस मामले में, नॉन-पाइपलाइन वाले तरीके से इनपुट-स्क्रीन की लेटेन्सी कम होगी.

नॉन-पाइपलाइन मोड

सातवीं इमेज. नॉन-पाइपलाइन मोड.

ऑटो मोड

ज़्यादातर गेम को यह नहीं पता होता कि स्वैप इंटरवल कैसे चुना जाए. यह वह अवधि होती है जिसके लिए हर फ़्रेम दिखाया जाता है. उदाहरण के लिए, 30 हर्ट्ज़ के लिए 33.3 मि॰से॰. कुछ डिवाइसों पर, गेम 60 FPS पर रेंडर हो सकता है. वहीं, किसी दूसरे डिवाइस पर इसे कम वैल्यू पर रेंडर करना पड़ सकता है. ऑटो मोड में, सीपीयू और जीपीयू के समय को मेज़र किया जाता है, ताकि ये काम किए जा सकें:

  • स्वैप इंटरवल अपने-आप चुनने की सुविधा: कुछ सीन में 30 हर्ट्ज़ और कुछ में 60 हर्ट्ज़ की फ़्रेम दर वाले गेम, लाइब्रेरी को इस इंटरवल को डाइनैमिक तरीके से अडजस्ट करने की अनुमति दे सकते हैं.
  • बहुत तेज़ी से रेंडर होने वाले फ़्रेम के लिए, पाइपलाइनिंग की सुविधा बंद करें: इससे सभी मामलों में, इनपुट-स्क्रीन की सबसे कम लेटेंसी मिलती है.

रीफ़्रेश करने की एक से ज़्यादा दरें

जिन डिवाइसों पर रीफ़्रेश रेट बदलने की सुविधा होती है वे स्वैप इंटरवल चुनने के लिए ज़्यादा विकल्प देते हैं. इससे वीडियो ज़्यादा स्मूद दिखता है:

  • 60 हर्ट्ज़ वाले डिवाइसों पर: 60 फ़्रेम प्रति सेकंड / 30 फ़्रेम प्रति सेकंड / 20 फ़्रेम प्रति सेकंड
  • 60 हर्ट्ज़ + 90 हर्ट्ज़ वाले डिवाइसों पर: 90 फ़्रेम प्रति सेकंड / 60 फ़्रेम प्रति सेकंड / 45 फ़्रेम प्रति सेकंड / 30 फ़्रेम प्रति सेकंड
  • 60 हर्ट्ज़ + 90 हर्ट्ज़ + 120 हर्ट्ज़ वाले डिवाइसों पर: 120 फ़्रेम प्रति सेकंड / 90 फ़्रेम प्रति सेकंड / 60 फ़्रेम प्रति सेकंड / 45 फ़्रेम प्रति सेकंड / 40 फ़्रेम प्रति सेकंड / 30 फ़्रेम प्रति सेकंड

लाइब्रेरी, रीफ़्रेश रेट को इस तरह से चुनती है कि वह गेम के फ़्रेम रेंडर होने की अवधि से सबसे ज़्यादा मेल खाए. इससे विज़ुअल अनुभव बेहतर होता है.

अलग-अलग रीफ़्रेश रेट पर फ़्रेम पेसिंग के बारे में ज़्यादा जानने के लिए, Android पर ज़्यादा रीफ़्रेश रेट वाली रेंडरिंग ब्लॉग पोस्ट पढ़ें.

फ़्रेम के आंकड़े

फ़्रेम पेसिंग लाइब्रेरी, डीबग करने और प्रोफ़ाइलिंग के लिए ये आंकड़े उपलब्ध कराती है:

  • यह हिस्टोग्राम, रेंडरिंग पूरी होने के बाद कंपोज़िटर क्यू में किसी फ़्रेम के इंतज़ार करने के दौरान स्क्रीन रीफ़्रेश की संख्या दिखाता है.
  • यह हिस्टोग्राम, अनुरोध किए गए प्रज़ेंटेशन टाइम और असल प्रज़ेंटेशन टाइम के बीच पास किए गए स्क्रीन रीफ़्रेश की संख्या दिखाता है.
  • दो लगातार फ़्रेम के बीच, स्क्रीन रीफ़्रेश की संख्या का हिस्टोग्राम.
  • इस फ़्रेम के लिए सीपीयू का काम शुरू होने और मौजूदा समय के बीच, स्क्रीन रीफ़्रेश की संख्या का हिस्टोग्राम.

अगला चरण

Android Frame Pacing लाइब्रेरी को अपने गेम में इंटिग्रेट करने के लिए, इनमें से कोई एक गाइड देखें:

अन्य संसाधन