Vulkan 구현

Vulkan은 고성능 3D 그래픽을 위한 오버헤드가 낮은 크로스 플랫폼 API입니다. OpenGL ES(GLES)와 마찬가지로 Vulkan은 앱에서 고품질의 실시간 그래픽을 만들 수 있는 도구를 제공합니다. Vulkan을 사용하면 CPU 오버헤드를 줄이고 SPIR-V 바이너리 중간 언어를 지원하는 등의 이점을 얻을 수 있습니다.

Vulkan을 구현하려면 기기에 다음이 포함되어야 합니다.

  • Android 기반의 Vulkan 로더
  • Vulkan API를 구현하며 GPU IHV와 같은 SoC에서 제공하는 Vulkan 드라이버. Vulkan 기능을 지원하려면 Android 기기에 Vulkan 지원 GPU 하드웨어 및 관련 드라이버가 필요합니다. 또한 GPU는 GLES 3.1 이상을 지원해야 합니다. SoC 공급업체에 문의하여 드라이버 지원을 요청하세요.

기기에 Vulkan 드라이버가 있는 경우 기기의 기능을 정확하게 반영하는 버전으로 FEATURE_VULKAN_HARDWARE_LEVELFEATURE_VULKAN_HARDWARE_VERSION 시스템 기능을 선언해야 합니다. 이렇게 하면 기기가 호환성 정의 문서(CDD)를 준수할 수 있습니다.

Vulkan 로더

Vulkan 로더 platform/frameworks/native/vulkan은 Vulkan 앱과 기기의 Vulkan 드라이버 간의 기본 인터페이스입니다. Vulkan 로더는 /system/lib[64]/libvulkan.so에 설치됩니다. 로더는 핵심 Vulkan API 진입점, Android CDD에서 요구하는 확장 프로그램의 진입점 및 다양한 추가 확장 프로그램을 제공합니다. Window System Integration(WSI) 확장 프로그램은 로더를 통해 내보내지고 드라이버보다 로더에서 주로 구현됩니다. 또한 로더는 추가 확장 프로그램을 노출하고 드라이버로 이동 중인 핵심 API 호출을 가로챌 수 있는 레이어의 열거 및 로드를 지원합니다.

NDK에는 연결을 위한 스텁 libvulkan.so 라이브러리가 포함되어 있습니다. 라이브러리는 로더와 동일한 기호를 내보냅니다. 앱은 실제 libvulkan.so 라이브러리에서 내보낸 함수를 호출하여 로더의 트램펄린 함수에 진입하고, 이 함수는 첫 번째 인수에 따라 적절한 레이어 또는 드라이버로 전달됩니다. vkGet*ProcAddr() 호출은 트램펄린이 전달되는 함수 포인터를 반환합니다. 즉, 핵심 API 코드로 직접 호출합니다. 내보낸 기호가 아닌 함수 포인터를 통해 호출하면 트램펄린과 전달을 건너뛰므로 더 효율적입니다.

드라이버 열거 및 로드

시스템 이미지가 구축되면 Android는 시스템에서 사용 가능한 GPU를 파악할 수 있기를 원합니다. 로더는 hardware.h의 기존 HAL 메커니즘을 사용하여 드라이버를 검색하고 로드합니다. 32비트 및 64비트 Vulkan 드라이버의 기본 경로는 다음과 같습니다.

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

Android 7.0 이상에서는 Vulkan hw_module_t 파생이 단일 hw_module_t 구조를 래핑합니다. 하나의 드라이버만 지원되며 상수 문자열인 HWVULKAN_DEVICE_0open()으로 전달됩니다.

Vulkan hw_device_t 파생은 여러 실제 기기를 지원할 수 있는 단일 드라이버에 상응합니다. hw_device_t 구조를 확장하여 vkGetGlobalExtensionProperties(), vkCreateInstance(), vkGetInstanceProcAddr() 함수를 내보낼 수 있습니다. 로더는 hw_device_t 구조의 vkGetInstanceProcAddr()을 호출하여 다른 모든 VkInstance(), VkPhysicalDevice(), vkGetDeviceProcAddr() 함수를 찾을 수 있습니다.

