Vulkan را اجرا کنید

ولکان یک API چند پلتفرمی با سربار کم برای گرافیک‌های سه‌بعدی با کارایی بالا است. ولکان مانند OpenGL ES (GLES) ، ابزارهایی برای ایجاد گرافیک‌های با کیفیت بالا و بلادرنگ در برنامه‌ها فراهم می‌کند. مزایای استفاده از ولکان شامل کاهش سربار CPU و پشتیبانی از زبان SPIR-V Binary Intermediate است.

برای پیاده‌سازی موفقیت‌آمیز Vulkan، یک دستگاه باید شامل موارد زیر باشد:

  • لودر Vulkan، ارائه شده توسط اندروید.
  • یک درایور Vulkan، که توسط SoCهایی مانند GPU IHVها ارائه می‌شود و API Vulkan را پیاده‌سازی می‌کند. برای پشتیبانی از قابلیت Vulkan، دستگاه اندروید به سخت‌افزار GPU سازگار با Vulkan و درایور مرتبط با آن نیاز دارد. GPU همچنین باید از GLES 3.1 و بالاتر پشتیبانی کند. برای درخواست پشتیبانی درایور با فروشنده SoC خود مشورت کنید.

اگر دستگاهی شامل درایور Vulkan باشد، دستگاه باید ویژگی‌های سیستمی FEATURE_VULKAN_HARDWARE_LEVEL و FEATURE_VULKAN_HARDWARE_VERSION را به همراه نسخه‌هایی که به طور دقیق قابلیت‌های دستگاه را منعکس می‌کنند، اعلام کند. این امر به اطمینان از مطابقت دستگاه با سند تعریف سازگاری (CDD) کمک می‌کند.

لودر ولکان

لودر Vulkan platform/frameworks/native/vulkan رابط اصلی بین برنامه‌های Vulkan و درایور Vulkan دستگاه است. لودر Vulkan در /system/lib[64]/libvulkan.so نصب شده است. این لودر نقاط ورودی API اصلی Vulkan، نقاط ورودی افزونه‌های مورد نیاز Android CDD و بسیاری از افزونه‌های اختیاری اضافی را فراهم می‌کند. افزونه‌های Window System Integration (WSI) توسط لودر صادر می‌شوند و عمدتاً در لودر پیاده‌سازی می‌شوند نه در درایور. لودر همچنین از شمارش و بارگذاری لایه‌هایی پشتیبانی می‌کند که می‌توانند افزونه‌های اضافی را در معرض نمایش قرار دهند و فراخوانی‌های API اصلی را در مسیر رسیدن به درایور رهگیری کنند.

NDK شامل یک کتابخانه libvulkan.so برای لینک کردن است. این کتابخانه همان نمادهای لودر را صادر می‌کند. برنامه‌ها توابع صادر شده از کتابخانه واقعی libvulkan.so را برای وارد کردن توابع trampoline در لودر فراخوانی می‌کنند که بر اساس اولین آرگومان خود به لایه یا درایور مناسب ارسال می‌شوند. فراخوانی vkGet*ProcAddr() نشانگرهای تابعی را که trampolineها به آنها ارسال می‌شوند، برمی‌گرداند (یعنی مستقیماً به کد API اصلی فراخوانی می‌شود). فراخوانی از طریق نشانگرهای تابع، به جای نمادهای صادر شده، کارآمدتر است زیرا از trampoline و ارسال صرف نظر می‌کند.

شمارش و بارگذاری درایورها

وقتی تصویر سیستم ساخته می‌شود، اندروید انتظار دارد که سیستم بداند کدام پردازنده‌های گرافیکی (GPU) در دسترس هستند. لودر از مکانیزم HAL موجود در hardware.h برای کشف و بارگذاری درایور استفاده می‌کند. مسیرهای ترجیحی برای درایورهای 32 بیتی و 64 بیتی Vulkan عبارتند از:

/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

در اندروید ۷.۰ و بالاتر، مشتق hw_module_t در Vulkan یک ساختار hw_module_t را در بر می‌گیرد؛ فقط یک درایور پشتیبانی می‌شود و رشته ثابت HWVULKAN_DEVICE_0 به open() ارسال می‌شود.

