הטמעת 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 וקריאה חוזרת ל-SurfaceFlinger כדי להודיע לו כשאירוע VSYNC מתרחש.

ממשק HIDL

Android 8.0 ואילך משתמש ממשק HIDL שנקרא Composer HAL עבור IPC משולב בין 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, ראו composer. למידע מפורט על הפונקציות של HWC, תוכלו לעיין במאמר hwcomposer2.h.

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

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

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

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

מצבים

כל פריים נמצא באחד משלושה מצבים אחרי ש-SurfaceFlinger קורא שיטת HWC validateDisplay():

  • GLES — ה-GPU מורכב מכל השכבות, ככה ישירות למאגר הנתונים הזמני של הפלט. ה-HWC לא מעורב בהרכבה.
  • MIXED — ה-GPU מרכיב כמה שכבות ה-framebuffer ו-HWC מרכיבים את ה-framebuffer ואת השכבות שנותרו, לכתוב ישירות למאגר הנתונים הזמני של הפלט.
  • HWC — HWC מורכב מכל השכבות וכותב ישירות למאגר הנתונים הזמני של הפלט.

פורמט פלט

פורמטים של פלט של מאגר וירטואלי לתצוגה תלויים במצב שלו:

  • מצב GLES – מנהל ה-EGL מגדיר את הפורמט של מאגר הפלט ב-dequeueBuffer(), בדרך כלל RGBA_8888. לצרכן צריכה להיות אפשרות לקבל את פורמט הפלט שהנהג מגדיר או לא ניתן לקרוא את מאגר הנתונים הזמני.
  • מצבי MIXED ו-HWC – אם הצרכן צריך מעבד (CPU) גישה, הצרכן מגדיר את הפורמט. אחרת, הפורמט הוא IMPLEMENTATION_DEFINED, ו-Gralloc מגדיר את הפורמט הטוב ביותר על סמך דגלי השימוש. לדוגמה, Gralloc מגדיר פורמט YCbCr אם הצרכן הוא מקודד וידאו ו-HWC יכול לכתוב את הפורמט ביעילות.

גדרות סנכרון

גדרות סנכרון (sync) הן היבט חיוני במערכת הגרפיקה של Android. גדרות מאפשרות למעבד (CPU) לפעול בנפרד מעבודה של GPU בו-זמנית, חסימה רק כשיש תלות אמיתית.

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

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

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