레이어 검색 및 로드

Vulkan 로더는 추가 확장 프로그램을 노출하고 드라이버에 전달되는 핵심 API 호출을 가로챌 수 있는 레이어를 열거하고 로드할 수 있습니다. Android의 시스템 이미지에는 레이어가 포함되지 않지만 앱의 APK에는 레이어가 포함될 수 있습니다.

레이어를 사용할 때 Android의 보안 모델과 정책은 다른 플랫폼과 크게 다르다는 점에 유의하세요. 특히 Android는 루팅되지 않은 프로덕션 기기의 디버그할 수 없는 프로세스로 외부 코드를 로드하거나 외부 코드가 프로세스의 메모리, 상태 등을 검사 또는 제어하는 것을 허용하지 않습니다. 또한 나중에 검사할 수 있도록 코어 덤프, API 트레이스 등을 디스크에 저장하는 것도 금지됩니다. 디버그할 수 없는 앱의 일부로 제공되는 레이어만 프로덕션 기기에서 사용되며 드라이버는 이러한 정책을 위반하는 기능을 제공해서는 안 됩니다.

레이어의 사용 사례는 다음과 같습니다.

  • 개발 시간 레이어 - 프로덕션 기기의 시스템 이미지에 추적/프로파일링/디버깅 도구의 유효성 검사 계층과 shim을 설치해서는 안 됩니다. 추적/프로파일링/디버깅 도구의 유효성 검사 계층과 shim은 시스템 이미지 없이도 업데이트할 수 있어야 합니다. 예를 들어 개발 중에 이러한 레이어 중 하나를 사용하려는 개발자는 네이티브 라이브러리 디렉터리에 파일을 추가하여 앱 패키지를 수정할 수 있습니다. 수정 불가능한 앱을 제공할 수 없는 오류를 진단하려는 IHV 및 OEM 엔지니어는 디버그 가능한 앱이 아닌 경우 시스템 이미지의 루팅된 비프로덕션 빌드에 액세스할 수 있다고 간주됩니다. 자세한 내용은 Android의 Vulkan 유효성 검사 계층을 참고하세요.
  • 유틸리티 레이어 - 이 레이어는 기기 메모리용 메모리 관리자를 구현하는 레이어와 같은 확장 프로그램을 노출합니다. 개발자는 앱에서 사용할 레이어와 레이어의 버전을 선택해야 합니다. 동일한 레이어를 사용하는 여러 앱에서는 다른 버전을 계속 사용할 수 있습니다. 개발자는 앱 패키지에 제공할 레이어를 선택해야 합니다.
  • 삽입된(암시적) 레이어 - 프레임 속도, 소셜 네트워크, 게임 런처 오버레이 등 앱의 인지나 동의 없이 사용자 또는 일부 기타 앱에서 제공하는 레이어가 포함됩니다. 이러한 레이어는 Android의 보안 정책을 위반하므로 지원되지 않습니다.

디버그할 수 없는 앱의 경우 로더는 앱의 네이티브 라이브러리 디렉터리의 레이어만 검색하고 특정 패턴과 일치하는 이름을 가진 라이브러리를 로드하려고 시도합니다(예: libVKLayer_foo.so).

디버그할 수 있는 앱의 경우 로더는 /data/local/debug/vulkan의 레이어를 검색하고 특정 패턴과 일치하는 라이브러리를 로드하려고 시도합니다.

Android는 Android와 다른 플랫폼 간의 빌드 환경 변경사항을 반영하여 레이어를 포팅할 수 있습니다. 레이어와 로더 간의 인터페이스에 관한 자세한 내용은 Vulkan 로더 인터페이스의 아키텍처를 참고하세요. Khronos에서 관리하는 유효성 검사 계층은 Vulkan 유효성 검사 계층에 호스팅됩니다.