مشتق hw_device_t در Vulkan مربوط به یک درایور واحد است که می‌تواند از چندین دستگاه فیزیکی پشتیبانی کند. ساختار hw_device_t می‌تواند به توابع export vkGetGlobalExtensionProperties() ، vkCreateInstance() و vkGetInstanceProcAddr() گسترش یابد. لودر می‌تواند با فراخوانی vkGetInstanceProcAddr() ساختار hw_device_t ، تمام توابع VkInstance() ، VkPhysicalDevice() و vkGetDeviceProcAddr() دیگر را پیدا کند.

از اندروید ۱۵ به بعد، این لودر از APEX برای بارگذاری درایور Vulkan پشتیبانی می‌کند. برای بارگذاری Vulkan از APEX، ro.vulkan.apex را روی نام Vulkan APEX تنظیم کنید.

کشف و بارگذاری لایه

لودر Vulkan از شمارش و بارگذاری لایه‌ها پشتیبانی می‌کند که می‌توانند افزونه‌های اضافی را در معرض نمایش قرار دهند و فراخوانی‌های API اصلی را در مسیر رسیدن به درایور رهگیری کنند. اندروید لایه‌هایی را در تصویر سیستم شامل نمی‌کند. با این حال، برنامه‌ها ممکن است لایه‌هایی را در APK خود داشته باشند.

هنگام استفاده از لایه‌ها، به خاطر داشته باشید که مدل و سیاست‌های امنیتی اندروید با سایر پلتفرم‌ها تفاوت قابل توجهی دارد. به طور خاص، اندروید اجازه بارگذاری کد خارجی را در یک فرآیند غیرقابل اشکال‌زدایی در دستگاه‌های تولیدی (غیر روت) نمی‌دهد و همچنین به کد خارجی اجازه بازرسی یا کنترل حافظه، وضعیت و غیره فرآیند را نمی‌دهد. این شامل ممنوعیت ذخیره نسخه‌های اصلی، ردیابی‌های API و غیره در دیسک برای بررسی‌های بعدی می‌شود. فقط لایه‌هایی که به عنوان بخشی از برنامه‌های غیرقابل اشکال‌زدایی ارائه می‌شوند، در دستگاه‌های تولیدی فعال هستند و درایورها نباید عملکردی را ارائه دهند که این سیاست‌ها را نقض کند.

موارد استفاده از لایه‌ها عبارتند از:

  • لایه‌های زمان توسعه — لایه‌های اعتبارسنجی و ابزارهای ردیابی/پروفایلینگ/اشکال‌زدایی نباید روی تصویر سیستم دستگاه‌های تولیدی نصب شوند. لایه‌های اعتبارسنجی و ابزارهای ردیابی/پروفایلینگ/اشکال‌زدایی باید بدون تصویر سیستم قابل به‌روزرسانی باشند. توسعه‌دهندگانی که می‌خواهند در طول توسعه از یکی از این لایه‌ها استفاده کنند، می‌توانند بسته برنامه را تغییر دهند، به عنوان مثال، با اضافه کردن یک فایل به دایرکتوری کتابخانه‌های بومی خود. فرض می‌شود مهندسان IHV و OEM که می‌خواهند خرابی‌های موجود در ارسال برنامه‌های غیرقابل تغییر را تشخیص دهند، به نسخه‌های غیرتولیدی (روت‌شده) تصویر سیستم دسترسی دارند، مگر اینکه آن برنامه‌ها قابل اشکال‌زدایی باشند. برای اطلاعات بیشتر به لایه‌های اعتبارسنجی Vulkan در اندروید مراجعه کنید.
  • لایه‌های کاربردی - این لایه‌ها افزونه‌هایی را در معرض نمایش قرار می‌دهند، مانند لایه‌ای که یک مدیر حافظه را برای حافظه دستگاه پیاده‌سازی می‌کند. توسعه‌دهندگان لایه‌ها و نسخه‌هایی از آن لایه‌ها را برای استفاده در برنامه خود انتخاب می‌کنند؛ برنامه‌های مختلفی که از یک لایه استفاده می‌کنند ممکن است همچنان از نسخه‌های مختلفی استفاده کنند. توسعه‌دهندگان انتخاب می‌کنند که کدام یک از این لایه‌ها را در بسته برنامه خود قرار دهند.
  • لایه‌های تزریق‌شده (ضمنی) - شامل لایه‌هایی مانند نرخ فریم، شبکه‌های اجتماعی و پوشش‌های لانچر بازی است که توسط کاربر یا برخی برنامه‌های دیگر بدون اطلاع یا رضایت برنامه ارائه می‌شوند. این موارد سیاست‌های امنیتی اندروید را نقض می‌کنند و پشتیبانی نمی‌شوند.

