ไปป์ไลน์กราฟิก HAR

หน้านี้แสดงรายละเอียดไปป์ไลน์กราฟิกที่สมบูรณ์ของตัวแสดงผลความพร้อมใช้งานสูง (HAR) โดยติดตามโฟลว์ของข้อมูลจากเอกสารการออกแบบ Figma ไปจนถึงพิกเซลสุดท้ายที่แสดงบนหน้าจอ

ภาพรวม

ไปป์ไลน์จะแปลงคำจำกัดความ UI ระดับสูงเป็นคำสั่งกราฟิกในระดับต่ำ และนำเสนออย่างมีประสิทธิภาพบนจอแสดงผลฮาร์ดแวร์ ไปป์ไลน์นี้ออกแบบมาสำหรับ แอปที่สำคัญต่อความปลอดภัยของยานยนต์ โดยเน้นการแสดงผลที่แน่นอน การจัดการสถานะที่มีประสิทธิภาพ และการโต้ตอบที่แข็งแกร่งกับกราฟิกของแพลตฟอร์ม ระบบย่อย เช่น Direct Rendering Manager (DRM) และ Generic Buffer Management (GBM)

โดยไปป์ไลน์แบ่งออกเป็น 4 ระยะหลักๆ ดังนี้

  1. การแสดงผลล่วงหน้า: การประมวลผลกราฟฉาก การใช้การปรับแต่ง และ การแก้ปัญหาเลย์เอาต์
  2. การสร้างคำสั่ง: แปลงกราฟฉากที่แก้ไขแล้วเป็นรายการแสดงผลที่ไม่ขึ้นกับแบ็กเอนด์
  3. การแสดงผล: การเรียกใช้คำสั่งการวาดโดยใช้เครื่องมือการแสดงกราฟิก Impeller
  4. การนำเสนอ: การจัดการเฟรมบัฟเฟอร์และการซิงค์กับฮาร์ดแวร์จอแสดงผล

โฟลว์กราฟิก HAR

รูปที่ 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_customizations Crate UIModel struct ใน harry-app-core crate เป็นตัวอย่างของเรื่องนี้
  • Squoosh: มีโครงสร้างข้อมูล SquooshView และที่เก็บตัวแปร ซึ่งใช้ในการแสดงผล UI ตามการออกแบบ dc_bundle Crate จะโหลดเอกสารการออกแบบที่แปลงเป็นอนุกรมจากไลบรารี DesignCompose และแปลงเป็นโครงสร้าง SquooshView แบบต้นไม้เพื่อประสิทธิภาพรันไทม์ ที่มีประสิทธิภาพ

1.2 ลูปตัวลด

ไปป์ไลน์จะขับเคลื่อนด้วยการดำเนินการ เฟรมเวิร์กจะระบุActions ประเภทที่แจงนับซึ่งกำหนดการดำเนินการภายในที่เฟรมเวิร์กใช้เอง แต่ ยังรวมถึงตัวแปร CustomAction ซึ่งช่วยให้ผู้ใช้กำหนดการดำเนินการเพิ่มเติม เฉพาะแอปได้ (เช่น UpdateVehicleSpeed หรือ ButtonPress)

เฟรมเวิร์กยังมีลักษณะ StateAction ที่ ช่วยลดความซับซ้อนในการติดตั้งใช้งานการดำเนินการที่ส่งผลต่อสถานะของแอป และอาจ สร้างผลข้างเคียงที่ส่งกลับไปยังแอปจาก ตัวลดสำหรับการประมวลผล CustomActions enum ใน harry-app-core crate มีตัวอย่างโดยละเอียดของเรื่องนี้