Vulkan API 버전 및 기능

다음 표에는 여러 Android 버전의 Vulkan API 버전이 나와 있습니다.
Android 버전 Vulkan 버전
Android 13 Vulkan 1.3
Android 9 Vulkan 1.1
Android 7 Vulkan 1.0

Vulkan 1.3 기능 개요

Vulkan 1.3은 이전의 다양한 선택적 확장 프로그램을 Vulkan 핵심 기능으로 정규화합니다. 이 기능 중 상당 부분은 Vulkan 프로그래밍 인터페이스를 통해 제어 및 세부사항을 개선하고자 하는 의도로 포함되었습니다. 단일 패스 렌더 패스 인스턴스에는 더 이상 렌더 패스 객체 또는 프레임 버퍼가 필요하지 않습니다. 파이프라인 상태 객체의 총 개수는 줄일 수 있으며 API 내 동기화가 정비되었습니다. Vulkan 1.3은 Vulkan 1.2, 1.1, 1.0과 하드웨어 요구사항이 동일하지만 대부분은 프레임워크가 아닌 SoC 전용 그래픽 드라이버를 통해 구현됩니다.

Android에서 가장 중요한 Vulkan 1.3의 기능은 다음과 같습니다.

  • 단일 패스 렌더 패스 인스턴스 지원
  • 셰이더 호출의 즉시 종료 지원
  • 파이프라인 생성, 공유, 제어에 관한 세부사항

또한 Vulkan 1.3에는 여러 소규모 기능과 API 사용성 개선사항이 포함됩니다. 부 버전 1.3을 사용하는 핵심 Vulkan API의 모든 변경사항은 핵심 버전(Vulkan 1.3)에서 확인할 수 있습니다.

Vulkan 1.2 기능 개요

Vulkan 1.2는 API 노출 영역을 단순화하는 여러 기능과 확장 프로그램을 추가합니다. 여기에는 통합된 메모리 모델 및 기기 드라이버에서 쿼리할 수 있는 추가 정보가 포함됩니다. Vulkan 1.2는 Vulkan 1.0과 하드웨어 요구사항이 동일하지만 모두 프레임워크가 아닌 SOC 전용 그래픽 드라이버를 통해 구현됩니다.

가장 중요한 Android Vulkan 1.2 기능은 8비트 저장소 지원 기능입니다.

또한 Vulkan 1.2에는 여러 소규모 기능과 API 사용성 개선사항이 포함됩니다. 부 버전 1.2를 사용하는 핵심 Vulkan API의 모든 변경사항은 핵심 버전(Vulkan 1.2)에서 확인할 수 있습니다.

Vulkan 1.1 기능 개요

Vulkan 1.1에는 OEM이 기기에서 Vulkan 1.1을 지원할 수 있도록 하는 메모리/동기화 상호 운용 관련 지원이 포함됩니다. 또한 메모리/동기화 상호 운용을 통해 개발자는 Vulkan 1.1이 기기에서 지원되는지 확인할 수 있으며, 지원되는 경우 이를 기기에서 효과적으로 사용할 수 있습니다. Vulkan 1.1은 Vulkan 1.0과 하드웨어 요구사항이 동일하지만 대부분은 프레임워크가 아닌 SOC 전용 그래픽 드라이버를 통해 구현됩니다.

Android에서 가장 중요한 Vulkan 1.1의 기능은 다음과 같습니다.

  • 카메라, 코덱, GLES 관련 상호 운용을 위해 Vulkan 외부의 메모리 버퍼 및 동기화 객체 가져오기 및 내보내기 지원
  • YCbCr 형식 지원

또한 Vulkan 1.1에는 여러 소규모 기능과 API 사용성 개선사항이 포함됩니다. 부 버전 1.1을 사용하는 핵심 Vulkan API의 모든 변경사항은 핵심 버전(Vulkan 1.1)에서 확인할 수 있습니다.

Vulkan 지원 선택