برای برنامه‌های غیرقابل اشکال‌زدایی، لودر فقط در دایرکتوری کتابخانه بومی برنامه به دنبال لایه‌ها می‌گردد و سعی می‌کند هر کتابخانه‌ای را که نامش با الگوی خاصی مطابقت دارد (مثلاً libVKLayer_foo.so ) بارگذاری کند.

برای برنامه‌های قابل اشکال‌زدایی، لودر به دنبال لایه‌ها در /data/local/debug/vulkan می‌گردد و سعی می‌کند هر کتابخانه‌ای را که با الگوی خاصی مطابقت دارد، بارگیری کند.

اندروید امکان انتقال لایه‌ها با تغییرات محیط ساخت بین اندروید و سایر پلتفرم‌ها را فراهم می‌کند. برای جزئیات بیشتر در مورد رابط بین لایه‌ها و لودر، به معماری رابط‌های لودر Vulkan مراجعه کنید. لایه‌های اعتبارسنجی نگهداری شده توسط Khronos در Vulkan Validation Layers میزبانی می‌شوند.

نسخه‌ها و قابلیت‌های رابط برنامه‌نویسی کاربردی ولکان

جدول زیر نسخه‌های API ولکان را برای چندین نسخه اندروید فهرست می‌کند.
نسخه اندروید نسخه ولکان
اندروید ۱۳ ولکان ۱.۳
اندروید ۹ ولکان ۱.۱
اندروید ۷ ولکان ۱.۰

مروری بر قابلیت‌های ولکان ۱.۳

ولکان ۱.۳ تعدادی از افزونه‌های قبلاً اختیاری را به قابلیت‌های اصلی ولکان اضافه کرده است. بخش عمده‌ای از این قابلیت‌ها با هدف افزایش کنترل و جزئیات بیشتر بر رابط برنامه‌نویسی ولکان گنجانده شده است. نمونه‌های رندر تک‌گذر دیگر نیازی به اشیاء رندر یا فریم‌بافر ندارند. تعداد کل اشیاء حالت خط لوله می‌تواند کاهش یابد و همگام‌سازی درون API مورد بازنگری قرار می‌گیرد. ولکان ۱.۳ همان الزامات سخت‌افزاری ولکان ۱.۲، ۱.۱ و ۱.۰ را دارد و بیشتر پیاده‌سازی آن در درایور گرافیکی مخصوص SoC انجام شده است، نه در چارچوب.

مهم‌ترین ویژگی‌های Vulkan 1.3 برای اندروید عبارتند از:

  • پشتیبانی از نمونه‌های رندر تک‌گذر
  • پشتیبانی از خاتمه فوری فراخوانی سایه‌زن
  • جزئیات دقیق‌تر در مورد ایجاد، اشتراک‌گذاری و کنترل پایپ‌لاین

ولکان ۱.۳ همچنین شامل چندین ویژگی کوچک‌تر و بهبودهایی در قابلیت استفاده از API است. تمام تغییرات اعمال شده در هسته API ولکان با نسخه جزئی ۱.۳ را می‌توانید در Core Revisions (ولکان ۱.۳) بیابید.

مروری بر قابلیت‌های ولکان ۱.۲

