Vulkan implementieren

Vulkan ist eine plattformübergreifende API mit geringem Aufwand für leistungsstarke 3D-Grafiken. Ähnlich wie OpenGL ES (GLES) bietet Vulkan Tools zum Erstellen hochwertiger Echtzeitgrafiken in Apps. Zu den Vorteilen von Vulkan gehören eine Verringerung des CPU-Aufwands und die Unterstützung der SPIR-V-Binary Intermediate-Sprache.

Damit Vulkan auf einem Gerät implementiert werden kann, muss es Folgendes enthalten:

  • Das von Android bereitgestellte Vulkan-Ladeprogramm.
  • Ein Vulkan-Treiber, der von SoCs wie GPU IHVs bereitgestellt wird und die Vulkan API implementiert. Damit Vulkan-Funktionen unterstützt werden, benötigt das Android-Gerät eine GPU-Hardware, die Vulkan unterstützt, und den zugehörigen Treiber. Die GPU muss außerdem GLES 3.1 und höher unterstützen. Wenden Sie sich an Ihren SoC-Anbieter, um Treiberunterstützung anzufordern.

Wenn ein Gerät einen Vulkan-Treiber enthält, müssen die Systemfunktionen FEATURE_VULKAN_HARDWARE_LEVEL und FEATURE_VULKAN_HARDWARE_VERSION mit Versionen deklariert werden, die die Funktionen des Geräts genau widerspiegeln. So wird sichergestellt, dass das Gerät dem Compatibility Definition Document (CDD) entspricht.

Vulkan-Ladeprogramm

Das Vulkan-Ladeprogramm platform/frameworks/native/vulkan ist die primäre Schnittstelle zwischen Vulkan-Apps und dem Vulkan-Treiber eines Geräts. Das Vulkan-Ladeprogramm ist unter /system/lib[64]/libvulkan.so installiert. Der Loader bietet die wichtigsten Vulkan-API-Einstiegspunkte, die Einstiegspunkte von Erweiterungen, die vom Android CDD benötigt werden, und viele zusätzliche optionale Erweiterungen. WSI-Erweiterungen (Window System Integration) werden vom Loader exportiert und hauptsächlich im Loader und nicht im Treiber implementiert. Der Loader unterstützt auch das Aufzählen und Laden von Layern, die zusätzliche Erweiterungen verfügbar machen und Core-API-Aufrufe auf dem Weg zum Treiber abfangen können.

Das NDK enthält eine Stub-libvulkan.so-Bibliothek für die Verknüpfung. Die Bibliothek exportiert dieselben Symbole wie der Loader. Apps rufen die Funktionen auf, die aus der echten libvulkan.so-Bibliothek exportiert werden, um Trampolinfunktionen im Loader aufzurufen, die je nach erstem Argument an die entsprechende Ebene oder den entsprechenden Treiber weitergeleitet werden. Der vkGet*ProcAddr()-Aufruf gibt die Funktionszeiger zurück, an die die Trampoline weiterleiten (d. h., er ruft direkt den Core-API-Code auf). Der Aufruf über die Funktionszeiger anstelle der exportierten Symbole ist effizienter, da Trampolin und Dispatch übersprungen werden.

Aufzählen und Laden von Treibern

Wenn das System-Image erstellt wird, erwartet Android, dass das System weiß, welche GPUs verfügbar sind. Der Loader verwendet den vorhandenen HAL-Mechanismus in hardware.h, um den Treiber zu erkennen und zu laden. Die bevorzugten Pfade für 32-Bit- und 64-Bit-Vulkan-Treiber sind:

/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
.

In Android 7.0 und höher umschließt das Vulkan-hw_module_t-Derivat eine einzelne hw_module_t-Struktur. Es wird nur ein Treiber unterstützt und der konstante String HWVULKAN_DEVICE_0 wird an open() übergeben.

Das Vulkan-hw_device_t-Derivat entspricht einem einzelnen Treiber, der mehrere physische Geräte unterstützen kann. Die hw_device_t-Struktur kann auf die Exportfunktionen vkGetGlobalExtensionProperties(), vkCreateInstance() und vkGetInstanceProcAddr() erweitert werden. Der Loader kann alle anderen VkInstance()-, VkPhysicalDevice()- und vkGetDeviceProcAddr()-Funktionen finden, indem er die vkGetInstanceProcAddr() der hw_device_t-Struktur aufruft.