Android 기기는 64비트 ABI를 지원하고 메모리가 적지 않은 경우에는 사용 가능한 고급 Vulkan 기능 집합을 지원해야 합니다.

Android 13 이상으로 출시되는 기기는 Vulkan 1.3을 지원해야 합니다.

Android 10을 통해 실행되는 기기는 Vulkan 1.1을 지원해야 합니다.

그 외 기기에서는 Vulkan 1.3, 1.2, 1.1을 선택적으로 지원할 수 있습니다.

Vulkan 버전 지원

Android 기기는 다음 조건이 충족되는 경우 Vulkan 버전을 지원합니다.

  1. 원하는 Vulkan 버전(Vulkan 버전 1.3, 1.1, 1.0 중 하나여야 함)을 지원하는 Vulkan 드라이버를 Android 버전의 추가 CDD 요구사항과 함께 추가함 또는 이보다 낮은 vulkan 버전 번호의 기존 Vulkan 드라이버를 업데이트함.
  2. Vulkan 1.3 또는 1.1의 경우 패키지 관리자를 통해 반환된 시스템 기능이 올바른 vulkan 버전에 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
      

Window System Integration(WSI)

libvulkan.so에서 드라이버는 다음과 같은 Window System Integration(WSI) 확장 프로그램을 구현합니다.

  • VK_KHR_surface
  • VK_KHR_android_surface
  • VK_KHR_swapchain
  • Android 10에서만 Vulkan 1.1용으로 구현되는 VK_KHR_driver_properties
  • Android 10에서 모든 Vulkan 버전용으로 구현되는 VK_GOOGLE_display_timing

VkSurfaceKHR 객체와 VkSwapchainKHR 객체, 그리고 ANativeWindow와의 모든 상호작용은 플랫폼에 의해 처리되며 드라이버에 노출되지 않습니다. WSI 구현은 드라이버에서 지원해야 하는 VK_ANDROID_native_buffer 확장 프로그램을 사용합니다. 이 확장 프로그램은 WSI 구현에서만 사용되며 앱에 노출되지 않습니다.

Gralloc 사용 플래그

Vulkan을 구현하려면 구현이 정의된 비공개 Gralloc 사용 플래그를 통해 swapchain 버퍼를 할당해야 할 수 있습니다. 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
);

formatimageUsage 매개변수는 VkSwapchainCreateInfoKHR 구조에서 가져옵니다. 드라이버는 형식과 사용에 필요한 Gralloc 사용 플래그로 *grallocConsumerUsage*grallocProducerUsage를 채워야 합니다. 드라이버에 의해 반환된 사용 플래그는 버퍼를 할당할 때 swapchain 소비자가 요청한 사용 플래그와 결합됩니다.

Android 7.x에서는 이름이 vkGetSwapchainGrallocUsageANDROID()VkSwapchainImageUsageFlagsANDROID()의 이전 버전을 호출합니다. Android 8.0 이상에서는 vkGetSwapchainGrallocUsageANDROID()를 지원하지 않지만 드라이버에서 vkGetSwapchainGrallocUsage2ANDROID()를 제공하지 않는 경우 vkGetSwapchainGrallocUsageANDROID()를 계속 호출합니다.

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

vkGetSwapchainGrallocUsageANDROID()는 swapchain 사용 플래그나 확장된 Gralloc 사용 플래그를 지원하지 않습니다.

Gralloc 지원 이미지

VkNativeBufferANDROID는 Gralloc 버퍼에서 지원하는 이미지를 생성하기 위한 vkCreateImage 확장 프로그램 구조입니다. VkNativeBufferANDROIDVkImageCreateInfo 구조 체인의 vkCreateImage()에 제공됩니다. vkCreateSwapchainKHR가 호출되는 동안 VkNativeBufferANDROID를 통해 vkCreateImage()가 호출됩니다. 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

