קצב רענון מרובים

ב-Android 11 נוספה תמיכה במכשירים עם כמה שיעורי רענון. בתכונה הזו יש שלושה רכיבים עיקריים:

  • ממשקי HAL API חדשים שהוצגו ב-android.hardware.graphics.composer@2.4.
  • קוד פלטפורמה לניתוח הגדרות המכשיר לקצבי רענון שונים ולהגדרת קצב הרענון הרצוי
  • ממשקי API חדשים של SDK ו-NDK שמאפשרים לאפליקציות להגדיר את קצב הפריימים הרצוי

הטמעה

הוספנו תמיכה ייעודית למעבר בין קצב רענון ל-android.hardware.graphics.composer@2.4 HAL. מומלץ מאוד להשתמש בגרסה הזו, כי בגרסאות הקודמות של הקומפוזיציה HAL יש תמיכה מוגבלת בשינוי של קצב הרענון.

קבוצות תצורה

נוסף מאפיין חדש CONFIG_GROUP ל-IComposerClient::Attribute, שאפשר לשלוח עליו שאילתות באמצעות ה-API של getDisplayAttribute_2_4. המאפיין הזה מאפשר לספקים לקבץ יחד הגדרות של תצוגות. הגדרות באותה קבוצה מאפשרות לעבור ביניהן בצורה חלקה ברוב המקרים. הפלטפורמה משתמשת בקבוצת ההגדרות כדי להבדיל בין ההגדרות שאפשר לעבור ביניהן כדי לשנות את קצב הרענון, ולא בין מאפיינים אחרים של הגדרה.

הדוגמה הבאה ממחישה את היתרונות של שימוש בקבוצות config במכשיר שתומך בארבע הגדרות תצוגה:

  • 1080p@60Hz
  • 1080p ב-90Hz
  • 1080i‏@72Hz
  • 1080i@48Hz

למרות שהמכשיר תומך בשיעורי רענון של 48Hz, ‏ 60Hz, ‏ 72Hz ו-90Hz, המסך פועל במצב אחר. המעבר מ-60Hz ל-72Hz משנה את הגדרת המסך מ-1080p ל-1080i, ויכול להיות שזו לא ההתנהגות הרצויה. כדי לפתור את הבעיה הזו, משתמשים בקבוצות של הגדרות. על ידי קיבוץ של 60Hz ו-90Hz בקבוצת תצורה אחת ו-48Hz ו-72Hz בקבוצת תצורה אחרת. הפלטפורמה יודעת שהיא יכולה לעבור בין 60Hz ל-90Hz ובין 48Hz ל-72Hz, אבל לא בין 60Hz ל-72Hz, כי זה יוביל לשינוי בתצורה ולא רק לשינוי של קצב הרענון.

עדכונים לגבי Composer API

getDisplayVsyncPeriod
נוספה ההגדרה getDisplayVsyncPeriod כדי לשפר את השליטה והחזויה כשמשנים את קצב הרענון. הפונקציה getDisplayVsyncPeriod מחזירה את קצב הרענון הנוכחי (במונחים של תקופת vsync) שבו המסך פועל. האפשרות הזו שימושית במיוחד במעבר בין שיעורי רענון, והפלטפורמה זקוקה לשיעור הרענון הנוכחי כדי להחליט מתי להתחיל את המסגרת הבאה.
setActiveConfigWithConstraints
ה-method‏ setActiveConfigWithConstraints הוא תוסף חדש לשיטה הקיימת setActiveConfig, ומספק מידע נוסף על שינוי התצורה. האילוצים מוצגים כחלק מהפרמטרים של vsyncPeriodChangeConstraints ומכילים את הפרמטרים הבאים.
    desiredTimeNanos
    הזמן ב-CLOCK_MONOTONIC שאחרי שאפשר לשנות את תקופת ה-vsync (כלומר, תקופת ה-vsync לא יכולה להשתנות לפני הזמן הזה). האפשרות הזו שימושית כשהפלטפורמה רוצה לתכנן מראש שינוי של קצב הרענון, אבל כבר יש לה כמה מאגרי נתונים בתור להצגה. הפלטפורמה מגדירה את הזמן הזה בהתאם כדי להביא בחשבון את מאגרי הנתונים האלה ולוודא שהמעבר של קצב הרענון יהיה חלק ככל האפשר.
    seamlessRequired
    אם הערך הוא true, השינוי של תקופת ה-vsync חייב להתבצע בצורה חלקה, ללא פגיעה חזותית משמעותית. הפלטפורמה משתמשת בדגל הזה כשצריך לשנות את קצב הרענון כתוצאה משינוי בתוכן (לדוגמה, המכשיר לא פעיל והאנימציה מתחילה). כך הספק יכול לא לאפשר שינויים מסוימים בהגדרות אם הם עלולים לגרום לבעיה חזותית בולטת. אם לא ניתן לשנות את ההגדרות בצורה חלקה והמדיניות seamlessRequired מוגדרת לערך true, ההטמעה צפויה להחזיר SEAMLESS_NOT_POSSIBLE כקוד ההחזרה ותתבצע קריאה חוזרת (callback) של onSeamlessPossible אם אפשר לבצע את אותו שינוי הגדרה בצורה חלקה.