Ab Android 15 unterstützt der Loader APEX zum Laden des Vulkan-Treibers. Legen Sie ro.vulkan.apex auf den Namen des Vulkan-APEX fest, um Vulkan aus dem APEX zu laden.

Ebenenerkennung und -laden

Der Vulkan-Loader unterstützt das Aufzählen und Laden von Layern, die zusätzliche Erweiterungen verfügbar machen und Core-API-Aufrufe auf dem Weg zum Treiber abfangen können. Apps können Ebenen in ihr APK einfügen. Android enthält keine Ebenen im System-Image.

Beachten Sie bei der Verwendung von Ebenen, dass sich das Sicherheitsmodell und die Richtlinien von Android erheblich von anderen Plattformen unterscheiden. Insbesondere lässt Android nicht zu, dass externer Code auf Produktionsgeräten (nicht gerootet) in einen nicht debugfähigen Prozess geladen wird. Außerdem darf externer Code den Speicher, den Status usw. des Prozesses nicht untersuchen oder steuern. Dazu gehört ein Verbot, Core-Dumps, API-Traces usw. zur späteren Überprüfung auf der Festplatte zu speichern. Auf Produktionsgeräten werden nur Ebenen aktiviert, die als Teil von nicht debugbaren Apps bereitgestellt werden. Treiber dürfen keine Funktionen bieten, die gegen diese Richtlinien verstoßen.

Anwendungsfälle für Ebenen:

  • Entwicklungszeitschichten: Validierungsschichten und Shims für Tracing-, Profiling- und Debugging-Tools sollten nicht im System-Image von Produktionsgeräten installiert werden. Validierungsebenen und Shims für Tools zum Tracing, Profiling und Debugging sollten ohne System-Image aktualisiert werden können. Entwickler, die eine dieser Ebenen während der Entwicklung verwenden möchten, können das App-Paket ändern, indem sie beispielsweise eine Datei in das Verzeichnis ihrer nativen Bibliotheken einfügen. IHV- und OEM-Entwickler, die Fehler bei der Auslieferung nicht modifizierbarer Apps diagnostizieren möchten, haben in der Regel Zugriff auf nicht produktionsreife (gerootete) Builds des System-Image, sofern diese Apps nicht debugfähig sind. Weitere Informationen finden Sie unter Vulkan-Validierungsebenen auf Android.
  • Utility-Ebenen: Diese Ebenen stellen Erweiterungen bereit, z. B. eine Ebene, die einen Arbeitsspeicher-Manager für den Gerätespeicher implementiert. Entwickler wählen die Ebenen und Versionen dieser Ebenen aus, die in ihrer App verwendet werden sollen. In verschiedenen Apps, die dieselbe Ebene verwenden, können trotzdem unterschiedliche Versionen verwendet werden. Entwickler entscheiden, welche dieser Ebenen in ihrem App-Paket enthalten sein sollen.
  • Eingefügte (implizite) Ebenen: Dazu gehören Ebenen wie Framerate, Overlays für soziale Netzwerke und Game Launcher, die vom Nutzer oder einer anderen App ohne Wissen oder Zustimmung der App bereitgestellt werden. Diese verstoßen gegen die Sicherheitsrichtlinien von Android und werden nicht unterstützt.

Bei Apps, die nicht debugfähig sind, sucht der Loader nur im nativen Bibliotheksverzeichnis der App nach Layern und versucht, jede Bibliothek mit einem Namen zu laden, der einem bestimmten Muster entspricht (z. B. libVKLayer_foo.so). Diese Layer werden in den Namespace der App geladen. Daher müssen sie mit dem NDK erstellt werden.

Bei Apps, die debuggt werden können, sucht der Loader in /data/local/debug/vulkan nach Layern und versucht, alle Bibliotheken zu laden, die einem bestimmten Muster entsprechen. Ab Android 10 (API-Level 29) können mit Vulkan auch Entwicklungsschichten aus einem anderen APK geladen werden. In beiden Fällen wählt der Loader anhand der Systemeinstellungen aus, welche Ebenen pro App aktiviert werden sollen. Diese Ebenen werden in vkEnumerateInstanceLayerProperties aufgeführt (d. h., die App hat möglicherweise Kenntnis von ihnen), auch wenn sie ohne Zustimmung der App geladen werden.

