הטמעת Vulkan

Vulkan הוא ממשק API בפלטפורמות שונות עם תקורה נמוכה לגרפיקה תלת-ממדית עם ביצועים גבוהים. בדומה ל-OpenGL ES (GLES),‏ Vulkan מספק כלים ליצירת גרפיקה באיכות גבוהה בזמן אמת באפליקציות. היתרונות של שימוש ב-Vulkan כוללים צמצום התקורה של ה-CPU ותמיכה בשפת הביניים הבינארית SPIR-V.

כדי להטמיע את Vulkan בהצלחה, המכשיר צריך לכלול:

  • רכיב הטעינה של Vulkan, שמסופק על ידי Android.
  • דרייבר של Vulkan, שמסופק על ידי מערכות על שבב (SoC) כמו ספקי חומרה עצמאיים (IHV) של GPU, שמיישם את Vulkan API. כדי לתמוך בפונקציונליות של Vulkan, מכשיר Android צריך חומרה של GPU עם יכולות Vulkan ואת הדרייבר שמשויך אליה. ה-GPU צריך לתמוך גם ב-GLES 3.1 ומעלה. כדי לבקש תמיכה במנהלי התקנים, צריך לפנות לספק ה-SoC.

אם מכשיר כולל דרייבר של Vulkan, המכשיר צריך להצהיר על תכונות המערכת FEATURE_VULKAN_HARDWARE_LEVEL ו-FEATURE_VULKAN_HARDWARE_VERSION, עם גרסאות שמשקפות בצורה מדויקת את היכולות של המכשיר. כך אפשר לוודא שהמכשיר עומד בדרישות של מסמך הגדרת התאימות (CDD).

Vulkan loader

רכיב הטעינה של Vulkan‏ platform/frameworks/native/vulkan הוא הממשק העיקרי בין אפליקציות Vulkan לבין הדרייבר של Vulkan במכשיר. רכיב הטעינה של Vulkan מותקן ב-/system/lib[64]/libvulkan.so. רכיב הטעינה מספק את נקודות הכניסה של ליבת Vulkan API, את נקודות הכניסה של התוספים שנדרשים על ידי Android CDD, ועוד הרבה תוספים אופציונליים. תוספים של Window System Integration ‏ (WSI) מיוצאים על ידי טוען התוספים ומיושמים בעיקר בטוען התוספים ולא במנהל ההתקן. רכיב הטעינה תומך גם בספירה ובטעינה של שכבות שיכולות לחשוף תוספים נוספים וליירט קריאות ל-API ליבה בדרך אל הדרייבר.

‫NDK כולל ספריית stub‏ libvulkan.so לקישור. הספרייה מייצאת את אותם סמלים כמו רכיב הטעינה. האפליקציות קוראות לפונקציות שמיוצאות מהספרייה האמיתית libvulkan.so כדי להיכנס לפונקציות של טרמפולינה בטוען, ששולחות לשכבה או לדרייבר המתאימים על סמך הארגומנט הראשון שלהן. הקריאה vkGet*ProcAddr() מחזירה את המצביעים לפונקציות שאליהן מועברות ההפניות (כלומר, היא קוראת ישירות לקוד הליבה של ה-API). התקשרות דרך מצביעי הפונקציות, ולא דרך הסמלים המיוצאים, יעילה יותר כי היא מדלגת על ה-trampoline והשיגור.

ספירה וטעינה של מנהלי התקנים

כשיוצרים את קובץ אימג' של המערכת, מערכת Android מצפה שהמערכת תדע אילו מעבדי GPU זמינים. טוען המערכת משתמש במנגנון HAL הקיים ב-hardware.h כדי לגלות ולטעון את מנהל ההתקן. הנתיבים המועדפים למנהלי התקנים של Vulkan ב-32 ביט וב-64 ביט הם:

/vendor/lib/hw/vulkan.<ro.hardware.vulkan>.so
/vendor/lib/hw/vulkan.<ro.board.platform>.so
/vendor/lib64/hw/vulkan.<ro.hardware.vulkan>.so
/vendor/lib64/hw/vulkan.<ro.board.platform>.so

