HAR গ্রাফিক্স পাইপলাইন

এই পৃষ্ঠায় হাই অ্যাভেইলেবিলিটি রেন্ডারার (HAR)-এর সম্পূর্ণ গ্রাফিক্স পাইপলাইন বিশদভাবে বর্ণনা করা হয়েছে, যেখানে একটি ফিগমা ডিজাইন ডকুমেন্ট থেকে স্ক্রিনে প্রদর্শিত চূড়ান্ত পিক্সেল পর্যন্ত ডেটার প্রবাহ তুলে ধরা হয়েছে।

সংক্ষিপ্ত বিবরণ

এই পাইপলাইনটি উচ্চ-স্তরের UI ডেফিনিশনগুলোকে নিম্ন-স্তরের গ্রাফিক্স কমান্ডে রূপান্তরিত করে এবং সেগুলোকে হার্ডওয়্যার ডিসপ্লেতে দক্ষতার সাথে উপস্থাপন করে। পাইপলাইনটি অটোমোটিভ সেফটি-ক্রিটিক্যাল অ্যাপের জন্য ডিজাইন করা হয়েছে, যেখানে ডিটারমিনিস্টিক রেন্ডারিং, দক্ষ স্টেট ম্যানেজমেন্ট এবং প্ল্যাটফর্ম গ্রাফিক্স সাবসিস্টেম, যেমন ডিরেক্ট রেন্ডারিং ম্যানেজার (DRM) ও জেনেরিক বাফার ম্যানেজমেন্ট (GBM)-এর সাথে শক্তিশালী ইন্টারঅ্যাকশনের উপর জোর দেওয়া হয়েছে।

পাইপলাইনটিকে চারটি প্রধান পর্যায়ে ভাগ করা যেতে পারে:

  1. প্রি-রেন্ডার: সিন গ্রাফ প্রক্রিয়াকরণ, কাস্টমাইজেশন প্রয়োগ এবং লেআউট চূড়ান্ত করা।
  2. কমান্ড তৈরি: সমাধান করা সিন গ্রাফকে একটি ব্যাকএন্ড-নিরপেক্ষ প্রদর্শন তালিকায় রূপান্তর করা।
  3. রেন্ডারিং: ইম্পেলার গ্রাফিক্স ইঞ্জিন ব্যবহার করে অঙ্কন কমান্ড কার্যকর করা।
  4. উপস্থাপনা: ফ্রেমবাফার ব্যবস্থাপনা এবং ডিসপ্লে হার্ডওয়্যারের সাথে সিঙ্ক্রোনাইজেশন।

HAR গ্রাফিক্স প্রবাহ

চিত্র ১. HAR গ্রাফিক্স প্রবাহ।

পর্যায় ১: প্রি-রেন্ডার

এই পর্যায়টি স্ট্যাটিক ফিগমা ডিজাইন এবং ডাইনামিক অ্যাপ স্টেটকে রেন্ডারিংয়ের জন্য প্রস্তুত একটি সম্পূর্ণ রিজলভড, ইন-মেমরি UI ট্রি-তে রূপান্তরিত করে। এই পর্যায়টি মূল ডিসপ্লে লুপ থেকে আলাদা একটি ডেডিকেটেড রিডিউসার থ্রেডে চলে।

১.১ ডিজাইনকম্পোজ ভিত্তি

