โครงสร้างข้อมูลสำคัญใน RenderingNG

Chris Harrelson
Chris Harrelson
Daniel Cheng
Daniel Cheng
Philip Rogers
Philip Rogers
Koji Ishi
Koji Ishi
Ian Kilpatrick
Ian Kilpatrick
Kyle Charbonneau
Kyle Charbonneau

มาดูโครงสร้างข้อมูลหลักกัน ซึ่งเป็นอินพุตและเอาต์พุตของไปป์ไลน์การแสดงผล

โครงสร้างข้อมูลเหล่านี้ ได้แก่

  • เฟรมทรีประกอบด้วยโหนดในเครื่องและโหนดระยะไกลที่แสดงถึงเว็บเอกสารที่อยู่ในกระบวนการแสดงผลและโปรแกรมแสดงผล Blink ใด
  • ต้นไม้เศษข้อมูลที่แก้ไขไม่ได้แสดงผลลัพธ์ของ (และอินพุตสำหรับ) อัลกอริทึมข้อจำกัดการจัดวาง
  • ลําดับชั้นพร็อพเพอร์ตี้แสดงลําดับชั้นการเปลี่ยนรูปแบบ คลิป เอฟเฟกต์ และการเลื่อนของเอกสารเว็บ ซึ่งจะใช้ตลอดทั้งไปป์ไลน์
  • รายการที่แสดงและกลุ่มสีเป็นอินพุตสำหรับอัลกอริทึมการแรสเตอร์และการแบ่งเลเยอร์
  • เฟรมคอมโพสิตจะห่อหุ้มพื้นผิว พื้นผิวการแสดงผล และไทล์พื้นผิวของ GPU ที่ใช้ในการวาดโดยใช้ GPU

ก่อนที่จะอธิบายโครงสร้างข้อมูลเหล่านี้ ตัวอย่างต่อไปนี้จะต่อยอดจากตัวอย่างในการตรวจสอบสถาปัตยกรรม ตัวอย่างนี้ใช้ตลอดทั้งเอกสารนี้พร้อมการสาธิตวิธีใช้โครงสร้างข้อมูล

<!-- Example code -->
<html>
  <div style="overflow: hidden; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
      id="one" src="foo.com/etc"></iframe>
  </div>
  <iframe style="top:200px;
    transform: scale(1.1) translateX(200px)"
    id="two" src="bar.com"></iframe>
</html>

ต้นไม้เป็นกรอบ

ในบางครั้ง Chrome อาจเลือกที่จะแสดงผลเฟรมข้ามแหล่งที่มาในกระบวนการแสดงผลที่แตกต่างจากเฟรมหลัก

ในตัวอย่างนี้ มีเฟรมทั้งหมด 3 เฟรม ดังนี้

เฟรมหลัก foo.com ซึ่งมี iframe 2 รายการ

เมื่อใช้การแยกเว็บไซต์ Chromium จะใช้กระบวนการแสดงผล 2 รายการเพื่อแสดงผลหน้าเว็บนี้ กระบวนการแสดงผลแต่ละรายการมีการนําเสนอแผนผังเฟรมสําหรับหน้าเว็บนั้นๆ ดังนี้

ต้นไม้เฟรม 2 ต้นที่แสดงถึงกระบวนการแสดงผล 2 รายการ

เฟรมที่แสดงผลในกระบวนการอื่นจะแสดงเป็นเฟรมระยะไกล เฟรมระยะไกลจะเก็บข้อมูลขั้นต่ำที่จำเป็นเพื่อใช้เป็นตัวยึดตําแหน่งในการแสดงผล เช่น ขนาด มิเช่นนั้นเฟรมระยะไกลจะไม่มีข้อมูลที่จำเป็นในการแสดงผลเนื้อหาจริง

ในทางตรงกันข้าม เฟรมในเครื่องแสดงถึงเฟรมที่ผ่านไปป์ไลน์การแสดงผลมาตรฐาน เฟรมในเครื่องมีข้อมูลทั้งหมดที่จำเป็นในการเปลี่ยนข้อมูลของเฟรมนั้น (เช่น ต้นไม้ DOM และข้อมูลสไตล์) ให้เป็นสิ่งที่แสดงผลได้

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

<iframe src="bar.com"></iframe>

และเฟรมย่อย bar.com ต่อไปนี้

<iframe src="foo.com/etc"></iframe>

แม้ว่าจะมีโปรแกรมแสดงผลเพียง 2 รายการ แต่ตอนนี้ก็มีเศษส่วนของเฟรมเทรียร์ในเครื่อง 3 รายการ โดย 2 รายการอยู่ในกระบวนการแสดงผลสำหรับ foo.com และ 1 รายการอยู่ในกระบวนการแสดงผลสำหรับ bar.com ดังนี้

การนําเสนอภาพเรนเดอร์ 2 ภาพและเศษส่วนของต้นไม้เฟรม 3 รายการ

หากต้องการสร้างเฟรมคอมโพสิต 1 เฟรมสําหรับหน้าเว็บ วิซจะขอเฟรมคอมโพสิตจากเฟรมรูทของต้นไม้เฟรมในเครื่อง 3 ต้นพร้อมกัน จากนั้นจะรวบรวมเฟรมเหล่านั้น โปรดดูที่ส่วนเฟรมคอมโพสิเตอร์