ב-Android מגרסה 7.0 ואילך, נגזרת Vulkan‏ hw_module_t עוטפת מבנה hw_module_t יחיד. נתמך רק דרייבר אחד, והמחרוזת הקבועה HWVULKAN_DEVICE_0 מועברת אל open().

הנגזרת של Vulkan hw_device_t מתאימה למנהל התקן יחיד שיכול לתמוך בכמה מכשירים פיזיים. אפשר להרחיב את המבנה של hw_device_t כדי לייצא פונקציות של vkGetGlobalExtensionProperties(),‏ vkCreateInstance() ו-vkGetInstanceProcAddr(). רכיב הטעינה יכול למצוא את כל הפונקציות האחרות VkInstance(), VkPhysicalDevice() ו-vkGetDeviceProcAddr() על ידי קריאה ל-vkGetInstanceProcAddr() של המבנה hw_device_t.

החל מ-Android 15, רכיב הטעינה תומך ב-APEX כדי לטעון את מנהל ההתקן של Vulkan. מגדירים את ro.vulkan.apex לשם של Vulkan APEX כדי לטעון את Vulkan מ-APEX.

גילוי וטעינה של שכבות

רכיב הטעינה של Vulkan תומך בספירה ובטעינה של שכבות שיכולות לחשוף תוספים נוספים וליירט קריאות ל-API מרכזיות בדרך לדרייבר. אפליקציות יכולות לכלול שכבות בחבילת ה-APK שלהן. ‫Android לא כוללת שכבות בקובץ האימג' של המערכת.

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

תרחישים לדוגמה לשימוש בשכבות:

  • שכבות בזמן הפיתוח – אסור להתקין שכבות אימות ושימס למעקב, ליצירת פרופילים ולניפוי באגים בקובץ אימג' של המערכת של מכשירי ייצור. שכבות אימות ו-shims לכלים של מעקב, פרופילים וניפוי באגים צריכים להיות ניתנים לעדכון ללא תמונת מערכת. מפתחים שרוצים להשתמש באחת מהשכבות האלה במהלך הפיתוח יכולים לשנות את חבילת האפליקציה, למשל, על ידי הוספת קובץ לספריית הספריות המקוריות שלהם. מהנדסי IHV ו-OEM שרוצים לאבחן כשלים באפליקציות שאי אפשר לשנות, אמורים לקבל גישה ל-builds של קובץ אימג' של המערכת שאינם בייצור (עם הרשאות root), אלא אם אפשר לבצע באפליקציות האלה ניפוי באגים. מידע נוסף זמין במאמר בנושא שכבות אימות של Vulkan ב-Android.
  • שכבות שירות – השכבות האלה חושפות הרחבות, כמו שכבה שמטמיעה מנהל זיכרון לזיכרון המכשיר. המפתחים בוחרים את השכבות ואת הגרסאות של השכבות האלה שבהן הם רוצים להשתמש באפליקציה שלהם. יכול להיות שאפליקציות שונות ישתמשו באותה שכבה אבל בגרסאות שונות. המפתחים בוחרים אילו מהשכבות האלה ייכללו בחבילת האפליקציה שלהם.
  • שכבות מוזרקות (משתמעות) – כוללות שכבות כמו שכבות-על של קצב פריימים, רשתות חברתיות ומשגרי משחקים שסופקו על ידי המשתמש או על ידי אפליקציה אחרת כלשהי ללא ידיעת האפליקציה או הסכמתה. הקבצים האלה מפרים את מדיניות האבטחה של Android ואין להם תמיכה.

באפליקציות שלא ניתן לבצע בהן ניפוי באגים, רכיב טעינת השכבות מחפש שכבות רק בספריית ה-Native library של האפליקציה ומנסה לטעון כל ספרייה עם שם שתואם לתבנית מסוימת (לדוגמה, libVKLayer_foo.so). השכבות האלה נטענות למרחב השמות של האפליקציה. לכן, צריך לבנות אותם באמצעות NDK.