นี่คือโครงร่างพื้นฐานของลูปตัวลด

  • การประมวลผลการดำเนินการ: Reducer ได้รับการดำเนินการและอัปเดต สถานะปัจจุบัน นี่คือข้อมูลดิบ เช่น ความเร็วปัจจุบันหรือ สัญญาณเตือน (ไฟเตือน) ที่ทำงานอยู่ ซึ่งอาจทำให้เกิดผลข้างเคียงด้วย (เช่น สัญญาณจะส่งเสียงกริ่งเมื่อไฟเข็มขัดนิรภัยกะพริบ)
  • Presentation: Presenter จะแมปสถานะใหม่เป็น UIModel UIModel คือโมเดลมุมมองที่เก็บข้อมูลซึ่งจัดรูปแบบมาโดยเฉพาะสำหรับ 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: แปลงรายการแสดงผลจากเฟสก่อนการแสดงผลเป็น คำสั่งการแสดงผลของ Impeller

  • Impeller Rust API: Wraps the Impeller library for use in Rust (the impeller and impeller-rs-bindgen crates).

  • TypographyContext: จัดการการลงทะเบียนแบบอักษรและการจัดรูปแบบข้อความ

impeller-video

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

  1. ล้างบัฟเฟอร์และใช้การแปลงทั่วโลกสำหรับการปรับขนาด DPI และการหมุนจอแสดงผล

  2. วนซ้ำผ่านรายการ DisplayListEntry ที่ป้อน:

    • สถานะ: ใช้ save() และ restore() เพื่อพุชและป๊อปการเปลี่ยนรูปแบบ และภูมิภาคคลิป
    • องค์ประกอบพื้นฐาน: Rect และ RoundedRect วาดโดยใช้การดำเนินการระบายสีมาตรฐาน
    • เส้นทาง: ระบบจะสร้างและวาดเส้นทางเวกเตอร์ที่ซับซ้อน (รวมถึงอินสแตนซ์ Arc แบบไดนามิก)
    • ข้อความ: Text และ StyledText แสดงผลโดยใช้ TypographyContext
    • รูปภาพ: รูปภาพมาตรฐานและรูปภาพภายนอกจะวาดโดยใช้ draw_texture_rect
  3. ส่งรายการแสดงผลของ Impeller ที่สร้างขึ้นไปยัง Surface โดยใช้ surface.draw_display_list() ซึ่งจะสร้างคำสั่ง GL พื้นฐาน

  4. เรียกใช้ swap_buffers() ในบริบทพื้นฐานเพื่อทริกเกอร์เฟส 4

ระยะที่ 4: การนำเสนอ

เฟสสุดท้ายนี้จะจัดการการโต้ตอบกับฮาร์ดแวร์จอแสดงผลเพื่อแสดงเฟรมที่เรนเดอร์ HAR ใช้เส้นทางการแสดงผลโดยตรงที่แข็งแกร่งใน Android Automotive OS (AAOS) Software-Defined Vehicle (SDV)

องค์ประกอบสำคัญของเฟสนี้คือ HarDirectRenderingContext (ใน har-gl-context crate)

4.1 สถาปัตยกรรม

เลเยอร์การนำเสนอใช้แนวทางแบบบัฟเฟอร์คู่ที่มีเป้าหมายการวาดภาพนอกหน้าจอ

  1. บัฟเฟอร์การวาด: FBO นอกหน้าจอที่ Impeller แสดงฉาก

  2. บัฟเฟอร์ความละเอียด (ไม่บังคับ): บัฟเฟอร์เสริมที่ไม่บังคับเพื่อรองรับ การป้องกันรอยหยักแบบหลายตัวอย่าง (MSAA)

    • ซึ่งจะเปิดใช้ได้เมื่อจำเป็นโดยการติดตั้งใช้งานหรือการกำหนดค่า OpenGL ES พื้นฐาน ในกรณีดังกล่าว จะทำหน้าที่เป็นเป้าหมายระดับกลางเพื่อ แก้ไขบัฟเฟอร์การวาดภาพแบบหลายตัวอย่างก่อนที่จะทำการ Blit (การโอนบิตบล็อก) ไปยังบัฟเฟอร์การแสดงผล
  3. บัฟเฟอร์การแสดงผล: บัฟเฟอร์ทั่วไปที่ได้รับการสนับสนุนจากออบเจ็กต์ GBM ซึ่งสอดคล้อง กับบัฟเฟอร์ด้านหลังในห่วงโซ่การสลับกราฟิกทั่วไป

  4. บัฟเฟอร์ด้านหน้า: บัฟเฟอร์ GBM ที่สแกนออกไปยังจอแสดงผล

