HAR ग्राफ़िक्स पाइपलाइन

इस पेज पर, हाई अवेलेबिलिटी रेंडरर (एचएआर) की पूरी ग्राफ़िक्स पाइपलाइन के बारे में बताया गया है. इसमें, Figma के डिज़ाइन दस्तावेज़ से लेकर स्क्रीन पर दिखने वाले फ़ाइनल पिक्सल तक के डेटा के फ़्लो को ट्रेस किया गया है.

खास जानकारी

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

पाइपलाइन को चार मुख्य चरणों में बांटा जा सकता है:

  1. प्रीरेंडर: सीन ग्राफ़ को प्रोसेस करना, पसंद के मुताबिक बनाना, और लेआउट की समस्या हल करना.
  2. कमांड जनरेट करना: हल किए गए सीन ग्राफ़ को, बैकएंड से जुड़ी जानकारी के बिना डिसप्ले लिस्ट में बदलना.
  3. रेंडरिंग: Impeller ग्राफ़िक्स इंजन का इस्तेमाल करके, ड्रॉइंग के निर्देशों को लागू करना.
  4. प्रज़ेंटेशन: फ़्रेमबफ़र मैनेज करना और डिसप्ले हार्डवेयर के साथ सिंक करना.

HAR ग्राफ़िक्स फ़्लो

पहली इमेज. HAR ग्राफ़िक्स फ़्लो.

पहला फ़ेज़: प्रीरेंडर

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

1.1 DesignCompose की बुनियादी बातें