HAR পাইপলাইনটি DesignCompose ইকোসিস্টেমের উপর ভিত্তি করে নির্মিত।

  • উৎস: ইউআইটি ফিগমাতে ডিজাইন করা হয়েছে এবং ডিজাইনকম্পোজ প্লাগইন ব্যবহার করে এক্সপোর্ট করা হয়েছে।
  • সংজ্ঞা: আউটপুটটি হলো DesignComposeDefinition এর একটি ইনস্ট্যান্স, যা ডিজাইনের (নোড, স্টাইল, ভ্যারিয়েন্ট) একটি ক্রমিক উপস্থাপনা।
  • ডেটা বাইন্ডিং: অ্যাপটির UI মডেল প্রসিডিউরাল ম্যাক্রো (উদাহরণস্বরূপ, #[Design(node = "#speed")] ) ব্যবহার করে রাস্ট স্ট্রাক্ট ফিল্ডগুলোকে ফিগমা ডকুমেন্টের নির্দিষ্ট নামযুক্ত নোডগুলোর সাথে সুস্পষ্টভাবে বাইন্ড করে। এর ফলে অ্যাপের স্টেট স্বয়ংক্রিয়ভাবে ভিজ্যুয়াল এলিমেন্টগুলোর প্রোপার্টিগুলোকে চালনা করতে পারে।

এই ভিত্তির মূল উপাদানগুলো হলো:

  • রিডিউসার: এটি কেন্দ্রীয় ইভেন্ট লুপ হিসেবে কাজ করে, বিভিন্ন অ্যাকশন প্রসেস করে এবং বর্তমান স্টেট আপডেট করে। ফ্রেমওয়ার্কটি DefaultReducer প্রদান করে, কিন্তু প্রয়োজন হলে একটি কাস্টম রিডিউসার ইমপ্লিমেন্টেশনও দেওয়া যেতে পারে।
  • প্রেজেন্টার: বর্তমান স্টেটকে UI মডেলের সাথে সংযুক্ত করে। Presenter ট্রেইটটি harry ফ্রেমওয়ার্ক ক্রেট দ্বারা নির্দিষ্ট করা হয়েছে, এবং harry-app-core ক্রেটে একটি রেফারেন্স ইমপ্লিমেন্টেশন ( UIModelPresenter ) প্রদান করা হয়েছে।
  • UI মডেল: বর্তমান অবস্থার উপর ভিত্তি করে কাস্টমাইজেশন তৈরি করে। derive_customizations ক্রেট দ্বারা প্রদত্ত DesignDocument ম্যাক্রো ব্যবহার করে UI মডেল কোড তৈরি করা হয়। harry-app-core ক্রেটের UIModel স্ট্রাকচারটি এর একটি উদাহরণ প্রদান করে।
  • Squoosh: SquooshView ডেটা স্ট্রাকচার এবং ভ্যারিয়েন্ট রিপোজিটরি প্রদান করে, যা ডিজাইন অনুযায়ী UI রেন্ডার করতে ব্যবহৃত হয়। DesignCompose লাইব্রেরি থেকে dc_bundle ক্রেট দ্বারা একটি সিরিয়ালাইজড ডিজাইন ডকুমেন্ট লোড করা হয় এবং কার্যকর রানটাইম পারফরম্যান্সের জন্য এটিকে SquooshView স্ট্রাক্ট-এর একটি ট্রি-তে রূপান্তরিত করা হয়।

১.২ রিডিউসার লুপ

পাইপলাইনটি অ্যাকশন দ্বারা চালিত হয়। ফ্রেমওয়ার্কটি ‘ Actions ) নামক একটি এনুমারেটেড টাইপ নির্দিষ্ট করে, যা ফ্রেমওয়ার্কটির নিজস্ব ব্যবহৃত অভ্যন্তরীণ অ্যাকশনগুলো সংজ্ঞায়িত করে। তবে এতে একটি CustomAction ) ভ্যারিয়েন্টও অন্তর্ভুক্ত রয়েছে, যা ব্যবহারকারীদের অ্যাপ-নির্দিষ্ট অতিরিক্ত অ্যাকশন (যেমন, UpdateVehicleSpeed বা ButtonPress ’) সংজ্ঞায়িত করার সুযোগ দেয়।

এই ফ্রেমওয়ার্কটি StateAction ট্রেইটও প্রদান করে, যা অ্যাপের স্টেটকে প্রভাবিত করে এমন অ্যাকশনগুলোর বাস্তবায়নকে সহজ করে এবং ঐচ্ছিকভাবে সাইড এফেক্ট তৈরি করে, যা পরবর্তীতে প্রসেসিংয়ের জন্য রিডিউসার থেকে অ্যাপে ফেরত পাঠানো হয়। harry-app-core ক্রেটের CustomActions enum-টি এর একটি বিস্তারিত উদাহরণ প্রদান করে।