4.2 เชนการสวอป

เมื่อมีการเรียกใช้ swap_buffers HAR จะทำตามขั้นตอนต่อไปนี้

  1. ส่งเนื้อหาของบัฟเฟอร์การวาดไปยังบัฟเฟอร์การแสดงผล (โดยมีการส่งผ่านกลางไปยังบัฟเฟอร์การแก้ปัญหา หากการใช้งานจำเป็นต้องใช้)

  2. เรียกใช้ glFlush() ในบริบท GL และสร้าง อินสแตนซ์ของ EGL_SYNC_NATIVE_FENCE_ANDROID เพื่อติดตามการทำงานของ GPU ให้เสร็จสมบูรณ์

  3. สร้างคำขอแบบอะตอมของ DRM เพื่อสลับบัฟเฟอร์การแสดงผลไปยังหน้าจอ คำขอนี้มี FD ของรั้ว GPU (เรียกว่ารั้วขาเข้า) เพื่อป้องกันไม่ให้ ตัวควบคุมการแสดงผลแสดงบัฟเฟอร์การแสดงผลก่อนที่ GPU จะวาดเสร็จ

  4. ขอรั้วใหม่จาก DRM พร้อมกัน (เรียกว่ารั้วภายนอก) เพื่อส่งสัญญาณเมื่อบัฟเฟอร์ก่อนหน้า (บัฟเฟอร์ด้านหน้าสำหรับเฟรมก่อนหน้า) ไม่ได้อยู่บนหน้าจออีกต่อไป

  5. ส่งคำขอแบบอะตอมโดยใช้แฟล็กแบบไม่บล็อก เพื่อให้เทรดหลักทำงานต่อไปได้ในขณะที่ระบบย่อยกราฟิกยังคงซิงค์อยู่

  6. จัดเก็บรั้วใหม่ที่อยู่นอกบริบทเพื่อให้ 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 เวิร์กโฟลว์

เวิร์กโฟลว์จะเป็นไปตามลำดับต่อไปนี้

  1. บริการภายนอกจะเริ่มต้นและลงทะเบียนตัวเองกับ Looper หลัก โดยระบุแท็ก Figma (เช่น #cluster/3d-car) ที่แสดง

  2. บริการจะรอสัญญาณ RenderStart จาก Looper เพื่อจัดแนวการแสดงผลกับสัญญาณ VSYNC ของจอแสดงผล

  3. นอกหน้าจอ บริการจะแสดงเนื้อหาใน Framebuffer ที่ SurfacePool จัดเตรียมไว้

  4. บริการจะเรียกใช้ swap_buffers ในบริบทของตัวเอง ซึ่งจะหมุนเวียนพูลและ ทำให้เฟรมที่เสร็จสมบูรณ์พร้อมใช้งานเป็นอินสแตนซ์ของ SharedSurface

  5. SharedSurface จะอยู่ใน ExternalImage และส่งผ่านช่อง Rust MPSC ไปยัง Looper

  6. ตัวแสดงผล 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 เริ่มต้น ซึ่งช่วยให้ การแสดงผลไปยังบัฟเฟอร์นอกหน้าจอได้โดยไม่ต้องมีหน้าต่างที่มองเห็นได้หรือการเข้าถึงฮาร์ดแวร์ การแสดงผลโดยตรง โดยส่วนใหญ่จะใช้สำหรับการทดสอบอัตโนมัติหรือการประมวลผล แบ็กเอนด์