גרפיקה

סמל של Android Graphics HAL

ב-Android framework יש מגוון ממשקי API לעיבוד גרפיקה דו-ממדית ותלת-ממדית, שפועלים באינטראקציה עם יישומי יצרנים של דרייברים לגרפיקה. לכן חשוב להבין איך ממשקי ה-API האלה פועלים ברמה גבוהה יותר. בדף הזה מוסבר על שיטת הפשטת חומרה (HAL) של גרפיקה, שעליה מבוססים מנהלי ההתקנים האלה. לפני שממשיכים בחלק הזה, כדאי להכיר את המונחים הבאים:

‫canvas (מונח כללי), Canvas (רכיב API)
Canvas הוא משטח ציור שמטפל בשילוב של הביטים בפועל עם מפת סיביות או עם אובייקט Surface. למחלקת Canvas יש שיטות לציור סטנדרטי במחשב של מפות סיביות, קווים, עיגולים, מלבנים, טקסט וכו', והיא קשורה למפת סיביות או למשטח. קנבס הוא הדרך הכי פשוטה וקלה לצייר אובייקטים דו-ממדיים על המסך. המחלקה הבסיסית היא Canvas.
פריט גרפי שניתן להזזה
משאב drawable הוא משאב חזותי שעבר קומפילציה ואפשר להשתמש בו כרקע, ככותרת או כחלק אחר של המסך. בדרך כלל, רכיב drawable נטען לרכיב אחר בממשק המשתמש, למשל כתמונת רקע. אובייקט drawable לא יכול לקבל אירועים, אבל הוא מקצה מאפיינים שונים אחרים כמו מצב ותזמון, כדי לאפשר מחלקות משנה כמו אובייקטים של אנימציה או ספריות תמונות. הרבה אובייקטים שניתנים לציור נטענים מקובצי משאבים שניתנים לציור – קובצי XML או קובצי מפת סיביות שמתארים את התמונה. משאבים מסוג Drawable עוברים קומפילציה לתת-מחלקות של android.graphics.drawable. מידע נוסף על נכסי drawable ומשאבים אחרים זמין במאמר סקירה כללית על משאבי אפליקציות.
משאב פריסה
משאב פריסה הוא קובץ XML שמתאר את הפריסה של מסך פעילות. מידע נוסף זמין במאמר בנושא משאב פריסה.
‫nine-patch (9-patch, NinePatch)
תמונה מסוג nine-patch היא משאב של מפת סיביות שאפשר לשנות את הגודל שלה, ואפשר להשתמש בה כרקע או כתמונה אחרת במכשיר. מידע נוסף זמין במאמר בנושא Nine-patch.
OpenGL ES
OpenGL ES הוא ממשק API בפלטפורמות שונות לעיבוד גרפיקה דו-ממדית ותלת-ממדית. ‫Android מספקת ספריות OpenGL ES לעיבוד תלת-ממדי עם האצת חומרה. לרינדור דו-ממדי, קנבס הוא האפשרות הפשוטה יותר. ‫OpenGL ES זמין ב-Android Native Development Kit (NDK). החבילות android.opengl ו-javax.microedition.khronos.opengles חושפות את הפונקציונליות של OpenGL ES.
surface (generic term), Surface (API element)
משטח מייצג בלוק של זיכרון שמוצג במסך. האובייקט Surface מכיל קנבס לציור, ומספק שיטות עזר שונות לציור שכבות ולשינוי הגודל של אובייקט Surface. משתמשים במחלקה SurfaceView במקום במחלקה Surface ישירות.
תצוגה (מונח כללי), SurfaceView (רכיב API)
תצוגת משטח היא אובייקט View שעוטף אובייקט Surface לצורך ציור, וחושף שיטות לציון הגודל והפורמט שלו באופן דינמי. תצוגת Surface מאפשרת לצייר בנפרד משרשור UI עבור פעולות שדורשות הרבה משאבים, כמו משחקים או תצוגות מקדימות של מצלמה, אבל היא משתמשת בזיכרון נוסף. תצוגת Surface תומכת בגרפיקה של canvas וגם בגרפיקה של OpenGL ES. המחלקה הבסיסית לאובייקט SurfaceView היא SurfaceView.
עיצוב
עיצוב הוא קבוצה של מאפיינים, כמו גודל הטקסט וצבע הרקע, שמאוגדים יחד כדי להגדיר הגדרות תצוגה שונות שמוגדרות כברירת מחדל. ב-Android יש כמה ערכות נושא רגילות, שמפורטות בR.style ושמצוינות באמצעות Theme_.
תצוגה (מונח כללי), View (רכיב API)
תצוגה יוצרת אזור מלבני במסך ומטפלת באירועים של קליקים, הקשות ואינטראקציות אחרות. המחלקות View הן מחלקות הבסיס של רוב רכיבי הפריסה של פעילות או מסך דו-שיח, כמו תיבות טקסט וחלונות. אובייקט View מקבל קריאות מאובייקט האב שלו (ראו ViewGroup) כדי לצייר את עצמו, ומודיע לאובייקט האב על הגודל והמיקום המועדפים שלו, שאובייקט האב עשוי שלא להתחשב בהם. מידע נוסף זמין במאמר View.
קבוצת תצוגות (מונח כללי), ViewGroup (רכיב API)
קבוצת תצוגה מקבצת קבוצה של תצוגות צאצא. קבוצת התצוגה אחראית להחלטה איפה למקם את תצוגות הצאצא ומה הגודל שלהן, וגם לקרוא לכל אחת מהן כדי לצייר את עצמה כשצריך. חלק מקבוצות התצוגה בלתי נראות ומשמשות רק לפריסה, ואחרות כוללות ממשק משתמש מובנה, כמו תיבת רשימה עם אפשרות גלילה. קבוצות התצוגה נמצאות בחבילה android.widget, אבל הן מרחיבות את המחלקה ViewGroup.
היררכיית תצוגות
היררכיית תצוגות היא סידור של אובייקטים של תצוגות וקבוצות תצוגות שמגדיר את ממשק המשתמש לכל רכיב באפליקציה. ההיררכיה מורכבת מקבוצות תצוגות שמכילות תצוגות צאצא או קבוצות צאצא של תצוגות. כדי לקבל ייצוג חזותי של היררכיית תצוגה לצורך ניפוי באגים ואופטימיזציה, אפשר להשתמש בHierarchy Viewer שמסופק עם Android SDK.
Vulkan
Vulkan הוא ממשק API בפלטפורמות שונות עם תקורה נמוכה לגרפיקה תלת-ממדית עם ביצועים גבוהים.
ווידג'ט
ווידג'ט הוא אחד מסדרה של מחלקות משנה של תצוגה שהוטמעו במלואן, שמציגות רכיבי טופס ורכיבים אחרים בממשק המשתמש, כמו תיבת טקסט או תפריט קופץ. כי הווידג'ט מיושם באופן מלא, והוא מטפל במדידה, בציור ובתגובה לאירועים במסך. הווידג'טים כלולים בחבילה android.widget.
חלון (מונח כללי), Window (רכיב API)
באפליקציית Android, חלון הוא אובייקט שנגזר מהמחלקה המופשטת Window שמציינת את האלמנטים של חלון כללי, כמו המראה והסגנון, הטקסט בשורת הכותרת, המיקום והתוכן של התפריטים. בתיבות דו-שיח ובפעילויות נעשה שימוש בהטמעה של המחלקה Window כדי לעבד אובייקט Window. לא צריך להטמיע את המחלקה Window או להשתמש בחלונות באפליקציה.

