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