שכבות ה-HAL המשולבות של Hardware Composer (HWC) מתקבלות מ-SurfaceFlinger, וכך מפחיתות את כמות ההרכבה של OpenGL ES (GLES) וה-GPU.
HWC מפשט אובייקטים, כמו שכבות-על ובליטות דו-ממדיות, למשטחים מורכבים ומתקשרים עם חומרה מיוחדת להרכבת חלונות לחלונות מורכבים. שימוש ב-HWC כדי ליצור קומפוזיציה של חלונות במקום ליצור קומפוזיציה של SurfaceFlinger עם ה-GPU. רוב המעבדים הגרפיים לא מותאמים להרכבה, וכשה-GPU יוצר שכבות מ-SurfaceFlinger, האפליקציות לא יכולות להשתמש ב-GPU לצורך העיבוד שלהן.
הטמעות של HWC צריכות לתמוך באפשרויות הבאות:
- לפחות ארבע שכבות-על:
- שורת סטטוס
- סרגל המערכת
- אפליקציה
- טפט/רקע
- שכבות גדולות יותר מהמסך (לדוגמה, טפט)
- שילוב אלפא בו-זמנית לכל פיקסל ולכל מישור
- נתיב חומרה להפעלת סרטונים מוגנים
- סדר האריזה של RGBA, פורמטים של YUV ומאפייני טיילוינג, ערבוב וסטרייד
כדי להטמיע את ה-HWC:
- הטמעת HWC לא פעיל ושליחת כל עבודת הקומפוזיציה ל-GLES.
- הטמעת אלגוריתם להענקת גישה להרכבה ל-HWC באופן מצטבר. לדוגמה, אפשר להאציל רק את שלוש או ארבע הפלטפורמות הראשונות לחומרת שכבת-העל של ה-HWC.
- מבצעים אופטימיזציה של HWC. העדכון עשוי לכלול את הפעולות הבאות:
- בחירת פלטפורמות שמגדילות את העומס שמורידים מה-GPU ושולחים אותן ל-HWC.
- מתבצע עדכון של המסך. אם לא, צריך להעביר את היצירה ל-GLES במקום ל-HWC כדי לחסוך בחשמל. כשהמסך יתעדכן שוב, ממשיכים להוריד את העומס על ההרכבה ל-HWC.
- הכנה לתרחישים נפוצים, כמו:
- מסך הבית, שכולל את שורת הסטטוס, את סרגל המערכת, את חלון האפליקציה ואת הטפטים החיים
- משחקים במסך מלא במצב פורטרט ובמצב לרוחב
- צפייה בסרטון במסך מלא עם כתוביות ובקרת הפעלה
- הפעלת סרטונים מוגנים
- ריבוי חלונות במסך מפוצל
פרימיטיבים של HWC
HWC מספק שני רכיבים בסיסיים, שכבות ומסכים, שמייצגים את עבודת העריכה ואת האינטראקציה שלה עם חומרת המסך. ב-HWC יש גם שליטה על VSYNC וקריאה חוזרת (callback) ל-SurfaceFlinger כדי להודיע לו כשאירוע VSYNC מתרחש.
ממשק HIDL
ב-Android מגרסה 8.0 ואילך נעשה שימוש בממשק HIDL שנקרא Composer HAL ל-IPC מצורף בין HWC ל-SurfaceFlinger. HAL של Composer מחליף את הממשק הקודם hwcomposer2.h
. אם הספקים מספקים הטמעה של Composer HAL ל-HWC, Composer HAL מקבל ישירות קריאות HIDL מ-SurfaceFlinger. אם הספקים מספקים הטמעה מדור קודם של HWC, Composer HAL טוען את הפונקציות של הפונקציות מ-hwcomposer2.h
, ומעביר את הקריאות של HIDL לקריאות של הפונקציות.
ה-HWC מספק פונקציות לקביעת המאפיינים של מסך נתון, למעבר בין הגדרות מסך שונות (כמו רזולוציית 4K או 1080p) ומצבי צבע שונים (כמו צבע מקורי או sRGB אמיתי), ולהפעלה, להשבתה או להעברה של המסך למצב צריכת אנרגיה נמוכה, אם האפשרות הזו נתמכת.
מצביעים לפונקציות
אם ספקים מטמיעים את Composer HAL ישירות, SurfaceFlinger קורא לפונקציות שלו דרך HIDL IPC. לדוגמה, כדי ליצור שכבה, SurfaceFlinger קורא לפונקציה createLayer()
ב-Composer HAL.
אם ספקים מטמיעים את הממשק hwcomposer2.h
, Composer HAL מבצע קריאה למצביעי הפונקציות של hwcomposer2.h
. בהערות hwcomposer2.h
, הפונקציות של ממשק HWC מופיעות בשמות ב-lowerCamelCase שלא קיימים בממשק כשדות עם שם. כמעט כל פונקציה נטענת על ידי בקשה למצביע פונקציה באמצעות getFunction
שמסופק על ידי hwc2_device_t
. לדוגמה, הפונקציה createLayer
היא הפניה לפונקציה מסוג HWC2_PFN_CREATE_LAYER
, שמוחזרת כשהערך המנומר HWC2_FUNCTION_CREATE_LAYER
מועבר אל getFunction
.
למסמכים מפורטים על פונקציות HAL של Composer ועל פונקציות העברה של HWC, ראו composer
. למידע מפורט על הפונקציות של HWC, תוכלו לעיין במאמר hwcomposer2.h
.
ידיות של שכבות ותצוגות
שכבות ותצוגות מותאמות אישית על ידי נקודות אחיזה שנוצרו על ידי HWC. הכינוי אטום ל-SurfaceFlinger.
כש-SurfaceFlinger יוצר שכבה חדשה, הוא קורא ל-createLayer
, שמחזיר אובייקט מסוג Layer
להטמעות ישירות או hwc2_layer_t
להטמעות העברה. כש-SurfaceFlinger משנה מאפיין של השכבה הזו, הוא מעביר את הערך hwc2_layer_t
לפונקציית השינוי המתאימה, יחד עם כל המידע הנוסף הנדרש לביצוע השינוי. הטיפוס hwc2_layer_t
גדול מספיק כדי להכיל סמן או אינדקס.
צגים פיזיים נוצרים על ידי חיבור חם. כשמסך פיזי מחובר לחשמל, צוות HWC יוצר נקודת אחיזה ומעביר את הידית ל-SurfaceFlinger דרך הקריאה החוזרת (callback) של ה-Hotspot. המסכים הווירטואליים נוצרים על ידי SurfaceFlinger, שמפעיל את createVirtualDisplay()
כדי לבקש מסך. אם ה-HWC תומך בהרכבת תצוגה וירטואלית, הוא מחזיר אחיזה (handle). לאחר מכן, SurfaceFlinger מאציל את היצירה של המסך ל-HWC. אם ה-HWC לא תומך בהרכבת תצוגה וירטואלית, SurfaceFlinger יוצר את נקודת האחיזה ומרכיב את המסך.
פעולות הרכבה במסך
פעם לכל VSYNC, SurfaceFlinger מתעורר אם יש לו תוכן חדש שצריך לשלב. התוכן החדש יכול להיות מאגרי תמונות חדשים מאפליקציות או שינוי במאפיינים של שכבה אחת או יותר. כש-SurfaceFlinger מעיר אותו:
- טיפול בעסקאות, אם הן קיימות.
- מתבצעת נעילה של מאגרי נתונים גרפיים חדשים, אם יש כאלה.
- מבצע קומפוזיציה חדשה, אם שלב 1 או 2 הביאו לשינוי בתוכן המוצג.
כדי לבצע הרכבה חדשה, SurfaceFlinger יוצר ומשמיד שכבות או משנה מצבי שכבה, לפי הצורך. הוא גם מעדכן שכבות עם התוכן הנוכחי שלהן, באמצעות קריאות כמו setLayerBuffer
או setLayerColor
. אחרי שכל השכבות מתעדכנות, SurfaceFlinger קורא ל-validateDisplay
, שמורה ל-HWC לבדוק את מצב השכבות ולהחליט איך תתבצע ההרכבה. כברירת מחדל, SurfaceFlinger מנסה להגדיר כל שכבה כך שהשכבה תהיה מורכבת על ידי HWC. עם זאת, בנסיבות מסוימות, SurfaceFlinger יוצר שכבות מורכבות באמצעות חלופה ל-GPU.
אחרי הקריאה ל-validateDisplay
, SurfaceFlinger קורא ל-getChangedCompositionTypes
כדי לבדוק אם HWC רוצה לשנות את סוגי הרכב השכבות לפני ביצוע ההרכבה. כדי לאשר את השינויים, SurfaceFlinger קורא ל-acceptDisplayChanges
.
אם שכבות מסוימות מסומנות בקומפוזיציה של SurfaceFlinger, SurfaceFlinger מחבר אותן למאגר הנתונים הזמני של היעד. לאחר מכן, SurfaceFlinger קורא ל-setClientTarget
כדי להעביר את המאגר לצג, כך שניתן יהיה להציג את המאגר במסך או לשלב אותו עם שכבות שלא סומנו ליצירת קומפוזיציה ב-SurfaceFlinger. אם לא מסומנות שכבות ליצירת קומפוזיציה ב-SurfaceFlinger, SurfaceFlinger עוקף את שלב היצירה.
לבסוף, SurfaceFlinger שולח קריאה ל-presentDisplay
כדי לומר ל-HWC להשלים את תהליך ההרכבה ולהציג את התוצאה הסופית.
מודעות לרשת המדיה בכמה גדלים
ב-Android 10 יש תמיכה בכמה מסכים פיזיים. כשמתכננים הטמעת HWC שמיועדת לשימוש ב-Android 7.0 ואילך, יש מספר הגבלות שלא קיימות בהגדרת HWC:
- ההנחה היא שיש רק מסך פנימי אחד. המסך הפנימי הוא המסך שעליו מדווח ה-hotplug הראשוני במהלך האתחול. אחרי שהמסך הפנימי מחובר לחשמל, לא ניתן לנתק אותו.
- בנוסף למסך הפנימי, אפשר לחבר מספר בלתי מוגבל של מסכים חיצוניים במהלך הפעולה הרגילה של המכשיר. במסגרת הזו, ההנחה היא שכל החיבורים החמים אחרי המסך הפנימי הראשון הם מסכים חיצוניים. לכן, אם מוסיפים עוד מסכים פנימיים, הם מסווגים באופן שגוי כ-
Display.TYPE_HDMI
במקום כ-Display.TYPE_BUILT_IN
.
פעולות SurfaceFlinger המתוארות למעלה מתבצעות לכל מסך בנפרד, אבל הן מתבצעות ברצף בכל המסכים הפעילים, גם אם התוכן של מסך אחד בלבד מתעדכן.
לדוגמה, אם המסך החיצוני מתעדכן, הרצף הוא:
// In Android 9 and lower: // Update state for internal display // Update state for external display validateDisplay(<internal display>) validateDisplay(<external display>) presentDisplay(<internal display>) presentDisplay(<external display>) // In Android 10 and higher: // Update state for internal display // Update state for external display validateInternal(<internal display>) presentInternal(<internal display>) validateExternal(<external display>) presentExternal(<external display>)
הרכבת מסך וירטואלי
ההרכב של תצוגה וירטואלית דומה להרכב של תצוגה חיצונית. ההבדל בין הרכבת תצוגה וירטואלית לבין הרכבת תצוגה פיזית הוא שבתצוגות וירטואליות הפלט נשלח למאגר של Gralloc במקום למסך. ה-Hardware Composer (HWC) כותב את הפלט למאגר, מספק את 'מגדל הסיום' ושולח את המאגר לצרכנים (כמו מקודד הווידאו, ה-GPU, ה-CPU וכו'). תצוגות וירטואליות יכולות להשתמש ב-2D/blitter או שכבות-על אם צינור עיבוד הנתונים של התצוגה כותב בזיכרון.
מצבים
כל פריים נמצא באחד משלושת המצבים הבאים אחרי ש-SurfaceFlinger קורא לשיטה validateDisplay()
HWC:
- GLES – ה-GPU משלב את כל השכבות וכותב ישירות למאגר הפלט. ה-HWC לא מעורב בהרכבה.
- MIXED – ה-GPU משלב שכבות מסוימות במאגר התמונות, ו-HWC משלב את מאגר התמונות ואת השכבות הנותרות, וכותב ישירות למאגר הפלט.
- HWC – HWC מרכיב את כל השכבות וכותב ישירות למאגר הנתונים הזמני של הפלט.
פורמט הפלט
פורמטים של פלט של מאגר וירטואלי לתצוגה תלויים במצב שלו:
- מצב GLES – מנהל ה-EGL מגדיר את הפורמט של מאגר הפלט ב-
dequeueBuffer()
, בדרך כללRGBA_8888
. הצרכן צריך להיות מסוגל לקבל את פורמט הפלט שהנהג מגדיר, אחרת לא ניתן יהיה לקרוא את המאגר. - המצבים MIXED ו-HWC – אם לצרכנים יש צורך בגישה ל-CPU, הם מגדירים את הפורמט. אחרת, הפורמט הוא
IMPLEMENTATION_DEFINED
ו-Gralloc מגדיר את הפורמט הטוב ביותר על סמך דגלי השימוש. לדוגמה, Gralloc מגדיר פורמט YCbCr אם הצרכן הוא מקודד וידאו ו-HWC יכול לכתוב את הפורמט ביעילות.
גדרות סנכרון
גדרות סנכרון (sync) הן היבט חיוני במערכת הגרפיקה של Android. מחסומי גישה מאפשרים לעבודה של המעבד להתקדם בנפרד מעבודה בו-זמנית של המעבד הגרפי, ומבצעים חסימה רק כשיש תלות אמיתית.
לדוגמה, כשאפליקציה שולחת מאגר שנוצר ב-GPU, היא שולחת גם אובייקט של sync fence. הגדרת האותות לאחר מכן כשה-GPU מסיים לכתוב במאגר הנתונים הזמני.
ה-HWC דורש שה-GPU תסיים לכתוב את מאגר הנתונים הזמני לפני הצגת מאגר הנתונים הזמני. גדרות סנכרון מועברות דרך צינור עיבוד הנתונים של הגרפיקה עם מאגרים ומאותתים כשמאגרים נכתבים. לפני שהמאגר מוצג, ה-HWC בודק אם גדר הסנכרון שלח אות, ואם כן, הוא מציג את המאגר.
מידע נוסף על גדרות סנכרון אפשר למצוא במאמר שילוב של Hardware Composer.