Android ermöglicht das Portieren von Ebenen mit Änderungen an der Build-Umgebung zwischen Android und anderen Plattformen. Weitere Informationen zur Schnittstelle zwischen Layern und dem Loader finden Sie unter Architektur der Vulkan-Loader-Schnittstellen. Die von Khronos verwalteten Validierungslayer werden in Vulkan Validation Layers gehostet.

Vulkan-API-Versionen und ‑Funktionen

In der folgenden Tabelle sind die Vulkan API-Versionen für verschiedene Android-Versionen aufgeführt.
Android-Version Vulkan-Version
Android 16 Vulkan 1.4
Android 13 Vulkan 1.3
Android 9 Vulkan 1.1
Android 7 Vulkan 1.0

Übersicht über die Funktionen von Vulkan 1.4

In Vulkan 1.4 werden eine Reihe von zuvor optionalen Erweiterungen in die Vulkan-Kernfunktionen aufgenommen. Viele dieser Funktionen sind enthalten, um die Kontrolle und Granularität der Vulkan-Programmierschnittstelle zu erhöhen. Vulkan 1.4 erhöht die Hardwareanforderungen im Vergleich zu Vulkan 1.3. Die meisten Implementierungen erfolgen im SoC-spezifischen Grafiktreiber und nicht im Framework.

Vulkan 1.3 – Funktionsübersicht

In Vulkan 1.3 werden eine Reihe von zuvor optionalen Erweiterungen in die Vulkan-Kernfunktionen aufgenommen. Viele dieser Funktionen sind enthalten, um die Kontrolle und Granularität der Vulkan-Programmierschnittstelle zu erhöhen. Für Render-Pass-Instanzen mit nur einem Durchgang sind keine Render-Pass-Objekte oder Framebuffer mehr erforderlich. Die Gesamtzahl der Pipeline-Statusobjekte kann reduziert werden und die Synchronisierung innerhalb der API wird überarbeitet. Vulkan 1.3 hat dieselben Hardwareanforderungen wie Vulkan 1.2, 1.1 und 1.0. Die meisten Implementierungen erfolgen im SoC-spezifischen Grafiktreiber und nicht im Framework.

Die wichtigsten Vulkan 1.3-Funktionen für Android sind:

  • Unterstützung für Single-Pass-Render-Pass-Instanzen
  • Unterstützung für das sofortige Beenden eines Shader-Aufrufs
  • Feinere Detaillierung bei der Erstellung, Freigabe und Steuerung von Pipelines

Vulkan 1.3 enthält auch mehrere kleinere Funktionen und Verbesserungen der API-Nutzerfreundlichkeit. Alle Änderungen, die an der Core Vulkan API mit der geringfügigen Revision 1.3 vorgenommen wurden, finden Sie unter Core Revisions (Vulkan 1.3).

Vulkan 1.2 – Funktionsübersicht

Vulkan 1.2 bietet eine Reihe von Funktionen und Erweiterungen, die die API-Oberfläche vereinfachen. Dazu gehören ein einheitliches Memory-Modell und zusätzliche Informationen, die von einem Gerätetreiber abgefragt werden können. Vulkan 1.2 hat dieselben Hardwareanforderungen wie Vulkan 1.0 und 1.1. Die gesamte Implementierung erfolgt im SoC-spezifischen Grafiktreiber, nicht im Framework.

Das wichtigste Vulkan 1.2-Feature für Android ist die Unterstützung von 8-Bit-Speicher.

Vulkan 1.2 enthält auch mehrere kleinere Funktionen und Verbesserungen der API-Nutzerfreundlichkeit. Alle Änderungen an der Vulkan-Kern-API mit der Nebenversion 1.2 finden Sie unter Core Revisions (Vulkan 1.2).

Vulkan 1.1 – Funktionsübersicht

