มาดูโครงสร้างข้อมูลหลักกัน ซึ่งเป็นอินพุตและเอาต์พุตของไปป์ไลน์การแสดงผล
โครงสร้างข้อมูลเหล่านี้ ได้แก่
- เฟรมทรีประกอบด้วยโหนดในเครื่องและโหนดระยะไกลที่แสดงถึงเว็บเอกสารที่อยู่ในกระบวนการแสดงผลและโปรแกรมแสดงผล 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 เฟรม ดังนี้
เมื่อใช้การแยกเว็บไซต์ Chromium จะใช้กระบวนการแสดงผล 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
ดังนี้
หากต้องการสร้างเฟรมคอมโพสิต 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
เช่น
<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 เช่น การแทรกสลับที่เกิดจากระยะขอบลบ
<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 และข้อความ "ฉันกำลังล้ม" |
แผนผังคุณสมบัติในการเปลี่ยนรูปแบบและกลุ่มสีจะมีลักษณะต่อไปนี้ (ง่ายขึ้นเพื่อความกระชับ)
รายการชิ้นส่วนสีที่มีลำดับซึ่งคือกลุ่มของรายการแสดงผลและสถานะของแผนผังพร็อพเพอร์ตี้ คืออินพุตสำหรับขั้นตอนการทำให้เป็นเลเยอร์ของไปป์ไลน์การแสดงผล รายการข้อมูลทั้งหมดของกลุ่มสีสามารถผสานเป็นเลเยอร์คอมโพสิตเลเยอร์เดียวและแรสเตอร์ร่วมกันได้ แต่วิธีนี้จะต้องทำการแรสเตอร์ที่สิ้นเปลืองทุกครั้งที่ผู้ใช้เลื่อน คุณอาจสร้างเลเยอร์แบบผสมสำหรับแต่ละกลุ่มสีและแรสเตอร์แยกกันเพื่อหลีกเลี่ยงการแรสเตอร์ซ้ำทั้งหมด แต่อาจทำให้หน่วยความจำ GPU หมดอย่างรวดเร็ว ขั้นตอนการจัดวางเลเยอร์ต้องหาจุดสมดุลระหว่างหน่วยความจํา GPU กับต้นทุนที่ลดลงเมื่อมีการเปลี่ยนแปลง แนวทางทั่วไปที่ดีคือการผสานข้อมูลโค้ดย่อยโดยค่าเริ่มต้น และจะไม่ผสานข้อมูลโค้ดย่อยของการวาดภาพที่มีสถานะต้นไม้พร็อพเพอร์ตี้ที่คาดว่าจะเปลี่ยนแปลงในเธรดคอมโพสิต เช่น กับการเลื่อนของเธรดคอมโพสิตหรือภาพเคลื่อนไหวการเปลี่ยนรูปแบบของเธรดคอมโพสิต
ตัวอย่างก่อนหน้านี้ควรสร้างเลเยอร์แบบคอมโพสิต 2 เลเยอร์ ดังนี้
- เลเยอร์คอมโพสิตขนาด 800x600 ที่มีคำสั่งวาด ดังนี้
drawRect
ขนาด 800x600 และสีขาวdrawRect
ขนาด 100x100 ที่ตําแหน่ง 0,0 และสีชมพู
- เลเยอร์แบบผสมขนาด 144x224 ที่มีคำสั่งวาด:
drawTextBlob
ที่มีตําแหน่ง 0,0 และข้อความ "Hello world"- แปล 0,18
rotateZ(25deg)
drawRect
ขนาด 75x200 ที่ตําแหน่ง 0,0 และสีส้ม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 แยกกันรองรับแต่ละชิ้นส่วนด้วยพิกเซลที่แรสเตอร์สำหรับบางส่วนของวิวพอร์ต จากนั้นโปรแกรมแสดงผลจะอัปเดตแต่ละไทล์หรือแม้แต่เปลี่ยนตำแหน่งบนหน้าจอของไทล์ที่มีอยู่ ตัวอย่างเช่น เมื่อเลื่อนเว็บไซต์ ตำแหน่งของไทล์ที่มีอยู่จะเลื่อนขึ้น และจะต้องแรสเตอร์ไทล์ใหม่เป็นครั้งคราวสำหรับเนื้อหาที่เลื่อนลงไปด้านล่างของหน้า
ควอดและพื้นผิว
ไทล์พื้นผิวของ GPU เป็น Quad ชนิดพิเศษ ซึ่งเป็นชื่อที่เรียกพื้นผิวในหมวดหมู่หนึ่งๆ รูปสี่เหลี่ยมระบุพื้นผิวอินพุต และระบุวิธีเปลี่ยนรูปแบบและใช้เอฟเฟกต์ภาพ ตัวอย่างเช่น ไทล์เนื้อหาปกติจะมีการเปลี่ยนรูปแบบที่ระบุตำแหน่ง x, y ในตารางกริดของไทล์
ไทล์ที่แรสเตอร์เหล่านี้จะรวมอยู่ในเรนเดอร์พาส ซึ่งเป็นรายการสี่เหลี่ยมจัตุรัส พาสการแสดงผลไม่มีข้อมูลพิกเซล แต่จะมีวิธีการเกี่ยวกับตําแหน่งและวิธีวาดแต่ละรูปสี่เหลี่ยมจัตุรัสเพื่อสร้างเอาต์พุตพิกเซลที่ต้องการ มี 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 ของแต่ละรายการ
- วาดสี่เหลี่ยมจัตุรัสสำหรับเนื้อหาการ์ดของ
- แสดงผลบัตร 1:
- รูปสี่เหลี่ยมจัตุรัสการวาดพื้นผิว: มีรหัส 2 วาดด้วยการเปลี่ยนรูปแบบการแปลงขนาดและการเปลี่ยนตำแหน่ง
- วาดรูปสี่เหลี่ยมจัตุรัสในการแสดงผล: วาดด้วยการเบลอ 3 พิกเซลและตัดคลิปลงในการแสดงผล 0
- แสดงผลบัตร 0: วาดไปยังเอาต์พุต
- แพลตฟอร์ม UI ของเบราว์เซอร์: ID=1
- แสดงผลบัตร 0: วาดไปยังเอาต์พุต
- วาดรูปสี่เหลี่ยมจัตุรัสสําหรับ UI เบราว์เซอร์ (ใช้การแบ่งส่วนด้วย)
- แสดงผลบัตร 0: วาดไปยังเอาต์พุต
bar.com/index.html
surface: ID=2- ผ่านการแสดงผล 0: วาดไปยังเอาต์พุต
- วาดสี่เหลี่ยมจัตุรัสสำหรับเนื้อหาของ
#two
iframe พร้อมตำแหน่ง x และ y ของแต่ละรายการ
- วาดสี่เหลี่ยมจัตุรัสสำหรับเนื้อหาของ
- ผ่านการแสดงผล 0: วาดไปยังเอาต์พุต
ภาพโดย Una Kravets