מפתחי אפליקציות מציירים תמונות על המסך בשלוש דרכים: באמצעות Canvas,‏ OpenGL ES או Vulkan.

רכיבי גרפיקה של Android

לא משנה באיזה API לעיבוד משתמשים המפתחים, הכול מעובד על פני השטח. ה-Surface מייצג את הצד של היצרן בתור במאגר נתונים זמני (buffer queue), שלרוב נצרך על ידי SurfaceFlinger. כל חלון שנוצר בפלטפורמת Android מגובה על ידי Surface. כל המשטחים הגלויים שעברו עיבוד מורכבים על המסך על ידי SurfaceFlinger.

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

רכיבי עיבוד תמונה

איור 1. איך הפלטפורמות מעובדות.

הרכיבים העיקריים מתוארים בקטעים הבאים.

יוצרים של זרמי תמונות

מפיק של זרם תמונות יכול להיות כל דבר שמפיק מאגרי גרפיקה לצריכה. דוגמאות: OpenGL ES,‏ Canvas 2D ומפענחי וידאו של mediaserver.

צרכנים של זרם תמונות

הצרכן הנפוץ ביותר של זרמי תמונות הוא SurfaceFlinger, שירות המערכת שצורך את המשטחים שמוצגים כרגע ומצרף אותם לתצוגה באמצעות מידע שסופק על ידי מנהל החלונות. ‫SurfaceFlinger הוא השירות היחיד שיכול לשנות את התוכן של המסך. ‫SurfaceFlinger משתמש ב-OpenGL וב-Hardware Composer ‏ (HWC) כדי ליצור קומפוזיציה של קבוצת משטחים.