Vulkan 1.1 unterstützt die Interoperabilität von Speicher und Synchronisierung, sodass OEMs Vulkan 1.1 auf Geräten unterstützen können. Außerdem können Entwickler mit der Memory-/Synchronization-Interop-Funktion feststellen, ob Vulkan 1.1 auf einem Gerät unterstützt wird, und es dann effektiv nutzen. Vulkan 1.1 hat dieselben Hardwareanforderungen wie Vulkan 1.0, aber der Großteil der Implementierung befindet sich im SOC-spezifischen Grafiktreiber und nicht im Framework.

Die wichtigsten Vulkan 1.1-Funktionen für Android sind:

  • Unterstützung für das Importieren und Exportieren von Speicherpuffern und Synchronisierungsobjekten von außerhalb von Vulkan (für die Interoperabilität mit Kamera, Codecs und GLES)
  • Unterstützung für YCbCr-Formate

Vulkan 1.1 enthält auch mehrere kleinere Funktionen und Verbesserungen der API-Nutzerfreundlichkeit. Alle Änderungen an der Core Vulkan API mit der Nebenversion 1.1 finden Sie unter Core Revisions (Vulkan 1.1).

Vulkan-Unterstützung auswählen

Alle Android-Geräte müssen den fortschrittlichsten verfügbaren Vulkan-Funktionsumfang unterstützen, sofern sie ein 64‑Bit-ABI unterstützen und nicht über wenig Arbeitsspeicher verfügen.

Geräte, die bei Markteinführung Android 16 oder höher nutzen, müssen Vulkan 1.4 unterstützen.

Geräte, die bei Markteinführung Android 13 oder höher nutzen, müssen Vulkan 1.3 unterstützen.

Geräte, die mit Android 10 auf den Markt kommen, müssen Vulkan 1.1 unterstützen.

Andere Geräte können optional Vulkan 1.4, 1.3, 1.2 und 1.1 unterstützen.

Vulkan-Version unterstützen

Ein Android-Gerät unterstützt eine Vulkan-Version, wenn die folgenden Bedingungen erfüllt sind:

  1. Fügen Sie einen Vulkan-Treiber hinzu, der die gewünschte Vulkan-Version unterstützt (Vulkan-Version 1.4, 1.3, 1.1 oder 1.0) und die zusätzlichen CDD-Anforderungen der Android-Version erfüllt. Alternativ können Sie einen vorhandenen Vulkan-Treiber mit einer niedrigeren Vulkan-Versionsnummer aktualisieren.
  2. Prüfen Sie für Vulkan 1.4, 1.3 oder 1.1, ob die vom Paketmanager zurückgegebene Systemfunktion true für die richtige Vulkan-Version zurückgibt.
    • Für Vulkan 1.4 ist das Feature PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x404000).
    • Für Vulkan 1.3 ist das Feature PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x403000).
    • Für Vulkan 1.1 ist das Feature PackageManager#hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000).
    Der Paketmanager gibt true für Vulkan 1.4, 1.3 und 1.1 zurück, indem er einer entsprechenden device.mk-Datei eine Regel hinzufügt, wie unten dargestellt.
    • Fügen Sie Folgendes für Vulkan 1.4 hinzu:
      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
    • Fügen Sie Folgendes für Vulkan 1.3 hinzu:
      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
    • Fügen Sie für Vulkan 1.1 Folgendes hinzu:
      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

Android-Baseline-Profil (ABP)

Wir empfehlen, dass alle Android-Geräte dem neuesten Android Baseline-Profil 2022 entsprechen, wie im Android Baseline-Profilleitfaden beschrieben.

Alle Geräte, die Android 14 oder höher und die Vulkan API unterstützen, müssen alle Funktionen erfüllen, die im Android Baseline 2021-Profil definiert sind. Die vollständige Liste der erforderlichen Funktionen ist in der Vulkan-Profildatei json aufgeführt. Eine wichtige Teilmenge der erforderlichen Funktionen umfasst Folgendes:

  • Komprimierte Texturen über ASTC und ETC.
  • Variable Farbräume über VK_EXT_swapchain_colorspace.
  • Beispiel für Schattierung und Multisample-Interpolation über sampleRateShading.

Fenstersystemintegration (Window System Integration, WSI)