เฟรมหลัก foo.com และเฟรมย่อย foo.com/other-page เป็นส่วนหนึ่งของแผนผังเฟรมเดียวกันและแสดงผลในกระบวนการเดียวกัน อย่างไรก็ตาม เฟรม 2 เฟรมนี้ยังคงมีวงจรชีวิตของเอกสารแยกกันเนื่องจากเป็นส่วนหนึ่งของเศษส่วนของต้นไม้เฟรมในเครื่องที่แตกต่างกัน ด้วยเหตุนี้ จึงเป็นไปไม่ได้ที่จะสร้างเฟรมตัวประกอบ 1 เฟรมสำหรับทั้งสองการอัปเดตครั้งนี้ กระบวนการแสดงผลมีข้อมูลไม่เพียงพอที่จะคอมโพสเฟรมคอมโพสิตที่สร้างสำหรับ foo.com/other-page ลงในเฟรมคอมโพสิตสำหรับเฟรมหลัก foo.com โดยตรง เช่น เฟรมหลัก bar.com ที่อยู่นอกกระบวนการอาจส่งผลต่อการแสดงผลของ iframe foo.com/other-url โดยการเปลี่ยนรูปแบบ iframe ด้วย CSS หรือบดบังบางส่วนของ iframe ด้วยองค์ประกอบอื่นๆ ใน DOM

Waterfall การอัปเดตพร็อพเพอร์ตี้ภาพ

พร็อพเพอร์ตี้ภาพ เช่น ปัจจัยที่มีผลต่อขนาดการแสดงผลของอุปกรณ์และขนาดวิวพอร์ต จะส่งผลต่อเอาต์พุตที่แสดงผล และจะต้องซิงค์กันระหว่างเศษส่วนของต้นไม้เฟรมในเครื่อง รูทของส่วนโครงสร้างเฟรมในเครื่องแต่ละรายการมีออบเจ็กต์วิดเจ็ตที่เชื่อมโยงอยู่ การอัปเดตคุณสมบัติภาพจะไปที่วิดเจ็ตของเฟรมหลักก่อนที่จะเผยแพร่ไปยังวิดเจ็ตที่เหลือจากบนลงล่าง

ตัวอย่างเช่น เมื่อขนาดวิวพอร์ตเปลี่ยนแปลง

แผนภาพกระบวนการที่อธิบายไว้ในข้อความก่อนหน้า

กระบวนการนี้ไม่ได้เกิดขึ้นทันที ดังนั้นพร็อพเพอร์ตี้ภาพแบบทำซ้ำจึงมีโทเค็นการซิงค์ด้วย คอมโพสิตวิชวลใช้โทเค็นการซิงค์นี้เพื่อรอให้เศษส่วนของต้นไม้เฟรมในเครื่องทั้งหมดส่งเฟรมคอมโพสิตที่มีโทเค็นการซิงค์ปัจจุบัน กระบวนการนี้จะช่วยหลีกเลี่ยงการผสมเฟรมคอมโพสิตกับพร็อพเพอร์ตี้ภาพที่แตกต่างกัน

ต้นไม้ที่เปลี่ยนแปลงไม่ได้ของข้อมูลโค้ด

แผนผัง Fragment ที่เปลี่ยนแปลงไม่ได้คือเอาต์พุตของขั้นตอนเลย์เอาต์ของไปป์ไลน์การแสดงผล ซึ่งแสดงตําแหน่งและขนาดขององค์ประกอบทั้งหมดในหน้า (โดยไม่ใช้การเปลี่ยนรูปแบบ)

การนําเสนอส่วนของข้อมูลในแต่ละต้นไม้ โดยมีการทําเครื่องหมายให้ชิ้นส่วนหนึ่งว่าจําเป็นต้องจัดวางเลย์เอาต์

ส่วนย่อยแต่ละรายการแสดงถึงส่วนขององค์ประกอบ DOM โดยปกติแล้วจะมีเพียง 1 รายการต่อองค์ประกอบ 1 รายการ แต่อาจมีมากกว่านี้หากมีการแบ่งออกเป็นหน้าต่างๆ เมื่อพิมพ์ หรือแบ่งออกเป็นคอลัมน์ต่างๆ เมื่ออยู่ในบริบทแบบหลายคอลัมน์

หลังจากวางเลย์เอาต์แล้ว แต่ละส่วนจะเปลี่ยนแปลงไม่ได้และจะไม่มีการเปลี่ยนแปลงอีก และที่สำคัญ เรายังมีข้อจำกัดเพิ่มเติมอีก 2-3 ข้อ เราไม่ทำสิ่งต่อไปนี้

  • อนุญาตการอ้างอิง "ขึ้น" ในลําดับชั้น (บุตรหลานไม่สามารถชี้ไปที่ผู้ปกครองได้)
  • "ขยาย" ข้อมูลลงในลําดับชั้น (โหนดย่อยจะอ่านข้อมูลจากโหนดย่อยเท่านั้น ไม่ใช่จากโหนดหลัก)

ข้อจํากัดเหล่านี้ช่วยให้เรานําข้อมูลโค้ดที่ตัดมาจากหน้าเว็บมาใช้ซ้ำในเลย์เอาต์ต่อๆ ไปได้ หากไม่มีข้อจำกัดเหล่านี้ เราจะต้องสร้างต้นไม้ทั้งต้นขึ้นมาใหม่บ่อยครั้ง ซึ่งเป็นเรื่องที่มีค่าใช้จ่ายสูง

โดยปกติแล้ว เลย์เอาต์ส่วนใหญ่เป็นการอัปเดตแบบเพิ่มทีละน้อย เช่น เว็บแอปที่อัปเดต UI เพียงส่วนเล็กๆ เพื่อตอบสนองต่อการที่ผู้ใช้คลิกองค์ประกอบ ตามหลักการแล้ว เลย์เอาต์ควรทํางานตามสัดส่วนกับสิ่งที่เปลี่ยนแปลงบนหน้าจอจริงเท่านั้น ซึ่งทำได้ด้วยการนําส่วนต่างๆ ของโครงสร้างเดิมมาใช้ซ้ำมากที่สุด ซึ่งหมายความว่า (โดยทั่วไป) เราจําเป็นต้องสร้างกระดูกสันหลังของต้นไม้ขึ้นมาใหม่เท่านั้น