এটি হলো রিডিউসার লুপের একটি প্রাথমিক রূপরেখা:

  • অ্যাকশন প্রসেসিং: Reducer একটি অ্যাকশন গ্রহণ করে এবং বর্তমান স্টেট আপডেট করে। এটি হলো র ডেটা, যেমন বর্তমান গতি বা কোন টেলটেল (সতর্কীকরণ বাতি) সক্রিয় আছে। এটি সাইড এফেক্টও তৈরি করতে পারে (উদাহরণস্বরূপ, সিট বেল্টের বাতি জ্বলে উঠলে একটি সিগন্যাল চিম বাজায়)।
  • উপস্থাপন: Presenter নতুন স্টেটটিকে UIModel এ ম্যাপ করেন। UIModel হলো একটি ভিউ মডেল, যা UI-এর জন্য বিশেষভাবে ফরম্যাট করা ডেটা ধারণ করে (উদাহরণস্বরূপ, "120" স্পিডকে "65 mph" স্ট্রিং-এ ফরম্যাট করা)।
  • কাস্টমাইজেশন তৈরি: এক সেট RenderCustomization ইনস্ট্যান্স তৈরি করার জন্য UI মডেলের apply মেথডটি কল করা হয়। এগুলো হলো ফিগমা ডিজাইন পরিবর্তন করার জন্য সুস্পষ্ট নির্দেশাবলী (উদাহরণস্বরূপ, "#speed নোডের টেক্সট '65 mph'-এ সেট করুন")।
  • অপ্টিমাইজেশনের জন্য UpdatePolicy : প্রতিটি প্রি-রেন্ডার পাসের পরে, একটি UpdatePolicy ভ্যালু রিটার্ন করা হয়, যা নির্দেশ করে কখন পরবর্তী রেন্ডারিং আপডেট প্রয়োজন। যদি কোনো স্টেট পরিবর্তন পেন্ডিং না থাকে এবং কোনো অ্যানিমেশন চালু না থাকে, তাহলে UpdatePolicy সংকেত দেয় যে তাৎক্ষণিকভাবে আর কোনো আপডেটের প্রয়োজন নেই। এই ধরনের ক্ষেত্রে, Reducer নতুন ডিসপ্লে লিস্ট তৈরি করা বন্ধ করে দেয়, যা অপ্রয়োজনীয় রেন্ডারিং সাইকেল প্রতিরোধ করে এবং কোনো নতুন অ্যাকশন বা ইভেন্ট পরিবর্তনটি ট্রিগার না করা পর্যন্ত রিসোর্স সংরক্ষণ করে।

১.৩ ভিউ ইনজেশন এবং রিপোজিটরি প্রারম্ভিকীকরণ

পাইপলাইনটি একটি DesignComposeDefinition ইনস্ট্যান্স দিয়ে শুরু হয়। এটি হলো ফিগমা ডিজাইন ডকুমেন্ট, যা DesignCompose দ্বারা একটি প্রোটোকল বাফার স্ট্রাকচারে সিরিয়ালাইজ করা হয়।

  • প্রাথমিক লোড: চালুর সময়, মূল ডিজাইনটি (যা এর রুট নোড দ্বারা নির্দিষ্ট করা হয়) DesignComposeDefinition থেকে একটি প্রাথমিক SquooshView ট্রি-তে রূপান্তরিত হয়। এটি একটি এককালীন প্রক্রিয়া।

  • রিপোজিটরি: SquooshVariantRepository পুনঃব্যবহারযোগ্য কম্পোনেন্ট ভ্যারিয়েন্ট এবং প্রাথমিকভাবে লোড হওয়া ভিউগুলো পরিচালনা করে।

  • লেজি লোডিং: স্টার্টআপ টাইম এবং মেমরি ব্যবহার কমানোর জন্য, অতিরিক্ত ভিউগুলো (যেগুলো প্রাথমিক রুট নোড ট্রির অংশ নয়) ডকুমেন্ট থেকে শুধুমাত্র তখনই লেজি লোড করা হয়, যখন রেন্ডার লজিকের জন্য সেগুলোকে স্পষ্টভাবে রেফারেন্স করা হয় এবং প্রয়োজন হয় (উদাহরণস্বরূপ, একটি তালিকা কাস্টমাইজেশনের সময়)।

১.৪ কাস্টমাইজেশন পাস

ডাইনামিক অ্যাপ স্টেট প্রয়োগ করার জন্য SquooshView ট্রি-টি ট্র্যাভার্স করা হয়:

  • ভ্যারিয়েন্ট অদলবদল: রানটাইম লজিকের উপর ভিত্তি করে কম্পোনেন্ট ইনস্ট্যান্সগুলোকে নির্দিষ্ট ভ্যারিয়েন্টের সাথে অদলবদল করা হয় (উদাহরণস্বরূপ, বর্তমান ড্রাইভ মোডের আইকনটি স্পোর্ট থেকে ইকো-তে পরিবর্তন করা)।

  • তালিকা সম্প্রসারণ: ফিগমাতে একটি একক টেমপ্লেট আইটেমকে তার চাইল্ড আইটেমগুলোর একটি ডাইনামিক তালিকা দ্বারা প্রতিস্থাপন করা হয়। অ্যানিমেশনের জন্য একটি স্থিতিশীল পরিচয় যাচাই করতে এই চাইল্ড আইটেমগুলোর জন্য নতুন অনন্য আইডি তৈরি করা হয়।

  • টেক্সট এবং স্টাইল ওভাররাইড: টেক্সট কন্টেন্ট (যেমন, স্পিড ভ্যালু) এবং স্টাইল (যেমন, অপাসিটি, কালার) বর্তমান অবস্থা থেকে আপডেট করা হয়।

