גרפיקה

הסמל של Android Graphics HAL

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

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

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

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

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

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

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

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

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

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

מפיץ של מקור נתונים של תמונות יכול להיות כל דבר שיוצר מאגרי גרפיקה לשימוש. דוגמאות לכך הן OpenGL ES,‏ Canvas 2D ו-mediaserver video decoders.

צרכני מקור תמונות

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

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

Hardware Composer

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

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 הוא מבנה נתונים שמשלב מאגר מאגרים עם תור, ומשתמש ב-Binder IPC כדי להעביר מאגרים בין תהליכים. ממשק הבעלים, או מה שמעבירים למישהו שרוצה ליצור מאגרי גרפיקה, הוא IGraphicBufferProducer (חלק מ-SurfaceTexture). בין היתר, BufferQueue משמש לעיתים קרובות לעיבוד (רנדרינג) ב-Surface ולשימוש ב-GL Consumer.

אפשר להפעיל את BufferQueue בשלושה מצבים שונים:

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

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

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