ในอนาคต การออกแบบแบบคงที่นี้อาจช่วยให้เราทําสิ่งที่น่าสนใจได้ เช่น ส่งผ่านต้นไม้ของชิ้นส่วนแบบคงที่ข้ามขอบเขตของเธรด หากจําเป็น (เพื่อดําเนินการระยะถัดไปในเธรดอื่น) สร้างต้นไม้หลายต้นเพื่อให้ภาพเคลื่อนไหวของเลย์เอาต์ราบรื่น หรือดําเนินการเลย์เอาต์แบบคาดการณ์แบบขนาน นอกจากนี้ เรายังใช้เลย์เอาต์แบบหลายเธรดได้อีกด้วย

รายการข้อมูลโค้ดที่ติดทั่วเว็บไซต์

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

ระบบจะสร้างรายการแบบแบนสำหรับบริบทการจัดรูปแบบในบรรทัดแต่ละรายการตามลำดับการค้นหาแบบเข้าหาระดับลึกของต้นไม้ย่อยของเลย์เอาต์ในบรรทัด รายการแต่ละรายการในลิสต์คือทูเปิลของ (ออบเจ็กต์, จํานวนรายการสืบทอด) ตัวอย่างเช่น ลองพิจารณา DOM นี้

<div style="width: 0;">
  <span style="color: blue; position: relative;">Hi</span> <b>there</b>.
</div>

มีการตั้งค่าพร็อพเพอร์ตี้ width เป็น 0 เพื่อให้บรรทัดอยู่ระหว่าง "สวัสดี" กับ "มี"

เมื่อแสดงบริบทการจัดรูปแบบในบรรทัดสำหรับสถานการณ์นี้ในรูปแบบต้นไม้ บริบทจะมีลักษณะดังต่อไปนี้

{
  "Line box": {
    "Box <span>": {
      "Text": "Hi"
    }
  },
  "Line box": {
    "Box <b>": {
      "Text": "There"
    }
  },
  {
    "Text": "."
  }
}

โดยรายการแบบเดี่ยวจะมีลักษณะดังนี้

  • (กล่องบรรทัด, 2)
  • (Box <span>, 1)
  • (ข้อความ "สวัสดี", 0)
  • (ช่องเส้น, 3)
  • (กล่อง <b>, 1)
  • (ข้อความ "มี", 0)
  • (ข้อความ ".", 0)

โครงสร้างข้อมูลนี้มีผู้ใช้จำนวนมาก เช่น API การช่วยเหลือพิเศษ และ API เรขาคณิต เช่น getClientRects และ contenteditable โดยแต่ละรายการมีข้อกำหนดที่แตกต่างกัน คอมโพเนนต์เหล่านี้เข้าถึงโครงสร้างข้อมูลที่เรียบง่ายผ่านเคอร์เซอร์ที่สะดวก

เคอร์เซอร์มี API เช่น MoveToNext, MoveToNextLine, CursorForChildren การนําเสนอเคอร์เซอร์นี้มีประสิทธิภาพมากสําหรับเนื้อหาข้อความเนื่องด้วยเหตุผลหลายประการ ดังนี้

  • การทำซ้ำตามลําดับการค้นหาแบบเข้าหาลําดับชั้นจะทําได้อย่างรวดเร็ว โดยใช้บ่อยมากเพราะคล้ายกับการเคลื่อนไหวของเคอร์เซอร์ข้อความ เนื่องจากเป็นรายการแบบแบน การค้นหาจากระดับลึกจึงเพิ่มเฉพาะออฟเซตของอาร์เรย์เท่านั้น ซึ่งทำให้การวนซ้ำรวดเร็วและมีการเข้าถึงหน่วยความจำในบริเวณใกล้เคียง
  • ซึ่งจะทำการค้นหาแบบกว้างก่อน ซึ่งจำเป็นในกรณีต่างๆ เช่น การวาดพื้นหลังของกล่องบรรทัดและคอลัมน์ในบรรทัด
  • การรู้จำนวนองค์ประกอบรองลงมาจะทำให้ย้ายไปยังกลุ่มข้างเคียงถัดไปได้อย่างรวดเร็ว (เพียงเพิ่มออฟเซ็ตอาร์เรย์ด้วยตัวเลขนั้น)

โครงสร้างพร็อพเพอร์ตี้

DOM คือต้นไม้ขององค์ประกอบ (รวมถึงโหนดข้อความ) และ CSS สามารถใช้รูปแบบต่างๆ กับองค์ประกอบได้

ซึ่งปรากฏได้ 4 วิธีดังนี้

  • เลย์เอาต์: ข้อมูลป้อนเข้าอัลกอริทึมข้อจํากัดของเลย์เอาต์
  • Paint: วิธีวาดและแรสเตอร์องค์ประกอบ (แต่ไม่ใช่องค์ประกอบย่อย)
  • ภาพ: เอฟเฟกต์แรสเตอร์/วาดที่ใช้กับ DOM ย่อย เช่น การเปลี่ยนรูปแบบ ฟิลเตอร์ และการครอบตัด
  • การเลื่อน: มุมที่ปัดเศษและปรับแนวตามแกน การครอบตัดและการเลื่อนของแผนผังย่อยที่รวมอยู่

ต้นไม้พร็อพเพอร์ตี้คือโครงสร้างข้อมูลที่อธิบายว่าเอฟเฟกต์ภาพและการเลื่อนมีผลกับองค์ประกอบ DOM อย่างไร โดยบอกวิธีตอบคำถาม เช่น ตำแหน่งและตำแหน่งของ DOM เป็นองค์ประกอบใด โดยพิจารณาจากขนาดและตำแหน่งของเลย์เอาต์ และควรใช้ลำดับการดำเนินการของ GPU ในข้อใดเพื่อใช้เอฟเฟกต์ภาพและการเลื่อน

