ה-HAL של Hardware Composer (HWC) מרכיב שכבות שהתקבלו מ-SurfaceFlinger, ומפחית את כמות ההרכבה של OpenGL ES (GLES) ואת הביצועים של ה-GPU.
ה-HWC מבצע הפשטה של אובייקטים, כמו שכבות-על ו-2D blitters, כדי ליצור משטחים מורכבים, ומתקשר עם חומרה מיוחדת של חלונות מורכבים כדי ליצור חלונות מורכבים. משתמשים ב-HWC כדי ליצור קומפוזיציה של חלונות במקום ליצור קומפוזיציה של SurfaceFlinger באמצעות ה-GPU. רוב יחידות ה-GPU לא מותאמות להרכבה, וכשיחידת ה-GPU מרכיבה שכבות מ-SurfaceFlinger, אפליקציות לא יכולות להשתמש ב-GPU לעיבוד משלהן.
הטמעות של HWC צריכות לתמוך ב:
- לפחות ארבע שכבות-על:
- שורת סטטוס
- סרגל המידע
- אפליקציה
- טפט/רקע
- שכבות שגדולות יותר מהתצוגה (לדוגמה, טפט)
- מיזוג אלפא בו-זמני של כל פיקסל בנפרד ומיזוג אלפא של כל מישור בנפרד
- נתיב חומרה להפעלת סרטונים מוגנים
- סדר האריזה של RGBA, פורמטים של YUV ומאפיינים של tiling, swizzling ו-stride
כדי להטמיע את HWC:
- הטמעה של HWC לא פעיל ושליחה של כל העבודה שקשורה לקומפוזיציה אל GLES.
- מטמיעים אלגוריתם להעברת ההרכבה ל-HWC באופן מצטבר. לדוגמה, אפשר להקצות רק את שלוש או ארבע הפלטפורמות הראשונות לחומרה של שכבת העל של ה-HWC.
- אופטימיזציה של ה-HWC. למשל:
- בחירת פלטפורמות שממזערות את העומס על ה-GPU ושליחתן ל-HWC.
- זיהוי אם המסך מתעדכן. אם לא, כדי לחסוך בחשמל, צריך להעביר את ההרכבה ל-GLES במקום ל-HWC. כשהמסך מתעדכן שוב, ממשיכים להעביר את ההרכבה ל-HWC.
- הכנה לתרחישים נפוצים לדוגמה, כמו:
- מסך הבית, שכולל את שורת הסטטוס, סרגל המערכת, חלון האפליקציה וטפטים דינמיים
- משחקים במסך מלא במצב לאורך ובפריסה לרוחב
- סרטון במסך מלא עם כתוביות ושליטה בהפעלה
- הפעלה של סרטון מוגן
- ריבוי חלונות במסך מפוצל
פרימיטיבים של HWC
ה-HWC מספק שני פרימיטיבים, שכבות ומסכים, כדי לייצג את עבודת ההרכבה ואת האינטראקציה שלה עם חומרת המסך. HWC גם מספק שליטה ב-VSync וקריאה חוזרת ל-SurfaceFlinger כדי להודיע לו כשמתרחש אירוע VSync.
ממשק HIDL
ב-Android מגרסה 8.0 ואילך נעשה שימוש בממשק HIDL שנקרא Composer HAL לצורך IPC עם Binder בין 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.
מסמכים מפורטים על פונקציות Composer HAL ופונקציות HWC passthrough זמינים במאמר composer. לתיעוד מפורט על מצביעים לפונקציות של HWC, אפשר לעיין בhwcomposer2.h.
ידיות של שכבות ותצוגות
השכבות והתצוגות מופעלות על ידי נקודות אחיזה שנוצרות על ידי ה-HWC. הכינויים אטומים ל-SurfaceFlinger.
כש-SurfaceFlinger יוצר שכבה חדשה, הוא קורא ל-createLayer, שמחזירה ערך מהסוג Layer להטמעות ישירות או hwc2_layer_t להטמעות של העברת נתונים. כש-SurfaceFlinger משנה מאפיין של השכבה הזו, הוא מעביר את הערך hwc2_layer_t לפונקציית השינוי המתאימה, יחד עם כל מידע אחר שנדרש לביצוע השינוי. הסוג hwc2_layer_t גדול מספיק כדי להכיל מצביע או אינדקס.
מסכים פיזיים נוצרים על ידי חיבור מהיר (hotplug). כשמחברים מסך פיזי בזמן שהמחשב פועל (hotplug), HWC יוצרת נקודת אחיזה ומעבירה אותה ל-SurfaceFlinger דרך הקריאה החוזרת של hotplug. תצוגות וירטואליות נוצרות על ידי SurfaceFlinger
שקורא ל-createVirtualDisplay() כדי לבקש תצוגה. אם ה-HWC
תומך בהרכבת תצוגה וירטואלית, הוא מחזיר נקודת אחיזה. לאחר מכן, SurfaceFlinger מעביר את הקומפוזיציה של התצוגות ל-HWC. אם ה-HWC לא תומך בהרכבה של מסך וירטואלי, SurfaceFlinger יוצר את ה-handle ומרכיב את המסך.
הצגת פעולות של יצירת קומפוזיציה
פעם אחת בכל VSync, SurfaceFlinger מתעורר אם יש לו תוכן חדש להרכבה. התוכן החדש יכול להיות מאגרי תמונות חדשים מאפליקציות או שינוי במאפיינים של שכבה אחת או יותר. כשהוא מתעורר מ-SurfaceFlinger:
- מטפל בעסקאות, אם יש כאלה.
- נועל את מאגרי הגרפיקה החדשים, אם קיימים.
- מבצע קומפוזיציה חדשה, אם שלב 1 או 2 הביאו לשינוי בתוכן התצוגה.
כדי לבצע קומפוזיציה חדשה, SurfaceFlinger יוצר ומבטל שכבות או משנה את מצבי השכבות, לפי הצורך. הוא גם מעדכן את השכבות עם התוכן הנוכחי שלהן, באמצעות קריאות כמו setLayerBuffer או setLayerColor. אחרי שכל השכבות מתעדכנות, SurfaceFlinger קורא ל-validateDisplay, שמורה ל-HWC לבדוק את מצב השכבות ולקבוע איך יתבצע השילוב. כברירת מחדל, SurfaceFlinger מנסה להגדיר כל שכבה כך שהשכבה תורכב על ידי HWC. עם זאת, בנסיבות מסוימות, SurfaceFlinger מרכיב שכבות באמצעות GPU fallback.
אחרי הקריאה ל-validateDisplay, SurfaceFlinger קורא ל-getChangedCompositionTypes כדי לבדוק אם HWC רוצה לשנות את אחד מסוגי ההרכבה של השכבות לפני ביצוע ההרכבה. כדי לאשר את השינויים, SurfaceFlinger קורא ל-acceptDisplayChanges.
אם יש שכבות שמסומנות להרכבה ב-SurfaceFlinger, SurfaceFlinger מרכיב אותן לתוך מאגר היעד. לאחר מכן, SurfaceFlinger קורא ל-setClientTarget כדי להעביר את המאגר לתצוגה, כך שהמאגר יוצג במסך או יורכב עם שכבות שלא סומנו להרכבה ב-SurfaceFlinger. אם לא מסומנות שכבות להרכבה של SurfaceFlinger, המערכת מדלגת על שלב ההרכבה.
לבסוף, SurfaceFlinger קורא ל-presentDisplay כדי להודיע ל-HWC להשלים את תהליך ההרכבה ולהציג את התוצאה הסופית.
מספר מסכים
Android 10 תומך במספר מסכים פיזיים. כשמתכננים הטמעה של HWC שמיועדת לשימוש ב-Android 7.0 ומעלה, יש כמה הגבלות שלא מופיעות בהגדרה של HWC:
- מניחים שיש בדיוק מסך פנימי אחד. המסך הפנימי הוא המסך שעליו מדווחים על חיבור מהיר במהלך האתחול. אחרי שמחברים את המסך הפנימי, אי אפשר לנתק אותו.
- בנוסף למסך הפנימי, אפשר לחבר ולנתק מסכים חיצוניים בזמן הפעולה הרגילה של המכשיר. המסגרת מניחה שכל החיבורים והניתוקים אחרי המסך הפנימי הראשון הם מסכים חיצוניים, ולכן אם מוסיפים עוד מסכים פנימיים, הם מסווגים בצורה שגויה כ-
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 קורא ל-method validateDisplay() HWC:
- GLES – ה-GPU מרכיב את כל השכבות וכותב ישירות למאגר הפלט. ה-HWC לא מעורב ביצירה.
- MIXED – ה-GPU מרכיב כמה שכבות לתוך מאגר המסגרות, וה-HWC מרכיב את מאגר המסגרות ואת השכבות שנותרו, וכותב ישירות למאגר הפלט.
- HWC – HWC יוצר קומפוזיציה של כל השכבות וכותב ישירות אל מאגר הפלט.
פורמט פלט
פורמטים של פלט של מאגר וירטואלי לתצוגה תלויים במצב שלו:
- מצב GLES – הדרייבר EGL מגדיר את הפורמט של מאגר הפלט ב-
dequeueBuffer(), בדרך כללRGBA_8888. הצרכן צריך להיות מסוגל לקבל את פורמט הפלט שהוגדר על ידי מנהל ההתקן, אחרת לא ניתן לקרוא את המאגר. - מצבי MIXED ו-HWC – אם צרכן צריך גישה למעבד, הוא מגדיר את הפורמט. אחרת, הפורמט הוא
IMPLEMENTATION_DEFINED, ו-Gralloc מגדיר את הפורמט הכי טוב על סמך דגלי השימוש. לדוגמה, Gralloc מגדיר פורמט YCbCr אם הצרכן הוא מקודד וידאו ו-HWC יכול לכתוב את הפורמט ביעילות.
גדרות סנכרון
גדרות סנכרון הן היבט חשוב במערכת הגרפיקה של Android. הגדרת גדרות מאפשרת לעבודת ה-CPU להתבצע באופן עצמאי מעבודת ה-GPU המקבילה, ולחסום רק כשיש תלות אמיתית.
לדוגמה, כששולחים מאגר נתונים זמני שנוצר ב-GPU, שולחים גם אובייקט של גדר סנכרון. הגדרת הגדר הזה מאותתת מתי ה-GPU סיים לכתוב לתוך המאגר.
ה-HWC דורש שה-GPU יסיים לכתוב את המאגרים לפני שהמאגרים יוצגו. גדרות סנכרון מועברות דרך צינור הגרפיקה עם מאגרי נתונים (buffers) ומאותתות כשמאגרי הנתונים נכתבים. לפני שמוצג מאגר, HWC בודק אם גדר הסנכרון אותתה, ואם כן, הוא מציג את המאגר.
מידע נוסף על גדרות סנכרון זמין במאמר שילוב של Hardware Composer.