HAR पाइपलाइन, DesignCompose के नेटवर्क पर काम करती है.

  • सोर्स: यूज़र इंटरफ़ेस (यूआई) को Figma में डिज़ाइन किया गया है. इसे DesignCompose प्लगिन का इस्तेमाल करके एक्सपोर्ट किया गया है.
  • परिभाषा: आउटपुट, DesignComposeDefinition का एक इंस्टेंस होता है. यह डिज़ाइन (नोड, स्टाइल, वैरिएंट) का सीरियलाइज़ किया गया वर्शन होता है.
  • डेटा बाइंडिंग: ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) मॉडल, प्रोसीजरल मैक्रो (उदाहरण के लिए, #[Design(node = "#speed")]) का इस्तेमाल करता है. इससे, Figma दस्तावेज़ में मौजूद खास नाम वाले नोड के साथ, Rust struct फ़ील्ड को साफ़ तौर पर बाइंड किया जा सकता है. इससे ऐप्लिकेशन की स्थिति के आधार पर, विज़ुअल एलिमेंट की प्रॉपर्टी अपने-आप तय होती हैं.

इस फ़ाउंडेशन के मुख्य कॉम्पोनेंट ये हैं:

  • रिड्यूसर: यह सेंट्रल इवेंट लूप के तौर पर काम करता है. यह कार्रवाइयों को प्रोसेस करता है और मौजूदा स्थिति को अपडेट करता है. फ़्रेमवर्क DefaultReducer उपलब्ध कराता है. हालांकि, ज़रूरत पड़ने पर कस्टम रिड्यूसर लागू किया जा सकता है.
  • Presenter: यह यूज़र इंटरफ़ेस (यूआई) मॉडल को मौजूदा स्थिति से जोड़ता है. Presenter ट्रेट को harry फ़्रेमवर्क क्रेट से तय किया जाता है. साथ ही, harry-app-core क्रेट में रेफ़रंस इंप्लीमेंटेशन (UIModelPresenter) दिया जाता है.
  • यूज़र इंटरफ़ेस (यूआई) मॉडल: मौजूदा स्थिति के आधार पर, कस्टमाइज़ेशन जनरेट करता है. यूआई मॉडल कोड, DesignDocument मैक्रो का इस्तेमाल करके जनरेट किया जाता है. यह मैक्रो, derive_customizations क्रेट से मिलता है. harry-app-core क्रेट में मौजूद UIModel स्ट्रक्चर, इसका एक उदाहरण देता है.
  • Squoosh: यह SquooshView डेटा स्ट्रक्चर और वैरिएंट रिपॉज़िटरी उपलब्ध कराता है. इसका इस्तेमाल, डिज़ाइन के मुताबिक यूज़र इंटरफ़ेस (यूआई) को रेंडर करने के लिए किया जाता है. dc_bundle क्रेट, DesignCompose लाइब्रेरी से एक क्रमबद्ध डिज़ाइन दस्तावेज़ लोड करता है. इसके बाद, इसे SquooshView स्ट्रक्चर के ट्री में बदलता है, ताकि रनटाइम पर बेहतर परफ़ॉर्मेंस मिल सके.

1.2 रेड्यूसर लूप

पाइपलाइन को कार्रवाइयों के हिसाब से बनाया जाता है. फ़्रेमवर्क, Actions गिनती किए गए टाइप के बारे में बताता है. यह फ़्रेमवर्क में इस्तेमाल होने वाली इंटरनल कार्रवाइयों के बारे में बताता है. हालांकि, इसमें CustomAction वैरिएंट भी शामिल होता है. इसकी मदद से, उपयोगकर्ता ऐप्लिकेशन के हिसाब से अतिरिक्त कार्रवाइयां तय कर सकते हैं. उदाहरण के लिए, UpdateVehicleSpeed या ButtonPress.

फ़्रेमवर्क, StateAction ट्रेट भी उपलब्ध कराता है. इससे ऐप्लिकेशन की स्थिति पर असर डालने वाली कार्रवाइयों को लागू करना आसान हो जाता है. साथ ही, यह ट्रेट ऐसे साइड इफ़ेक्ट जनरेट करती है जिन्हें प्रोसेस करने के लिए, रिड्यूसर से ऐप्लिकेशन को वापस भेज दिया जाता है. हालांकि, ऐसा करना ज़रूरी नहीं है. harry-app-core क्रेट में मौजूद CustomActions enum में, इसका एक उदाहरण दिया गया है.

यहां रिड्यूसर लूप की बुनियादी जानकारी दी गई है:

  • कार्रवाई की प्रोसेस: Reducer को कार्रवाई मिलती है और वह मौजूदा स्थिति को अपडेट करता है. यह रॉ डेटा होता है. जैसे, मौजूदा स्पीड या कौनसी टेलटेल (चेतावनी वाली लाइट) चालू हैं. इससे साइड इफ़ेक्ट भी जनरेट हो सकते हैं. उदाहरण के लिए, सीट बेल्ट की लाइट चमकने पर सिग्नल बज सकता है.
  • प्रज़ेंटेशन: Presenter, नई स्थिति को UIModel में मैप करता है. UIModel एक व्यू मॉडल है. इसमें यूज़र इंटरफ़ेस (यूआई) के लिए खास तौर पर फ़ॉर्मैट किया गया डेटा होता है. उदाहरण के लिए, स्पीड "120" को "65 मील प्रति घंटा" स्ट्रिंग में फ़ॉर्मैट करना.
  • कस्टमाइज़ेशन जनरेशन: RenderCustomization इंस्टेंस का सेट जनरेट करने के लिए, यूज़र इंटरफ़ेस (यूआई) मॉडल के apply तरीके को कॉल किया जाता है. ये Figma डिज़ाइन में बदलाव करने के लिए, साफ़ तौर पर दिए गए निर्देश हैं. उदाहरण के लिए, "नोड #speed के टेक्स्ट को '65 मील प्रति घंटा' पर सेट करें".
  • UpdatePolicy ऑप्टिमाइज़ेशन के लिए: हर प्रीरेंडर पास के बाद, UpdatePolicy वैल्यू वापस आ जाती है. इससे पता चलता है कि अगला रेंडरिंग अपडेट कब ज़रूरी है. अगर स्टेटस में कोई बदलाव नहीं हुआ है और कोई ऐनिमेशन नहीं चल रहा है, तो UpdatePolicy से पता चलता है कि तुरंत कोई और अपडेट ज़रूरी नहीं है. ऐसे मामलों में, Reducer नई डिसप्ले लिस्ट जनरेट करना बंद कर देता है. इससे, रेंडरिंग के गैर-ज़रूरी साइकल रुक जाते हैं और संसाधन तब तक सुरक्षित रहते हैं, जब तक कोई नई कार्रवाई या इवेंट बदलाव को ट्रिगर नहीं करता.

1.3 डेटा इंटेक और रिपॉज़िटरी के शुरू होने की जानकारी देखना

पाइपलाइन, DesignComposeDefinition इंस्टेंस से शुरू होती है. यह Figma डिज़ाइन दस्तावेज़ है. इसे DesignCompose ने प्रोटोकॉल बफ़र स्ट्रक्चर में क्रम से लगाया है.

  • शुरुआती लोड: स्टार्टअप के समय, मुख्य डिज़ाइन (इसके रूट नोड से तय किया गया) को DesignComposeDefinition से शुरुआती SquooshView ट्री में बदल दिया जाता है. यह प्रोसेस सिर्फ़ एक बार की जाती है.

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

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

1.4 पसंद के मुताबिक बनाने का पास

डाइनैमिक ऐप्लिकेशन की स्थिति लागू करने के लिए, SquooshView ट्री को ट्रैवर्स किया जाता है:

  • वैरिएंट स्वैप: रनटाइम लॉजिक के आधार पर, कॉम्पोनेंट इंस्टेंस को खास वैरिएंट से स्वैप किया जाता है. उदाहरण के लिए, मौजूदा ड्राइव मोड को दिखाने वाले आइकॉन को स्पोर्ट से बदलकर ईको मोड पर सेट करना.

  • लिस्ट का बड़ा होना: Figma में मौजूद किसी एक टेंप्लेट आइटम को, बच्चों की डाइनैमिक लिस्ट से बदल दिया जाता है. इन चाइल्ड नोड के लिए नए यूनीक आईडी जनरेट किए जाते हैं, ताकि ऐनिमेशन के लिए एक जैसी पहचान की पुष्टि की जा सके.

  • टेक्स्ट और स्टाइल में बदलाव: टेक्स्ट कॉन्टेंट (उदाहरण के लिए, स्पीड वैल्यू) और स्टाइल (उदाहरण के लिए, ओपैसिटी, रंग) को मौजूदा स्थिति के हिसाब से अपडेट किया जाता है.

1.5 स्ट्रीम में रिज़ॉल्यूशन के विकल्प

Figma में या ऐप्लिकेशन में स्थानीय तौर पर तय किए गए डिज़ाइन टोकन और वैरिएबल को हल किया जाता है.

  • बाइंडिंग: SquooshView वैरिएबल (जैसे कि रंग या डाइमेंशन) का रेफ़रंस देने वाली प्रॉपर्टी को मौजूदा फ़्रेम के लिए उनकी वैल्यू से बदल दिया जाता है.

1.6 लेआउट का हिसाब

  • डाइनैमिक लेआउट: DynamicLayout, SquooshView ट्री में मौजूद हर नोड की फ़ाइनल पोज़िशन और साइज़ (बाउंड्री) का हिसाब लगाता है.

  • टेक्स्ट लेआउट: TextHelper, टेक्स्ट मेट्रिक, रैपिंग, और शेप का हिसाब लगाने के लिए LayoutHelper ट्रेट का इस्तेमाल करता है. इससे यह पुष्टि करने में मदद मिलती है कि रेंडर करने से पहले, टेक्स्ट अपनी सीमाओं के अंदर सही तरीके से फ़्लो हो रहा है या नहीं.

1.7 डायल और गेज

यह ऑटोमोटिव यूज़र इंटरफ़ेस (यूआई) के लिए खास तौर पर बनाया गया चरण है.

  • MeterData: अगर किसी नोड में मीटर का डेटा (Figma में तय किया गया) है, तो उसकी ज्यामिति को meter_value के आधार पर डाइनैमिक तरीके से बदला जाता है. उदाहरण के लिए, वाहन की स्पीड.
    • आर्क: इसमें स्वीप ऐंगल को अडजस्ट किया जाता है.
    • रोटेशन: रोटेशन ट्रांसफ़ॉर्म का हिसाब, शुरू और खत्म होने वाले कोणों के आधार पर लगाया जाता है.
    • प्रोग्रेस बार: आयत की चौड़ाई या ऊंचाई को स्केल किया जाता है.
    • प्रोग्रेस वेक्टर: वेक्टर पाथ की लंबाई को अडजस्ट किया जाता है.

1.8 ऐनिमेशन

  • डिफ़िंग: इसमें मौजूदा SquooshView की तुलना, PreRenderCache के previous_squoosh_view से की जाती है.

  • इंटरपोलेशन: अगर प्रॉपर्टी में बदलाव हुआ है, तो Squoosh इंटरपोलेटर बनाता है, ताकि समय के साथ वैल्यू (उदाहरण के लिए, ओपैसिटी या ट्रांसफ़ॉर्म) में आसानी से बदलाव किया जा सके.

दूसरा चरण: निर्देश जनरेट करना

SquooshView ट्री पूरी तरह से हल हो जाने और ऐनिमेट होने के बाद, इसे ड्राइंग कमांड के लीनियर सीक्वेंस में बदल दिया जाता है.

इस फ़ेज़ का मुख्य कॉम्पोनेंट DisplayList क्रेट है:

  • generate_dl: यह फ़ंक्शन, SquooshView ट्री को बार-बार ट्रैवर्स करता है.

  • अनुवाद:

    • शेप और पाथ: इन्हें सही DisplayListAppearance वैरिएंट (उदाहरण के लिए, Rect या Path) के साथ DisplayListEntry में बदल दिया जाता है
    • टेक्स्ट: TextHelper की मदद से, टेक्स्ट को ड्रॉइंग की एंट्री में बदला गया.
    • बदलाव और क्लिप: इन्हें PushTransform3D और PopTransform3D या PushClipRegion और PopClipRegion के जोड़े में बदला जाता है, ताकि ड्राइंग की स्थिति के स्टैक को मैनेज किया जा सके.
    • मास्किंग: लेयर को सही तरीके से बनाने और ब्लेंड करने के लिए, PushMaskLayer और PopMaskLayer पेयर में बदला गया.

फ़ाइनल नतीजा, Vec<DisplayListEntry> का एक इंस्टेंस होता है. इससे यह पता चलता है कि क्या बनाना है. इससे यह पता नहीं चलता कि इसे कैसे बनाना है.

2.1 लूपर को हैंडऑफ़ करना

DisplayList जनरेट होने के बाद, Reducer इसे ViewDescriptor के इंस्टेंस में रैप करता है और इसे Rust MPSC चैनल (LooperMessage) पर, लूपर थ्रेड को भेजता है. Looper, रेंडरिंग और डिसप्ले फ़ेज़ के लिए ज़िम्मेदार है. इससे Reducer थ्रेड, ग्राफ़िक्स पाइपलाइन को ब्लॉक नहीं कर पाती.

तीसरा चरण: रेंडरिंग

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

HAR, Impeller का इस्तेमाल करता है. यह रेंडरिंग इंजन, मूल रूप से Flutter के लिए बनाया गया था. इंपेलर को इस तरह से डिज़ाइन किया गया है कि यह शेडर कंपाइलेशन की वजह से होने वाली फ़्रेम रेट की गड़बड़ियों को ठीक कर सके. इसके लिए, यह बिल्ड टाइम पर शेडर का एक छोटा और असरदार सेट पहले से कंपाइल करता है. इस तरीके के साथ-साथ, असरदार बैचिंग और बेहतर तरीके से ऑप्टिमाइज़ किए गए बैकएंड का इस्तेमाल करने से, ये फ़ायदे मिलते हैं:

  • डिटरमिनिस्टिक परफ़ॉर्मेंस: इससे रनटाइम शेडर कंपाइलेशन की गड़बड़ियां लगभग खत्म हो जाती हैं.
  • तेज़ी से शुरू होना: इससे शुरू होने में लगने वाला समय कम हो जाता है.
  • कम स्टोरेज का इस्तेमाल: इससे बाइनरी का साइज़ छोटा होता है.

Impeller के आर्किटेक्चर के बारे में पूरी जानकारी पाने के लिए, [Introducing Impeller - Flutter's new rendering engine][impeller-video] देखें. इस वीडियो में Flutter के बारे में बताया गया है. हालांकि, इन मुख्य फ़ायदों से सीधे तौर पर HAR के ऑटोमोटिव स्टैक को फ़ायदा मिलता है.

रेंडरिंग फ़ेज़ के मुख्य कॉम्पोनेंट ये हैं:

  • ImpellerRenderer: यह डिसप्ले लिस्ट को प्रीरेंडर फ़ेज़ से Impeller रेंडरिंग कमांड में बदलता है.

  • Impeller Rust API: यह Impeller लाइब्रेरी को रैप करता है, ताकि इसे Rust में इस्तेमाल किया जा सके. इसके लिए, impeller और impeller-rs-bindgen क्रेट का इस्तेमाल किया जाता है.

  • TypographyContext: यह कुकी, फ़ॉन्ट रजिस्ट्रेशन और टेक्स्ट को आकार देने की प्रोसेस को मैनेज करती है.

impeller-video

3.1 शुरुआत और सर्फ़ेस मैनेजमेंट

  • कॉन्टेक्स्ट बनाना: रेंडरर, OpenGL ES बैकएंड के साथ impeller::Context के इंस्टेंस को शुरू करता है. साथ ही, प्लैटफ़ॉर्म के GL कॉन्टेक्स्ट से OpenGL ES फ़ंक्शन पॉइंटर को हल करने के लिए, एक कॉलबैक पास करता है.

  • रैप्ड एफ़बीओ सर्फ़ेस: Impeller, अपनी विंडो बनाने के बजाय, Phase 4 की ओर से उपलब्ध कराए गए मौजूदा OpenGL फ़्रेमबफ़र ऑब्जेक्ट (एफ़बीओ) में रेंडर करता है. इसके लिए, Surface::create_wrapped_fbo को कॉल किया जाता है.

3.2 संसाधन मैनेजमेंट

  • इमेज: स्टैंडर्ड फ़ॉर्मैट और KTX2 कंप्रेस किए गए टेक्सचर के साथ काम करता है. इन्हें जीपीयू टेक्सचर पर अपलोड किया जाता है और इंटरनल Resources स्ट्रक्चर मैनेज करता है.

  • फ़ॉन्ट: TrueType और OpenType फ़ॉन्ट लोड किए जाते हैं और टेक्स्ट रेंडरिंग के लिए TypographyContext के साथ रजिस्टर किए जाते हैं.

  • बाहरी इमेज: बाहरी टेक्सचर (उदाहरण के लिए, कैमरे के फ़ीड और बाहरी 3D रेंडरर) को खास तरीके से हैंडल करने के लिए, EGLImage इंस्टेंस या बाहरी OpenGL टेक्सचर को Impeller Texture ऑब्जेक्ट से बाइंड करना होता है, ताकि बिना कॉपी किए रेंडर किया जा सके.

3.3 रेंडर पास

render लूप, DisplayListBuilder का इस्तेमाल करके Impeller DisplayList इंस्टेंस बनाता है. इसे प्रीरेंडर फ़ेज़ से जनरेट हुए Vec<DisplayListEntry> से भ्रमित नहीं होना चाहिए:

  1. यह बफ़र को मिटाता है और डीपीआई स्केलिंग और डिसप्ले रोटेशन के लिए ग्लोबल ट्रांसफ़ॉर्म लागू करता है.

  2. इनपुट किए गए DisplayListEntry आइटम के ज़रिए इटरेट करता है:

    • स्टेट: save() और restore() का इस्तेमाल, ट्रांसफ़ॉर्म को पुश और पॉप करने के लिए किया जाता है. साथ ही, इनका इस्तेमाल क्लिप क्षेत्रों के लिए भी किया जाता है.
    • प्रिमिटिव: Rect और RoundedRect को स्टैंडर्ड पेंट ऑपरेशन का इस्तेमाल करके बनाया जाता है.
    • पाथ: जटिल वेक्टर पाथ (इसमें डाइनैमिक Arc इंस्टेंस शामिल हैं) बनाए और ड्रॉ किए जाते हैं.
    • टेक्स्ट: Text और StyledText को TypographyContext का इस्तेमाल करके रेंडर किया जाता है.
    • इमेज: स्टैंडर्ड और बाहरी इमेज को draw_texture_rect का इस्तेमाल करके बनाया जाता है.
  3. यह surface.draw_display_list() का इस्तेमाल करके, बनाई गई Impeller डिसप्ले लिस्ट को प्लैटफ़ॉर्म पर सबमिट करता है. साथ ही, बुनियादी GL कमांड जनरेट करता है.

  4. यह फ़ंक्शन, फ़ेज़ 4 को ट्रिगर करने के लिए, मौजूदा कॉन्टेक्स्ट पर swap_buffers() को कॉल करता है.

चौथा चरण: प्रज़ेंटेशन

इस आखिरी फ़ेज़ में, रेंडर किए गए फ़्रेम को दिखाने के लिए, डिसप्ले हार्डवेयर के साथ इंटरैक्शन को मैनेज किया जाता है. HAR, Android Automotive OS (AAOS) के सॉफ़्टवेयर-डिफ़ाइंड वाहन (एसडीवी) पर डायरेक्ट रेंडरिंग पाथ का इस्तेमाल करता है.

इस फ़ेज़ का मुख्य कॉम्पोनेंट HarDirectRenderingContext है (har-gl-context क्रेट में).

4.1 आर्किटेक्चर

प्रेज़ेंटेशन लेयर, ऑफ़स्क्रीन ड्रॉ टारगेट के साथ डबल-बफ़र्ड अप्रोच का इस्तेमाल करती है:

  1. ड्रॉ बफ़र: यह ऑफ़स्क्रीन FBO होता है, जहां Impeller सीन को रेंडर करता है.

  2. रिज़ॉल्व बफ़र (ज़रूरी नहीं): मल्टीसैंपल ऐंटी-एलियासिंग (एमएसएए) के लिए, सहायक बफ़र (ज़रूरी नहीं)

    • इसे तब चालू किया जा सकता है, जब OpenGL ES के लागू होने या कॉन्फ़िगरेशन की वजह से इसकी ज़रूरत हो. ऐसे मामलों में, यह एक इंटरमीडिएट टारगेट के तौर पर काम करता है. इससे रेंडर बफ़र में ब्लिटिंग (बिट ब्लॉक ट्रांसफ़र) से पहले, मल्टीसैंपल किए गए ड्रॉ बफ़र को हल किया जाता है.
  3. रेंडर बफ़र: यह एक सामान्य बफ़र होता है, जिसे GBM ऑब्जेक्ट से बैक किया जाता है. यह सामान्य ग्राफ़िक्स स्वैप चेन में बैक बफ़र से मेल खाता है.

  4. फ़्रंट बफ़र: यह GBM बफ़र होता है, जिसे डिसप्ले पर स्कैन किया जाता है.

4.2 स्वैप चेन

swap_buffers को कॉल करने पर, HAR यह तरीका अपनाता है:

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

  2. यह GL कॉन्टेक्स्ट पर glFlush() को कॉल करता है और GPU के काम पूरा होने को ट्रैक करने के लिए, EGL_SYNC_NATIVE_FENCE_ANDROID का एक इंस्टेंस बनाता है.

  3. यह स्क्रीन पर रेंडर बफ़र को स्वैप करने के लिए, DRM एटॉमिक अनुरोध बनाता है. इस अनुरोध में, जीपीयू फ़ेंस FD (इसे इन फ़ेंस कहा जाता है) शामिल है. इससे डिसप्ले कंट्रोलर, जीपीयू के ड्रॉइंग पूरी करने से पहले रेंडर बफ़र को नहीं दिखा पाता.

  4. साथ ही, DRM से नए फ़ेंस (जिसे आउट फ़ेंस कहा जाता है) का अनुरोध करता है, ताकि यह पता चल सके कि पिछला बफ़र (पिछले फ़्रेम के लिए फ़्रंट बफ़र) अब स्क्रीन पर नहीं है.

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

  6. यह कुकी, कॉन्टेक्स्ट में नया आउट फ़ेंस सेव करती है, ताकि HAR अगले फ़्रेम पर swap_buffers प्रोसेस की शुरुआत में, इसके सिग्नल मिलने का इंतज़ार कर सके. इससे जीपीयू, ऐसे बफ़र में ड्रॉ नहीं कर पाता जिसे अब भी दिखाया जा रहा है.

4.3 डायरेक्ट मोड की सेटिंग

HAR, DRM और Kernel Mode Setting (KMS) सबसिस्टम का इस्तेमाल करके, सीधे तौर पर कर्नल के साथ इंटरैक्ट करता है. इससे AAOS SDV के डिसप्ले रिज़ॉल्यूशन को कॉन्फ़िगर किया जा सकता है. साथ ही, SurfaceFlinger जैसे विंडो मैनेजर के साथ इंटरैक्शन को बायपास किया जा सकता है. इससे डिसप्ले हार्डवेयर को खास और ज़्यादा प्राथमिकता वाला कंट्रोल मिलता है.

4.4 बाहरी रेंडरिंग

HAR, खास यूज़र इंटरफ़ेस (यूआई) एलिमेंट (Figma में टैग से पहचाने जाते हैं) को रेंडर करने की प्रोसेस को बाहरी प्रोसेस या थ्रेड को सौंपने की सुविधा देता है. यह जटिल 3D सीन को इंटिग्रेट करने के लिए काम आता है. उदाहरण के लिए, Kanzi या Unity जैसे इंजन से ईगो कार विज़ुअलाइज़ेशन या ऐसा अन्य कॉन्टेंट जिसे OpenGL कॉन्टेक्स्ट की ज़रूरत होती है.

4.4.1 मुख्य कॉम्पोनेंट

  • HarExternalRenderContext: बाहरी सेवा के लिए, स्क्रीन से बाहर का एक खास EGL कॉन्टेक्स्ट.
  • SurfacePool: यह डबल या ट्रिपल बफ़रिंग के लिए, LocalSurface (Texture और EGLImage) बफ़र के सेट को मैनेज करता है.
  • SharedSurfaceExternalImage: यह थ्रेड-सेफ़ रैपर है. इसका इस्तेमाल, बाहरी सेवा और मुख्य रेंडरर के बीच EGLImage हैंडल पास करने के लिए किया जाता है.

4.4.2 वर्कफ़्लो

वर्कफ़्लो इस क्रम में काम करता है:

  1. बाहरी सेवा शुरू होती है और मुख्य लूपर के साथ खुद को रजिस्टर करती है. इससे यह पता चलता है कि यह कौनसे Figma टैग (उदाहरण के लिए, #cluster/3d-car) रेंडर करती है.

  2. यह सेवा, लूपर से RenderStart सिग्नल का इंतज़ार करती है, ताकि डिसप्ले के VSYNC सिग्नल के साथ रेंडरिंग को अलाइन किया जा सके.

  3. स्क्रीन से बाहर, सेवा अपने कॉन्टेंट को SurfacePool की ओर से उपलब्ध कराए गए फ़्रेमबफ़र में रेंडर करती है.

  4. यह सेवा, अपने कॉन्टेक्स्ट पर swap_buffers को कॉल करती है. इससे पूल रोटेट होता है और पूरा किया गया फ़्रेम, SharedSurface के इंस्टेंस के तौर पर उपलब्ध होता है.

  5. SharedSurface को ExternalImage में रैप किया जाता है और इसे Rust MPSC चैनल के ज़रिए लूपर को भेजा जाता है.

  6. मुख्य इंपेलर रेंडरर (तीसरा चरण) को बाहरी इमेज मिलती है. यह पिक्सल डेटा को कॉपी करने के बजाय, EGLImage को सीधे तौर पर टेक्सचर से बाइंड करता है. साथ ही, इसे मुख्य सीन के हिस्से के तौर पर दिखाता है. इससे ज़ीरो-कॉपी कंपोज़िशन मिलती है.

4.5 डेवलपमेंट और टेस्टिंग प्लैटफ़ॉर्म (har-platform-linux)

डेवलपमेंट और टेस्टिंग के लिए, HAR ऐप्लिकेशन स्टैंडर्ड Linux डेस्कटॉप एनवायरमेंट और हेडलेस सेटअप को टारगेट कर सकते हैं. इन प्लैटफ़ॉर्म को crates/reference/platforms/har-platform-linux क्रेट में लागू किया जाता है.

प्रोडक्शन AAOS SDV टारगेट के उलट, ये प्लैटफ़ॉर्म डिसप्ले आउटपुट के लिए har-gl-context के direct-rendering सबसिस्टम का इस्तेमाल नहीं करते हैं. इसके बजाय, ये स्टैंडर्ड Rust OpenGL क्रेट पर निर्भर करते हैं:

  • विंडोड मोड: यह विंडो मैनेजमेंट और इवेंट लूप के लिए winit का इस्तेमाल करता है. साथ ही, OpenGL ES कॉन्टेक्स्ट बनाने और विंडो सिस्टम के साथ इंटिग्रेट करने के लिए glutin का इस्तेमाल करता है.

  • हेडलेस मोड: यह har-gl-context क्रेट का इस्तेमाल करके, डिफ़ॉल्ट EGL डिसप्ले के साथ एक ऑफ़स्क्रीन पीबफ़र कॉन्टेक्स्ट बनाता है. इससे, स्क्रीन पर न दिखने वाले बफ़र में रेंडरिंग की जा सकती है. इसके लिए, दिखने वाली विंडो या डिसप्ले हार्डवेयर के डायरेक्ट ऐक्सेस की ज़रूरत नहीं होती. इसका इस्तेमाल मुख्य रूप से, अपने-आप होने वाली टेस्टिंग या बैकएंड प्रोसेसिंग के लिए किया जाता है.