ولکان ۱.۲ تعدادی ویژگی و افزونه اضافه کرده است که سطح API را ساده می‌کند. این شامل یک مدل حافظه یکپارچه و اطلاعات اضافی است که می‌توان از درایور دستگاه درخواست کرد. ولکان ۱.۲ همان الزامات سخت‌افزاری ولکان ۱.۰ و ۱.۱ را دارد؛ تمام پیاده‌سازی‌ها در درایور گرافیکی مخصوص SoC است، نه در چارچوب.

مهم‌ترین ویژگی Vulkan 1.2 برای اندروید، پشتیبانی از ذخیره‌سازی ۸ بیتی است.

ولکان ۱.۲ همچنین شامل چندین ویژگی کوچک‌تر و بهبودهایی در قابلیت استفاده از API است. تمام تغییرات اعمال شده در هسته API ولکان با نسخه جزئی ۱.۲ را می‌توانید در Core Revisions (ولکان ۱.۲) بیابید.

مروری بر قابلیت‌های ولکان ۱.۱

Vulkan 1.1 شامل پشتیبانی از تعامل حافظه/همگام‌سازی است که به تولیدکنندگان اصلی تجهیزات (OEM) امکان می‌دهد از Vulkan 1.1 در دستگاه‌ها پشتیبانی کنند. علاوه بر این، تعامل حافظه/همگام‌سازی به توسعه‌دهندگان این امکان را می‌دهد که تشخیص دهند آیا Vulkan 1.1 در یک دستگاه پشتیبانی می‌شود یا خیر و در صورت پشتیبانی، از آن به طور مؤثر استفاده کنند. Vulkan 1.1 الزامات سخت‌افزاری مشابه Vulkan 1.0 دارد، اما بیشتر پیاده‌سازی آن در درایور گرافیکی مخصوص SOC است، نه در چارچوب.

مهم‌ترین ویژگی‌های Vulkan 1.1 برای اندروید عبارتند از:

  • پشتیبانی از وارد کردن و صادر کردن بافرهای حافظه و اشیاء همگام‌سازی از خارج از Vulkan (برای تعامل با دوربین، کدک‌ها و GLES)
  • پشتیبانی از فرمت‌های YCbCr

ولکان ۱.۱ همچنین شامل چندین ویژگی کوچک‌تر و بهبودهایی در قابلیت استفاده از API است. تمام تغییرات اعمال شده در هسته API ولکان با نسخه جزئی ۱.۱ را می‌توانید در Core Revisions (ولکان ۱.۱) بیابید.

پشتیبانی Vulkan را انتخاب کنید

همه دستگاه‌های اندروید باید از پیشرفته‌ترین مجموعه ویژگی‌های Vulkan موجود پشتیبانی کنند، مشروط بر اینکه از ABI 64 بیتی پشتیبانی کنند و حافظه کمی نداشته باشند.

دستگاه‌هایی که با اندروید ۱۳ و بالاتر عرضه می‌شوند، باید از Vulkan 1.3 پشتیبانی کنند.

دستگاه‌هایی که با اندروید ۱۰ عرضه می‌شوند باید از Vulkan 1.1 پشتیبانی کنند.

سایر دستگاه‌ها می‌توانند به صورت اختیاری از Vulkan 1.3، 1.2 و 1.1 پشتیبانی کنند.

پشتیبانی از نسخه Vulkan

یک دستگاه اندروید در صورت برآورده شدن شرایط زیر از نسخه Vulkan پشتیبانی می‌کند:

  1. یک درایور Vulkan که از نسخه Vulkan مورد نظر شما پشتیبانی می‌کند (این باید یکی از نسخه‌های Vulkan 1.3، 1.1 یا 1.0 باشد) را در کنار الزامات CDD اضافی نسخه اندروید اضافه کنید. روش دیگر، به‌روزرسانی درایور Vulkan موجود با شماره نسخه پایین‌تر Vulkan است.
  2. برای ولکان ۱.۳ یا ۱.۱، مطمئن شوید که ویژگی سیستمی برگردانده شده توسط مدیر بسته، برای نسخه صحیح ولکان true را برمی‌گرداند.
    • برای Vulkan 1.3 این ویژگی به PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x403000) است.
    • برای Vulkan 1.1 این ویژگی به PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000) است.
    مدیر بسته با اضافه کردن یک قانون، که به شرح زیر نشان داده شده است، به فایل device.mk مناسب، برای Vulkan 1.3 و Vulkan 1.1 true برمی‌گرداند.
    • موارد زیر را برای 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