เอฟเฟกต์ภาพและการเลื่อนบนเว็บมีความซับซ้อนมาก ดังนั้น สิ่งสำคัญที่สุดสำหรับโครงสร้างพร็อพเพอร์ตี้ก็คือการแปลความซับซ้อนเป็นโครงสร้างข้อมูลเดียวที่แสดงถึงโครงสร้างและความหมายขององค์ประกอบนั้นได้อย่างถูกต้อง ในขณะเดียวกันก็นำความซับซ้อนที่เหลือของ DOM และ CSS ออกไปด้วย วิธีนี้ช่วยให้เราติดตั้งใช้งานอัลกอริทึมสำหรับการจัดวางองค์ประกอบและการเลื่อนได้อย่างมั่นใจยิ่งขึ้น โดยเฉพาะอย่างยิ่งฟีเจอร์ต่อไปนี้

  • เรขาคณิตที่มีโอกาสเกิดข้อผิดพลาดและการคำนวณอื่นๆ สามารถรวมไว้ในที่เดียว
  • ความซับซ้อนในการสร้างและการอัปเดตโครงสร้างคุณสมบัติ จะแยกออกมาอยู่ในขั้นตอนของไปป์ไลน์การแสดงผลระดับหนึ่ง
  • การส่งแผนผังพร็อพเพอร์ตี้ไปยังเทรดและกระบวนการต่างๆ นั้นทำได้ง่ายและรวดเร็วกว่าสถานะ DOM แบบเต็ม จึงทำให้นำไปใช้สำหรับกรณีการใช้งานได้หลายกรณี
  • ยิ่งมีกรณีการใช้งานมากเท่าใด เราก็ยิ่งได้รับประโยชน์มากขึ้นจากการแคชรูปทรงเรขาคณิตที่สร้างขึ้นเพิ่มเติม เนื่องจากสามารถนําแคชของกันและมาใช้ซ้ำได้

RenderingNG ใช้ต้นไม้พร็อพเพอร์ตี้เพื่อวัตถุประสงค์หลายอย่าง ซึ่งรวมถึง

  • การแยกการคอมโพสออกจากการวาด และการคอมโพสออกจากเธรดหลัก
  • การกำหนดกลยุทธ์การคอมโพส / วาดภาพที่เหมาะสมที่สุด
  • การวัดเรขาคณิตของ IntersectionObserver
  • หลีกเลี่ยงการทำงานกับองค์ประกอบที่อยู่นอกหน้าจอและชิ้นส่วนพื้นผิว GPU
  • ทำให้สีและแรสเตอร์กลายเป็นโมฆะอย่างมีประสิทธิภาพและแม่นยำ
  • การวัดการเปลี่ยนเลย์เอาต์และ Largest Contentful Paint ใน Core Web Vitals

เอกสารบนเว็บแต่ละฉบับจะมีแผนผังพร็อพเพอร์ตี้แยกกัน 4 แบบ ได้แก่ การแปลง, คลิป, เอฟเฟกต์ และการเลื่อน (*) แผนผังการแปลงแสดงถึงการแปลงและการเลื่อน CSS (การเปลี่ยนแบบเลื่อนจะแสดงเป็นเมทริกซ์การแปลงแบบ 2 มิติ) ต้นไม้คลิปแสดงคลิปที่เกินขีดจำกัด แผนผังเอฟเฟกต์จะแสดงเอฟเฟกต์ภาพอื่นๆ ทั้งหมด ได้แก่ ความทึบแสง ฟิลเตอร์ มาสก์ โหมดผสาน และคลิปประเภทอื่นๆ เช่น เส้นทางคลิป ต้นไม้การเลื่อนแสดงข้อมูลเกี่ยวกับการเลื่อน เช่น วิธีที่การเลื่อนเชื่อมโยงกัน ซึ่งจำเป็นต้องใช้สำหรับการเลื่อนในเธรดคอมโพสิต โหนดแต่ละโหนดในต้นไม้พร็อพเพอร์ตี้แสดงการเลื่อนหรือเอฟเฟกต์ภาพที่ใช้โดยองค์ประกอบ DOM หากองค์ประกอบมีเอฟเฟกต์หลายรายการ อาจมีโหนดต้นไม้พร็อพเพอร์ตี้มากกว่า 1 โหนดในแต่ละต้นไม้สำหรับองค์ประกอบเดียวกัน

โทโพโลยีของแต่ละต้นไม้เป็นเหมือนการแสดง DOM แบบคร่าวๆ เช่น หากมีองค์ประกอบ DOM 3 รายการที่มีคลิปรายการเพิ่มเติม ก็จะมีโหนดแผนผังคลิป 3 โหนด และโครงสร้างของแผนผังคลิปจะยึดตามความสัมพันธ์ของบล็อกที่มีระหว่างคลิปรายการเพิ่มเติม นอกจากนี้ยังมีลิงก์ระหว่างต้นไม้ด้วย ลิงก์เหล่านี้จะระบุลำดับชั้น DOM แบบสัมพัทธ์ และลำดับการใช้งานของโหนด เช่น หากการเปลี่ยนรูปแบบในองค์ประกอบ DOM อยู่ใต้องค์ประกอบ DOM อื่นที่มีตัวกรอง แน่นอนว่าการเปลี่ยนรูปแบบจะมีผลก่อนตัวกรอง