Android 8.0 이상에서 플랫폼은 swapchain에 swapchain 이미지 사용 플래그가 필요한 경우 vkCreateImage에 제공되는 VkImageCreateInfo 체인의 VkSwapchainImageCreateInfoKHR 확장 구조를 제공합니다. 확장 구조에는 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 앱에서 swapchain 메모리가 지원하는 VkImage를 만들 수 있습니다. Vulkan 앱은 먼저 VkImageSwapchainCreateInfoKHR 구조가 VkImageCreateInfo 구조에 연결된 vkCreateImage를 호출합니다. 그런 다음 VkBindImageMemorySwapchainInfoKHR 구조가 VkBindImageMemoryInfo 구조에 연결된 vkBindImageMemory2(KHR)를 호출합니다. VkBindImageMemorySwapchainInfoKHR 구조에 지정된 imageIndex는 유효한 swapchain 이미지 색인이어야 합니다. 한편 플랫폼은 상응하는 Gralloc 버퍼 정보가 있는 VkNativeBufferANDROID 확장 구조를 VkBindImageMemoryInfo 체인에 제공하므로 드라이버는 VkImage를 바인딩할 Gralloc 버퍼를 식별할 수 있습니다.

이미지 획득

vkAcquireImageANDROID는 swapchain 이미지의 소유권을 획득하고 외부에서 신호를 받는 네이티브 펜스를 기존의 VkSemaphore 객체와 VkFence 객체로 가져옵니다.

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

앱에서 제공하는 VkSemaphoreVkFence 객체로 네이티브 펜스를 가져오기 위해 vkAcquireNextImageKHR이 실행되는 동안 vkAcquireImageANDROID()가 호출됩니다. 하지만 세마포어와 펜스 객체는 이 호출에서 선택사항입니다. 드라이버는 이 기회를 사용하여 Gralloc 버퍼 상태의 모든 외부 변경사항을 인식하고 처리할 수도 있습니다. 이때 드라이버의 대다수는 아무것도 처리할 필요가 없습니다. 이 호출은 vkQueueSubmit에서 신호를 보낸 경우 VkSemaphoreVkFence를 동일한 대기 상태로 전환하므로 대기열은 세마포어를 기다릴 수 있으며 앱은 펜스를 기다릴 수 있습니다.

두 객체는 기본 네이티브 펜스가 신호를 보낼 때 신호를 받습니다. 네이티브 펜스가 이미 신호를 보낸 경우 세마포어는 이 함수가 반환될 때 신호를 받은 상태가 됩니다. 드라이버는 펜스 파일 설명자의 소유권을 가져오며 펜스 파일 설명자가 더 이상 필요하지 않을 때 이를 닫습니다. 드라이버는 세마포어와 펜스 객체가 모두 제공되지 않거나 vkAcquireImageANDROID가 실패하여 오류를 반환하더라도 동일하게 작동해야 합니다. fenceFd가 -1이면 네이티브 펜스가 이미 신호를 받은 것으로 간주됩니다.

이미지 릴리스

vkQueueSignalReleaseImageANDROID는 외부 사용을 위한 swapchain 이미지를 준비하고, 네이티브 펜스를 만들고, 입력 세마포어가 신호를 보낸 후 이 신호를 받을 네이티브 펜스를 예약합니다.

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

vkQueuePresentKHR()은 제공된 대기열에 있는 vkQueueSignalReleaseImageANDROID()를 호출합니다. 드라이버는 pWaitSemaphores의 모든 waitSemaphoreCount 세마포어가 신호를 보내고 image의 표시를 위해 필요한 모든 추가 작업이 완료될 때까지 신호를 보내지 않는 네이티브 펜스를 만들어야 합니다.

대기 상태인 세마포어가 이미 신호를 보냈으며 queue가 이미 유휴 상태인 경우, 드라이버는 *pNativeFenceFd를 실제 네이티브 펜스 파일 설명자 대신 -1로 설정하여 기다릴 대상이 없음을 나타낼 수 있습니다. 호출자는 *pNativeFenceFd에서 반환된 파일 설명자를 소유하고 이를 닫습니다.