עבור אפליקציות שניתן לבצע בהן ניפוי באגים, רכיב טעינת השכבות מחפש שכבות ב-/data/local/debug/vulkan ומנסה לטעון כל ספרייה שתואמת לדפוס מסוים. החל מ-Android 10 (רמת API‏ 29), ‏ Vulkan יכול גם לטעון שכבות של זמן פיתוח מ-APK אחר. בשני המקרים, טוען השכבות בוחר אילו שכבות להפעיל על בסיס כל אפליקציה, באמצעות הגדרות המערכת. השכבות האלה מפורטות ב-vkEnumerateInstanceLayerProperties (כלומר, יכול להיות שהאפליקציה יודעת עליהן), גם אם הן נטענות ללא הסכמת האפליקציה.

‫Android מאפשרת להעביר שכבות עם שינויים בסביבת הבנייה בין Android לפלטפורמות אחרות. פרטים על הממשק בין השכבות לבין טוען השכבות זמינים במאמר בנושא ארכיטקטורה של ממשקי טוען השכבות של Vulkan. שכבות האימות שמתחזקת Khronos מתארחות בשכבות האימות של Vulkan.

גרסאות ויכולות של Vulkan API

בטבלה הבאה מפורטות גרסאות של Vulkan API לכמה מהדורות של Android.
גרסת Android גרסת Vulkan
Android 16 ‫Vulkan 1.4
Android 13 ‫Vulkan 1.3
‫Android 9 ‫Vulkan 1.1
‫Android 7 Vulkan 1.0

סקירה כללית של הפונקציונליות של Vulkan 1.4

‫Vulkan 1.4 מכליל מספר הרחבות שהיו אופציונליות בעבר בפונקציונליות הליבה של Vulkan. חלק גדול מהפונקציונליות הזו כלול במטרה להגביר את השליטה והגרנולריות בממשק התכנות של Vulkan. גרסה Vulkan 1.4 מעלה את דרישות החומרה בהשוואה לגרסה Vulkan 1.3, כאשר רוב ההטמעה נמצאת בדרייבר הגרפי הספציפי ל-SoC, ולא במסגרת.

סקירה כללית של הפונקציונליות של Vulkan 1.3

ב-Vulkan 1.3, מספר תוספים שהיו אופציונליים בעבר הופכים לחלק מהפונקציונליות הבסיסית של Vulkan. חלק גדול מהפונקציונליות הזו כלול במטרה להגביר את השליטה והגרנולריות בממשק התכנות של Vulkan. לא צריך יותר אובייקטים של מעבר רינדור או מאגרי מסגרות למופעים של מעבר רינדור במעבר יחיד. אפשר לצמצם את המספר הכולל של אובייקטים של מצב צינור, והסנכרון ב-API שופץ. ל-Vulkan 1.3 יש את אותן דרישות חומרה כמו ל-Vulkan 1.2,‏ 1.1 ו-1.0, ורוב ההטמעה מתבצעת בדרייבר הגרפי הספציפי ל-SoC, ולא במסגרת.

התכונות הכי חשובות של Vulkan 1.3 ל-Android הן:

  • תמיכה במופעים של מעבר רינדור חד-שלבי
  • תמיכה בהפסקת הפעלה מיידית של הצללה
  • גרנולריות טובה יותר ביצירה, בשיתוף ובשליטה של צינורות

‫Vulkan 1.3 כולל גם כמה תכונות קטנות יותר ושיפורים בשימושיות של ה-API. כל השינויים שבוצעו ב-Vulkan API עם תיקון משני 1.3 מפורטים בכתובת Core Revisions (Vulkan 1.3).

סקירה כללית של הפונקציונליות של Vulkan 1.2

ב-Vulkan 1.2 הוספנו מספר תכונות והרחבות שמפשטות את ממשק ה-API. זה כולל מודל זיכרון מאוחד ומידע נוסף שאפשר לשלוף ממנהל התקן של מכשיר. ל-Vulkan 1.2 יש את אותן דרישות חומרה כמו ל-Vulkan 1.0 ו-1.1. כל ההטמעה נמצאת בדרייבר הגרפי הספציפי ל-SoC, ולא במסגרת.

התכונה הכי חשובה ב-Vulkan 1.2 ל-Android היא התמיכה באחסון של 8 ביט.

‫Vulkan 1.2 כולל גם כמה תכונות קטנות יותר ושיפורים בשימושיות של ה-API. כל השינויים שבוצעו ב-Core Vulkan API עם תיקון משני 1.2 מפורטים בכתובת Core Revisions (Vulkan 1.2).