องค์ประกอบ DOM แต่ละรายการมีสถานะต้นไม้พร็อพเพอร์ตี้ ซึ่งเป็นชุด 4 รายการ (การเปลี่ยนรูปแบบ คลิป เอฟเฟกต์ เลื่อน) ที่ระบุคลิป การเปลี่ยนรูปแบบ และโหนดต้นไม้เอฟเฟกต์ของบรรพบุรุษที่อยู่ใกล้ที่สุดซึ่งมีผลกับองค์ประกอบนั้น ซึ่งสะดวกมากเนื่องจากข้อมูลนี้ช่วยให้เราทราบรายการคลิป การเปลี่ยนรูปแบบ และเอฟเฟกต์ที่ใช้กับองค์ประกอบนั้นๆ และลำดับที่แน่นอน ซึ่งบอกตำแหน่งบนหน้าจอและวิธีวาด

ตัวอย่าง

(source)

<html>
  <div style="overflow: scroll; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
  id="one" srcdoc="iframe one"></iframe>
  </div>
  <iframe style="top:200px;
      transform: scale(1.1) translateX(200px)" id=two
      srcdoc="iframe two"></iframe>
</html>

สําหรับตัวอย่างก่อนหน้านี้ (ซึ่งแตกต่างจากตัวอย่างในส่วนนําเข้าเล็กน้อย) องค์ประกอบหลักของต้นไม้พร็อพเพอร์ตี้ที่สร้างขึ้นมีดังนี้

ตัวอย่างองค์ประกอบต่างๆ ในทรีพร็อพเพอร์ตี้

แสดงรายการและพาร์ท Paint

รายการที่แสดงมีคำสั่งวาดระดับต่ำ (ดูที่นี่) ซึ่งสามารถแรสเตอร์ได้ด้วย Skia โดยทั่วไปแล้ว รายการที่แสดงจะเรียบง่าย โดยมีคำสั่งวาดเพียงไม่กี่คำสั่ง เช่น การวาดเส้นขอบหรือพื้นหลัง แผนผังเพ้นท์ทรีเดินวนไปบนแผนผังเลย์เอาต์และส่วนย่อยที่เกี่ยวข้องตามลำดับการวาดภาพ CSS เพื่อสร้างรายการรายการ Display

เช่น

กล่องสีน้ำเงินที่มีคำว่า &quot;Hello World&quot; ภายในสี่เหลี่ยมผืนผ้าสีเขียว

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="blue" style="width:100px;
  height:100px; background:blue;
  position:absolute;
  top:0; left:0; z-index:-1;">
</div>

HTML และ CSS นี้จะสร้างรายการที่แสดงต่อไปนี้ โดยที่แต่ละเซลล์เป็นรายการที่แสดง

พื้นหลังของมุมมอง #blue เบื้องหลัง #green เบื้องหลัง #green ข้อความในบรรทัด
drawRect ขนาด 800x600 และสีขาว drawRect ขนาด 100x100 ที่ตําแหน่ง 0,0 และสีน้ําเงิน drawRect ในขนาด 80x18 ที่ตำแหน่ง 8.8 และเป็นสีเขียว drawTextBlob พร้อมตำแหน่งที่ 8,8 และส่งข้อความ "สวัสดีทุกคน"

รายการรายการที่แสดงจะเรียงจากหลังไปหน้า ในตัวอย่างด้านบน div สีเขียวอยู่ก่อน div สีน้ำเงินตามลําดับ DOM แต่ลําดับการวาดของ CSS กําหนดให้ div สีน้ำเงินที่มี z-index ติดลบต้องวาดก่อน (ขั้นตอนที่ 3) div สีเขียว (ขั้นตอนที่ 4.1) รายการที่แสดงจะสอดคล้องกับขั้นตอนพื้นฐานของข้อกำหนดลำดับการวาด CSS โดยคร่าวๆ องค์ประกอบ DOM รายการเดียวอาจส่งผลให้มีรายการที่แสดงหลายรายการ เช่น #green มีรายการที่แสดงสำหรับพื้นหลังและรายการที่แสดงอีกรายการสำหรับข้อความย่อย ความละเอียดนี้สำคัญต่อการนำเสนอความซับซ้อนทั้งหมดของข้อกำหนดลำดับการวาด CSS เช่น การแทรกสลับที่เกิดจากระยะขอบลบ

สี่เหลี่ยมผืนผ้าสีเขียวที่มีกล่องสีเทาวางซ้อนอยู่บางส่วนและคำว่า &quot;Hello world&quot;

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="gray" style="width:35px; height:20px;
  background:gray;margin-top:-10px;"></div>

ซึ่งจะสร้างรายการที่แสดงต่อไปนี้ โดยแต่ละเซลล์คือรายการที่แสดง

พื้นหลังของมุมมอง #green เบื้องหลัง #gray เบื้องหลัง #green ข้อความในบรรทัด
drawRect ในขนาด 800x600 สีขาว drawRect ขนาด 80x18 ที่ตําแหน่ง 8,8 และสีเขียว drawRect ขนาด 35x20 ที่ตําแหน่ง 8,16 และสีเทา drawTextBlob ที่มีตําแหน่ง 8,8 และข้อความ "Hello world"

ระบบจะจัดเก็บรายการสินค้าที่จะแสดงไว้และนํากลับมาใช้ใหม่ในการอัปเดตในภายหลัง หากออบเจ็กต์เลย์เอาต์ไม่มีการเปลี่ยนแปลงระหว่างการเรียกใช้ต้นไม้ Paint ระบบจะคัดลอกรายการที่แสดงจากรายการก่อนหน้า การเพิ่มประสิทธิภาพเพิ่มเติมอาศัยพร็อพเพอร์ตี้ของข้อกำหนดคำสั่ง Paint ของ CSS ซึ่งได้แก่ การจัดเรียงบริบทจะแสดงแบบอะตอม หากไม่มีออบเจ็กต์เลย์เอาต์เปลี่ยนแปลงภายในบริบทการซ้อน ระบบจะข้ามบริบทการซ้อนและคัดลอกลำดับรายการที่แสดงทั้งหมดจากรายการก่อนหน้า