১.৫ পরিবর্তনশীল রেজোলিউশন

ফিগমাতে অথবা অ্যাপের মধ্যে স্থানীয়ভাবে সংজ্ঞায়িত ডিজাইন টোকেন ও ভেরিয়েবলগুলো সমাধান করা হয়।

  • বাইন্ডিং: SquooshView যে প্রোপার্টিগুলো ভেরিয়েবলকে রেফারেন্স করে (যেমন রং বা ডাইমেনশন), সেগুলোকে বর্তমান ফ্রেমের জন্য তাদের সুনির্দিষ্ট মান দিয়ে প্রতিস্থাপন করা হয়।

১.৬ লেআউট গণনা

  • ডাইনামিক লেআউট: DynamicLayout , SquooshView ট্রি-এর প্রতিটি নোডের চূড়ান্ত অবস্থান এবং আকার (বাউন্ডস) নির্ধারণ করে।

  • টেক্সট লেআউট: TextHelper টেক্সটের মেট্রিক্স, র‍্যাপিং এবং শেপিং গণনা করার জন্য LayoutHelper ট্রেইটের একটি ইমপ্লিমেন্টেশন ব্যবহার করে। এটি রেন্ডার করার আগে টেক্সট তার সীমাবদ্ধতার মধ্যে সঠিকভাবে প্রবাহিত হচ্ছে কিনা তা যাচাই করতে সাহায্য করে।

১.৭ ডায়াল এবং গেজ

এটি অটোমোটিভ ইউআই-এর জন্য একটি বিশেষায়িত ধাপ।

  • MeterData : যদি কোনো নোডের মিটার ডেটা থাকে (যা ফিগমাতে সংজ্ঞায়িত করা আছে), তাহলে meter_value (যেমন, গাড়ির গতি) উপর ভিত্তি করে এর জ্যামিতি গতিশীলভাবে পরিবর্তিত হয়।
    • আর্ক: সুইপ অ্যাঙ্গেল সামঞ্জস্য করা হয়।
    • ঘূর্ণন: ঘূর্ণন রূপান্তরটি শুরু এবং শেষ কোণের উপর ভিত্তি করে গণনা করা হয়।
    • প্রোগ্রেস বার: একটি আয়তক্ষেত্রের প্রস্থ বা উচ্চতা পরিমাপ করা হয়।
    • অগ্রগতি ভেক্টর: একটি ভেক্টর পথের দৈর্ঘ্য সমন্বয় করা হয়।

১.৮ অ্যানিমেশন

  • পার্থক্য নির্ণয়: বর্তমান SquooshView PreRenderCache এর previous_squoosh_view এর সাথে তুলনা করা হয়।

  • ইন্টারপোলেশন: প্রোপার্টি পরিবর্তিত হলে, Squoosh সময়ের সাথে সাথে মানগুলির (যেমন, অপাসিটি বা ট্রান্সফর্ম) মসৃণ পরিবর্তনের জন্য ইন্টারপোলেটর তৈরি করে।

পর্যায় ২: কমান্ড তৈরি

SquooshView ট্রি-টি সম্পূর্ণরূপে রিজলভ ও অ্যানিমেট হওয়ার পর, এটি ড্রয়িং কমান্ডের একটি রৈখিক অনুক্রমে রূপান্তরিত হয়।

এই পর্যায়ের মূল উপাদান হলো DisplayList ক্রেট:

  • generate_dl : এই ফাংশনটি পুনরাবৃত্তিমূলকভাবে SquooshView ট্রি-কে ট্র্যাভার্স করে।

  • অনুবাদ:

    • আকৃতি এবং পাথ: উপযুক্ত DisplayListAppearance ভ্যারিয়েন্ট (যেমন, Rect বা Path ) ব্যবহার করে DisplayListEntry তে রূপান্তরিত হয়।
    • টেক্সট: TextHelper ব্যবহার করে টেক্সট ড্রয়িং এন্ট্রিতে রূপান্তরিত করা হয়েছে।
    • ট্রান্সফর্ম এবং ক্লিপ: ড্রয়িং স্টেট স্ট্যাক পরিচালনা করার জন্য এগুলোকে PushTransform3DPopTransform3D অথবা PushClipRegionPopClipRegion জোড়ায় রূপান্তর করা হয়।
    • মাস্কিং: লেয়ারগুলো সঠিকভাবে তৈরি ও মিশ্রিত করার জন্য PushMaskLayer এবং PopMaskLayer জোড়ায় রূপান্তরিত করা হয়েছে।