סקירה כללית של הפונקציונליות של Vulkan 1.1

‫Vulkan 1.1 כולל תמיכה ביכולת פעולה הדדית של זיכרון/סנכרון, שמאפשר ל-OEM (יצרן ציוד מקורי) לתמוך ב-Vulkan 1.1 במכשירים. בנוסף, יכולת פעולה הדדית של זיכרון/סנכרון מאפשרת למפתחים לקבוע אם יש תמיכה ב-Vulkan 1.1 במכשיר, ולהשתמש בו ביעילות אם יש תמיכה. ל-Vulkan 1.1 יש את אותן דרישות חומרה כמו ל-Vulkan 1.0, אבל רוב ההטמעה נמצאת בדרייבר הגרפי הספציפי ל-SOC, ולא במסגרת.

התכונות הכי חשובות של Vulkan 1.1 ל-Android הן:

  • תמיכה בייבוא וייצוא של מאגרי זיכרון ואובייקטים של סנכרון מחוץ ל-Vulkan (ליכולת פעולה הדדית עם מצלמה, רכיבי codec ו-GLES)
  • תמיכה בפורמטים של YCbCr

‫Vulkan 1.1 כולל גם כמה תכונות קטנות יותר ושיפורים בשימושיות של ה-API. כל השינויים שבוצעו ב-Vulkan API עם תיקון משני 1.1 מפורטים בתיקונים מרכזיים (Vulkan 1.1).

בחירת תמיכה ב-Vulkan

כל מכשירי Android חייבים לתמוך בערכת התכונות המתקדמת ביותר של Vulkan שזמינה, בתנאי שהם תומכים ב-ABI של 64 ביט ואין להם זיכרון נמוך.

מכשירים שמופעלים עם Android 16 ומעלה צריכים לתמוך ב-Vulkan 1.4.

מכשירים שמופעלים עם Android 13 ומעלה חייבים לתמוך ב-Vulkan 1.3.

מכשירים שמופעלים באמצעות Android 10 חייבים לתמוך ב-Vulkan 1.1.

מכשירים אחרים יכולים לתמוך ב-Vulkan 1.4,‏ 1.3,‏ 1.2 ו-1.1.

תמיכה בגרסת Vulkan

