מסגרת הסנכרון מתארת במפורש תלות בין פעולות אסינכרוניות שונות במערכת הגרפיקה אנדרואיד. המסגרת מספקת API המאפשר לרכיבים לציין מתי משתחררים מאגרים. המסגרת מאפשרת גם להעביר פרימיטיבים של סנכרון בין מנהלי התקנים מהקרנל למרחב המשתמש ובין תהליכי מרחב המשתמש עצמם.
לדוגמה, יישום עשוי לעמוד בתור עבודה לביצוע ב-GPU. ה-GPU מתחיל לצייר את התמונה הזו. למרות שהתמונה עדיין לא נמשכה לזיכרון, מצביע ה-buffer מועבר לקומפוזיטור החלון יחד עם גדר שמציינת מתי תסתיים עבודת ה-GPU. מרכיב החלון מתחיל בעיבוד מבעוד מועד ומעביר את העבודה לבקר התצוגה. באופן דומה, עבודת המעבד נעשית מבעוד מועד. ברגע שה-GPU מסתיים, בקר התצוגה מציג מיד את התמונה.
מסגרת הסנכרון גם מאפשרת למיישמים למנף משאבי סנכרון ברכיבי החומרה שלהם. לבסוף, המסגרת מספקת נראות לתוך צינור הגרפיקה כדי לסייע באיתור באגים.
סנכרון מפורש
סנכרון מפורש מאפשר ליצרנים ולצרכנים של מאגרים גרפיים לאותת כאשר הם מסיימים להשתמש במאגר. סנכרון מפורש מיושם ב-kernel-space.
היתרונות של סנכרון מפורש כוללים:
- פחות שונות בהתנהגות בין מכשירים
- תמיכה טובה יותר באגים
- מדדי בדיקה משופרים
למסגרת הסינכרון יש שלושה סוגי אובייקטים:
-
sync_timeline
-
sync_pt
-
sync_fence
sync_timeline
sync_timeline
הוא ציר זמן מונוטוני שגדל באופן מונוטוני שעל הספקים ליישם עבור כל מופע של מנהל התקן, כגון הקשר GL, בקר תצוגה או 2D bliter. sync_timeline
סופר משימות שנשלחו לליבה עבור פיסת חומרה מסוימת. sync_timeline
מספק ערבויות לגבי סדר הפעולות ומאפשר יישומים ספציפיים לחומרה.
פעל לפי ההנחיות הבאות בעת יישום sync_timeline
:
- ספק שמות שימושיים לכל הדרייברים, צירי הזמן והגדרות כדי לפשט את ניפוי הבאגים.
- הטמע את האופרטורים
timeline_value_str
ו-pt_value_str
זמן כדי להפוך את פלט ניפוי הבאגים לקריאה יותר. - הטמע את ה-fill
driver_data
כדי לתת לספריות מרחב משתמש, כגון ספריית GL, גישה לנתוני ציר זמן פרטיים, אם תרצה בכך.data_driver
מאפשר לספקים להעביר מידע על ה-sync_fence
לשינוי ו-sync_pts
כדי לבנות שורות פקודה המבוססות עליהם. - אל תאפשר למרחב המשתמש ליצור או לסמן במפורש גדר. יצירה מפורשת של אותות/גדרות גורמת להתקפת מניעת שירות שעוצרת את פונקציונליות הצינור.
- אל תיגש באופן מפורש לרכיבי
sync_timeline
,sync_pt
אוsync_fence
. ה-API מספק את כל הפונקציות הנדרשות.
sync_pt
sync_pt
הוא ערך בודד או נקודה ב- sync_timeline
. לנקודה יש שלושה מצבים: פעילה, מסומנת ושגיאה. נקודות מתחילות במצב פעיל ועוברות למצבי האותות או השגיאה. לדוגמה, כאשר צרכן תמונה כבר לא צריך מאגר, sync_pt
כך שמפיק תמונה יודע שזה בסדר לכתוב למאגר שוב.
sync_fence
sync_fence
הוא אוסף של ערכי sync_pt
שלעתים קרובות יש להם הורים שונים sync_timeline
(כגון עבור בקר התצוגה ו-GPU). sync_fence
, sync_pt
ו- sync_timeline
הם הפרימיטיבים העיקריים שבהם משתמשים מנהלי התקנים ומרחב המשתמש כדי לתקשר את התלות שלהם. כאשר גדר מסומנת, מובטחות שלמות כל הפקודות שהוצאו לפני הגדר מכיוון שמנהל ההתקן של הליבה או בלוק החומרה מבצעים פקודות לפי הסדר.
מסגרת הסינכרון מאפשרת לצרכנים או יצרנים מרובים לאותת כאשר הם מסיימים להשתמש במאגר, ולתקשר את מידע התלות עם פרמטר פונקציה אחד. גדרות מגובות על ידי מתאר קבצים ומועברות ממרחב הקרנל למרחב המשתמש. לדוגמה, גדר יכולה להכיל שני ערכי sync_pt
המסמנים כאשר שני צרכני תמונה נפרדים מסיימים לקרוא מאגר. כאשר מאותתת הגדר, יצרני התמונות יודעים ששני הצרכנים סיימו לצרוך.
גדרות, כמו ערכי sync_pt
, מתחילות פעילות ומשנות מצב בהתבסס על מצב הנקודות שלהן. אם כל ערכי sync_pt
איתות, ה- sync_fence
מקבל איתות. אם sync_pt
אחד נופל למצב שגיאה, לכל sync_fence
יש מצב שגיאה.
החברות ב- sync_fence
אינה ניתנת לשינוי לאחר יצירת הגדר. כדי לקבל יותר מנקודה אחת בגדר, מתבצע מיזוג שבו נקודות משתי גדרות נפרדות מתווספות לגדר שלישית. אם אחת מאותן נקודות הייתה מסומנת בגדר המקור והשנייה לא הייתה מסומנת, גם הגדר השלישית לא תהיה במצב מסומן.
כדי ליישם סנכרון מפורש, ספק את הדברים הבאים:
- תת-מערכת ליבה-חלל המיישמת את מסגרת הסינכרון עבור מנהל התקן חומרה מסוים. מנהלי התקנים שצריכים להיות מודעים לגדר הם בדרך כלל כל דבר שניגש ל- Hardware Composer או מתקשר איתו. קבצי מפתח כוללים:
- יישום ליבה:
-
kernel/common/include/linux/sync.h
-
kernel/common/drivers/base/sync.c
-
- תיעוד ב-
kernel/common/Documentation/sync.txt
- ספריה לתקשורת עם מרחב הליבה
platform/system/core/libsync
- יישום ליבה:
- על הספק לספק את גדרות הסנכרון המתאימות כפרמטרים לפונקציות
validateDisplay()
ו-presentDisplay()
ב-HAL. - שתי הרחבות GL הקשורות לגדר (
EGL_ANDROID_native_fence_sync
ו-EGL_ANDROID_wait_sync
) ותמיכה בגדר במנהל ההתקן הגרפי.
מקרה מבחן: הטמעת דרייבר לתצוגה
כדי להשתמש ב-API התומך בפונקציית הסנכרון, פתח מנהל התקן תצוגה בעל פונקציית מאגר תצוגה. לפני שמסגרת הסינכרון הייתה קיימת, פונקציה זו תקבל אובייקטי dma-buf
, תכניס את המאגרים הללו לתצוגה ותחסום בזמן שהמאגר היה גלוי. לדוגמה:
/* * assumes buffer is ready to be displayed. returns when buffer is no longer on * screen. */ void display_buffer(struct dma_buf *buffer);
עם מסגרת הסינכרון, הפונקציה display_buffer
מורכבת יותר. בזמן הצבת חוצץ לתצוגה, המאגר משויך לגדר המציינת מתי המאגר יהיה מוכן. ניתן לעמוד בתור וליזום את העבודה לאחר פינוי הגדר.
עמידה בתור וייזום עבודה לאחר פינוי הגדר לא חוסמים דבר. אתה מיד מחזיר את הגדר שלך, מה שמבטיח מתי החיץ ירד מהתצוגה. בזמן שאתה מעמיד בתור מאגרים, הליבה מפרטת תלות עם מסגרת הסנכרון:
/* * displays buffer when fence is signaled. returns immediately with a fence * that signals when buffer is no longer displayed. */ struct sync_fence* display_buffer(struct dma_buf *buffer, struct sync_fence *fence);
שילוב סנכרון
סעיף זה מסביר כיצד לשלב את מסגרת סינכרון הקרנל-חלל עם חלקי מרחב המשתמשים של מסגרת Android ומנהלי ההתקן שחייבים לתקשר זה עם זה. אובייקטי מרחב ליבה מיוצגים כמתארי קבצים במרחב המשתמש.
מוסכמות אינטגרציה
פעל לפי המוסכמות של ממשק ה-Android HAL:
- אם ה-API מספק מתאר קובץ המתייחס ל-
sync_pt
, מנהל ההתקן של הספק או ה-HAL המשתמש ב-API חייבים לסגור את מתאר הקובץ. - אם מנהל ההתקן של הספק או ה-HAL מעביר מתאר קובץ המכיל
sync_pt
לפונקציית API, אסור למנהל ההתקן של הספק או ל-HAL לסגור את מתאר הקובץ. - כדי להמשיך להשתמש במתאר קובץ הגדר, על מנהל ההתקן או ה-HAL לשכפל את המתאר.
שם חפץ גדר שונה בכל פעם שהוא עובר דרך BufferQueue. תמיכת גדר ליבה מאפשרת לגדרות לכלול מחרוזות לשמות, כך שמסגרת הסינכרון משתמשת בשם החלון ובאינדקס המאגר שנמצא בתור כדי לתת שם לגדר, כגון SurfaceView:0
. זה מועיל בניפוי באגים כדי לזהות את המקור למבוי סתום שכן השמות מופיעים בפלט של /d/sync
ודוחות באג.
אינטגרציה של ANativeWindow
ANativeWindow מודע לגדר. dequeueBuffer
, queueBuffer
ו- cancelBuffer
יש פרמטרים של גדר.
אינטגרציה של OpenGL ES
שילוב סנכרון OpenGL ES מסתמך על שתי הרחבות EGL:
-
EGL_ANDROID_native_fence_sync
מספק דרך לעטוף או ליצור מתארי קבצים מקוריים של גדר אנדרואיד באובייקטים שלEGLSyncKHR
. -
EGL_ANDROID_wait_sync
מאפשר עמידה בצד ה-GPU ולא בצד המעבד, מה שגורם ל-GPU להמתין ל-EGLSyncKHR
. תוסףEGL_ANDROID_wait_sync
זהה לסיומתEGL_KHR_wait_sync
.
כדי להשתמש בהרחבות אלו באופן עצמאי, הטמיע את התוסף EGL_ANDROID_native_fence_sync
יחד עם תמיכת הליבה המשויכת. לאחר מכן, הפעל את תוסף EGL_ANDROID_wait_sync
במנהל ההתקן שלך. ההרחבה EGL_ANDROID_native_fence_sync
מורכבת מסוג אובייקט EGLSyncKHR
של גדר מקורית. כתוצאה מכך, הרחבות החלות על סוגי אובייקטים קיימים של EGLSyncKHR
לא בהכרח חלות על אובייקטי EGL_ANDROID_native_fence
, תוך הימנעות מאינטראקציות לא רצויות.
ההרחבה EGL_ANDROID_native_fence_sync
משתמשת בתכונה מקורית של מתאר קובץ גדר שניתן להגדיר רק בזמן היצירה ולא ניתן לבצע שאילתה ישירות הלאה מאובייקט סנכרון קיים. ניתן להגדיר תכונה זו לאחד משני מצבים:
- מתאר קובץ גדר חוקי עוטף מתאר קובץ גדר אנדרואיד מקורי באובייקט
EGLSyncKHR
. - -1 יוצר מתאר קובץ גדר אנדרואיד מקורי מאובייקט
EGLSyncKHR
.
השתמש בקריאת הפונקציה DupNativeFenceFD()
כדי לחלץ את האובייקט EGLSyncKHR
מתאר קובץ הגדר המקורי של Android. יש לזה אותה תוצאה כמו שאילתה על תכונת הסט, אך עומדת במוסכמה לפיה הנמען סוגר את הגדר (ומכאן הפעולה הכפולה). לבסוף, השמדת אובייקט EGLSyncKHR
סוגרת את תכונת הגדר הפנימית.
אינטגרציה של חומרה מלחין
ה- Hardware Composer מטפל בשלושה סוגים של גדרות סנכרון:
- גדרות רכישה מועברות יחד עם מאגרי קלט
setLayerBuffer
ו-setClientTarget
. אלה מייצגים כתיבה ממתינה למאגר וחייבים לאותת לפני שה-SurfaceFlinger או ה-HWC מנסים לקרוא מהמאגר המשויך לביצוע קומפוזיציה. - גדרות שחרור מאוחזרות לאחר הקריאה ל-
presentDisplay
באמצעות הקריאהgetReleaseFences
. אלה מייצגים קריאה ממתינה מהמאגר הקודם באותה שכבה. גדר שחרור מאותתת כאשר ה-HWC אינו משתמש יותר במאגר הקודם מכיוון שהמאגר הנוכחי החליף את המאגר הקודם בתצוגה. גדרות שחרור מועברות חזרה לאפליקציה יחד עם המאגרים הקודמים שיוחלפו במהלך ההרכב הנוכחי. על האפליקציה להמתין עד שגדר שחרור מאותתת לפני כתיבת תוכן חדש למאגר שהוחזר אליה. - גדרות נוכחות מוחזרות, אחת לכל מסגרת, כחלק מהקריאה ל-
presentDisplay
. גדרות נוכחיות מייצגות מתי ההרכב של המסגרת הזו הושלם, או לחילופין, כאשר אין עוד צורך בתוצאת ההרכב של המסגרת הקודמת. עבור תצוגות פיזיות,presentDisplay
מחזירה גדרות נוכחות כאשר המסגרת הנוכחית מופיעה על המסך. לאחר החזרת גדרות קיימות, בטוח לכתוב שוב למאגר היעד של SurfaceFlinger, אם ישים. עבור תצוגות וירטואליות, גדרות נוכחות מוחזרות כאשר זה בטוח לקרוא ממאגר הפלט.