בואו נבחן את מבני הנתונים העיקריים, שהם קלט ופלט צינור עיבוד נתונים לעיבוד.
מבני הנתונים הבאים הם:
- עצי מסגרת מורכבים מצמתים מקומיים ומרוחקים שמייצגים את רשת האינטרנט נמצאים בתהליך רינדור ובעיבוד של 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 עשוי לפעמים לעבד מסגרת ממקורות שונים בתהליך עיבוד שונה ממסגרת ההורה שלו.
בקוד לדוגמה, קיימות שלוש פריימים בסך הכול:
באמצעות הבידוד של אתרים, Chromium משתמש בשני תהליכי רינדור כדי לעבד את דף האינטרנט הזה. לכל תהליך עיבוד יש ייצוג משלו של עץ המסגרות של אותו דף אינטרנט:
מסגרת שמעובדת בתהליך אחר מיוצגת כמסגרת מרוחקת. מסגרת מרוחקת מכילה את המידע המינימלי שנדרש כדי לשמש כ-placeholder ברינדור. כמו המידות שלו, לדוגמה. אחרת, המסגרת המרוחקת לא מכילה מידע שנדרש לעיבוד התוכן שלה בפועל.
לעומת זאת, מסגרת מקומית מייצגת מסגרת שעוברת דרך לצינור עיבוד נתונים. המסגרת המקומית מכילה את כל המידע הנדרש כדי להפעיל את הנתונים עבור אותה מסגרת (כמו עץ ה-DOM ונתוני סגנון) שאפשר לעבד ולהציג.
צינור עיבוד הנתונים פועל על רמת פירוט של
מקטע של עץ מסגרת מקומי.
דוגמה מורכבת יותר שבה המסגרת הראשית היא foo.com
:
<iframe src="bar.com"></iframe>
וגם תת-המסגרת הבאה: bar.com
:
<iframe src="foo.com/etc"></iframe>
למרות שעדיין יש רק שני כלים לעיבוד, יש עכשיו שלושה פריימים מקומיים
שברי עצים, שבהם שניים נמצאים בתהליך העיבוד של foo.com
ואחד
תהליך העיבוד של bar.com
:
כדי ליצור מסגרת קומפוזיציה אחת עבור דף האינטרנט, Viz מבקשת בו-זמנית מסגרת קומפוזבילית ממסגרת הבסיס של כל אחד את שלושת עצי המסגרת המקומיים שצוברים אותם. כדאי לעיין גם בקטע 'מסגרות של קומפוזבילי'.
הפריים הראשי foo.com
ותת-הפריים foo.com/other-page
חלק מאותו עץ מסגרת ומעובדים באותו תהליך.
עם זאת, לשתי המסגרות עדיין יש תמיכה
מחזורי החיים של מסמכים
כי הם חלק מקטעים שונים של עץ מסגרת מקומי.
לכן אין אפשרות ליצור מסגרת קומפוזיציה אחת עבור שניהם בעדכון אחד.
תהליך העיבוד לא מכיל מספיק מידע
להרכיב את מסגרת הקומפוזיציה שנוצרה עבור foo.com/other-page
ישירות למסגרת הקומפוזבילי של המסגרת הראשית foo.com
.
לדוגמה, מסגרת ההורה bar.com
שאינה בתהליך עשויה להשפיע על תצוגת ה-iframe של foo.com/other-url
,
על ידי טרנספורמציה של ה-iframe באמצעות CSS או הסתרת חלקים של ה-iframe עם רכיבים אחרים ב-DOM שלו.
Waterfall עדכון הנכסים החזותי
מאפיינים חזותיים כמו הגורם לקביעת קנה המידה של המכשיר וגודל אזור התצוגה משפיעים על הפלט המעובד וצריך לסנכרן אותו בין קטעים של עץ המסגרת המקומי. הרמה הבסיסית (root) של כל מקטע של עץ מסגרת מקומי כוללת אובייקט ווידג'ט שמשויך אליו. עדכונים של המאפיינים החזותיים עוברים לווידג'ט של המסגרת הראשית לפני ההפצה לווידג'טים הנותרים.
לדוגמה, כשהגודל של אזור התצוגה משתנה:
התהליך הזה לא מיידי, כך שהמאפיינים הוויזואליים המשוכפלים כוללים גם אסימון סנכרון. הרכיב Viz משתמש באסימון הסנכרון הזה כדי להמתין לכל המקטעים של עץ המסגרת המקומי כדי לשלוח מסגרת קומפוזיציה עם אסימון הסנכרון הנוכחי. התהליך הזה מונע שילוב של פריימים של קומפוזבילי עם מאפיינים ויזואליים שונים.
עץ המקטעים שלא ניתן לשינוי
עץ המקטעים שלא ניתן לשינוי הוא הפלט של שלב הפריסה של הרינדור צינור עיבוד נתונים. הוא מייצג את המיקום והגודל של כל הרכיבים בדף (בלי להחיל שינויים).
כל מקטע מייצג חלק של רכיב DOM. בדרך כלל יש רק מקטע אחד לכל רכיב, אבל יכולים להיות עוד יותר אם הוא מחולק בין דפים שונים במהלך ההדפסה, או עמודות בהקשר מרובה-עמודות.
אחרי הפריסה, כל מקטע הופך לבלתי ניתן לשינוי ולא משתנה שוב. חשוב לציין גם כמה הגבלות נוספות. מה אנחנו לא עושים:
- מתן הרשאה לכל "למעלה" בעץ. (לילדים לא יכול להיות מצביע אל ההורה שלהם).
- 'בועה' במורד העץ (ילדים קוראים מידע רק מהילדים, ולא מההורים שלהם).
ההגבלות האלה מאפשרות לנו לעשות שימוש חוזר במקטע בפריסה הבאה. בלי ההגבלות האלה, לעיתים קרובות נצטרך לייצר מחדש את העץ כולו, וזה יקר.
רוב הפריסות הן בדרך כלל עדכונים מצטברים. לדוגמה, אפליקציית אינטרנט שמעדכנת חלק קטן מממשק המשתמש בתגובה למשתמש שלוחצים על אלמנט. באופן אידיאלי, הפריסה צריכה לפעול רק באופן יחסי למה שהשתנה בפועל במסך. נוכל לעשות זאת על ידי שימוש חוזר בכמה שיותר חלקים מהעץ הקודם. כלומר (בדרך כלל) אנחנו צריכים לבנות מחדש את עמוד השדרה של העץ.
בעתיד, העיצוב הזה, שלא ניתן לשינוי, יוכל לאפשר לנו לעשות דברים מעניינים למשל, העברת עץ המקטע שלא ניתן לשינוי מעבר לגבולות השרשור במקרה הצורך. (כדי לבצע את השלבים הבאים בשרשור אחר), ליצור כמה עצים לאנימציה בפריסה חלקה, או לבצע פריסות ספקולטיביות מקבילות. הוא גם נותן לנו את הפוטנציאל של פריסת ריבוי שרשורים עצמה.
פריטי מקטע מוטבעים
בתוכן מוטבע (הטקסט המעוצב בעיקר) יש ייצוג קצת שונה. במקום במבנה של עץ עם תיבות ומצביעים, אנחנו מייצגים תוכן מוטבע ברשימה שטוחה שמייצגת את העץ. היתרון העיקרי הוא שייצוג של רשימה שטוחה עבור שורות מוטבעות הוא מהיר, כשרוצים לבדוק מבני נתונים מוטבעים או לשלוח שאילתות לגביהם, יעיל בזיכרון. זה חשוב מאוד לביצועים של רינדור באינטרנט, מכיוון שרינדור טקסט הוא מורכב מאוד, ויכול להפוך בקלות לחלק האיטי ביותר בצינור עיבוד הנתונים, אלא אם מתבצעת אופטימיזציה שלו בצורה גבוהה.
המערכת יוצרת רשימה שטוחה עבור כל אחד הקשר של עיצוב מוטבע בסדר של חיפוש מעמיקים לפי עץ המשנה של הפריסה המוטבעת שלו. כל ערך ברשימה הוא מספר (אובייקט, מספר צאצאים). לדוגמה, נבחן את ה-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 יכול להחיל מגוון לרכיבים.
יש ארבע דרכים לכך:
- פריסה: ערכי הקלט לאלגוריתם של מגבלת הפריסה.
- צבע: איך לצבוע וליצור רשת נקודות של הרכיב (אבל לא הצאצאים שלו).
- ויזואלי: אפקטים של רסטר/שרטוט שהוחלו על עץ המשנה DOM, כמו טרנספורמציות, פילטרים וחיתוך.
- גלילה: פינה מעוגלת ומיושרת לציר יצירת חיתוך וגלילה של עץ המשנה שכלול בו.
עצי מאפיינים הם מבני נתונים שמסבירים איך אפקטים חזותיים ואפקטים גלילה חלים על רכיבי DOM. הם מספקים אמצעים למענה על שאלות כמו: איפה, ביחס למסך, הוא רכיב DOM נתון, בהתחשב בגודל ובמיקום של הפריסה? בנוסף: באיזה רצף של פעולות GPU יש להשתמש כדי להחיל אפקטים חזותיים ואפקטים של גלילה?
אפקטים ויזואליים ואפקטים נגללים באינטרנט מורכבים מאוד ואפשרו להם תהילה מלאה. הדבר הכי חשוב שעצי הנדל"ן עושים הוא לתרגם את המורכבות הזו למבנה נתונים יחיד שמייצג במדויק את המבנה והמשמעות שלהם, ובו-זמנית להסיר את שאר המורכבות של ה-DOM וה-CSS. כך אנחנו יכולים להטמיע אלגוריתמים להרכבת וגלילה בביטחון רב יותר. הקפידו במיוחד על הדברים הבאים:
- גיאומטריה שעלולה להוביל לשגיאות וחישובים אחרים אפשר לרכז אותם במקום אחד.
- המורכבות של יצירה ועדכון של עצי נכסים מבודדים לשלב אחד של צינור עיבוד נתונים לעיבוד.
- הרבה יותר קל ומהיר לשלוח עצי מאפיינים לשרשורים ותהליכים שונים מאשר מצב DOM מלא, וכך ניתן להשתמש בהם במקרים רבים.
- ככל שיש יותר תרחישים לדוגמה, כך נצליח יותר זכיות משמירה במטמון בגיאומטריה שבנויה על בסיס, כי הם יכולים להשתמש מחדש זה עם זה נשמרים במטמון.
בתהליך עיבוד התמונה (RenderingNG) משתמשים בעצי מאפיין למטרות רבות, כולל:
- הפרדת הרכבה מצבע והרכבה מה-thread הראשי.
- קביעת אסטרטגיה אופטימלית של הרכבה / ציור.
- מדידה IntersectionObserver גיאומטריה.
- הימנעות מעבודה עם רכיבים שנמצאים מחוץ למסך ובמרחבי טקסטורה של GPU.
- ביטול התוקף של צבע ורסטר באופן יעיל ומדויק.
- מדידה שינוי פריסה המהירות שבה נטען רכיב התוכן הכי גדול (LCP) בדוח מדדי הליבה לבדיקת חוויית המשתמש באתר.
לכל מסמך אינטרנט יש ארבעה עצי מאפיין נפרדים: טרנספורמציה, חיתוך, אפקט וגלילה.(*) עץ הטרנספורמציה מייצג המרות וגלילה ב-CSS. (טרנספורמציה של גלילה מיוצגת כמטריצת טרנספורמציה דו-ממדית). עץ הקליפים מייצג קליפים נוספים. עץ האפקטים מייצג את כל האפקטים החזותיים האחרים: אטימוּת, פילטרים, מסכות מצבי שילוב וסוגים אחרים של קליפים כמו קליפ. עץ הגלילה מייצג מידע על גלילה, כמו איך גוללים שרשור ביחד; הוא נדרש לביצוע גלילה בשרשור של המחבר. כל צומת בעץ מאפיינים מייצג גלילה או אפקט חזותי שהוחל על ידי רכיב DOM. אם יש לזה כמה אפקטים, יכול להיות בכל עץ יותר מצומת אחד של עץ נכסים עבור אותו רכיב.
הטופולוגיה של כל עץ דומה לייצוג דל של ה-DOM. לדוגמה, אם יש שלושה רכיבי DOM עם קטעי גלישה נוספים, אז יהיו שלושה צמתים של עץ קליפ, והמבנה של עץ הקליפים יופיע קשר הבלוקים המכיל בין הקליפים הנוספים. יש גם קישורים בין העצים. הקישורים האלה מציינים את ההיררכיה היחסית של DOM, ולכן גם סדר היישום של הצמתים. לדוגמה, אם טרנספורמציה ברכיב DOM נמצאת מתחת לרכיב DOM אחר עם מסנן, כמובן שהטרנספורמציה חלה לפני המסנן.
לכל רכיב DOM יש מצב עץ מאפיינים, שהוא אפור משולש (טרנספורמציה, חיתוך, אפקט, גלילה) שמציין את קליפ האב הקרוב ביותר לשנות ולהשפיע על צומתי עצים שנכנסים לתוקף על הרכיב הזה. זה מאוד נוח, כי בעזרת המידע הזה אנחנו יודעים בדיוק את רשימת הקליפים, טרנספורמציות ואפקטים שחלים על היסוד הזה, ובאיזה סדר. התכונה הזו מאפשרת לנו לדעת איפה הוא נמצא על המסך ואיך לצייר אותו.
דוגמה
(מקור)
<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. כדי ליצור רשימת פריטים לתצוגה.
לדוגמה:
<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 אחד עשוי לגרום לכמה פריטי תצוגה, למשל, איך #greener כולל פריט תצוגה בשביל הרקע ופריט תצוגה אחר עבור הטקסט המוטבע. רמת הפירוט הזו חשובה לייצוג המורכבות המלאה של מפרט הזמנת הצבע ב-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 והטקסט "שלום עולם". |
רשימת הפריטים ברשת המדיה מאוחסנת ונעשה בה שימוש חוזר בעדכונים עתידיים. אם אובייקט פריסה לא השתנה במהלך הליכה בעץ הצבע, שפריטי התצוגה שלו מועתקים מהרשימה הקודמת. אופטימיזציה נוספת מסתמכת על מאפיין של מפרט הזמנת הצבע ב-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 והטקסט "אני נופל". |
במצב כזה, מקטעי עץ הטרנספורמציה ומקטעי הצבע יהיו (פשוטים לצורך קיצור):
את הרשימה המסודרת של מקטעי צבע, שהן קבוצות של פריטים לתצוגה ומצב של עץ נכסים, הם הקלט לשלב השכבות של צינור עיבוד הנתונים. אפשר למזג את כל הרשימה של מקטעי צבע לשכבה מורכבת אחת ולרסטר אותה יחד, אבל לשם כך תצטרכו לבצע עיבוד לרסטריזציה יקרה בכל פעם שהמשתמש יגלול. אפשר ליצור שכבה מורכבת לכל מקטע צבע ויצר רסטר בנפרד כדי למנוע כל עיבוד מחדש לרסטריזציה, אבל מה שיגרום לניצול מהיר של הזיכרון של ה-GPU. שלב השכבות צריך לפצות על זיכרון ה-GPU והפחתת העלויות כששינויים משתנים. גישה כללית טובה היא למזג מקטעים כברירת מחדל, ולא למזג מקטעי צבע שיש להם מצבי עץ נכסים שצפוי להשתנות בשרשור של המחבר, למשל, באמצעות גלילה בקומפוזיטור-שרשור או אנימציות לטרנספורמציה של שרשור קומפוזיטור.
הדוגמה שלמעלה אמורה ליצור שתי שכבות מורכבות:
- שכבה מורכבת בגודל 800x600 המכילה את פקודות השרטוט:
drawRect
בגודל 800x600 ובצבע לבןdrawRect
בגודל 100x100 במיקום 0.0 ובצבע ורוד
- שכבה מורכבת של 144x224 המכילה את פקודות השרטוט:
drawTextBlob
במיקום 0,0 והטקסט "שלום עולם"- תרגום ל-0,18
rotateZ(25deg)
drawRect
בגודל 75x200 במיקום 0.0 ובצבע כתוםdrawTextBlob
עם מיקום 0,0 והטקסט "אני נופל"
אם המשתמש גולל ב-#scroll
,
השכבה המורכבת השנייה מועברת, אבל לא צריך ליצור רסטר.
לדוגמה, מהקטע הקודם על עצי מאפיינים, יש שישה גושים של צבע. ביחד עם מצבי עץ המאפיין (טרנספורמציה, קליפ, אפקט, גלילה) הם:
- רקע המסמך: גלילה במסמך, קליפ, שורש, גלילת מסמך.
- פינה אופקית, אנכית וגלילה ל-div (שלוש מקטעי צבע נפרדים):
גלילה במסמך, קליפ במסמך,
#one
טשטוש, גלילה במסמך. - iframe
#one
:#one
סיבוב, קליפ גלילה לאפשרויות נוספות,#one
טשטוש, גלילה ב-div. - iframe
#two
: קנה מידה של#two
, קליפ של מסמך, בסיס, גלילה במסמך.
פריימים של קומפוזיציה: משטחים, משטחים, משטחים ומשבצות טקסטורה של GPU
תהליכי הדפדפן והעיבוד מנהלים רסטריזציה של תוכן, אחר כך שולחים מסגרות קומפוזביליות לתהליך Viz לצורך הצגה במסך. פריימים מסוג קומפוזבילי מראים איך לחבר תוכן שעבר עיבוד לרסטר ולצייר אותו ביעילות באמצעות ה-GPU.
כרטיס מידע
בתיאוריה, תהליך רינדור או מרכיב של תהליך דפדפן יכול ליצור רסטריזציה של פיקסלים למרקם אחד בגודל המלא של אזור התצוגה של כלי הרינדור, ולשלוח את המרקם הזה ל-Viz. כדי להציג אותו, מרכיב התצוגה צריך פשוט להעתיק את הפיקסלים מהטקסטורה הבודדת למיקום המתאים במאגר הנתונים הזמני של המסגרת (לדוגמה, המסך). עם זאת, אם המחבר הזה רצה לעדכן אפילו לגבי פיקסל בודד, יהיה צורך ליצור מחדש רסטריזציה של אזור התצוגה המלא ולשלוח טקסטורה חדשה ל-Viz.
במקום זאת, אזור התצוגה מחולק למשבצות. קטע נפרד של מרקם של GPU מגבה כל משבצת עם הפיקסלים שעברו עיבוד רסטר עבור חלק מאזור התצוגה. לאחר מכן, כלי הרינדור יכול לעדכן משבצות ספציפיות או אפילו פשוט משנים את המיקום במסך של המשבצות הקיימות. לדוגמה, כשגוללים באתר, המיקום של המשבצות הקיימות ישתנה למעלה ורק מדי פעם יהיה צורך לבצע רסטר של משבצת חדשה עבור תוכן בחלק התחתון של הדף.
ארבעה ופלטפורמות
אריחי טקסטורה של GPU הם מרובעים מסוג מיוחד, שזה פשוט שם מהודר לקטגוריית מרקם אחת או אחרת. מקש ארבע מזהה את טקסטורת הקלט ומציין איך לשנות אותה ולהשתמש באפקטים חזותיים. לדוגמה, למשבצות תוכן רגילות יש טרנספורמציה שמציינת את המיקום שלהן ב-x ו-y ברשת המשבצות.
המשבצות האלה מעובדות בתוך רסטר וארוזות בכרטיס עיבוד, שהוא רשימה של ריבועים. אישור העיבוד לא מכיל פרטי פיקסלים. במקום זאת, יש בו הוראות שמסבירות איפה ואיך לצייר כל מרובע כדי להפיק את פלט הפיקסל הרצוי. לכל משבצת של טקסטורה של GPU יש ריבוע. מחבר התצוגה צריך רק לחזור על רשימת הריבועים, ציור של כל אחת מהן עם האפקטים החזותיים שצוינו, כדי להפיק את פלט הפיקסל הרצוי עבור מעבר העיבוד. הרכבה של מרובעות ציור (quads) של מעבר רינדור יכולה להתבצע ביעילות ב-GPU, כי האפקטים החזותיים המותרים נבחרים בקפידה להיות אפקטים שממפים ישירות לתכונות של GPU.
יש סוגים נוספים של שורות משיכה מעבר למשבצות רסטר. לדוגמה, יש ריבועים בצבע אחיד שלא מגובים בכלל במרקם, או מרקם משרטט מרובעים למרקמים ללא אריחים, כמו סרטון או קנבס.
יכולה להיות גם שמסגרת קומפוזיציה תטמיע מסגרת נוספת של קומפוזבילי. לדוגמה, קומפוזיציה של הדפדפן מפיקה מסגרת קומפוזיציה עם ממשק המשתמש של הדפדפן, ומלבן ריק שבו יוטמע התוכן של רכיב הרינדור. דוגמה נוספת היא מסגרות iframe מבודדות מאתרים. ההטמעה הזו מתבצעת באמצעות פלטפורמות.
כאשר קומפוזיטור שולח מסגרת קומפוזיציה, הוא מלווה במזהה, נקרא Surface ID, וכך מאפשר למסגרות קומפוזביליות אחרות להטמיע אותו לפי הפניה. מסגרת הקומפוזיציה החדשה ביותר שנשלחה עם מזהה משטח מסוים נשמרת על ידי Viz. אחר כך, מסגרת קומפוזיטור אחרת יכולה להתייחס אליו מאוחר יותר באמצעות מרובע שרטוט על פני השטח, ולכן Viz יודעת מה לצייר. (חשוב לשים לב שהמרובעים של ציור פני השטח מכילים רק מזהי משטחים, ולא מרקמים).
אישורים לעיבוד ביניים
אפקטים חזותיים מסוימים, כמו פילטרים או מצבי שילוב מתקדמים, יימשכו שתי מרובעות או יותר למרקם ביניים. לאחר מכן מרקם הביניים משורטט למאגר נתונים זמני של יעד ב-GPU (או אולי למרקם ביניים אחר), החלת האפקט החזותי בו-זמנית. כדי לאפשר זאת, מסגרת קומפוזיציה מכילה למעשה רשימה של אישורי רינדור. תמיד יש אישור מעבר לרמה הבסיסית (root), שציור של האחרון והיעד שלו תואם למאגר הנתונים הזמני של הפריים ויכול להיות שיהיו עוד.
אפשר לקבל הסבר על השם במספר אישורי רינדור 'render Pass'. צריך להריץ כל כרטיס ברצף ב-GPU, בכמה 'אישורים', אבל אפשר להשלים כרטיס יחיד בחישוב של GPU מקביל משמעותי אחד.
צבירה
כמה פריימים של קומפוזיטור נשלחים ל-Viz, והם צריכים לצייר אותם יחד למסך. ניתן להשיג זאת באמצעות שלב צבירה שממיר אותן לתרחיש אחד, מסגרת קומפוזיציה מצטברת. פונקציית הצבירה מחליפה את קווי השרטוט (quads) של פני השטח לפי הפריימים של המרכיב שהם מציינים. זו גם הזדמנות להעלים מרקמים מתווכים מיותרים או תוכן שאינו מוצג במסך. לדוגמה, במקרים רבים, מסגרת הקומפוזיציה עבור iframe מבודד אתר לא צריך טקסטורת ביניים משלו, וניתן לצייר אותו ישירות לתוך מאגר הנתונים הזמני של הפריים באמצעות ריבועי משיכה מתאימים. שלב הצבירה קובע אופטימיזציות כאלה ומיישמת אותם על סמך ידע גלובלי שאינו נגיש למרכיבי עיבוד נפרדים.
דוגמה
אלה פריימים של הקומפוזיטור שמייצגים את הדוגמה מההתחלה הפוסט הזה.
- הפלטפורמה של
foo.com/index.html
: id=0- עיבוד אישור 0: משרטטים כדי להציג את הפלט.
- עיבוד הנתונים ב-Qud Pass: משרטטים עם טשטוש של 3 פיקסלים וחיתוך של כרטיס רינדור 0.
- עיבוד כרטיס 1:
- משרטטים מרובעים לתוכן של קטע
#one
ב-iframe, עם מיקומי x ו-y לכל אחד מהם.
- משרטטים מרובעים לתוכן של קטע
- עיבוד כרטיס 1:
- סוג ציור משטח: עם מזהה 2, מצויר עם קנה מידה ותרגום של טרנספורמציה.
- עיבוד הנתונים ב-Qud Pass: משרטטים עם טשטוש של 3 פיקסלים וחיתוך של כרטיס רינדור 0.
- עיבוד אישור 0: משרטטים כדי להציג את הפלט.
- הפלטפורמה של ממשק המשתמש של הדפדפן: ID=1
- עיבוד אישור 0: משרטטים כדי להציג את הפלט.
- שרטטו quads עבור ממשק המשתמש של הדפדפן (גם אריחים)
- עיבוד אישור 0: משרטטים כדי להציג את הפלט.
- הפלטפורמה של
bar.com/index.html
: ID=2- עיבוד אישור 0: משרטטים כדי להציג את הפלט.
- משרטטים מרובעים לתוכן של
#two
iframe, כאשר מיקומי x ו-y בכל אחד מהם.
- משרטטים מרובעים לתוכן של
- עיבוד אישור 0: משרטטים כדי להציג את הפלט.
איורים של Una Kravets.