ระบบจะรักษาสถานะต้นไม้พร็อพเพอร์ตี้ปัจจุบันไว้ในระหว่างการเรียกใช้ต้นไม้เพื่อวาดภาพ และจัดกลุ่มรายการที่แสดงเป็น "กลุ่ม" ของรายการที่แสดงซึ่งใช้สถานะต้นไม้พร็อพเพอร์ตี้เดียวกัน ดังที่เห็นได้จากตัวอย่างต่อไปนี้

กล่องสีชมพูที่มีกล่องสีส้มเอียง

<div id="scroll" style="background:pink; width:100px;
   height:100px; overflow:scroll;
   position:absolute; top:0; left:0;">
    Hello world
    <div id="orange" style="width:75px; height:200px;
      background:orange; transform:rotateZ(25deg);">
        I'm falling
    </div>
</div>

การดำเนินการนี้จะสร้างรายการแสดงต่อไปนี้ โดยที่แต่ละเซลล์เป็นรายการที่แสดง

พื้นหลังของมุมมอง #scroll เบื้องหลัง ข้อความในบรรทัด #scroll #orange เบื้องหลัง ข้อความในบรรทัด #orange
drawRect ขนาด 800x600 และสีขาว drawRect ขนาด 100x100 ที่ตําแหน่ง 0,0 และสีชมพู drawTextBlob ที่มีตําแหน่ง 0,0 และข้อความ "Hello world" drawRect ขนาด 75x200 ที่ตําแหน่ง 0,0 และสีส้ม drawTextBlob ที่มีตำแหน่ง 0,0 และข้อความ "ฉันกำลังล้ม"

แผนผังคุณสมบัติในการเปลี่ยนรูปแบบและกลุ่มสีจะมีลักษณะต่อไปนี้ (ง่ายขึ้นเพื่อความกระชับ)

รูปภาพของตารางก่อนหน้า, 2 เซลล์แรกในกลุ่ม 1, เซลล์ที่ 3 อยู่ในกลุ่มที่ 2, 2 เซลล์สุดท้ายในกลุ่มที่ 3

รายการชิ้นส่วนสีที่มีลำดับซึ่งคือกลุ่มของรายการแสดงผลและสถานะของแผนผังพร็อพเพอร์ตี้ คืออินพุตสำหรับขั้นตอนการทำให้เป็นเลเยอร์ของไปป์ไลน์การแสดงผล รายการข้อมูลทั้งหมดของกลุ่มสีสามารถผสานเป็นเลเยอร์คอมโพสิตเลเยอร์เดียวและแรสเตอร์ร่วมกันได้ แต่วิธีนี้จะต้องทำการแรสเตอร์ที่สิ้นเปลืองทุกครั้งที่ผู้ใช้เลื่อน คุณอาจสร้างเลเยอร์แบบผสมสำหรับแต่ละกลุ่มสีและแรสเตอร์แยกกันเพื่อหลีกเลี่ยงการแรสเตอร์ซ้ำทั้งหมด แต่อาจทำให้หน่วยความจำ GPU หมดอย่างรวดเร็ว ขั้นตอนการจัดวางเลเยอร์ต้องหาจุดสมดุลระหว่างหน่วยความจํา GPU กับต้นทุนที่ลดลงเมื่อมีการเปลี่ยนแปลง แนวทางทั่วไปที่ดีคือการผสานข้อมูลโค้ดย่อยโดยค่าเริ่มต้น และจะไม่ผสานข้อมูลโค้ดย่อยของการวาดภาพที่มีสถานะต้นไม้พร็อพเพอร์ตี้ที่คาดว่าจะเปลี่ยนแปลงในเธรดคอมโพสิต เช่น กับการเลื่อนของเธรดคอมโพสิตหรือภาพเคลื่อนไหวการเปลี่ยนรูปแบบของเธรดคอมโพสิต

ตัวอย่างก่อนหน้านี้ควรสร้างเลเยอร์แบบคอมโพสิต 2 เลเยอร์ ดังนี้

  • เลเยอร์คอมโพสิตขนาด 800x600 ที่มีคำสั่งวาด ดังนี้
    1. drawRect ขนาด 800x600 และสีขาว
    2. drawRect ขนาด 100x100 ที่ตําแหน่ง 0,0 และสีชมพู
  • เลเยอร์แบบผสมขนาด 144x224 ที่มีคำสั่งวาด:
    1. drawTextBlob ที่มีตําแหน่ง 0,0 และข้อความ "Hello world"
    2. แปล 0,18
    3. rotateZ(25deg)
    4. drawRect ขนาด 75x200 ที่ตําแหน่ง 0,0 และสีส้ม
    5. drawTextBlob ที่มีตำแหน่ง 0,0 และข้อความ "ฉันกำลังตก"

หากผู้ใช้เลื่อน #scroll ระบบจะย้ายเลเยอร์คอมโพสิตที่ 2 แต่ไม่จําเป็นต้องแรสเตอร์