אחרי שההטמעה מצליחה, היא מחזירה ערך VsyncPeriodChangeTimeline שאומר לפלטפורמה מתי לצפות לשינוי בקצב הרענון. יש להגדיר את הפרמטרים של newVsyncAppliedTimeNanos לשעה ב-CLOCK_MONOTONIC שבה המסך החדש יתחיל להתרענן בתקופת ה-vsync החדשה. האפשרות הזו, יחד עם desiredTimeNanos, מאפשרת לפלטפורמה לתכנן מראש את המעבר לשיעור הרענון החדש ולהתחיל לסמן אפליקציות לשיעור הרענון החדש מראש. כך אפשר לוודא שהמעבר יתבצע באופן חלק.

בהטמעות מסוימות צריך לשלוח מסגרת רענון לפני שאפשר לשלוח את קצב הרענון. לשם כך, ב-HAL יש את הפרמטר refreshRequired כדי לציין שדרושה מסגרת רענון, ואת הפרמטר refreshTimeNanos כדי לציין את ה-vsync הראשון שאחרי שצריך לשלוח מסגרת רענון.

onVsyncPeriodTimingChanged [callback]
קריאה חוזרת חדשה ש-HAL יכול להפעיל כדי להודיע לפלטפורמה שפרמטר כלשהו של ציר הזמן השתנה, והפלטפורמה צריכה לשנות את ציר הזמן שלה. הקריאה החוזרת הזו אמורה להתבצע אם מסיבה כלשהי המערכת לא הצליחה לעדכן את ציר הזמן הישן בגלל זמן עיבוד ארוך ב-HAL או מסגרת רענון מאוחרת.

איך פלטפורמת YouTube מחליטה לשנות את קצב הרענון?

בחירת קצב הרענון מתבצעת בשני שירותי המערכת הבאים:

DisplayManager
ה-DisplayManager מגדיר את המדיניות ברמה גבוהה לגבי קצב הרענון. היא קובעת הגדרת ברירת מחדל של התצוגה, שזהה להגדרת HAL של המלחין. בנוסף, הוא מגדיר טווח של ערכים מינימלי ומקסימלי ש-SurfaceFlinger יכול לבחור בתור קצב הרענון.
SurfaceFlinger
הגדרת תצורה באותה קבוצת תצורה כמו תצורת ברירת המחדל, עם קצב רענון בטווח המינימלי/מקסימלי, כדי לקבוע את קצב הרענון.