אפליקציות אחרות של OpenGL ES יכולות גם להשתמש בסטרימינג של תמונות, כמו אפליקציית המצלמה שמשתמשת בסטרימינג של תצוגה מקדימה של תמונות מהמצלמה. אפליקציות שאינן GL יכולות להיות גם צרכניות, למשל המחלקה ImageReader.

Hardware Composer

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

Hardware Composer HAL מבצע את החצי השני של העבודה, והוא הנקודה המרכזית לכל עיבוד הגרפיקה ב-Android. ה-HWC צריך לתמוך באירועים, שאחד מהם הוא VSync (אירוע נוסף הוא hotplug לתמיכה ב-HDMI plug-and-play).

Gralloc

הקצאת הזיכרון לגרפיקה (Gralloc) נדרשת להקצאת זיכרון שנדרש על ידי יוצרי תמונות. פרטים נוספים מופיעים במאמר בנושא BufferQueue ו-Gralloc.

זרימת נתונים

התרשים הבא מתאר את צינור העיבוד של הגרפיקה ב-Android:

זרימת נתונים גרפיים

איור 2. תרשים של זרימת הנתונים ב-Android.

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

BufferQueue

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

התרשים הבא מדגים את תהליך התקשורת של BufferQueue:

תהליך התקשורת של BufferQueue

איור 3. תהליך התקשורת של BufferQueue.

‫BufferQueue מכיל את הלוגיקה שמקשרת בין יצרנים של זרם תמונות לבין צרכנים של זרם תמונות. דוגמאות למפיקי תמונות: תצוגות מקדימות של המצלמה שנוצרות על ידי HAL של המצלמה או משחקי OpenGL ES. דוגמאות לצרכני תמונות: SurfaceFlinger או אפליקציה אחרת שמציגה שידור OpenGL ES, כמו אפליקציית המצלמה שמציגה את העינית של המצלמה.

‫BufferQueue הוא מבנה נתונים שמשלב מאגר של באפרים עם תור, ומשתמש בתקשורת בין תהליכים (IPC) של Binder כדי להעביר באפרים בין תהליכים. ממשק היצרן, או מה שמעבירים למי שרוצה ליצור מאגרי גרפיקה, הוא IGraphicBufferProducer (חלק מ-SurfaceTexture). לעיתים קרובות משתמשים ב-BufferQueue כדי לבצע רינדור ל-Surface ולצרוך עם GLConsumer, בין היתר.

‫BufferQueue יכול לפעול בשלושה מצבים שונים:

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

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

רכיב HAL של Hardware Composer מבצע את החצי השני של העבודה. ה-HAL הזה משמש כנקודה מרכזית לכל רינדור הגרפיקה ב-Android.