สำหรับตัวอย่างจากส่วนก่อนหน้านี้เกี่ยวกับต้นไม้พร็อพเพอร์ตี้ จะมีชิ้นส่วนสี 6 ชิ้น เมื่อพิจารณาสถานะโครงสร้างพร็อพเพอร์ตี้ (การเปลี่ยนรูปแบบ คลิป เอฟเฟกต์ เลื่อน) แล้ว จะอยู่ในสถานะดังนี้

  • พื้นหลังเอกสาร: การเลื่อนเอกสาร คลิปเอกสาร รูท การเลื่อนเอกสาร
  • มุมแนวนอน แนวตั้ง และมุมเลื่อนสำหรับ div (กลุ่มการวาด 3 กลุ่มแยกกัน) การเลื่อนเอกสาร คลิปเอกสาร #oneเบลอ การเลื่อนเอกสาร
  • Iframe #one: #one หมุน, คลิปการเลื่อนแบบแสดงผลเกิน, #one เบลอ, การเลื่อน div
  • Iframe #two: #two scale, document clip, root, document scroll

เฟรมคอมโพสิต: พื้นผิว พื้นผิวการแสดงผล และไทล์พื้นผิวของ GPU

เบราว์เซอร์และกระบวนการแสดงผลจะจัดการการแรสเตอร์เนื้อหา จากนั้นส่งเฟรมคอมโพสิตไปยังกระบวนการแสดงผลภาพเพื่อแสดงบนหน้าจอ เฟรมคอมโพสิตแสดงวิธีต่อเนื้อหาที่แรสเตอร์เข้าด้วยกัน และวาดเนื้อหาอย่างมีประสิทธิภาพโดยใช้ GPU

การ์ด

ในทางทฤษฎีแล้ว คอมโพสิตกระบวนการแสดงผลหรือคอมโพสิตกระบวนการของเบราว์เซอร์อาจแรสเตอร์พิกเซลเป็นพื้นผิวเดียวขนาดเต็มของวิวพอร์ตโปรแกรมแสดงผล และส่งพื้นผิวนั้นไปยัง Viz หากต้องการแสดงผล คอมโพสิตการแสดงผลจะต้องคัดลอกพิกเซลจากพื้นผิวเดียวนั้นไปยังตําแหน่งที่เหมาะสมในเฟรมบัฟเฟอร์ (เช่น หน้าจอ) อย่างไรก็ตาม หากเครื่องมือประกอบนั้นต้องการอัปเดตแม้แต่พิกเซลเดียว ก็จะต้องทำการแรสเตอร์วิวพอร์ตแบบเต็มอีกครั้งและส่งพื้นผิวใหม่ไปยัง Viz

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

4 การ์ด
รูปภาพนี้แสดงภาพในวันที่มีแดดและมีการ์ด 4 ใบ เมื่อมีการเลื่อน ไทล์ที่ 5 จะเริ่มปรากฏขึ้น ไทล์รายการหนึ่งมีเพียงสีเดียว (สีฟ้าน้ำทะเล) และยังมีวิดีโอและ iframe อยู่ด้านบน

ควอดและพื้นผิว

ไทล์พื้นผิวของ GPU เป็น Quad ชนิดพิเศษ ซึ่งเป็นชื่อที่เรียกพื้นผิวในหมวดหมู่หนึ่งๆ รูปสี่เหลี่ยมระบุพื้นผิวอินพุต และระบุวิธีเปลี่ยนรูปแบบและใช้เอฟเฟกต์ภาพ ตัวอย่างเช่น ไทล์เนื้อหาปกติจะมีการเปลี่ยนรูปแบบที่ระบุตำแหน่ง x, y ในตารางกริดของไทล์

ชิ้นส่วนพื้นผิวของ GPU

ไทล์ที่แรสเตอร์เหล่านี้จะรวมอยู่ในเรนเดอร์พาส ซึ่งเป็นรายการสี่เหลี่ยมจัตุรัส พาสการแสดงผลไม่มีข้อมูลพิกเซล แต่จะมีวิธีการเกี่ยวกับตําแหน่งและวิธีวาดแต่ละรูปสี่เหลี่ยมจัตุรัสเพื่อสร้างเอาต์พุตพิกเซลที่ต้องการ มี draw quad สำหรับแต่ละไทล์พื้นผิว GPU เครื่องมือประกอบการแสดงผลจะต้องทำซ้ำผ่านรายการกลุ่มจตุภาค โดยวาดแต่ละรายการด้วยเอฟเฟกต์ภาพที่ระบุ เพื่อสร้างเอาต์พุตพิกเซลที่ต้องการสำหรับการส่งผ่านการแสดงผล การคอมโพสิทวาดรูปสี่เหลี่ยมจัตุรัสสําหรับการผ่านการแสดงผลทําได้อย่างมีประสิทธิภาพใน GPU เนื่องจากเอฟเฟกต์ภาพที่อนุญาตได้รับการเลือกอย่างรอบคอบเพื่อให้จับคู่กับฟีเจอร์ GPU ได้โดยตรง

นอกเหนือจากสี่เหลี่ยมจัตุรัสแรสเตอร์แล้ว ยังมีสี่เหลี่ยมจัตุรัสวาดประเภทอื่นๆ เพิ่มเติม เช่น มีรูปสี่เหลี่ยมจัตุรัสสำหรับวาดสีพื้นที่ไม่มีพื้นผิวรองรับเลย หรือรูปสี่เหลี่ยมจัตุรัสสำหรับวาดพื้นผิวสำหรับพื้นผิวที่ไม่ใช่ไทล์ เช่น วิดีโอหรือภาพพิมพ์แคนวาส

นอกจากนี้ เฟรมคอมโพสิตยังฝังเฟรมคอมโพสิตอื่นได้ด้วย เช่น คอมโพสิตเบราว์เซอร์จะสร้างเฟรมคอมโพสิตที่มี UI ของเบราว์เซอร์ และสี่เหลี่ยมผืนผ้าว่างเปล่าที่จะฝังเนื้อหาคอมโพสิตการแสดงผล อีกตัวอย่างหนึ่งคือ iframe ที่แยกเว็บไซต์ การฝังนี้ทำได้ผ่านแพลตฟอร์ม