نمایه پایه اندروید (ABP)

ما همه دستگاه‌های اندروید را تشویق می‌کنیم که خود را با آخرین نسخه اندروید بیس‌لاین ۲۰۲۲، همانطور که در راهنمای اندروید بیس‌لاین پروفایل ذکر شده است، مطابقت دهند.

هر دستگاهی که از اندروید ۱۴ یا بالاتر و رابط برنامه‌نویسی کاربردی ولکان (Vulkan API) پشتیبانی می‌کند، باید تمام عملکردهای تعریف‌شده در پروفایل اندروید بیس‌لاین ۲۰۲۱ را برآورده کند. لیست کامل عملکردهای مورد نیاز در فایل json پروفایل ولکان فهرست شده است، اما زیرمجموعه‌ای کلیدی از عملکردهای مورد نیاز شامل موارد زیر است:

  • بافت‌های فشرده‌شده از طریق 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 در اندروید ۱۰ پیاده‌سازی شده است
  • VK_GOOGLE_display_timing ، برای هر نسخه Vulkan در اندروید ۱۰ پیاده‌سازی شده است

اشیاء VkSurfaceKHR و VkSwapchainKHR و تمام تعاملات با ANativeWindow توسط پلتفرم مدیریت می‌شوند و در معرض درایورها قرار ندارند. پیاده‌سازی WSI به افزونه‌ی VK_ANDROID_native_buffer متکی است که باید توسط درایور پشتیبانی شود؛ این افزونه فقط توسط پیاده‌سازی WSI استفاده می‌شود و در معرض برنامه‌ها قرار ندارد.

پرچم‌های استفاده از گرالک

پیاده‌سازی‌های Vulkan ممکن است نیاز داشته باشند که بافرهای swapchain با پرچم‌های استفاده خصوصی Gralloc که توسط پیاده‌سازی تعریف شده‌اند، تخصیص داده شوند. هنگام ایجاد یک swapchain، اندروید از درایور می‌خواهد که با فراخوانی دستور زیر، پرچم‌های استفاده از فرمت و تصویر درخواستی را به پرچم‌های استفاده از 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 هنگام تخصیص بافرها درخواست شده است، ترکیب می‌شوند.

اندروید ۷.x نسخه قدیمی‌تری از VkSwapchainImageUsageFlagsANDROID() را با نام vkGetSwapchainGrallocUsageANDROID() فراخوانی می‌کند. اندروید ۸.۰ و بالاتر vkGetSwapchainGrallocUsageANDROID() منسوخ می‌کند، اما اگر vkGetSwapchainGrallocUsageANDROID vkGetSwapchainGrallocUsageANDROID() vkGetSwapchainGrallocUsage2ANDROID() را فراخوانی می‌کند:

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

vkGetSwapchainGrallocUsageANDROID() از پرچم‌های استفاده از swapchain یا پرچم‌های استفاده از Gralloc توسعه‌یافته پشتیبانی نمی‌کند.

تصاویر با پشتیبانی گرالک

VkNativeBufferANDROID یک ساختار افزونه vkCreateImage برای ایجاد تصویری است که توسط یک بافر Gralloc پشتیبانی می‌شود. VkNativeBufferANDROID در زنجیره ساختار VkImageCreateInfo برای vkCreateImage() ارائه شده است. فراخوانی‌های vkCreateImage() با VkNativeBufferANDROID در طول فراخوانی vkCreateSwapchainKHR اتفاق می‌افتد. پیاده‌سازی WSI تعداد بافرهای بومی درخواست شده برای swapchain را اختصاص می‌دهد، سپس برای هر یک یک 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