드라이버의 대다수는 이미지 매개변수를 무시할 수 있지만 일부는 외부 이미지 소비자가 사용할 수 있도록 Gralloc 버퍼와 연결된 CPU 측 데이터 구조를 준비해야 할 수 있습니다. 외부 소비자가 사용할 수 있도록 버퍼 콘텐츠를 준비하는 작업은 이미지를 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR로 전환하는 과정에서 비동기적으로 처리되어야 합니다.

이미지가 VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID를 통해 생성된 경우 드라이버는 vkAcquireImageANDROID() 호출에 개입할 필요 없이 vkQueueSignalReleaseImageANDROID()가 반복적으로 호출될 수 있도록 해야 합니다.

공유된 표시 가능 이미지 지원

일부 기기에서는 디스플레이 파이프라인과 Vulkan 구현 간에 단일 이미지의 소유권을 공유하여 지연 시간을 최소화할 수 있습니다. Android 9 이상에서는 vkGetPhysicalDeviceProperties2 호출에 대한 드라이버의 응답에 따라 로더가 조건부로 VK_KHR_shared_presentable_image 확장을 알립니다.

드라이버가 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은 다음을 포함하는 CTS를 사용하여 Vulkan 구현을 테스트할 수 있습니다.

  • Vulkan 1.0, 1.1, 1.2, 1.3용 기능적 API 테스트가 포함된 CtsDeqpTestCases 모듈에서 이루어지는 Khronos Vulkan 적합성 테스트
  • 기기가 지원하는 Vulkan 기능에 적합하게 구성되었는지 기기를 테스트하는 CtsGraphicsTestCases 모듈

Vulkan 기능 플래그

Android 11 이상과 Vulkan API를 지원하는 기기는 android.software.vulkan.deqp.level 기능 플래그를 노출해야 합니다. 이 기능 플래그의 값은 날짜이며 정숫값으로 인코딩됩니다. 기기에서 통과했다고 명시하는 Vulkan dEQP 테스트와 연관된 날짜를 지정합니다.

YYYY-MM-DD의 날짜 형식은 다음과 같이 32비트 정수로 인코딩됩니다.

  • 0~15비트: 연도 저장
  • 16~23비트: 월 저장
  • 24~31비트: 일 저장

기능 플래그에 허용되는 최솟값은 0x07E30301로, Android 10의 Vulkan dEQP 테스트와 연관된 날짜인 2019년 3월 1일에 해당하는 값입니다. 기능 플래그가 이 값 이상이면 기기에서 모든 Android 10 Vulkan dEQP 테스트를 통과했다고 명시합니다.

0x07E40301 값은 2020년 3월 1일에 해당하며 이는 Android 11의 Vulkan dEQP 테스트와 연결된 날짜입니다. 기능 플래그가 이 값 이상이면 기기에서 모든 Android 11 Vulkan dEQP 테스트를 통과했다고 명시합니다.

0x07E60301 값은 2022년 3월 1일에 해당하며 이는 Android 13의 Vulkan dEQP 테스트와 연결된 날짜입니다. 기능 플래그가 이 값 이상이면 기기에서 모든 Android 13 Vulkan dEQP 테스트를 통과했다고 명시합니다.

특정 기능 플래그( 0x07E30301, 0x07E40301, 0x07E60301)를 노출하는 기기는 그 기능 플래그의 모든 Android Vulkan dEQP 테스트(Android 10, Android 11, Android 13 각각)를 통과했다고 명시합니다. 이 기기는 이후 Android 버전에서 Vulkan dEQP 테스트를 통과할 수도 있습니다.

Vulkan dEQP는 Android CTS 일부를 구성합니다. Android 11에서 CTS의 dEQP 테스트 실행자 구성요소는 android.software.vulkan.deqp.level 기능 플래그를 인식하고 이 기능 플래그에 따라 기기에서 지원한다고 명시하지 않은 모든 Vulkan dEQP 테스트를 건너뜁니다. 이러한 테스트는 쉽게 통과한 것으로 보고됩니다.