גרפיקה

הסמל של Android Graphics HAL

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

canvas (מונח כללי), Canvas (רכיב API)
Canvas הוא משטח ציור שמטפל ביצירת קומפוזיציה של הביטים בפועל מול קובץ bitmap או אובייקט Surface. ל-Canvas יש שיטות לציור סטנדרטי במחשב של בייטים, קווים, עיגולים, מלבנים, טקסט וכו', והוא מקושר לבייט או למשטח. קנבס הוא הדרך הפשוטה והקלה ביותר לצייר אובייקטים דו-ממדיים במסך. המחלקה הבסיסית היא Canvas.
drawable
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)
קבוצת תצוגות היא קבוצה של תצוגות צאצא. קבוצת התצוגה אחראית לקבוע איפה ממוקמות תצוגות הצאצאים ואת הגודל שלהן, וגם לקרוא לכל אחת מהן לצייר את עצמה במקרים המתאימים. חלק מקבוצות התצוגה הן בלתי נראות ומשמשות לפריסה בלבד, ואילו לחלקן יש ממשק משתמש מהותי, כמו תיבת רשימה לגלילה. קבוצות התצוגה נמצאות בחבילה widget, אבל הן מורשות מהקלאס ViewGroup.
היררכיית תצוגות
היררכיית תצוגות היא סידור של אובייקטים של תצוגות וקבוצות תצוגות שמגדיר את ממשק המשתמש של כל רכיב באפליקציה. ההיררכיה מורכבת מקבוצות תצוגות שמכילות תצוגה צאצאית אחת או יותר או קבוצות תצוגות צאצאיות. כדי לקבל ייצוג חזותי של היררכיית תצוגה לצורך ניפוי באגים וביצוע אופטימיזציה, אפשר להשתמש ב-Hierarchy Viewer שמסופק עם Android SDK.
Vulkan
Vulkan הוא ממשק API לפלטפורמות שונות עם תקורה נמוכה, שמאפשר ליצור גרפיקה תלת-ממדית עם ביצועים גבוהים.
widget
ווידג'ט הוא אחד מקבוצה של תתי-כיתות של תצוגות שמיושמות במלואן, ומציגות אלמנטים של טפסים ורכיבים אחרים של ממשק המשתמש, כמו תיבת טקסט או תפריט קופץ. מאחר שווידג'ט מוטמע במלואו, הוא מטפל במדידה, בציור שלו ובתגובה לאירועים במסך. הווידג'טים נמצאים בחבילה 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 כדי ליצור קומפוזיציה של קבוצת משטחים.

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

Hardware Composer

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

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

Gralloc

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

זרימת נתונים

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

זרימת נתונים של גרפיקה

איור 2. זרימת נתונים גרפיים דרך Android

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

BufferQueue

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

בתרשים הבא מוסבר תהליך התקשורת של BufferQueue.

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

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

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

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

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

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

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

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

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

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