চূড়ান্ত ফলাফলটি হলো Vec<DisplayListEntry> এর একটি ইনস্ট্যান্স, যা বর্ণনা করে কী আঁকতে হবে, কীভাবে আঁকতে হবে তা নির্বিশেষে।

২.১ লুফারের কাছে হস্তান্তর

DisplayList তৈরি হওয়ার পর, Reducer সেটিকে ViewDescriptor এর একটি ইনস্ট্যান্সে মোড়কজাত করে এবং একটি Rust MPSC চ্যানেলের ( LooperMessage ) মাধ্যমে লুফার থ্রেডে পাঠিয়ে দেয়। Looper রেন্ডারিং এবং ডিসপ্লে পর্যায়ের জন্য দায়ী থাকে, যা Reducer থ্রেডকে গ্রাফিক্স পাইপলাইন ব্লক করা থেকে বিরত রাখে।

পর্যায় ৩: রেন্ডারিং

প্ল্যাটফর্ম-নিরপেক্ষ DisplayList রেন্ডারিং ব্যাকএন্ডে হস্তান্তর করা হয়, যেখানে বিমূর্ত কমান্ডগুলোকে GPU নির্দেশাবলীতে অনুবাদ করা হয়।

HAR ইম্পেলার (Impeller) ব্যবহার করে, যা মূলত ফ্লাটারের (Flutter) জন্য নির্মিত একটি রেন্ডারিং ইঞ্জিন। বিল্ড টাইমে অল্প সংখ্যক ও কার্যকর শেডার প্রি-কম্পাইল করার মাধ্যমে শেডার কম্পাইলেশনের কারণে সৃষ্ট ফ্রেম রেটের ত্রুটি (glitch) সমস্যার সমাধান করার জন্য ইম্পেলারকে ডিজাইন করা হয়েছে। এই পদ্ধতি, কার্যকর ব্যাচিং এবং একটি অত্যন্ত অপ্টিমাইজ করা ব্যাকএন্ডের সাথে মিলিত হয়ে নিম্নলিখিত ফলাফল প্রদান করে:

  • সুনির্দিষ্ট কর্মক্ষমতা: রানটাইম শেডার কম্পাইলেশনের ত্রুটি প্রায় সম্পূর্ণরূপে দূর করে।
  • দ্রুত স্টার্টআপ: প্রারম্ভিককরণের অতিরিক্ত কাজ কমিয়ে দেয়।
  • স্বল্প আকার: একটি সংহত বাইনারি আকার তৈরি করে।