در اندروید ۸.۰ و بالاتر، پلتفرم یک ساختار افزونه VkSwapchainImageCreateInfoKHR را در زنجیره VkImageCreateInfo ارائه می‌دهد که در صورت نیاز به هرگونه پرچم استفاده از تصویر swapchain برای swapchain، در اختیار vkCreateImage قرار می‌گیرد. این ساختار افزونه شامل پرچم‌های استفاده از تصویر swapchain است:

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

    VkSwapchainImageUsageFlagsANDROID      usage;
} VkSwapchainImageCreateInfoANDROID;

در اندروید ۱۰ و بالاتر، این پلتفرم از VK_KHR_swapchain نسخه ۷۰ پشتیبانی می‌کند، بنابراین برنامه Vulkan قادر به ایجاد یک VkImage با پشتیبانی حافظه swapchain است. برنامه ابتدا vkCreateImage با ساختار VkImageSwapchainCreateInfoKHR که به ساختار VkImageCreateInfo زنجیر شده است، فراخوانی می‌کند. سپس برنامه vkBindImageMemory2(KHR) با ساختار VkBindImageMemorySwapchainInfoKHR که به ساختار VkBindImageMemoryInfo زنجیر شده است، فراخوانی می‌کند. imageIndex مشخص شده در ساختار VkBindImageMemorySwapchainInfoKHR باید یک شاخص تصویر معتبر swapchain باشد. در همین حال، این پلتفرم یک ساختار افزونه VkNativeBufferANDROID با اطلاعات بافر Gralloc مربوطه را به زنجیره VkBindImageMemoryInfo ارائه می‌دهد، بنابراین راننده می‌داند که VkImage با کدام بافر Gralloc متصل کند.

تصاویر را دریافت کنید

vkAcquireImageANDROID مالکیت یک تصویر swapchain را به دست می‌آورد و یک حصار بومی سیگنال‌دهی شده خارجی را هم به یک شیء VkSemaphore موجود و هم به یک شیء VkFence موجود وارد می‌کند:

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

vkAcquireImageANDROID() در طول vkAcquireNextImageKHR فراخوانی می‌شود تا یک حصار بومی را به اشیاء VkSemaphore و VkFence ارائه شده توسط برنامه وارد کند (با این حال، اشیاء semaphore و fence در این فراخوانی اختیاری هستند). درایور همچنین می‌تواند از این فرصت برای تشخیص و مدیریت هرگونه تغییر خارجی در وضعیت بافر Gralloc استفاده کند. بسیاری از درایورها نیازی به انجام کاری در اینجا ندارند. این فراخوانی، VkSemaphore و VkFence را در همان حالت معلق قرار می‌دهد که گویی توسط vkQueueSubmit سیگنال داده شده است، بنابراین صف‌ها می‌توانند در semaphore منتظر بمانند و برنامه می‌تواند در 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 را در اختیار می‌گیرد و می‌بندد.

بسیاری از درایورها می‌توانند پارامتر تصویر را نادیده بگیرند، اما برخی ممکن است نیاز داشته باشند ساختارهای داده سمت CPU مرتبط با یک بافر Gralloc را برای استفاده توسط مصرف‌کنندگان تصویر خارجی آماده کنند. آماده‌سازی محتوای بافر برای استفاده توسط مصرف‌کنندگان خارجی باید به صورت غیرهمزمان و به عنوان بخشی از انتقال تصویر به VK_IMAGE_LAYOUT_PRESENT_SRC_KHR انجام شود.

اگر تصویر با VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID ایجاد شده باشد، درایور باید اجازه دهد که vkQueueSignalReleaseImageANDROID() به طور مکرر و بدون دخالت در فراخوانی‌های vkAcquireImageANDROID() فراخوانی شود.

پشتیبانی از تصویر قابل ارائه مشترک

برخی از دستگاه‌ها می‌توانند مالکیت یک تصویر واحد را بین خط لوله نمایش و پیاده‌سازی Vulkan به اشتراک بگذارند تا تأخیر را به حداقل برسانند. در اندروید ۹ و بالاتر، لودر به طور مشروط افزونه 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 تنظیم می‌کند.

