קצב הפריימים

ספריית Android Frame Pacing, שנקראת גם Swappy, היא חלק מ-Android Game SDK. הוא עוזר למשחקים ב-OpenGL וב-Vulkan להשיג רינדור חלק וקצב פריימים תקין ב-Android.

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

  • אגירת פריימים קודמים באופן פנימי
  • זיהוי שליחת פריימים באיחור
  • המשך הצגת הפריים הנוכחי כשמזוהה פריים מאוחר

זמני הצגה לא עקביים של פריימים נגרמים מכך שמחזור העיבוד (render) של המשחק פועל בקצב שונה מהקצב שבו חומרת המסך המובנית תומכת. בעיות נוצרות כשמחזור ה-render של המשחק פועל לאט מדי עבור חומרת המסך הבסיסית, וכתוצאה מכך זמני התצוגה לא עקביים. לדוגמה, כשמשחק שפועל ב-30 fps מנסה לבצע רינדור במכשיר שתומך באופן מקורי ב-60 fps, לולאת הרינדור של המשחק גורמת לכך שפריים חוזר נשאר במסך למשך 16 אלפיות שנייה נוספות. סוג כזה של ניתוק יוצר חוסר עקביות משמעותי בזמני הפריימים, כמו 33 אלפיות שנייה, 16 אלפיות שנייה, 49 אלפיות שנייה וכו'. סצנות מורכבות מדי רק מחמירות את הבעיה הזו, כי הן גורמות לפריימים חסרים.

ספריית Frame Pacing מבצעת את המשימות הבאות:

  • פיצוי על גמגום שנגרם בגלל פריימים קצרים במשחק.
  • שימוש במחסומי סנכרון לפריימים ארוכים שגורמים לגמגום ולזמן אחזור ארוך.
    • הוספת זמן המתנה לאפליקציה. הזמן הזה מאפשר לצינור עיבוד הנתונים של המסך להתעדכן, במקום לאפשר ללחץ חוזר להצטבר.
    • נעשה שימוש במחסומי סנכרון (EGL_KHR_fence_sync ו-VkFence).
  • אם המכשיר תומך במספר שיעורי רענון, המערכת בוחרת קצב רענון שמספק גמישות ותצוגה חלקה.
  • הכלי מספק נתונים סטטיסטיים לניפוי באגים וליצירת פרופילים באמצעות נתוני פריימים.

במאמר מצבי הפעלה נתמכים מוסבר איך מגדירים את הספרייה לפעול במצבים שונים בהתאם לצרכים שלכם.

כדי להטמיע באמצעות עיבוד גרפי של OpenGL או עיבוד גרפי של Vulkan, אפשר לעיין במאמרים הבאים:

מידע נוסף זמין במאמר איך מגדירים את קצב הפריימים בצורה נכונה.

התערבות של הגבלת קצב הפריימים לשנייה

התערבות של הגבלת קצב הפריימים לשנייה (FPS) מאפשרת למשחקים לפעול בקצב FPS מתאים באמצעות שינויים בפלטפורמה בלבד, בלי צורך בפעולה כלשהי מצד המפתחים.

כדי להטמיע את ההתערבות של צמצום קצב הפריימים, אנחנו משתמשים ברכיבים הבאים:

GameManagerService

הרכיב GameManagerService שומר את כל המידע על מצב המשחק והתערבות במשחק לכל משתמש ולכל משחק. נתוני ה-FPS נשמרים ב-GameManagerService עם פרטי התערבות אחרים, כמו גורם הפחתת הרזולוציה, במיפוי <PACKAGE_NAME, Interventions> לכל פרופיל משתמש. הגישה למידע על FPS מתבצעת כשמצב המשחק משתנה או כשהתגובה מתעדכנת. הערך של UID הוא ייחודי לכל PACKAGE_NAME ולמשתמש, וניתן לתרגם אותו לזוג <UID, Frame Rate> כדי לשלוח אותו ל-SurfaceFlinger.

SurfaceFlinger

הרכיב SurfaceFlinger כבר תומך בהגבלת קצב הפריימים (FPS) של אפליקציה, כל עוד קצב הפריימים הוא מכפיל של קצב הרענון של המסך. במקרה של vsync, ‏SurfaceFlinger בודק את התוקף של ה-vsync לאפליקציה המוגבלת על ידי בדיקה אם חותמת הזמן של ה-vsync תואמת לשלב של קצב הפריימים של האפליקציה. אם קצב הפריימים לא תואם ל-vsync, המערכת של SurfaceFlinger שומרת את הפריים עד שקצב הפריימים ו-vsync יהיו תואמים.

בתרשים הבא מתוארת האינטראקציה בין GameManagerService לבין SurfaceFlinger:

אינטראקציה בין GameManagerService לבין SurfaceFlinger

איור 1. אינטראקציה בין GameServiceManager לבין SurfaceFlinger

SurfaceFinger שומר על מיפוי של זוג <UID, Frame Rate> כדי להגדיר עדיפות חדשה לוויסות קצב הפריימים. הערך של UID הוא ייחודי לכל משתמש ומשחק, כך שלכל משתמש במכשיר אחד יכולות להיות הגדרות שונות של קצב הפריימים באותו משחק. כדי להגביל את קצב הפריימים של משחק, GameServiceManager קורא ל-SurfaceFlinger כדי לשנות את קצב הפריימים של UID. בעזרת המנגנון הזה, SurfaceFlinger מעדכן את המיפוי בכל פעם שמשתנה מצב המשחק או שמתעדכנת ההתערבות. SurfaceFlinger מטפל בשינוי של FPS על ידי נעילה של מאגרים בהתאם.

למידע נוסף על הגבלת FPS, ראו מבוא להגבלת FPS.