הטמעת HAL של Hardware Composer

ה-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:

  1. הטמעה של HWC לא תפעולי ושליחה של כל עבודת ההרכבה אל GLES.
  2. מטמיעים אלגוריתם להעברת ההרכבה ל-HWC באופן מצטבר. לדוגמה, להקצות רק את שלוש או ארבע שכבות העל הראשונות לחומרה של HWC.
  3. אופטימיזציה של HWC. למשל:
    • בחירת פלטפורמות שממזערות את העומס על ה-GPU ושליחתן ל-HWC.
    • זיהוי אם המסך מתעדכן. אם לא, צריך להעביר את ההרכבה ל-GLES במקום ל-HWC כדי לחסוך בחשמל. כשהמסך מתעדכן שוב, ממשיכים להעביר את ההרכבה ל-HWC.
    • הכנה לתרחישים נפוצים לדוגמה, כמו:
      • מסך הבית, שכולל את שורת הסטטוס, סרגל המערכת, חלון האפליקציה וטפטים דינמיים
      • משחקים במסך מלא במצב תצוגה לאורך ולרוחב
      • סרטון במסך מלא עם כתוביות ושליטה בהפעלה
      • הפעלת סרטון מוגן
      • מסך מפוצל עם ריבוי חלונות

פרימיטיבים של HWC

ה-HWC מספק שני פרימיטיבים, שכבות ומסכים, כדי לייצג עבודת קומפוזיציה ואת האינטראקציה שלה עם חומרת המסך. ‫HWC גם מספק שליטה ב-VSync וקריאה חוזרת ל-SurfaceFlinger כדי להודיע לו כשמתרחש אירוע VSync.

ממשק HIDL

ב-Android מגרסה 8.0 ואילך נעשה שימוש בממשק HIDL שנקרא Composer HAL לצורך IPC עם Binder בין HWC ל-SurfaceFlinger. ה-Composer HAL מחליף את הממשק מדור קודם 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 function passthrough זמינים במאמר composer. מידע מפורט על מצביעים לפונקציות של HWC זמין בhwcomposer2.h.

ידיות של שכבות ותצוגות

השכבות והתצוגות מופעלות על ידי נקודות אחיזה שנוצרות על ידי ה-HWC. הכינויים אטומים ל-SurfaceFlinger.

כש-SurfaceFlinger יוצר שכבה חדשה, הוא קורא ל-createLayer, שמוחזרת מהסוג Layer להטמעות ישירות או hwc2_layer_t להטמעות של העברת נתונים. כש-SurfaceFlinger משנה מאפיין של השכבה הזו, הוא מעביר את הערך hwc2_layer_t לפונקציית השינוי המתאימה, יחד עם כל מידע אחר שנדרש לביצוע השינוי. הסוג hwc2_layer_t גדול מספיק כדי להכיל מצביע או אינדקס.

מסכים פיזיים נוצרים על ידי חיבור מהיר (hotplug). כשמחברים מסך פיזי, ה-HWC יוצר ידית ומעביר אותה ל-SurfaceFlinger דרך הקריאה החוזרת של hotplug. תצוגות וירטואליות נוצרות על ידי SurfaceFlinger שקורא ל-createVirtualDisplay() כדי לבקש תצוגה. אם HWC תומך בהרכבת תצוגה וירטואלית, הוא מחזיר נקודת אחיזה. לאחר מכן, SurfaceFlinger מעביר את הקומפוזיציה של התצוגות ל-HWC. אם ה-HWC לא תומך בהרכבה של מסכים וירטואליים, SurfaceFlinger יוצר את ה-handle ומרכיב את המסך.

פעולות של הרכב התצוגה

פעם אחת בכל VSync, ‏ SurfaceFlinger מתעורר אם יש לו תוכן חדש להרכבה. התוכן החדש יכול להיות מאגרי תמונות חדשים מאפליקציות או שינוי במאפיינים של שכבה אחת או יותר. כאשר SurfaceFlinger מעיר אותו:

  1. מטפל בעסקאות, אם יש כאלה.
  2. נועלת מאגרי גרפיקה חדשים, אם יש כאלה.
  3. מבצע קומפוזיציה חדשה, אם שלב 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.

לבסוף, 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 – אם צרכן צריך גישה למעבד, הוא מגדיר את הפורמט. אחרת, הפורמט הוא IMPLEMENTATION_DEFINED, ו-Gralloc מגדיר את הפורמט הכי טוב על סמך דגלי השימוש. לדוגמה, Gralloc מגדיר פורמט YCbCr אם הצרכן הוא מקודד וידאו ו-HWC יכול לכתוב את הפורמט ביעילות.

גדרות סנכרון

גדרות סנכרון הן היבט חשוב במערכת הגרפיקה של Android. הגדרת גדרות מאפשרת לעבודת המעבד להתבצע באופן עצמאי מעבודת המעבד הגרפי המקבילה, והחסימה מתרחשת רק כשיש תלות אמיתית.

לדוגמה, כששולחים מאפליקציה מאגר שנוצר ב-GPU, שולחים גם אובייקט של גדר סנכרון. הגדרת הגדר הזה מאותתת מתי ה-GPU סיים לכתוב לתוך המאגר.

ה-HWC דורש שה-GPU יסיים לכתוב את המאגרים לפני שהם יוצגו. גדרות סנכרון מועברות דרך צינור הגרפיקה עם מאגרי נתונים, והן מסמנות מתי מאגרי הנתונים נכתבים. לפני שמוצג מאגר, HWC בודק אם גדר הסנכרון אותתה, ואם כן, הוא מציג את המאגר.

מידע נוסף על גדרות סנכרון זמין במאמר Hardware Composer Integration.