โครงสร้างข้อมูลสำคัญใน 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

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

โครงสร้างข้อมูลเหล่านี้มีดังต่อไปนี้

  • Frame Tree ประกอบด้วยโหนดในเครื่องและโหนดระยะไกลที่แสดงว่าเอกสารบนเว็บใดที่อยู่ในกระบวนการแสดงผล และโหมดแสดงภาพ 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 คอมโพเนนต์สำหรับหน้าเว็บ Viiz จะขอเฟรม compositor จากเฟรมรูทของเฟรมคอมโพสเซอร์ภายใน 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 ส่วนย่อยต่อองค์ประกอบ แต่อาจมีมากกว่านี้หากแยกส่วนของหน้าต่างๆ เมื่อพิมพ์ หรือคอลัมน์เมื่ออยู่ในบริบทที่มีหลายคอลัมน์

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

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

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

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

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

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

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

ระบบจะสร้างรายการแบบแบนราบสำหรับบริบทการจัดรูปแบบในบรรทัดแต่ละรายการตามลำดับการค้นหาแบบเจาะลึกเป็นอันดับแรกของแผนผังย่อยของเลย์เอาต์ในบรรทัด แต่ละรายการในชุดรายการเป็น 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 การแสดงเคอร์เซอร์นี้มีประสิทธิภาพมากสำหรับเนื้อหาข้อความด้วยเหตุผลหลายประการดังนี้

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

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

DOM เป็นแผนผังขององค์ประกอบ (รวมโหนดข้อความ) และ CSS ใช้รูปแบบที่หลากหลายกับองค์ประกอบได้

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

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

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

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

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

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

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

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

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

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

ตัวอย่าง

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

<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 เพื่อสร้างรายการรายการ Display

เช่น

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

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

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

รายการชิ้นส่วนสีที่มีลำดับซึ่งคือกลุ่มของรายการแสดงผลและสถานะของแผนผังพร็อพเพอร์ตี้ คืออินพุตสำหรับขั้นตอนการทำให้เป็นเลเยอร์ของไปป์ไลน์การแสดงผล โดยอาจรวมชิ้นส่วนสีทั้งหมดไว้ในเลเยอร์ที่ทำการ Composite เดียวและแรสเตอร์เข้าด้วยกัน แต่การดำเนินการนี้จำเป็นต้องมีการแรสเตอร์ราคาแพงทุกครั้งที่ผู้ใช้เลื่อนดู คุณสามารถสร้างเลเยอร์แบบผสมสำหรับแต่ละกลุ่มสีและแรสเตอร์แยกกันเพื่อหลีกเลี่ยงการแรสเตอร์ซ้ำทั้งหมด แต่อาจทำให้หน่วยความจำ 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 ที่ 2 แต่ไม่จำเป็นต้องแรสเตอร์

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

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

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

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

การ์ด

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

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

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

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

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

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

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

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

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

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

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

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

ความเป็นไปได้ที่การส่งการแสดงผลหลายใบจะอธิบาย "บัตรผ่านที่แสดงผล" โดยบัตรแต่ละใบจะต้องดำเนินการตามลำดับบน GPU ในหลาย "บัตร" ขณะที่การส่ง 1 ครั้งจะเสร็จสิ้นได้ในการคำนวณ 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 Surface: ID=2
    • แสดงผลบัตร 0: วาดไปยังเอาต์พุต
      • วาดสี่เหลี่ยมจัตุรัสสำหรับเนื้อหาของ iframe ของ #two โดยกำหนดตำแหน่ง x และ y สำหรับแต่ละรายการ

ภาพโดย Una Kravets