מכשיר Android תומך בגרסת Vulkan אם מתקיימים התנאים הבאים:

  1. מוסיפים דרייבר של Vulkan שתומך בגרסת Vulkan הרלוונטית (אחת מהגרסאות 1.4,‏ 1.3,‏ 1.1 או 1.0) בנוסף לדרישות ה-CDD הנוספות של גרסת Android. אפשרות אחרת היא לעדכן דרייבר קיים של Vulkan עם מספר גרסה נמוך יותר.
  2. בגרסאות Vulkan 1.4,‏ 1.3 או 1.1, מוודאים שתכונת המערכת שמוחזרת על ידי מנהל החבילות מחזירה true לגרסת Vulkan הנכונה.
    • ב-Vulkan 1.4, התכונה היא PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x404000).
    • ב-Vulkan 1.3 התכונה היא PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x403000).
    • ב-Vulkan 1.1, התכונה היא PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000).
    מנהל החבילות יחזיר true עבור Vulkan 1.4,‏ 1.3 ו-1.1 על ידי הוספת כלל, כפי שמוצג בהמשך, לקובץ device.mk מתאים.
    • מוסיפים את הטקסט הבא ל-Vulkan 1.4:
      PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_4.xml:
      $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml
    • מוסיפים את הטקסט הבא ל-Vulkan 1.3:
      PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_3.xml:
      $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml
    • מוסיפים את הטקסט הבא ל-Vulkan 1.1:
      PRODUCT_COPY_FILES += frameworks/native/data/etc/android.hardware.vulkan.version-1_1.xml:
      $(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.vulkan.version.xml

פרופיל Baseline של Android ‏ (ABP)

מומלץ שכל מכשירי Android יתאימו לפרופיל Android Baseline 2022 העדכני, כמו שמתואר במדריך לפרופיל Android Baseline.

כל מכשיר שתומך ב-Android 14 ומעלה וב-Vulkan API חייב לעמוד בכל הפונקציונליות שמוגדרת בפרופיל Android Baseline 2021. הרשימה המלאה של הפונקציות הנדרשות מפורטת בקובץ json של פרופיל Vulkan, אבל קבוצת משנה מרכזית של הפונקציות הנדרשות כוללת:

  • דחיסת טקסטורות באמצעות ASTC ו-ETC.
  • מרחבי צבע משתנים דרך VK_EXT_swapchain_colorspace.
  • הצללה לדוגמה ואינטרפולציה של כמה דגימות באמצעות sampleRateShading.

שילוב של מערכת חלונות (WSI)

ב-libvulkan.so, הנהג מטמיע את התוספים הבאים של שילוב מערכת חלונות (WSI):

  • VK_KHR_surface
  • VK_KHR_android_surface
  • VK_KHR_swapchain
  • VK_KHR_driver_properties, הוטמע עבור Vulkan 1.1 רק ב-Android 10
  • VK_GOOGLE_display_timing, שמוטמעת בכל גרסת Vulkan ב-Android 10

הפלטפורמה מטפלת באובייקטים VkSurfaceKHR ו-VkSwapchainKHR ובכל האינטראקציות עם ANativeWindow, והם לא מוצגים לנהגים. ההטמעה של WSI מסתמכת על התוסף VK_ANDROID_native_buffer, שחייב להיות נתמך על ידי מנהל ההתקן. התוסף הזה משמש רק את ההטמעה של WSI ולא נחשף לאפליקציות.

דגלי שימוש ב-Gralloc

יכול להיות שיישומים של Vulkan יצטרכו להקצות מאגרי swapchain עם דגלי שימוש פרטיים ב-Gralloc שמוגדרים על ידי היישום. כשיוצרים שרשרת החלפה, מערכת Android מבקשת מהדרייבר לתרגם את הפורמט המבוקש ואת דגלי השימוש בתמונה לדגלי שימוש ב-Gralloc באמצעות הקריאה:

typedef enum VkSwapchainImageUsageFlagBitsANDROID {
    VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID = 0x00000001,
    VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkSwapchainImageUsageFlagBitsANDROID;
typedef VkFlags VkSwapchainImageUsageFlagsANDROID;

VkResult VKAPI vkGetSwapchainGrallocUsage2ANDROID(
    VkDevice                          device,
    VkFormat                          format,
    VkImageUsageFlags                 imageUsage,
    VkSwapchainImageUsageFlagsANDROID swapchainUsage,
    uint64_t*                         grallocConsumerUsage,
    uint64_t*                         grallocProducerUsage
);

הפרמטרים format ו-imageUsage נלקחים מהמבנה VkSwapchainCreateInfoKHR. מנהל ההתקן צריך למלא את *grallocConsumerUsage ואת *grallocProducerUsage בדגלי השימוש של Gralloc שנדרשים לפורמט ולשימוש. דגלי השימוש שמוחזרים על ידי מנהל ההתקן משולבים עם דגלי השימוש שהצרכן של swapchain מבקש כשמקצים מאגרי נתונים.

ב-Android מגרסה 7.x, מתבצעת קריאה לגרסה קודמת של VkSwapchainImageUsageFlagsANDROID(), בשם vkGetSwapchainGrallocUsageANDROID(). ‫Android מגרסה 8.0 ואילך מוציא משימוש את vkGetSwapchainGrallocUsageANDROID() אבל עדיין קורא ל-vkGetSwapchainGrallocUsageANDROID() אם vkGetSwapchainGrallocUsage2ANDROID() לא מסופק על ידי מנהל ההתקן:

VkResult VKAPI vkGetSwapchainGrallocUsageANDROID(
    VkDevice            device,
    VkFormat            format,
    VkImageUsageFlags   imageUsage,
    int*                grallocUsage
);

vkGetSwapchainGrallocUsageANDROID() לא תומך בדגלים של שימוש ב-swapchain או בדגלים של שימוש מורחב ב-Gralloc.

תמונות עם גיבוי של Gralloc

VkNativeBufferANDROID הוא מבנה של תוסף vkCreateImage ליצירת תמונה שמגובה על ידי מאגר Gralloc. ‫VkNativeBufferANDROID מסופק ל-vkCreateImage() בשרשרת המבנה VkImageCreateInfo. שיחות אל vkCreateImage() עם VkNativeBufferANDROID מתרחשות במהלך השיחה אל vkCreateSwapchainKHR. ההטמעה של WSI מקצה את מספר מאגרי הנתונים הזמניים המותאמים שנדרשים עבור שרשרת ההחלפה, ואז יוצרת VkImage לכל אחד מהם:

typedef struct {
    VkStructureType             sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID
    const void*                 pNext;

    // Buffer handle and stride returned from gralloc alloc()
    buffer_handle_t             handle;
    int                         stride;

    // Gralloc format and usage requested when the buffer was allocated.
    int                         format;
    int                         usage;
    // Beginning in Android 8.0, the usage field above is deprecated and the
    // usage2 struct below was added. The usage field is still filled in for
    // compatibility with Android 7.0 drivers. Drivers for Android 8.0
    // should prefer the usage2 struct, especially if the
    // android.hardware.graphics.allocator HAL uses the extended usage bits.
    struct {
        uint64_t                consumer;
        uint64_t                producer;
    } usage2;
} VkNativeBufferANDROID;

כשיוצרים תמונה שמגובה על ידי Gralloc, ‏VkImageCreateInfo מכיל את הנתונים הבאים:

  .sType               = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
  .pNext               = the above VkNativeBufferANDROID structure
  .imageType           = VK_IMAGE_TYPE_2D
  .format              = a VkFormat matching the format requested for the gralloc buffer
  .extent              = the 2D dimensions requested for the gralloc buffer
  .mipLevels           = 1
  .arraySize           = 1
  .samples             = 1
  .tiling              = VK_IMAGE_TILING_OPTIMAL
  .usage               = VkSwapchainCreateInfoKHR::imageUsage
  .flags               = 0
  .sharingMode         = VkSwapchainCreateInfoKHR::imageSharingMode
  .queueFamilyCount    = VkSwapchainCreateInfoKHR::queueFamilyIndexCount
  .pQueueFamilyIndices = VkSwapchainCreateInfoKHR::pQueueFamilyIndices

ב-Android מגרסה 8.0 ואילך, הפלטפורמה מספקת מבנה הרחבה של VkSwapchainImageCreateInfoKHR בשרשרת VkImageCreateInfo שמועברת אל vkCreateImage כשנדרשים דגלים לשימוש בתמונות של swapchain עבור ה-swapchain. מבנה התוסף מכיל את דגלי השימוש בתמונות של שרשרת ההחלפה:

typedef struct {
    VkStructureType                        sType; // must be VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID
    const void*                            pNext;

    VkSwapchainImageUsageFlagsANDROID      usage;
} VkSwapchainImageCreateInfoANDROID;

ב-Android מגרסה 10 ואילך, הפלטפורמה תומכת ב-VK_KHR_swapchain v70, כך שאפליקציית Vulkan יכולה ליצור VkImage שנתמך על ידי זיכרון swapchain. האפליקציה קודם קוראת ל-vkCreateImage עם מבנה VkImageSwapchainCreateInfoKHR שמשורשר למבנה VkImageCreateInfo. אחר כך האפליקציה קוראת ל-vkBindImageMemory2(KHR) עם מבנה VkBindImageMemorySwapchainInfoKHR שמשורשר למבנה VkBindImageMemoryInfo. הערך imageIndex שצוין במבנה VkBindImageMemorySwapchainInfoKHR חייב להיות אינדקס תקין של תמונה ב-swapchain. בינתיים, הפלטפורמה מספקת שרשרת VkBindImageMemoryInfo עם מבנה הרחבה VkNativeBufferANDROID ומידע על מאגר הנתונים הזמני של Gralloc, כך שהדרייבר יודע לאיזה מאגר נתונים זמני של Gralloc לקשר את VkImage.

הוספת תמונות

vkAcquireImageANDROID רוכש בעלות על תמונה ב-swapchain ומייבא גדר מקורית עם סימון חיצוני גם לאובייקט VkSemaphore קיים וגם לאובייקט VkFence קיים:

VkResult VKAPI vkAcquireImageANDROID(
    VkDevice            device,
    VkImage             image,
    int                 nativeFenceFd,
    VkSemaphore         semaphore,
    VkFence             fence
);

הפונקציה vkAcquireImageANDROID() מופעלת במהלך vkAcquireNextImageKHR כדי לייבא גדר מקורית לאובייקטים VkSemaphore ו-VkFence שסופקו על ידי האפליקציה (עם זאת, גם אובייקט הסמפור וגם אובייקט הגדר הם אופציונליים בקריאה הזו). הדרייבר יכול גם לנצל את ההזדמנות הזו כדי לזהות ולטפל בשינויים חיצוניים במצב של מאגר Gralloc. הרבה דרייברים לא צריכים לעשות שום דבר כאן. הקריאה הזו מעבירה את VkSemaphore ואת VkFence לאותו מצב המתנה כאילו הם אותתו על ידי vkQueueSubmit, כך שהתורים יכולים להמתין לסמפור והאפליקציה יכולה להמתין לגדר.

שני האובייקטים מקבלים אות כשהאותות של הגדר הגדרות המקוריות מופעלים. אם הגדר המקורית כבר הפעילה אותות, הסמפור נמצא במצב של אות כשהפונקציה הזו מחזירה ערך. הדרייבר מקבל בעלות על מתאר קובץ ה-fence וסוגר את מתאר קובץ ה-fence כשאין בו יותר צורך. הדרייבר חייב לעשות זאת גם אם לא סופק אובייקט סמפור או אובייקט גדר, או גם אם vkAcquireImageANDROID נכשלת ומחזירה שגיאה. אם הערך של fenceFd הוא ‎-1, כאילו הגדר הגדר כבר אותתה.

שחרור תמונות

vkQueueSignalReleaseImageANDROID מכין תמונה ב-swapchain לשימוש חיצוני, יוצר גדר מקומית ומתזמן את האות של הגדר המקומית אחרי שהסמפורים של הקלט אותתו:

VkResult VKAPI vkQueueSignalReleaseImageANDROID(
    VkQueue             queue,
    uint32_t            waitSemaphoreCount,
    const VkSemaphore*  pWaitSemaphores,
    VkImage             image,
    int*                pNativeFenceFd
);

vkQueuePresentKHR() שיחות vkQueueSignalReleaseImageANDROID() בתור שצוין. מנהל ההתקן צריך ליצור גידור מקורי שלא יאותת עד שכל הסמפורים waitSemaphoreCount ב-pWaitSemaphores יאותתו, ועד שתושלם כל עבודה נוספת שנדרשת כדי להכין את image להצגה.

אם הסמפורים של ההמתנה (אם יש כאלה) כבר אותתו, ו-queue כבר במצב סרק, מנהל ההתקן יכול להגדיר את *pNativeFenceFd ל--1 במקום לתיאור קובץ גדר מקורי בפועל, כדי לציין שאין למה לחכות. המתקשר הוא הבעלים של מתאר הקובץ שמוחזר ב-*pNativeFenceFd והוא סוגר אותו.

הרבה מנהלי התקנים יכולים להתעלם מפרמטר התמונה, אבל חלקם צריכים להכין מבני נתונים בצד המעבד שמשויכים למאגר Gralloc לשימוש על ידי צרכני תמונות חיצוניים. הכנת תוכן המאגר לשימוש על ידי צרכנים חיצוניים צריכה להתבצע באופן אסינכרוני כחלק מהמעבר של התמונה אל VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.

אם התמונה נוצרה באמצעות VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID, מנהל ההתקן צריך לאפשר קריאות חוזרות ל-vkQueueSignalReleaseImageANDROID() ללא קריאות ביניים ל-vkAcquireImageANDROID().

תמיכה בתמונות שניתן להציג

במכשירים מסוימים אפשר לשתף בעלות על תמונה יחידה בין צינור העיבוד של התצוגה לבין ההטמעה של Vulkan, כדי לצמצם את זמן האחזור. ב-Android מגרסה 9 ואילך, רכיב הטעינה מפרסם את התוסף VK_KHR_shared_presentable_image באופן מותנה, על סמך התגובה של הדרייבר לקריאה אל vkGetPhysicalDeviceProperties2.

אם מנהל ההתקן לא תומך ב-Vulkan 1.1 או בתוסף VK_KHR_physical_device_properties2, טוען המערכת לא יציג תמיכה בתמונות משותפות שניתנות להצגה. אחרת, רכיב הטעינה שולח שאילתה לגבי היכולות של הדרייבר על ידי קריאה ל-vkGetPhysicalDeviceProperties2() וכולל את המבנה הבא בשרשרת VkPhysicalDeviceProperties2::pNext:

typedef struct {
    VkStructureType sType; // must be VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID
    const void*     pNext;
    VkBool32        sharedImage;
} VkPhysicalDevicePresentationPropertiesANDROID;

אם מנהל ההתקן יכול לשתף בעלות על תמונה עם מערכת התצוגה, הוא מגדיר את sharedImage כ-VK_TRUE.

אימות

יצרני ציוד מקורי יכולים לבדוק את ההטמעה של Vulkan באמצעות CTS, שכולל את הרכיבים הבאים:

  • בדיקות התאמה של Khronos Vulkan במודול CtsDeqpTestCases, שכוללות בדיקות פונקציונליות של API ל-Vulkan 1.0,‏ 1.1,‏ 1.2,‏ 1.3 ו-1.4.
  • מודול CtsGraphicsTestCases, שבודק שהמכשיר מוגדר בצורה נכונה ליכולות Vulkan שהוא תומך בהן.

סימון תכונה של Vulkan

כדי לחשוף את ה-feature flag, android.software.vulkan.deqp.level, נדרש מכשיר שתומך ב-Android 11 ואילך ובתקן Vulkan API. הערך של feature flag זה הוא תאריך, שמקודד כמספר שלם. הוא מציין את התאריך שמשויך לבדיקות dEQP של Vulkan שהמכשיר טוען שהוא עבר.

תאריך בפורמט YYYY-MM-DD מקודד כמספר שלם בן 32 ביט באופן הבא:

  • ביטים 0-15 מאחסנים את השנה
  • ביטים 16-23 מכילים את החודש
  • ביטים 24-31 מאחסנים את היום

הערך המינימלי המותר של דגל התכונה הוא 0x07E30301, שמתאים לתאריך 2019-03-01, התאריך שמשויך לבדיקות Vulkan dEQP ל-Android 10. אם ערך ה-feature flag הוא לפחות הערך הזה, המכשיר טוען שהוא עבר את כל בדיקות ה-dEQP של Vulkan ב-Android 10.

הערך 0x07E40301 תואם לתאריך 2020-03-01, שהוא התאריך שמשויך לבדיקות Vulkan dEQP ל-Android 11. אם ערך דגל התכונה הוא לפחות הערך הזה, המכשיר טוען שהוא עבר את כל בדיקות ה-dEQP של Vulkan ב-Android 11.

הערך 0x07E60301 תואם לתאריך 2022-03-01, שהוא התאריך שמשויך לבדיקות Vulkan dEQP עבור Android 13. אם ערך ה-feature flag הוא לפחות הערך הזה, המכשיר טוען שהוא עבר את כל הבדיקות של Android 13 Vulkan dEQP.

מכשיר שחושף feature flag ספציפי (כלומר 0x07E30301, ‏ 0x07E40301, ‏ 0x07E60301) טוען שהוא עובר את כל בדיקות ה-dEQP של Android Vulkan של feature flag זה (Android 10,‏ Android 11, ‏ Android 13 בהתאמה). יכול להיות שהמכשיר הזה יעבור את בדיקות dEQP של Vulkan מגרסת Android מאוחרת יותר.

‫Vulkan dEQP הוא חלק מ-Android CTS. מגרסה Android 11, רכיב ההרצה של בדיקות dEQP ב-CTS מודע לדגל התכונה android.software.vulkan.deqp.level, ומדלג על כל בדיקות Vulkan dEQP שהמכשיר לא טוען שהוא תומך בהן – בהתאם לדגל התכונה הזה. הבדיקות האלה מדווחות כבדיקות שעברו בקלות.