In libvulkan.so implementiert der Treiber die folgenden WSI-Erweiterungen (Window System Integration):

  • VK_KHR_surface
  • VK_KHR_android_surface
  • VK_KHR_swapchain
  • VK_KHR_driver_properties, implementiert für Vulkan 1.1 nur in Android 10
  • VK_GOOGLE_display_timing, implementiert für jede Vulkan-Version in Android 10

Die Objekte VkSurfaceKHR und VkSwapchainKHR sowie alle Interaktionen mit ANativeWindow werden von der Plattform verarbeitet und sind für Fahrer nicht sichtbar. Die WSI-Implementierung basiert auf der Erweiterung VK_ANDROID_native_buffer, die vom Treiber unterstützt werden muss. Diese Erweiterung wird nur von der WSI-Implementierung verwendet und ist für Apps nicht verfügbar.

Gralloc-Nutzungsflags

Für Vulkan-Implementierungen müssen möglicherweise Swapchain-Puffer mit implementierungsdefinierten privaten Gralloc-Nutzungsflags zugewiesen werden. Beim Erstellen einer Swapchain fordert Android den Treiber auf, das angeforderte Format und die Flags für die Bildnutzung in Gralloc-Nutzungsflags zu übersetzen. Dazu wird Folgendes aufgerufen:

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
);

Die Parameter format und imageUsage stammen aus der Struktur VkSwapchainCreateInfoKHR. Der Treiber sollte *grallocConsumerUsage und *grallocProducerUsage mit den für das Format und die Verwendung erforderlichen Gralloc-Nutzungsflags füllen. Die vom Treiber zurückgegebenen Nutzungs-Flags werden beim Zuweisen von Puffern mit den vom Swapchain-Consumer angeforderten Nutzungs-Flags kombiniert.

Unter Android 7.x wird eine frühere Version von VkSwapchainImageUsageFlagsANDROID() aufgerufen, nämlich vkGetSwapchainGrallocUsageANDROID(). Unter Android 8.0 und höher wird vkGetSwapchainGrallocUsageANDROID() eingestellt, aber vkGetSwapchainGrallocUsageANDROID() wird weiterhin aufgerufen, wenn vkGetSwapchainGrallocUsage2ANDROID() nicht vom Treiber bereitgestellt wird:

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

vkGetSwapchainGrallocUsageANDROID() unterstützt keine Swapchain-Nutzungsflags oder erweiterten Gralloc-Nutzungsflags.

Gralloc-basierte Bilder

VkNativeBufferANDROID ist eine vkCreateImage-Erweiterungsstruktur zum Erstellen eines Bildes, das von einem Gralloc-Puffer unterstützt wird. VkNativeBufferANDROID wird vkCreateImage() in der VkImageCreateInfo-Strukturkette bereitgestellt. Anrufe an vkCreateImage() mit VkNativeBufferANDROID erfolgen während des Anrufs an vkCreateSwapchainKHR. Bei der WSI-Implementierung wird die Anzahl der nativen Puffer zugewiesen, die für die Swapchain angefordert wurden, und dann wird für jeden Puffer ein VkImage erstellt:

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;

Beim Erstellen eines Gralloc-basierten Bildes enthält VkImageCreateInfo die folgenden Daten:

  .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

Unter Android 8.0 und höher stellt die Plattform eine VkSwapchainImageCreateInfoKHR-Erweiterungsstruktur in der VkImageCreateInfo-Kette bereit, die an vkCreateImage übergeben wird, wenn für die Swapchain Swapchain-Image-Nutzungsflags erforderlich sind. Die Erweiterungsstruktur enthält die Nutzungsflags für Swapchain-Bilder:

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

    VkSwapchainImageUsageFlagsANDROID      usage;
} VkSwapchainImageCreateInfoANDROID;