ইম্পেলারের আর্কিটেকচার সম্পর্কে বিস্তারিত জানতে [Introducing Impeller - Flutter's new rendering engine][impeller-video] ভিডিওটি দেখুন। যদিও ভিডিওটিতে ফ্লাটার নিয়ে আলোচনা করা হয়েছে, এই মূল সুবিধাগুলো সরাসরি HAR অটোমোটিভ স্ট্যাককে শক্তিশালী করে।

রেন্ডারিং পর্বের মূল উপাদানগুলো হলো:

  • ImpellerRenderer : প্রি-রেন্ডার পর্যায়ের ডিসপ্লে তালিকাটিকে ইম্পেলার রেন্ডারিং কমান্ডে রূপান্তর করে।

  • ইম্পেলার রাস্ট এপিআই: রাস্টে ব্যবহারের জন্য ইম্পেলার লাইব্রেরিকে র‍্যাপ করে ( impeller এবং impeller-rs-bindgen ক্রেটগুলো)।

  • TypographyContext : ফন্ট নিবন্ধন এবং টেক্সটের আকার নির্ধারণ পরিচালনা করে।

ইম্পেলার-ভিডিও

৩.১ প্রারম্ভিককরণ এবং পৃষ্ঠতল ব্যবস্থাপনা

  • কনটেক্সট তৈরি: রেন্ডারার একটি OpenGL ES ব্যাকএন্ড সহ impeller::Context এর একটি ইনস্ট্যান্স ইনিশিয়ালাইজ করে এবং প্ল্যাটফর্মের GL কনটেক্সট থেকে OpenGL ES ফাংশন পয়েন্টারগুলো রিজলভ করার জন্য একটি কলব্যাক পাস করে।

  • র‍্যাপড এফবিও সারফেস: নিজস্ব উইন্ডো তৈরি করার পরিবর্তে, ইম্পেলার ফেজ ৪ দ্বারা সরবরাহকৃত একটি বিদ্যমান ওপেনজিএল ফ্রেমবাফার অবজেক্টে (এফবিও) রেন্ডার করে। এটি Surface::create_wrapped_fbo কল করার মাধ্যমে করা হয়।

৩.২ সম্পদ ব্যবস্থাপনা

  • ইমেজ: স্ট্যান্ডার্ড ফরম্যাট এবং KTX2 কম্প্রেসড টেক্সচার সমর্থন করে। এগুলো GPU টেক্সচারে আপলোড করা হয় এবং একটি অভ্যন্তরীণ Resources struct দ্বারা পরিচালিত হয়।

  • ফন্ট: টেক্সট রেন্ডারিংয়ের জন্য TrueType এবং OpenType ফন্টগুলো TypographyContext এ লোড ও রেজিস্টার করা হয়।

  • বাহ্যিক চিত্র: বাহ্যিক টেক্সচারের (যেমন, ক্যামেরা ফিড এবং বাহ্যিক 3D রেন্ডারার) জন্য বিশেষায়িত ব্যবস্থাপনার মধ্যে রয়েছে জিরো-কপি রেন্ডারিংয়ের উদ্দেশ্যে EGLImage ইনস্ট্যান্স বা বাহ্যিক OpenGL টেক্সচারকে Impeller Texture অবজেক্টের সাথে বাইন্ড করা।

৩.৩ রেন্ডার পাস

render লুপটি DisplayListBuilder ব্যবহার করে একটি Impeller DisplayList ইনস্ট্যান্স তৈরি করে (প্রি-রেন্ডার পর্যায়ে তৈরি Vec<DisplayListEntry> এর সাথে এটিকে গুলিয়ে ফেলবেন না):

  1. বাফারটি খালি করে এবং ডিপিআই স্কেলিং ও ডিসপ্লে রোটেশনের জন্য গ্লোবাল ট্রান্সফর্ম প্রয়োগ করে।

  2. ইনপুট DisplayListEntry আইটেমগুলোর মধ্যে দিয়ে পুনরাবৃত্তি করে:

    • অবস্থা: save() এবং restore() ট্রান্সফর্ম ও ক্লিপ রিজিয়ন পুশ ও পপ করতে ব্যবহৃত হয়।
    • প্রিমিটিভ: Rect এবং RoundedRect সাধারণ পেইন্ট অপারেশন ব্যবহার করে আঁকা হয়।
    • পাথ: জটিল ভেক্টর পাথ (ডাইনামিক Arc ইনস্ট্যান্স সহ) তৈরি ও অঙ্কন করা হয়।
    • Text: Text এবং StyledText TypographyContext ব্যবহার করে রেন্ডার করা হয়।
    • ছবি: সাধারণ ও বাহ্যিক ছবিগুলো draw_texture_rect ব্যবহার করে আঁকা হয়।
  3. surface.draw_display_list() ব্যবহার করে নির্মিত ইম্পেলার ডিসপ্লে তালিকাটি সারফেসে জমা দেয়, যা অন্তর্নিহিত জিএল কমান্ডগুলো তৈরি করে।

  4. চতুর্থ পর্যায় শুরু করার জন্য অন্তর্নিহিত কনটেক্সটে swap_buffers() কল করা হয়।

চতুর্থ পর্যায়: উপস্থাপনা

এই চূড়ান্ত পর্যায়টি রেন্ডার করা ফ্রেমটি দেখানোর জন্য ডিসপ্লে হার্ডওয়্যারের সাথে মিথস্ক্রিয়া পরিচালনা করে। HAR, Android Automotive OS (AAOS) Software-Defined Vehicle (SDV)-তে একটি শক্তিশালী ডাইরেক্ট রেন্ডারিং পাথ ব্যবহার করে।

এই পর্যায়ের মূল উপাদান হলো HarDirectRenderingContext (যা har-gl-context ক্রেটে অবস্থিত)।

৪.১ স্থাপত্য

প্রেজেন্টেশন লেয়ারটি একটি অফস্ক্রিন ড্র টার্গেট সহ ডাবল-বাফারড পদ্ধতি ব্যবহার করে:

  1. ড্র বাফার: অফস্ক্রিন এফবিও যেখানে ইম্পেলার দৃশ্যটি রেন্ডার করে।

  2. রিজলভ বাফার (ঐচ্ছিক): মাল্টিস্যাম্পল অ্যান্টি-এলাইজিং (MSAA) সমর্থন করার জন্য ঐচ্ছিক সহায়ক বাফার।

    • অন্তর্নিহিত OpenGL ES ইমপ্লিমেন্টেশন বা কনফিগারেশনের প্রয়োজনে এটি সক্রিয় করা যেতে পারে। এক্ষেত্রে, রেন্ডার বাফারে ব্লিটিং (বিট ব্লক স্থানান্তর) করার আগে মাল্টিস্যাম্পলড ড্র বাফারটি সমাধান করার জন্য এটি একটি অন্তর্বর্তী লক্ষ্য হিসাবে কাজ করে।
  3. রেন্ডার বাফার: একটি GBM অবজেক্ট দ্বারা সমর্থিত জেনেরিক বাফার, যা একটি সাধারণ গ্রাফিক্স সোয়াপ চেইনের ব্যাক বাফারের অনুরূপ।

  4. ফ্রন্ট বাফার: জিবিএম বাফার যা স্ক্যান করে ডিসপ্লেতে পাঠানো হয়।

৪.২ অদলবদল শৃঙ্খল

যখন swap_buffers কল করা হয়, HAR নিম্নলিখিত ধাপগুলো অনুসরণ করে:

  1. ড্র বাফারের বিষয়বস্তু রেন্ডার বাফারে ব্লিট করে (বাস্তবায়নের প্রয়োজনে, এর মাঝে রিজলভ বাফারেও একটি ব্লিট করা হয়)।

  2. GL কনটেক্সটে glFlush() কল করা হয়, এবং GPU কমপ্লিশন ট্র্যাক করার জন্য EGL_SYNC_NATIVE_FENCE_ANDROID এর একটি ইনস্ট্যান্স তৈরি করা হয়।

  3. রেন্ডার বাফারকে স্ক্রিনে সোয়াপ করার জন্য একটি ডিআরএম অ্যাটমিক রিকোয়েস্ট তৈরি করে। এই রিকোয়েস্টটিতে জিপিইউ ফেন্স এফডি (যাকে ইন ফেন্স বলা হয়) থাকে, যা জিপিইউ-এর ড্রয়িং শেষ হওয়ার আগে ডিসপ্লে কন্ট্রোলারকে রেন্ডার বাফারটি দেখানো থেকে বিরত রাখে।

  4. একই সাথে DRM-এর কাছে একটি নতুন ফেন্স (যাকে আউট ফেন্স বলা হয়) অনুরোধ করা হয়, যাতে পূর্ববর্তী বাফারটি (আগের ফ্রেমের ফ্রন্ট বাফার) যখন আর স্ক্রিনে থাকবে না, সেই সংকেত দেওয়া যায়।

  5. ননব্লকিং ফ্ল্যাগ ব্যবহার করে অ্যাটমিক রিকোয়েস্টটি কমিট করা হয়, যাতে গ্রাফিক্স সাবসিস্টেমগুলো সিনক্রোনাইজড থাকা অবস্থায় মেইন থ্রেড তার কাজ চালিয়ে যেতে পারে।

  6. নতুন আউট ফেন্সটিকে কনটেক্সটে সংরক্ষণ করা হয়, যাতে পরবর্তী ফ্রেমে swap_buffers প্রসেস শুরু হওয়ার সময় HAR এটির সিগন্যালের জন্য অপেক্ষা করতে পারে। এর ফলে GPU এমন কোনো বাফারে ড্র করতে পারে না যা তখনও প্রদর্শিত হচ্ছে।

৪.৩ ডাইরেক্ট মোড সেটিং

HAR, DRM এবং কার্নেল মোড সেটিং (KMS) সাবসিস্টেম ব্যবহার করে সরাসরি কার্নেলের সাথে যোগাযোগ করে AAOS SDV ডিসপ্লে রেজোলিউশন কনফিগার করে, যা (নির্দিষ্ট কনফিগারেশনে) সারফেসফ্লিঙ্গারের মতো উইন্ডো ম্যানেজারদের সাথে মিথস্ক্রিয়াকে বাইপাস করে এবং ডিসপ্লে হার্ডওয়্যারের উপর একচেটিয়া ও উচ্চ-অগ্রাধিকার নিয়ন্ত্রণ প্রদান করে।

৪.৪ বাহ্যিক রেন্ডারিং

HAR নির্দিষ্ট UI এলিমেন্টের (Figma-তে ট্যাগ দ্বারা চিহ্নিত) রেন্ডারিং-এর কাজকে বাহ্যিক প্রসেস বা থ্রেডের কাছে অর্পণ করা সমর্থন করে। এটি জটিল 3D সিন (উদাহরণস্বরূপ, Kanzi বা Unity-র মতো ইঞ্জিন থেকে তৈরি একটি ইগো কার ভিজ্যুয়ালাইজেশন) অথবা এমন অন্যান্য কন্টেন্ট ইন্টিগ্রেট করার জন্য উপযোগী, যার জন্য একটি ডেডিকেটেড OpenGL কনটেক্সট প্রয়োজন।

৪.৪.১ মূল উপাদানসমূহ

  • HarExternalRenderContext : এক্সটার্নাল সার্ভিসের জন্য একটি ডেডিকেটেড অফস্ক্রিন EGL কনটেক্সট।
  • SurfacePool : ডাবল বা ট্রিপল বাফারিংয়ের জন্য এক সেট LocalSurface ( TextureEGLImage ) বাফার পরিচালনা করে।
  • SharedSurfaceExternalImage : এক্সটার্নাল সার্ভিস এবং মূল রেন্ডারারের মধ্যে EGLImage হ্যান্ডেল আদান-প্রদানের জন্য একটি থ্রেড-সেফ র‍্যাপার।

৪.৪.২ কর্মপ্রবাহ

কার্যপ্রবাহটি এই ক্রম অনুসরণ করে:

  1. এক্সটার্নাল সার্ভিসটি চালু হয়ে মেইন লুপারের সাথে নিজেকে রেজিস্টার করে এবং কোন ফিগমা ট্যাগগুলো (যেমন, #cluster/3d-car ) এটি রেন্ডার করবে তা শনাক্ত করে।

  2. সার্ভিসটি তার রেন্ডারিংকে ডিসপ্লের VSYNC সিগন্যালের সাথে সামঞ্জস্যপূর্ণ করার জন্য লুফার থেকে RenderStart সিগন্যালের জন্য অপেক্ষা করে।

  3. অফস্ক্রিনে, পরিষেবাটি SurfacePool দ্বারা সরবরাহকৃত একটি ফ্রেমবাফারে তার বিষয়বস্তু রেন্ডার করে।

  4. সার্ভিসটি তার কনটেক্সটে swap_buffers কল করে, যা পুলটিকে রোটেট করে এবং সম্পন্ন ফ্রেমটিকে SharedSurface এর একটি ইনস্ট্যান্স হিসেবে উপলব্ধ করে।

  5. SharedSurface ExternalImage এর মধ্যে মোড়ানো হয় এবং একটি Rust MPSC চ্যানেলের মাধ্যমে লুফারে পাঠানো হয়।

  6. প্রধান ইম্পেলার রেন্ডারার (ফেজ ৩) এক্সটার্নাল ইমেজটি গ্রহণ করে। পিক্সেল ডেটা কপি করার পরিবর্তে, এটি অন্তর্নিহিত EGLImage সরাসরি একটি টেক্সচারের সাথে যুক্ত করে এবং মূল দৃশ্যের অংশ হিসেবে অঙ্কন করে, যার ফলে জিরো-কপি কম্পোজিশন সম্পন্ন হয়।

৪.৫ উন্নয়ন এবং পরীক্ষণ প্ল্যাটফর্ম (har-platform-linux)

উন্নয়ন এবং পরীক্ষার উদ্দেশ্যে, HAR অ্যাপগুলো স্ট্যান্ডার্ড লিনাক্স ডেস্কটপ এনভায়রনমেন্ট এবং হেডলেস সেটআপকে টার্গেট করতে পারে। এই প্ল্যাটফর্মগুলো crates/reference/platforms/har-platform-linux ক্রেটটিতে ইমপ্লিমেন্ট করা হয়েছে।

প্রোডাকশন AAOS SDV টার্গেটের বিপরীতে, এই প্ল্যাটফর্মগুলো ডিসপ্লে আউটপুটের জন্য har-gl-context এর direct-rendering সাবসিস্টেম ব্যবহার করে না। পরিবর্তে, এগুলো স্ট্যান্ডার্ড রাস্ট OpenGL ক্রেটগুলোর উপর নির্ভর করে:

  • উইন্ডোড মোড: উইন্ডো ব্যবস্থাপনা ও ইভেন্ট লুপের জন্য winit এবং OpenGL ES কনটেক্সট তৈরি ও উইন্ডোয়িং সিস্টেমের সাথে সমন্বয়ের জন্য glutin ব্যবহার করে।

  • হেডলেস মোড: ডিফল্ট EGL ডিসপ্লে সহ একটি অফস্ক্রিন pbuffer কনটেক্সট তৈরি করতে har-gl-context ক্রেটটি ব্যবহার করে। এটি কোনো দৃশ্যমান উইন্ডো বা সরাসরি ডিসপ্লে হার্ডওয়্যার অ্যাক্সেসের প্রয়োজন ছাড়াই একটি অফস্ক্রিন বাফারে রেন্ডারিং সক্ষম করে, যা প্রধানত স্বয়ংক্রিয় টেস্টিং বা ব্যাকএন্ড প্রসেসিংয়ের জন্য ব্যবহৃত হয়।