כדי לקבוע את המדיניות, מנהל התצוגה מבצע את השלבים הבאים:

  • חיפוש מזהה ברירת המחדל של ההגדרות באמצעות שאילתה על ההגדרות הפעילות מ-SurfaceFlinger
  • הגבלת הטווח של הערכים המינימליים והמקסימליים על ידי איטרציה על תנאי המערכת
    • הגדרת ברירת המחדל של קצב הרענון: ערך ברירת המחדל של קצב הרענון נקבע בשכבת-העל של ההגדרה R.integer.config_defaultRefreshRate. הערך הזה משמש לקביעת קצב הרענון הרגיל של המכשיר לצורך אנימציות ואינטראקציות מגע.
    • הגדרת קצב הרענון המקסימלי: הערך של קצב הרענון המקסימלי נקרא מ-Settings.System.PEAK_REFRESH_RATE. הערך הזה משתנה בזמן הריצה כדי לשקף את הגדרת המכשיר הנוכחית (למשל, מתוך אפשרות בתפריט). ערך ברירת המחדל מוגדר בשכבת-העל של ההגדרות R.integer.config_defaultPeakRefreshRate.
    • הגדרת קצב רענון מינימלי: הערך של קצב הרענון המינימלי נקרא מ-Settings.System.MIN_REFRESH_RATE. אפשר לשנות את הערך הזה בסביבת זמן הריצה כך שישקף את ההגדרה הנוכחית של המכשיר (למשל, מאפשרות בתפריט). ערך ברירת המחדל הוא 0, כך שאין ערך מינימלי שמוגדר כברירת מחדל.
    • Application requested ModeId: אפליקציות יכולות להגדיר את WindowManager.LayoutParams.preferredDisplayModeId כדי לשקף את ההגדרה המועדפת שבה המסך אמור לפעול. ברוב התנאים, DisplayManager מגדיר את מזהה ברירת המחדל של התצורה בהתאם, ומגדיר את קצב הרענון המינימלי והמקסימלי כך שיתאים לקצב הרענון של התצורה.
    • חיסכון בסוללה: קצב הרענון מוגבל ל-60Hz או לערכים נמוכים יותר כשהמכשיר נמצא במצב צריכת אנרגיה נמוכה, כפי שמצוין ב-Settings.Global.LOW_POWER_MODE.

אחרי שהמדיניות DisplayManager מגדירה את קצב הרענון, SurfaceFlinger מגדיר את קצב הרענון על סמך השכבות הפעילות (שכבות ששומרות בתור לעדכונים של פריימים). אם הבעלים של השכבה מגדיר קצב פריימים, SurfaceFlinger מנסה להגדיר את קצב הרענון כמכפיל של הקצב הזה. לדוגמה, אם קצב הפריימים של שתי שכבות פעילות מוגדר ל-24 ול-60, SurfaceFlinger יבחר ב-120Hz אם הוא זמין. אם SurfaceFlinger לא יכול להשתמש בקצב רענון כזה, הוא ינסה לבחור את קצב הרענון עם השגיאה המינימלית בקצב הפריימים. מידע נוסף זמין במסמכי התיעוד למפתחים בכתובת developer.android.com.

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

  • ro.surface_flinger.use_content_detection_for_refresh_rate: אם האפשרות מוגדרת, קצב הרענון נקבע על סמך השכבות הפעילות, גם אם לא הוגדרה תדירות פריימים. ‏SurfaceFlinger שומר על שיטת ניתוח נתונים (heuristic) שבה הוא מוצא את מספר הפריימים לשנייה הממוצע שהשכבה מפרסמת במאגרים על ידי בדיקת חותמת הזמן של הצגה שמצורפת למאגר.
  • ro.surface_flinger.set_touch_timer_ms: אם הערך > 0, תהיה שימוש בשיעור הרענון שמוגדר כברירת מחדל כשמשתמש נוגע במסך למשך זמן הקצוב לתפוגה. ההיוריסטיקה הזו מוכנה עם קצב הרענון שמוגדר כברירת מחדל לאנימציות.
  • ro.surface_flinger.set_idle_timer_ms: אם הערך גדול מ-0, תהיה שימוש בשיעור הרענון המינימלי כשלא יהיו עדכוני מסך במהלך הזמן הקצוב לתפוגה.
  • ro.surface_flinger.set_display_power_timer_ms: אם הערך > 0, תהיה שימוש בשיעור הרענון שמוגדר כברירת מחדל כשמפעילים את המסך (או כשמפסיק את AOD) למשך זמן הקצוב להשהיה.

Frame Rate API

ה-API של קצב הפריימים מאפשר לאפליקציות להודיע לפלטפורמת Android על קצב הפריימים המיועד שלהן, והוא זמין באפליקציות שמטרגטות את Android 11. מידע נוסף על Frame Rate API זמין בתיעוד למפתחים בכתובת developer.android.com.

אפשרויות למפתחים

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