הטמעת 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() מחזירה את מצביעי הפונקציה שאליהם מנתבים את ה-trampolines (כלומר, היא קוראת ישירות לקוד הליבה של ה-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 לכלים של מעקב, פרופילים וניפוי באגים צריכים להיות ניתנים לעדכון ללא תמונת מערכת. מפתחים שרוצים להשתמש באחת מהשכבות האלה במהלך הפיתוח יכולים לשנות את חבילת APK, למשל, על ידי הוספת קובץ לספריית הספריות המקוריות שלהם. מהנדסי IHV ו-OEM שרוצים לאבחן כשלים באפליקציות שאי אפשר לשנות, נדרשים לקבל גישה ל-builds של תמונת המערכת שאינם בייצור (עם הרשאות root), אלא אם אפשר לבצע באפליקציות האלה ניפוי באגים. מידע נוסף זמין במאמר בנושא שכבות אימות של Vulkan ב-Android.
  • שכבות שירות – השכבות האלה חושפות הרחבות, כמו שכבה שמטמיעה מנהל זיכרון לזיכרון המכשיר. המפתחים בוחרים את השכבות ואת הגרסאות של השכבות האלה שבהן הם רוצים להשתמש באפליקציה שלהם. אפליקציות שונות שמשתמשות באותה שכבה עדיין יכולות להשתמש בגרסאות שונות. המפתחים בוחרים אילו מהשכבות האלה ייכללו בחבילת APK שלהם.
  • שכבות מוזרקות (משתמעות) – כוללות שכבות כמו שכבות-על של קצב פריימים, רשתות חברתיות ומשגרי משחקים שסופקו על ידי המשתמש או על ידי אפליקציה אחרת כלשהי ללא ידיעת האפליקציה או הסכמתה. הקבצים האלה מפרים את מדיניות האבטחה של Android ואין להם תמיכה.

באפליקציות שלא ניתן לנפות בהן באגים, רכיב טעינת השכבות מחפש שכבות רק בספריית Native של האפליקציה ומנסה לטעון כל ספרייה עם שם שתואם לתבנית מסוימת (לדוגמה, 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 הן:

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

‫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 כולל תמיכה בהפעלה הדדית של זיכרון/סנכרון, שמאפשרת ל-OEMs לתמוך ב-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. כל השינויים שבוצעו ב-Core Vulkan API עם תיקון משני 1.1 מפורטים בCore Revisions (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 שמוגדרים על ידי היישום. כשיוצרים שרשרת החלפה (swapchain), מערכת 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 מקבל בעלות על תמונה של שרשרת החלפה ומייבא גדר מקורית עם סימון חיצוני גם לאובייקט 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 מכין תמונה של שרשרת החלפה לשימוש חיצוני, יוצר גדר מקומית ומתזמן את הגדר המקומית כך שתאותת אחרי שאותות הסמפור של הקלט אותתו:

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

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

אם הסמפורים של ההמתנה (אם יש כאלה) כבר אותתו, ו-queue כבר במצב סרק, מנהל ההתקן יכול להגדיר את *pNativeFenceFd ל--1 במקום ל-descriptor של קובץ גדר מקורי בפועל, כדי לציין שאין למה לחכות. המתקשר הוא הבעלים של מתאר הקובץ שמוחזר ב-*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 שהוא תומך בהן.

מתג feature flag של Vulkan

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

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

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

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