หน้านี้แสดงรายละเอียดไปป์ไลน์กราฟิกที่สมบูรณ์ของตัวแสดงผลความพร้อมใช้งานสูง (HAR) โดยติดตามโฟลว์ของข้อมูลจากเอกสารการออกแบบ Figma ไปจนถึงพิกเซลสุดท้ายที่แสดงบนหน้าจอ
ภาพรวม
ไปป์ไลน์จะแปลงคำจำกัดความ UI ระดับสูงเป็นคำสั่งกราฟิกในระดับต่ำ และนำเสนออย่างมีประสิทธิภาพบนจอแสดงผลฮาร์ดแวร์ ไปป์ไลน์นี้ออกแบบมาสำหรับ แอปที่สำคัญต่อความปลอดภัยของยานยนต์ โดยเน้นการแสดงผลที่แน่นอน การจัดการสถานะที่มีประสิทธิภาพ และการโต้ตอบที่แข็งแกร่งกับกราฟิกของแพลตฟอร์ม ระบบย่อย เช่น Direct Rendering Manager (DRM) และ Generic Buffer Management (GBM)
โดยไปป์ไลน์แบ่งออกเป็น 4 ระยะหลักๆ ดังนี้
- การแสดงผลล่วงหน้า: การประมวลผลกราฟฉาก การใช้การปรับแต่ง และ การแก้ปัญหาเลย์เอาต์
- การสร้างคำสั่ง: แปลงกราฟฉากที่แก้ไขแล้วเป็นรายการแสดงผลที่ไม่ขึ้นกับแบ็กเอนด์
- การแสดงผล: การเรียกใช้คำสั่งการวาดโดยใช้เครื่องมือการแสดงกราฟิก Impeller
- การนำเสนอ: การจัดการเฟรมบัฟเฟอร์และการซิงค์กับฮาร์ดแวร์จอแสดงผล
รูปที่ 1 โฟลว์กราฟิก HAR
ระยะที่ 1: แสดงผลล่วงหน้า
ในขั้นตอนนี้จะเปลี่ยนการออกแบบ Figma แบบคงที่และสถานะแอปแบบไดนามิกให้เป็นทรี UI ในหน่วยความจำที่ได้รับการแก้ไขอย่างสมบูรณ์พร้อมสำหรับการแสดงผล เฟสนี้จะทำงานใน เธรดตัวลดที่เฉพาะเจาะจง ซึ่งแยกจากลูปการแสดงผลหลัก
1.1 ฐานรากของ DesignCompose
ไปป์ไลน์ HAR สร้างขึ้นบนระบบนิเวศ DesignCompose
- แหล่งที่มา: UI ได้รับการออกแบบใน Figma และส่งออกโดยใช้ปลั๊กอิน DesignCompose
- คำจำกัดความ: เอาต์พุตคืออินสแตนซ์ของ
DesignComposeDefinitionซึ่งเป็น การแสดงการออกแบบ (โหนด สไตล์ ตัวแปร) ที่แปลงเป็นรูปแบบข้อมูล - การเชื่อมโยงข้อมูล: โมเดล UI ของแอปใช้มาโครแบบขั้นตอน (เช่น
#[Design(node = "#speed")]) เพื่อเชื่อมโยงฟิลด์โครงสร้าง Rust กับ โหนดที่มีชื่อเฉพาะในเอกสาร Figma อย่างชัดเจน ซึ่งจะช่วยให้สถานะของแอป ขับเคลื่อนพร็อพเพอร์ตี้ขององค์ประกอบภาพได้โดยอัตโนมัติ
องค์ประกอบสำคัญของรากฐานนี้มีดังนี้
- Reducer: ทำหน้าที่เป็นลูปเหตุการณ์ส่วนกลาง ประมวลผลการดำเนินการ และอัปเดต
สถานะปัจจุบัน เฟรมเวิร์กมี
DefaultReducerแต่คุณสามารถใช้ตัวลดที่กำหนดเองได้หากต้องการ - Presenter: เชื่อมต่อสถานะปัจจุบันกับโมเดล UI
Presenterลักษณะภาษาจะระบุโดยลังเฟรมเวิร์กharryและการใช้งานอ้างอิง (UIModelPresenter) จะมีให้ในลังharry-app-core - โมเดล UI: สร้างการปรับแต่งตามสถานะปัจจุบัน โค้ดโมเดล UI สร้างขึ้นโดยใช้มาโคร
DesignDocumentที่จัดทำโดยderive_customizationsCrateUIModelstruct ในharry-app-corecrate เป็นตัวอย่างของเรื่องนี้ - Squoosh: มีโครงสร้างข้อมูล
SquooshViewและที่เก็บตัวแปร ซึ่งใช้ในการแสดงผล UI ตามการออกแบบdc_bundleCrate จะโหลดเอกสารการออกแบบที่แปลงเป็นอนุกรมจากไลบรารี DesignCompose และแปลงเป็นโครงสร้างSquooshViewแบบต้นไม้เพื่อประสิทธิภาพรันไทม์ ที่มีประสิทธิภาพ
1.2 ลูปตัวลด
ไปป์ไลน์จะขับเคลื่อนด้วยการดำเนินการ เฟรมเวิร์กจะระบุActions
ประเภทที่แจงนับซึ่งกำหนดการดำเนินการภายในที่เฟรมเวิร์กใช้เอง แต่
ยังรวมถึงตัวแปร CustomAction ซึ่งช่วยให้ผู้ใช้กำหนดการดำเนินการเพิ่มเติม
เฉพาะแอปได้ (เช่น UpdateVehicleSpeed หรือ
ButtonPress)
เฟรมเวิร์กยังมีลักษณะ StateAction ที่
ช่วยลดความซับซ้อนในการติดตั้งใช้งานการดำเนินการที่ส่งผลต่อสถานะของแอป และอาจ
สร้างผลข้างเคียงที่ส่งกลับไปยังแอปจาก
ตัวลดสำหรับการประมวลผล CustomActions enum ใน harry-app-core crate
มีตัวอย่างโดยละเอียดของเรื่องนี้
นี่คือโครงร่างพื้นฐานของลูปตัวลด
- การประมวลผลการดำเนินการ:
Reducerได้รับการดำเนินการและอัปเดต สถานะปัจจุบัน นี่คือข้อมูลดิบ เช่น ความเร็วปัจจุบันหรือ สัญญาณเตือน (ไฟเตือน) ที่ทำงานอยู่ ซึ่งอาจทำให้เกิดผลข้างเคียงด้วย (เช่น สัญญาณจะส่งเสียงกริ่งเมื่อไฟเข็มขัดนิรภัยกะพริบ) - Presentation:
Presenterจะแมปสถานะใหม่เป็นUIModelUIModelคือโมเดลมุมมองที่เก็บข้อมูลซึ่งจัดรูปแบบมาโดยเฉพาะสำหรับ UI (เช่น การจัดรูปแบบความเร็ว "120" เป็นสตริง "65 mph") - การสร้างการปรับแต่ง: มีการเรียกใช้เมธอด
applyของโมเดล UI เพื่อ สร้างชุดอินสแตนซ์RenderCustomizationคำสั่งเหล่านี้เป็นคำสั่งที่ชัดเจน สำหรับการแก้ไขดีไซน์ Figma (เช่น "ตั้งค่าข้อความของโหนด #speed เป็น '65 mph'") UpdatePolicyสำหรับการเพิ่มประสิทธิภาพ: หลังจากผ่านการแสดงผลล่วงหน้าแต่ละครั้ง ระบบจะแสดงผลUpdatePolicyซึ่งระบุเวลาที่ต้องมีการอัปเดตการแสดงผลครั้งถัดไป หากไม่มีการเปลี่ยนแปลงสถานะที่รอดำเนินการและไม่มีภาพเคลื่อนไหวที่กำลังทำงานอยู่UpdatePolicyจะส่งสัญญาณว่าไม่จำเป็นต้องมีการอัปเดตเพิ่มเติมในทันที ในกรณีดังกล่าว Reducer จะหยุดสร้างรายการแสดงใหม่ ซึ่งจะป้องกันไม่ให้เกิดรอบการแสดงผลที่ไม่จำเป็นและประหยัดทรัพยากรจนกว่าการดำเนินการหรือเหตุการณ์ใหม่จะทําให้เกิดการเปลี่ยนแปลง
1.3 ดูการเริ่มต้นการนำเข้าและที่เก็บ
ไปป์ไลน์จะเริ่มต้นด้วยอินสแตนซ์ DesignComposeDefinition นี่คือเอกสารการออกแบบ Figma
ที่ DesignCompose ทำให้เป็นโครงสร้างบัฟเฟอร์โปรโตคอล
การโหลดครั้งแรก: เมื่อเริ่มต้นระบบจะแปลงดีไซน์หลัก (ที่ระบุโดยโหนดรูท) จาก
DesignComposeDefinitionเป็นทรีSquooshViewเริ่มต้น ขั้นตอนนี้จะทำเพียงครั้งเดียวที่เก็บ:
SquooshVariantRepositoryจัดการตัวแปรของคอมโพเนนต์ที่นำกลับมาใช้ใหม่ และมุมมองที่โหลดในตอนแรกการโหลดแบบ Lazy Loading: เพื่อลดเวลาเริ่มต้นและการใช้งานหน่วยความจำ ระบบจะโหลดมุมมองเพิ่มเติม (มุมมองที่ไม่ได้เป็นส่วนหนึ่งของทรีโหนดรูทเริ่มต้น) จากเอกสารเมื่อมีการอ้างอิงอย่างชัดเจนและจำเป็นต่อตรรกะการแสดงผลเท่านั้น (เช่น ระหว่างการปรับแต่งรายการ)
1.4 บัตรปรับแต่ง
ระบบจะข้ามSquooshViewทรีเพื่อใช้สถานะแอปแบบไดนามิก
การสลับตัวแปร: ระบบจะสลับอินสแตนซ์ของคอมโพเนนต์กับตัวแปรที่เฉพาะเจาะจง (เช่น เปลี่ยนไอคอนที่แสดงโหมดการขับขี่ปัจจุบันจากสปอร์ต เป็นอีโค) ตามตรรกะรันไทม์
การขยายรายการ: ระบบจะแทนที่รายการเทมเพลตรายการเดียวใน Figma ด้วยรายการย่อยแบบไดนามิก ระบบจะสร้างรหัสที่ไม่ซ้ำกันใหม่สำหรับองค์ประกอบย่อยเหล่านี้เพื่อยืนยัน ตัวตนที่เสถียรสำหรับภาพเคลื่อนไหว
การลบล้างข้อความและสไตล์: เนื้อหาข้อความ (เช่น ค่าความเร็ว) และสไตล์ (เช่น ความทึบ สี) จะได้รับการอัปเดตจากสถานะปัจจุบัน
1.5 ความละเอียดที่ปรับเปลี่ยนได้
ระบบจะแก้ไขโทเค็นการออกแบบและตัวแปรที่กำหนดไว้ใน Figma หรือในแอป
- การเชื่อมโยง: ระบบจะแทนที่พร็อพเพอร์ตี้
SquooshViewที่อ้างอิงตัวแปร (เช่น สีหรือ ขนาด) ด้วยค่าที่แน่นอนสำหรับเฟรมปัจจุบัน
1.6 การคำนวณเลย์เอาต์
เลย์เอาต์แบบไดนามิก:
DynamicLayoutคำนวณตำแหน่งและขนาดสุดท้าย (ขอบเขต) ของทุกโหนดในโครงสร้างSquooshViewการจัดวางข้อความ:
TextHelperใช้การติดตั้งใช้งานลักษณะLayoutHelperเพื่อคำนวณเมตริกข้อความ การตัดคำ และการจัดรูปแบบ ซึ่งจะช่วยยืนยันว่าข้อความ ไหลอย่างถูกต้องภายในข้อจำกัดก่อนที่จะแสดงผล
1.7 หน้าปัดและเกจ์
นี่คือขั้นตอนเฉพาะสำหรับ UI ของยานยนต์
MeterData: หากโหนดมีข้อมูลมิเตอร์ (กำหนดไว้ใน Figma) ระบบจะเปลี่ยนรูปทรงของโหนดแบบไดนามิกตามmeter_value(เช่น ความเร็วของยานพาหนะ)- ส่วนโค้ง: ปรับมุมกวาด
- การหมุน: ระบบจะคำนวณการหมุนตามมุมเริ่มต้นและมุมสิ้นสุด
- แถบความคืบหน้า: ระบบจะปรับขนาดความกว้างหรือความสูงของสี่เหลี่ยมผืนผ้า
- เวกเตอร์ความคืบหน้า: ปรับความยาวของเส้นทางเวกเตอร์
1.8 แอนิเมชัน
การเปรียบเทียบ:
SquooshViewปัจจุบันจะเปรียบเทียบกับprevious_squoosh_viewจากPreRenderCacheการประมาณค่า: หากพร็อพเพอร์ตี้มีการเปลี่ยนแปลง
Squooshจะสร้างตัวประมาณค่า เพื่อเปลี่ยนค่า (เช่น ความทึบแสงหรือการเปลี่ยนรูป) อย่างราบรื่นเมื่อเวลาผ่านไป
ระยะที่ 2: การสร้างคำสั่ง
หลังจากSquooshViewโครงสร้างได้รับการแก้ไขและเคลื่อนไหวอย่างเต็มรูปแบบแล้ว ระบบจะแปลงโครงสร้างนั้นเป็น
ลำดับคำสั่งวาดภาพเชิงเส้น
องค์ประกอบหลักของเฟสนี้คือ Crate DisplayList
generate_dl: ฟังก์ชันนี้จะไปยังSquooshViewแบบเรียกซ้ำคำแปล:
- รูปร่างและเส้นทาง: แปลงเป็น
DisplayListEntryโดยมีDisplayListAppearanceที่เหมาะสม (เช่นRectหรือPath) - ข้อความ: แปลงด้วย
TextHelperเป็นรายการวาดข้อความ - การเปลี่ยนรูปและการตัด: แปลงเป็นคู่
PushTransform3DและPopTransform3DหรือPushClipRegionและPopClipRegionเพื่อจัดการ สแต็กสถานะการวาด - การมาสก์: แปลงเป็นคู่
PushMaskLayerและPopMaskLayerเพื่อ สร้างและผสมเลเยอร์อย่างถูกต้อง
- รูปร่างและเส้นทาง: แปลงเป็น
ผลลัพธ์สุดท้ายคืออินสแตนซ์ของ Vec<DisplayListEntry> ที่อธิบายสิ่งที่
จะวาด โดยไม่ขึ้นอยู่กับวิธีวาด
2.1 ส่งต่อให้ตัววนซ้ำ
หลังจากสร้าง DisplayList แล้ว Reducer จะห่อไว้ในอินสแตนซ์ของ
ViewDescriptor และส่งผ่านช่อง MPSC ของ Rust (LooperMessage) ไปยัง
เธรด Looper Looper มีหน้าที่รับผิดชอบในระยะการแสดงผลและการแสดง
ซึ่งจะป้องกันไม่ให้เธรด Reducer บล็อกไปป์ไลน์กราฟิก
ระยะที่ 3: การแสดงผล
DisplayList ที่ไม่ขึ้นกับแพลตฟอร์มจะส่งไปยังแบ็กเอนด์การแสดงผล
ซึ่งจะแปลคำสั่งแบบนามธรรมเป็นคำสั่ง GPU
HAR ใช้ Impeller ซึ่งเป็นเครื่องมือการแสดงผลที่สร้างขึ้นสำหรับ Flutter โดยเฉพาะ Impeller ได้รับการออกแบบมาเพื่อแก้ปัญหาเฟรมเรตที่ขัดข้องเนื่องจากการคอมไพล์ Shader โดยการคอมไพล์ล่วงหน้าซึ่งเป็นชุด Shader ขนาดเล็กที่มีประสิทธิภาพในเวลาบิลด์ แนวทางนี้ เมื่อรวมกับการจัดกลุ่มที่มีประสิทธิภาพและแบ็กเอนด์ที่ได้รับการเพิ่มประสิทธิภาพอย่างสูง จะให้ผลลัพธ์ดังนี้
- ประสิทธิภาพที่แน่นอน: ขจัดข้อบกพร่องในการคอมไพล์เชเดอร์รันไทม์แทบทั้งหมด
- การเริ่มต้นอย่างรวดเร็ว: ลดค่าใช้จ่ายในการเริ่มต้น
- ขนาดเล็ก: สร้างไบนารีขนาดกะทัดรัด
หากต้องการดูข้อมูลเบื้องต้นเกี่ยวกับสถาปัตยกรรมของ Impeller อย่างละเอียด โปรดดู[Introducing Impeller - Flutter's new rendering engine][impeller-video] แม้ว่าวิดีโอจะพูดถึง Flutter แต่ประโยชน์หลักเหล่านี้ก็ช่วยเสริมประสิทธิภาพของ HAR Automotive Stack โดยตรง
องค์ประกอบหลักของระยะการแสดงผลมีดังนี้
ImpellerRenderer: แปลงรายการแสดงผลจากเฟสก่อนการแสดงผลเป็น คำสั่งการแสดงผลของ ImpellerImpeller Rust API: Wraps the Impeller library for use in Rust (the
impellerandimpeller-rs-bindgencrates).TypographyContext: จัดการการลงทะเบียนแบบอักษรและการจัดรูปแบบข้อความ
3.1 การเริ่มต้นและการจัดการพื้นผิว
การสร้างบริบท: ตัวแสดงผลจะเริ่มต้นอินสแตนซ์ของ
impeller::Contextด้วยแบ็กเอนด์ OpenGL ES โดยส่งการเรียกกลับเพื่อแก้ไข ตัวชี้ฟังก์ชัน OpenGL ES จากบริบท GL ของแพลตฟอร์มพื้นผิว FBO ที่ห่อหุ้ม: Impeller จะแสดงผลในออบเจ็กต์เฟรมบัฟเฟอร์ OpenGL (FBO) ที่มีอยู่ซึ่ง Phase 4 จัดเตรียมให้แทนที่จะสร้างหน้าต่างของตัวเอง โดยทำได้ด้วยการเรียกใช้
Surface::create_wrapped_fbo
3.2 การจัดการทรัพยากร
รูปภาพ: รองรับรูปแบบมาตรฐานและพื้นผิวที่บีบอัด KTX2 โดยจะ อัปโหลดไปยังพื้นผิว GPU และจัดการโดยโครงสร้าง
Resourcesภายในแบบอักษร: ระบบจะโหลดและลงทะเบียนแบบอักษร TrueType และ OpenType กับ
TypographyContextสำหรับการแสดงข้อความรูปภาพภายนอก: การจัดการพิเศษสำหรับเท็กซ์เจอร์ภายนอก (เช่น ฟีดกล้องและโปรแกรมแสดงผล 3 มิติภายนอก) เกี่ยวข้องกับการเชื่อมโยง
EGLImageอินสแตนซ์ หรือเท็กซ์เจอร์ OpenGL ภายนอกกับออบเจ็กต์Textureของ Impeller เพื่อการแสดงผลแบบไม่คัดลอก
3.3 Render Pass
ลูป render สร้างอินสแตนซ์ DisplayList ของ Impeller (อย่าสับสนกับ Vec<DisplayListEntry> ที่สร้างขึ้นในระยะการแสดงผลล่วงหน้า)
โดยใช้ DisplayListBuilder
ล้างบัฟเฟอร์และใช้การแปลงทั่วโลกสำหรับการปรับขนาด DPI และการหมุนจอแสดงผล
วนซ้ำผ่านรายการ
DisplayListEntryที่ป้อน:- สถานะ: ใช้
save()และrestore()เพื่อพุชและป๊อปการเปลี่ยนรูปแบบ และภูมิภาคคลิป - องค์ประกอบพื้นฐาน:
RectและRoundedRectวาดโดยใช้การดำเนินการระบายสีมาตรฐาน - เส้นทาง: ระบบจะสร้างและวาดเส้นทางเวกเตอร์ที่ซับซ้อน (รวมถึงอินสแตนซ์
Arcแบบไดนามิก) - ข้อความ:
TextและStyledTextแสดงผลโดยใช้TypographyContext - รูปภาพ: รูปภาพมาตรฐานและรูปภาพภายนอกจะวาดโดยใช้
draw_texture_rect
- สถานะ: ใช้
ส่งรายการแสดงผลของ Impeller ที่สร้างขึ้นไปยัง Surface โดยใช้
surface.draw_display_list()ซึ่งจะสร้างคำสั่ง GL พื้นฐานเรียกใช้
swap_buffers()ในบริบทพื้นฐานเพื่อทริกเกอร์เฟส 4
ระยะที่ 4: การนำเสนอ
เฟสสุดท้ายนี้จะจัดการการโต้ตอบกับฮาร์ดแวร์จอแสดงผลเพื่อแสดงเฟรมที่เรนเดอร์ HAR ใช้เส้นทางการแสดงผลโดยตรงที่แข็งแกร่งใน Android Automotive OS (AAOS) Software-Defined Vehicle (SDV)
องค์ประกอบสำคัญของเฟสนี้คือ HarDirectRenderingContext (ใน
har-gl-context crate)
4.1 สถาปัตยกรรม
เลเยอร์การนำเสนอใช้แนวทางแบบบัฟเฟอร์คู่ที่มีเป้าหมายการวาดภาพนอกหน้าจอ
บัฟเฟอร์การวาด: FBO นอกหน้าจอที่ Impeller แสดงฉาก
บัฟเฟอร์ความละเอียด (ไม่บังคับ): บัฟเฟอร์เสริมที่ไม่บังคับเพื่อรองรับ การป้องกันรอยหยักแบบหลายตัวอย่าง (MSAA)
- ซึ่งจะเปิดใช้ได้เมื่อจำเป็นโดยการติดตั้งใช้งานหรือการกำหนดค่า OpenGL ES พื้นฐาน ในกรณีดังกล่าว จะทำหน้าที่เป็นเป้าหมายระดับกลางเพื่อ แก้ไขบัฟเฟอร์การวาดภาพแบบหลายตัวอย่างก่อนที่จะทำการ Blit (การโอนบิตบล็อก) ไปยังบัฟเฟอร์การแสดงผล
บัฟเฟอร์การแสดงผล: บัฟเฟอร์ทั่วไปที่ได้รับการสนับสนุนจากออบเจ็กต์ GBM ซึ่งสอดคล้อง กับบัฟเฟอร์ด้านหลังในห่วงโซ่การสลับกราฟิกทั่วไป
บัฟเฟอร์ด้านหน้า: บัฟเฟอร์ GBM ที่สแกนออกไปยังจอแสดงผล
4.2 เชนการสวอป
เมื่อมีการเรียกใช้ swap_buffers HAR จะทำตามขั้นตอนต่อไปนี้
ส่งเนื้อหาของบัฟเฟอร์การวาดไปยังบัฟเฟอร์การแสดงผล (โดยมีการส่งผ่านกลางไปยังบัฟเฟอร์การแก้ปัญหา หากการใช้งานจำเป็นต้องใช้)
เรียกใช้
glFlush()ในบริบท GL และสร้าง อินสแตนซ์ของEGL_SYNC_NATIVE_FENCE_ANDROIDเพื่อติดตามการทำงานของ GPU ให้เสร็จสมบูรณ์สร้างคำขอแบบอะตอมของ DRM เพื่อสลับบัฟเฟอร์การแสดงผลไปยังหน้าจอ คำขอนี้มี FD ของรั้ว GPU (เรียกว่ารั้วขาเข้า) เพื่อป้องกันไม่ให้ ตัวควบคุมการแสดงผลแสดงบัฟเฟอร์การแสดงผลก่อนที่ GPU จะวาดเสร็จ
ขอรั้วใหม่จาก DRM พร้อมกัน (เรียกว่ารั้วภายนอก) เพื่อส่งสัญญาณเมื่อบัฟเฟอร์ก่อนหน้า (บัฟเฟอร์ด้านหน้าสำหรับเฟรมก่อนหน้า) ไม่ได้อยู่บนหน้าจออีกต่อไป
ส่งคำขอแบบอะตอมโดยใช้แฟล็กแบบไม่บล็อก เพื่อให้เทรดหลักทำงานต่อไปได้ในขณะที่ระบบย่อยกราฟิกยังคงซิงค์อยู่
จัดเก็บรั้วใหม่ที่อยู่นอกบริบทเพื่อให้ HAR รอรับสัญญาณได้ เมื่อเริ่มกระบวนการ
swap_buffersในเฟรมถัดไป ซึ่งจะป้องกันไม่ให้ GPU วาดลงในบัฟเฟอร์ที่ยังแสดงอยู่
4.3 การตั้งค่าโหมดโดยตรง
HAR จะโต้ตอบกับเคอร์เนลโดยตรงโดยใช้ DRM และระบบย่อย Kernel Mode Setting (KMS) เพื่อกำหนดค่าความละเอียดของจอแสดงผล AAOS SDV โดยข้าม การโต้ตอบกับตัวจัดการหน้าต่าง เช่น SurfaceFlinger (ในการกำหนดค่าที่เฉพาะเจาะจง) ซึ่งช่วยให้ควบคุมฮาร์ดแวร์จอแสดงผลได้แบบพิเศษและมีลำดับความสำคัญสูง
4.4 การแสดงผลภายนอก
HAR รองรับการมอบสิทธิ์การแสดงผลองค์ประกอบ UI ที่เฉพาะเจาะจง (ระบุโดย แท็กใน Figma) ให้กับกระบวนการหรือเธรดภายนอก ซึ่งจะมีประโยชน์สำหรับการผสานรวม ฉาก 3 มิติที่ซับซ้อน (เช่น ภาพการแสดงรถยนต์ของฉันจากเอนจินอย่าง Kanzi หรือ Unity) หรือเนื้อหาอื่นๆ ที่ต้องใช้บริบท OpenGL โดยเฉพาะ
4.4.1 องค์ประกอบสำคัญ
HarExternalRenderContext: บริบท EGL นอกหน้าจอเฉพาะสำหรับ บริการภายนอกSurfacePool: จัดการชุดLocalSurface(TextureบวกEGLImage) บัฟเฟอร์สำหรับการบัฟเฟอร์ 2 หรือ 3 เท่าSharedSurfaceExternalImage: Wrapper ที่ปลอดภัยสำหรับเธรดสำหรับการส่งEGLImageแฮนเดิลระหว่างบริการภายนอกกับโปรแกรมแสดงผลหลัก
4.4.2 เวิร์กโฟลว์
เวิร์กโฟลว์จะเป็นไปตามลำดับต่อไปนี้
บริการภายนอกจะเริ่มต้นและลงทะเบียนตัวเองกับ Looper หลัก โดยระบุแท็ก Figma (เช่น
#cluster/3d-car) ที่แสดงบริการจะรอสัญญาณ
RenderStartจาก Looper เพื่อจัดแนวการแสดงผลกับสัญญาณ VSYNC ของจอแสดงผลนอกหน้าจอ บริการจะแสดงเนื้อหาใน Framebuffer ที่
SurfacePoolจัดเตรียมไว้บริการจะเรียกใช้
swap_buffersในบริบทของตัวเอง ซึ่งจะหมุนเวียนพูลและ ทำให้เฟรมที่เสร็จสมบูรณ์พร้อมใช้งานเป็นอินสแตนซ์ของSharedSurfaceSharedSurfaceจะอยู่ในExternalImageและส่งผ่านช่อง Rust MPSC ไปยัง Looperตัวแสดงผล Impeller หลัก (เฟส 3) จะได้รับภาพจากภายนอก โดยจะผูก
EGLImageพื้นฐานกับเท็กซ์เจอร์โดยตรง และวาดเป็นส่วนหนึ่งของฉากหลัก ซึ่งทำให้เกิดการคอมโพสแบบไม่ต้องคัดลอก
4.5 แพลตฟอร์มการพัฒนาและการทดสอบ (har-platform-linux)
แอป HAR สามารถกำหนดเป้าหมายเป็นสภาพแวดล้อมเดสก์ท็อป Linux มาตรฐานและการตั้งค่าแบบไม่มีส่วนหัวเพื่อวัตถุประสงค์ในการพัฒนาและการทดสอบ แพลตฟอร์มเหล่านี้ได้รับการติดตั้งใช้งานใน
crates/reference/platforms/har-platform-linux Crate
แพลตฟอร์มเหล่านี้ไม่เหมือนกับเป้าหมาย SDV ของ AAOS ที่ใช้งานจริง ซึ่งไม่ได้ใช้direct-renderinghar-gl-context แต่จะใช้ Crate OpenGL มาตรฐานของ Rust แทน
โหมดหน้าต่าง: ใช้
winitสำหรับการจัดการหน้าต่างและลูปเหตุการณ์ และglutinสำหรับการสร้างบริบท OpenGL ES และการผสานรวมกับระบบ การจัดการหน้าต่างโหมดไม่มีส่วนหัว: ใช้ Crate
har-gl-contextเพื่อสร้างบริบท Pbuffer นอกหน้าจอด้วยการแสดงผล EGL เริ่มต้น ซึ่งช่วยให้ การแสดงผลไปยังบัฟเฟอร์นอกหน้าจอได้โดยไม่ต้องมีหน้าต่างที่มองเห็นได้หรือการเข้าถึงฮาร์ดแวร์ การแสดงผลโดยตรง โดยส่วนใหญ่จะใช้สำหรับการทดสอบอัตโนมัติหรือการประมวลผล แบ็กเอนด์