Unter Android 10 und höher unterstützt die Plattform VK_KHR_swapchain v70. Die Vulkan-App kann also ein VkImage erstellen, das durch Swapchain-Speicher unterstützt wird. Die App ruft zuerst vkCreateImage mit einer VkImageSwapchainCreateInfoKHR-Struktur auf, die mit der VkImageCreateInfo-Struktur verkettet ist. Anschließend ruft die App vkBindImageMemory2(KHR) mit einer VkBindImageMemorySwapchainInfoKHR-Struktur auf, die mit der VkBindImageMemoryInfo-Struktur verkettet ist. Der imageIndex, der in der VkBindImageMemorySwapchainInfoKHR-Struktur angegeben ist, muss ein gültiger Swapchain-Bildindex sein. Gleichzeitig stellt die Plattform der VkBindImageMemoryInfo-Kette eine VkNativeBufferANDROID-Erweiterungsstruktur mit den entsprechenden Gralloc-Pufferinformationen zur Verfügung, damit der Treiber weiß, an welchen Gralloc-Puffer die VkImage gebunden werden soll.

Bilder aufnehmen

vkAcquireImageANDROID übernimmt die Inhaberschaft eines Swapchain-Bildes und importiert einen extern signalisierten nativen Fence in ein vorhandenes VkSemaphore-Objekt und ein vorhandenes VkFence-Objekt:

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

vkAcquireImageANDROID() wird während vkAcquireNextImageKHR aufgerufen, um einen nativen Fence in die von der App bereitgestellten VkSemaphore- und VkFence-Objekte zu importieren. Sowohl Semaphore- als auch Fence-Objekte sind bei diesem Aufruf jedoch optional. Der Treiber kann diese Gelegenheit auch nutzen, um externe Änderungen am Gralloc-Pufferstatus zu erkennen und zu verarbeiten. Viele Treiber müssen hier nichts tun. Durch diesen Aufruf werden VkSemaphore und VkFence in denselben ausstehenden Status versetzt, als ob sie von vkQueueSubmit signalisiert würden. Warteschlangen können also auf das Semaphor und die App auf den Fence warten.

Beide Objekte werden signalisiert, wenn das zugrunde liegende native Fence signalisiert wird. Wenn das native Fence bereits signalisiert wurde, befindet sich das Semaphor beim Zurückgeben dieser Funktion im signalisierten Zustand. Der Treiber übernimmt den Besitz des Fence-Datei-Deskriptors und schließt ihn, wenn er nicht mehr benötigt wird. Der Treiber muss dies auch dann tun, wenn weder ein Semaphor- noch ein Fence-Objekt angegeben ist oder wenn vkAcquireImageANDROID fehlschlägt und einen Fehler zurückgibt. Wenn fenceFd gleich -1 ist, ist es so, als ob das native Fence bereits signalisiert wurde.

Bilder freigeben

vkQueueSignalReleaseImageANDROID bereitet ein Swapchain-Bild für die externe Verwendung vor, erstellt einen nativen Fence und plant, dass das Signal des nativen Fence nach dem Signal der Eingabesemaphore erfolgt:

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

vkQueuePresentKHR() ruft vkQueueSignalReleaseImageANDROID() für die bereitgestellte Warteschlange auf. Der Treiber muss einen nativen Fence erstellen, der erst signalisiert, wenn alle waitSemaphoreCount-Semaphore in pWaitSemaphores signalisieren und alle zusätzlichen Arbeiten zur Vorbereitung von image für die Präsentation abgeschlossen sind.

Wenn die Wartesemaphore (falls vorhanden) bereits signalisiert wurden und queue bereits im Leerlauf ist, kann der Treiber *pNativeFenceFd auf -1 anstelle eines tatsächlichen nativen Fence-Dateideskriptors setzen, um anzugeben, dass nichts zu warten ist. Der Aufrufer ist Eigentümer des in *pNativeFenceFd zurückgegebenen Dateideskriptors und schließt ihn.

Viele Treiber können den Bildparameter ignorieren, aber einige müssen möglicherweise CPU-seitige Datenstrukturen vorbereiten, die einem Gralloc-Puffer zugeordnet sind, damit sie von externen Bild-Consumern verwendet werden können. Das Vorbereiten von Pufferinhalten für die Verwendung durch externe Consumer muss asynchron erfolgen, wenn das Bild in VK_IMAGE_LAYOUT_PRESENT_SRC_KHR übergeht.

Wenn das Bild mit VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID erstellt wurde, muss der Treiber zulassen, dass vkQueueSignalReleaseImageANDROID() wiederholt aufgerufen wird, ohne dass zwischenzeitlich vkAcquireImageANDROID() aufgerufen wird.

