הטמעת HAL של Hardware Composer

שכבות ה-HAL המשולבות של Hardware Composer‏ (HWC) מתקבלות מ-SurfaceFlinger, וכך מפחיתות את כמות ההרכבה של OpenGL ES‏ (GLES) וה-GPU.

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

הטמעות של HWC צריכות לתמוך באפשרויות הבאות:

  • לפחות ארבע שכבות-על:
    • שורת סטטוס
    • סרגל המידע
    • אפליקציה
    • טפט/רקע
  • שכבות גדולות יותר מהמסך (לדוגמה, טפט)
  • שילוב אלפא בו-זמנית לכל פיקסל ולכל מישור
  • נתיב חומרה להפעלת וידאו מוגן
  • סדר האריזה של RGBA, פורמטים של YUV ומאפייני טיילוינג, ערבוב וסטרייד

כדי להטמיע את ה-HWC:

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

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

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

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

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

// In Android 10 and higher:

// Update state for internal display
// Update state for external display
validateInternal()
presentInternal()
validateExternal()
presentExternal()

הרכבת מסך וירטואלי

ההרכב של המסך הווירטואלי דומה להרכב של המסך החיצוני. ההבדל בין הרכבה של תצוגה וירטואלית לבין הרכבה של תצוגה פיזית הוא שבתצוגות וירטואליות הפלט נשלח למאגר של 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.