اعتبارسنجی

تولیدکنندگان تجهیزات اصلی (OEM) می‌توانند پیاده‌سازی Vulkan خود را با استفاده از CTS آزمایش کنند که شامل موارد زیر است:

  • تست‌های انطباق Khronos Vulkan در ماژول CtsDeqpTestCases که شامل تست‌های عملکردی API برای Vulkan 1.0، 1.1، 1.2 و 1.3 می‌شود.
  • ماژول CtsGraphicsTestCases که پیکربندی صحیح دستگاه را برای قابلیت‌های Vulkan که از آنها پشتیبانی می‌کند، آزمایش می‌کند.

پرچم ویژه ولکان

دستگاهی که از اندروید ۱۱ یا بالاتر و رابط برنامه‌نویسی کاربردی Vulkan پشتیبانی می‌کند، ملزم به نمایش یک feature flag به android.software.vulkan.deqp.level است. مقدار این feature flag یک تاریخ است که به صورت یک عدد صحیح کدگذاری شده است. این تاریخ، تاریخ مرتبط با تست‌های Vulkan dEQP را که دستگاه ادعا می‌کند در آنها قبول شده است، مشخص می‌کند.

یک تاریخ به شکل YYYY-MM-DD به صورت یک عدد صحیح ۳۲ بیتی به صورت زیر کدگذاری می‌شود:

  • بیت‌های ۰ تا ۱۵ سال را ذخیره می‌کنند
  • بیت‌های ۱۶ تا ۲۳ ماه را ذخیره می‌کنند
  • بیت‌های ۲۴ تا ۳۱، روز را ذخیره می‌کنند

حداقل مقدار مجاز برای feature flag برابر 0x07E30301 است که مربوط به تاریخ 2019-03-01 است، که تاریخ مرتبط با تست‌های Vulkan dEQP برای اندروید 10 است. اگر feature flag حداقل این مقدار را داشته باشد، دستگاه ادعا می‌کند که تمام تست‌های Vulkan dEQP اندروید 10 را با موفقیت پشت سر گذاشته است.

مقدار 0x07E40301 مربوط به تاریخ 2020-03-01 است، که تاریخ مرتبط با آزمایش‌های Vulkan dEQP برای اندروید 11 است. اگر feature flag حداقل این مقدار باشد، دستگاه ادعا می‌کند که تمام آزمایش‌های Vulkan dEQP اندروید 11 را با موفقیت پشت سر گذاشته است.

مقدار 0x07E60301 مربوط به تاریخ 2022-03-01 است، که تاریخ مرتبط با آزمایش‌های Vulkan dEQP برای اندروید ۱۳ است. اگر feature flag حداقل این مقدار باشد، دستگاه ادعا می‌کند که تمام آزمایش‌های Vulkan dEQP اندروید ۱۳ را با موفقیت پشت سر گذاشته است.

دستگاهی که یک feature flag خاص ( مثلاً 0x07E30301 ، 0x07E40301 ، 0x07E60301 ) را نمایش می‌دهد، ادعا می‌کند که تمام تست‌های dEQP اندروید Vulkan مربوط به آن feature flag (به ترتیب اندروید 10، اندروید 11، اندروید 13) را با موفقیت پشت سر گذاشته است. این دستگاه ممکن است تست‌های dEQP ولکان مربوط به نسخه‌های بعدی اندروید را با موفقیت پشت سر بگذارد.

Vulkan dEQP بخشی از Android CTS را تشکیل می‌دهد. از اندروید ۱۱، کامپوننت اجراکننده تست dEQP در CTS از پرچم ویژگی android.software.vulkan.deqp.level آگاه است و از هر تست Vulkan dEQP که - طبق این پرچم ویژگی - دستگاه ادعای پشتیبانی از آن را ندارد، صرف نظر می‌کند. چنین تست‌هایی به عنوان تست‌های بی‌اهمیت و موفق گزارش می‌شوند.