โครงสร้างข้อมูลสำคัญใน 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 เฟรมสำหรับหน้าเว็บ Viz ขอเฟรมคอมโพสิเตอร์จากเฟรมรูทของแต่ละเฟรมพร้อมกัน ต้นไม้เฟรมท้องถิ่น 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 การอัปเดตพร็อพเพอร์ตี้ภาพ

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

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

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

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

ส่วนย่อยที่เปลี่ยนแปลงไม่ได้

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

การแสดงส่วนย่อยในแต่ละต้นไม้ โดยมี 1 ส่วนย่อยที่มีการทำเครื่องหมายว่าต้องมีการออกแบบ

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

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

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

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

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

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

รายการ Fragment ในบรรทัด

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

จะมีการสร้างรายการแบบเดี่ยวสำหรับแต่ละรายการ บริบทการจัดรูปแบบอินไลน์ ตามลำดับการค้นหาที่มีความลึกเป็นหลักของแผนผังย่อยของเลย์เอาต์ในบรรทัด แต่ละรายการในชุดรายการเป็น Tuple ของ (ออบเจ็กต์ จำนวนองค์ประกอบสืบทอด) ตัวอย่างเช่น ลองพิจารณา 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)
  • (กล่อง <span>, 1)
  • (ข้อความ "สวัสดี", 0)
  • (ช่องเส้น, 3)
  • (กล่อง <b>, 1)
  • (ข้อความ "มี", 0)
  • (ข้อความ ".", 0)

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

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

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

ต้นไม้อสังหาริมทรัพย์

DOM เป็นแผนผังขององค์ประกอบ (รวมโหนดข้อความ) และ CSS สามารถใช้ เข้ากับองค์ประกอบ

ซึ่งจะแสดง 4 รูปแบบ ดังนี้

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

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

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

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

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

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

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

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

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

ตัวอย่าง

(แหล่งที่มา)

<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>

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

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

แสดงรายการและวาดภาพ

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

เช่น

กล่องสีฟ้าพร้อมคำว่า &quot;สวัสดีโลก&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 เป็นลบ ก่อน (ขั้นตอนที่ 3) div สีเขียว (ขั้นตอนที่ 4.1) รายการที่แสดงจะสอดคล้องกับขั้นตอนอะตอมของข้อกำหนดลำดับสี CSS เอลิเมนต์ DOM เดียวอาจ ทำให้มีรายการที่แสดงหลายรายการ เช่น #green มีรายการที่แสดงเป็นพื้นหลังและอีกรายการแสดงผลสำหรับข้อความในบรรทัด ความละเอียดนี้สำคัญในการแสดงความซับซ้อนทั้งหมดของข้อกำหนดคำสั่งการแสดงผล CSS เช่น การแทรกสอดประสานที่สร้างโดยอัตรากำไรติดลบ

สี่เหลี่ยมผืนผ้าสีเขียวที่มีกล่องสีเทาวางซ้อนอยู่บางส่วนและมีคำว่า &quot;สวัสดีโลก&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 และส่งข้อความ "สวัสดีทุกคน"

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

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

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

<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 และส่งข้อความ "สวัสดีทุกคน" drawRect ในขนาด 75x200 ที่ตำแหน่ง 0,0 และเป็นสีส้ม drawTextBlob ที่มีตำแหน่ง 0,0 และข้อความ "ฉันกำลังล้ม"

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

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

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

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

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

หากผู้ใช้เลื่อน#scroll เลเยอร์ที่ทำการ Composite จะย้ายไป แต่ไม่จำเป็นต้องมีการแรสเตอร์

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

  • พื้นหลังของเอกสาร: การเลื่อนเอกสาร คลิปเอกสาร ราก การเลื่อนเอกสาร
  • มุมแนวนอน แนวตั้ง และมุมเลื่อนสำหรับ div (ส่วนสี 3 ส่วนแยกกัน): การเลื่อนเอกสาร, คลิปเอกสาร, #one เบลอ, เลื่อนเอกสาร
  • iframe #one: หมุน #one, คลิปการเลื่อนรายการเพิ่มเติม, เบลอ #one, การเลื่อน div
  • iframe #two: สเกล #two, คลิปเอกสาร, ราก, การเลื่อนเอกสาร

เฟรมคอมโพสิต: พื้นผิว, แสดงผลพื้นผิว และชิ้นส่วนพื้นผิว GPU

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

การ์ด

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

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

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

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

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

ชิ้นส่วนพื้นผิว GPU

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

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

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

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

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

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

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

การรวม

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

ตัวอย่าง

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

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

ภาพโดย Una Kravets