גרפיקה

סמל של Android Graphics HAL

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

קנבס (מונח כללי), Canvas (רכיב API)
קנבס הוא משטח ציור שמטפל בשילוב של הביטים בפועל עם מפת סיביות או עם אובייקט Surface. למחלקת Canvas יש שיטות לציור סטנדרטי של מפות סיביות, קווים, עיגולים, מלבנים, טקסט וכו' במחשב, והיא קשורה למפת סיביות או למשטח. קנבס הוא הדרך הכי פשוטה וקלה לצייר אובייקטים דו-ממדיים על המסך. המחלקה הבסיסית היא Canvas.
פריט גרפי שניתן להזזה
משאב drawable הוא משאב חזותי שעבר קומפילציה ואפשר להשתמש בו כרקע, ככותרת או כחלק אחר של המסך. בדרך כלל, רכיב drawable נטען לרכיב אחר בממשק המשתמש, למשל כתמונת רקע. אי אפשר להשתמש ב-drawable כדי לקבל אירועים, אבל אפשר להקצות לו מאפיינים שונים כמו מצב ותזמון, כדי לאפשר שימוש במחלקות משנה כמו אובייקטים של אנימציה או ספריות תמונות. הרבה אובייקטים שניתנים לציור נטענים מקובצי משאבים שניתנים לציור – קובצי XML או קובצי מפת סיביות שמתארים את התמונה. משאבים מסוג Drawable עוברים קומפילציה לתת-מחלקות של android.graphics.drawable. מידע נוסף על נכסי drawable ומשאבים אחרים זמין במאמר סקירה כללית על משאבי אפליקציות.
משאב פריסה
משאב פריסה הוא קובץ XML שמתאר את הפריסה של מסך פעילות. מידע נוסף זמין במאמר בנושא משאב פריסה.
תיקון תשעה חלקים (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 (רכיב API)
משטח מייצג בלוק של זיכרון שנוסף למסך. משטח מכיל קנבס לציור, ומספק שיטות עזר שונות לציור שכבות ולשינוי הגודל של אובייקט Surface. משתמשים במחלקה SurfaceView במקום במחלקה Surface ישירות.
תצוגת פני השטח (מונח כללי), SurfaceView (רכיב API)
תצוגת משטח היא אובייקט View שעוטף אובייקט Surface לצורך ציור, וחושף שיטות לציון הגודל והפורמט שלו באופן דינמי. תצוגת Surface מספקת דרך לצייר באופן עצמאי משרשור ממשק המשתמש עבור פעולות שדורשות הרבה משאבים, כמו משחקים או תצוגות מקדימות של מצלמה, אבל היא משתמשת בזיכרון נוסף כתוצאה מכך. תצוגת Surface תומכת בגרפיקה של canvas וגם בגרפיקה של OpenGL ES. המחלקה הבסיסית לאובייקט SurfaceView היא SurfaceView.
עיצוב
עיצוב הוא קבוצה של מאפיינים, כמו גודל הטקסט וצבע הרקע, שמקובצים יחד כדי להגדיר הגדרות תצוגה שונות שמוגדרות כברירת מחדל. ב-Android יש כמה ערכות נושא רגילות, שמפורטות ב-R.style ושמופיע לפניהן Theme_.
תצוגה (מונח כללי), View (רכיב API)
רכיב View מצייר אזור מלבני במסך ומטפל באירועים של קליקים, הקשות ואינטראקציות אחרות. המחלקות 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 מייצג את הצד של היצרן בתור המאגר, שלרוב נצרך על ידי 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

התכונה BufferQueues מספקת את הדבק בין רכיבי הגרפיקה של 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.