เมื่อผู้จัดองค์ประกอบส่งเฟรมผู้จัดองค์ประกอบ เฟรมดังกล่าวจะมีตัวระบุที่เรียกว่ารหัสแพลตฟอร์ม ซึ่งช่วยให้เฟรมผู้จัดองค์ประกอบอื่นๆ สามารถฝังเฟรมดังกล่าวได้โดยอ้างอิง Viz จะจัดเก็บเฟรมคอมโพสิตใหม่ล่าสุดที่ส่งมาพร้อมรหัสพื้นผิวหนึ่งๆ จากนั้นเฟรมคอมโพสิตอื่นจะอ้างอิงเฟรมดังกล่าวในภายหลังผ่านรูปสี่เหลี่ยมจัตุรัสสำหรับวาดพื้นผิวได้ ด้วยเหตุนี้ Viz จึงรู้ว่าต้องวาดอะไร (โปรดทราบว่าสี่เหลี่ยมจัตุรัสการวาดพื้นผิวมีรหัสพื้นผิวเท่านั้น และไม่มีพื้นผิว)

การส่งผ่านการแสดงผลระดับกลาง

เอฟเฟกต์ภาพบางรายการ เช่น ฟิลเตอร์จำนวนมากหรือโหมดการผสมขั้นสูง จำเป็นต้องวาดรูปสี่เหลี่ยมจัตุรัสอย่างน้อย 2 รูปลงในพื้นผิวระดับกลาง จากนั้นพื้นผิวระดับกลางจะถูกวาดลงในบัฟเฟอร์ปลายทางบน GPU (หรืออาจจะเป็นพื้นผิวระดับกลางอีกด้าน) โดยใช้เอฟเฟกต์ภาพในเวลาเดียวกัน เฟรมคอมโพสิตจึงมีรายการของพาสการเรนเดอร์เพื่อให้รองรับการทำงานนี้ เสมอจะมีพาสการแสดงผลรูท ซึ่งจะวาดเป็นลำดับสุดท้ายและปลายทางสอดคล้องกับเฟรมบัฟเฟอร์ และอาจมีพาสอื่นๆ เพิ่มเติม

ความเป็นไปได้ที่การส่งการแสดงผลหลายใบจะอธิบาย "บัตรผ่านที่แสดงผล" แต่ละรอบต้องดำเนินการตามลำดับใน GPU ใน "รอบ" หลายรอบ ในขณะที่รอบเดียวจะดำเนินการเสร็จสมบูรณ์ได้ในการคำนวณแบบขนานจำนวนมากของ GPU ครั้งเดียว

การรวม

ระบบจะส่งเฟรมคอมโพสิตหลายเฟรมไปยัง Viz และจะต้องวาดเฟรมเหล่านั้นบนหน้าจอพร้อมกัน ซึ่งทำได้ด้วยระยะการรวมข้อมูลที่จะแปลงเฟรมคอมโพสิตต่างๆ ให้เป็นเฟรมคอมโพสิตแบบรวมเฟรมเดียว การรวมข้อมูลจะแทนที่สี่เหลี่ยมจัตุรัสการวาดพื้นผิวด้วยเฟรมคอมโพสิตที่ระบุ นอกจากนี้ยังเป็นโอกาสในการเพิ่มประสิทธิภาพพื้นผิวหรือเนื้อหาระดับกลางที่ไม่จำเป็นซึ่งอยู่นอกหน้าจอ เช่น ในหลายกรณี เฟรมคอมโพสิตสำหรับ iframe ที่แยกส่วนของเว็บไซต์ออกนั้นไม่จำเป็นต้องใช้เท็กเจอร์กลางของตัวเอง และสามารถวาดลงในเฟรมบัฟเฟอร์ได้โดยตรงผ่านสี่เหลี่ยมจัตุรัสการวาดที่เหมาะสม ขั้นตอนการรวบรวมข้อมูลจะระบุการเพิ่มประสิทธิภาพดังกล่าว แล้วนำไปใช้โดยอิงตามความรู้ที่ทุกคนทั่วโลกไม่สามารถเข้าถึงได้

ตัวอย่าง

นี่คือเฟรมคอมโพสิเตอร์ที่แสดงตัวอย่างตั้งแต่ต้นของโพสต์นี้

  • foo.com/index.html surface: id=0
    • แสดงผลบัตร 0: วาดไปยังเอาต์พุต
      • วาดรูปสี่เหลี่ยมจัตุรัสในการแสดงผล: วาดด้วยการเบลอ 3 พิกเซลและตัดคลิปลงในการแสดงผล 0
        • แสดงผลบัตร 1:
          • วาดสี่เหลี่ยมจัตุรัสสำหรับเนื้อหาการ์ดของ #one iframe พร้อมตำแหน่ง x และ y ของแต่ละรายการ
      • รูปสี่เหลี่ยมจัตุรัสการวาดพื้นผิว: มีรหัส 2 วาดด้วยการเปลี่ยนรูปแบบการแปลงขนาดและการเปลี่ยนตำแหน่ง
  • แพลตฟอร์ม UI ของเบราว์เซอร์: ID=1
    • แสดงผลบัตร 0: วาดไปยังเอาต์พุต
      • วาดรูปสี่เหลี่ยมจัตุรัสสําหรับ UI เบราว์เซอร์ (ใช้การแบ่งส่วนด้วย)
  • bar.com/index.html surface: ID=2
    • ผ่านการแสดงผล 0: วาดไปยังเอาต์พุต
      • วาดสี่เหลี่ยมจัตุรัสสำหรับเนื้อหาของ #two iframe พร้อมตำแหน่ง x และ y ของแต่ละรายการ

ภาพโดย Una Kravets