Unterstützung für freigegebene präsentierbare Bilder

Auf einigen Geräten kann ein einzelnes Bild zwischen der Display-Pipeline und der Vulkan-Implementierung geteilt werden, um die Latenz zu minimieren. Unter Android 9 und höher bewirbt der Loader die Erweiterung VK_KHR_shared_presentable_image bedingt, basierend auf der Antwort des Treibers auf einen Aufruf von vkGetPhysicalDeviceProperties2.

Wenn der Treiber weder Vulkan 1.1 noch die Erweiterung VK_KHR_physical_device_properties2 unterstützt, gibt der Loader keine Unterstützung für gemeinsam genutzte präsentierbare Bilder an. Andernfalls fragt der Loader die Treiberfunktionen durch Aufrufen von vkGetPhysicalDeviceProperties2() ab und fügt die folgende Struktur in die VkPhysicalDeviceProperties2::pNext-Kette ein:

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

Wenn der Fahrer das Eigentum an einem Bild mit dem Displaysystem teilen kann, wird das sharedImage-Mitglied auf VK_TRUE gesetzt.

Zertifizierungsstufe

OEMs können ihre Vulkan-Implementierung mit CTS testen. CTS umfasst Folgendes:

  • Khronos Vulkan Conformance-Tests im CtsDeqpTestCases-Modul, die funktionale API-Tests für Vulkan 1.0, 1.1, 1.2, 1.3 und 1.4 umfassen.
  • Das CtsGraphicsTestCases-Modul, mit dem getestet wird, ob das Gerät für die unterstützten Vulkan-Funktionen richtig konfiguriert ist.

Vulkan-Funktions-Flag

Für die Bereitstellung des Feature-Flags android.software.vulkan.deqp.level ist ein Gerät mit Android 11 oder höher erforderlich, das die Vulkan API unterstützt. Der Wert dieses Feature-Flags ist ein Datum, das als Ganzzahl codiert ist. Gibt das Datum an, das mit den Vulkan-dEQP-Tests verknüpft ist, die das Gerät angeblich bestanden hat.

Ein Datum im Format JJJJ-MM-TT wird als 32-Bit-Ganzzahl codiert:

  • In den Bits 0–15 wird das Jahr gespeichert.
  • In den Bits 16–23 wird der Monat gespeichert.
  • In den Bits 24–31 wird der Tag gespeichert.

Der zulässige Mindestwert für das Funktions-Flag ist 0x07E30301, was dem Datum 2019-03-01 entspricht. Dieses Datum ist mit den Vulkan-dEQP-Tests für Android 10 verknüpft. Wenn das Feature-Flag mindestens diesen Wert hat, gibt das Gerät an, alle dEQP-Tests für Vulkan unter Android 10 bestanden zu haben.

Der Wert 0x07E40301 entspricht dem Datum 2020-03-01, das mit den Vulkan-dEQP-Tests für Android 11 verknüpft ist. Wenn das Feature-Flag mindestens diesen Wert hat, gibt das Gerät an, alle Vulkan dEQP-Tests für Android 11 zu bestehen.

Der Wert 0x07E60301 entspricht dem Datum 2022-03-01, das dem Datum der Vulkan-dEQP-Tests für Android 13 entspricht. Wenn das Feature-Flag mindestens diesen Wert hat, gibt das Gerät an, alle dEQP-Tests für Vulkan unter Android 13 bestanden zu haben.

Ein Gerät, das ein bestimmtes Feature-Flag (z. B. 0x07E30301, 0x07E40301, 0x07E60301) bereitstellt, gibt an, dass es alle Android Vulkan dEQP-Tests für dieses Feature-Flag (Android 10, Android 11 bzw. Android 13) besteht. Dieses Gerät besteht möglicherweise die Vulkan-dEQP-Tests einer späteren Android-Version.

Vulkan dEQP ist Teil von Android CTS. Ab Android 11 berücksichtigt die dEQP-Testrunner-Komponente von CTS das android.software.vulkan.deqp.level-Funktionsflag und überspringt alle Vulkan-dEQP-Tests, die das Gerät laut diesem Funktionsflag nicht unterstützt. Solche Tests werden als trivial bestanden gemeldet.