Android पर Vulkan की पुष्टि करने वाली लेयर

ज़्यादातर साफ़ तौर पर जानकारी देने वाले ग्राफ़िक्स एपीआई गड़बड़ी की जांच नहीं करते, क्योंकि ऐसा करने से की वजह से परफ़ॉर्मेंस पर जुर्माना लग सकता है. Vulkan में पुष्टि करने के लिए लेयर इस्तेमाल की जाती हैं, जो डेवलपमेंट के दौरान गड़बड़ी की जांच करते हैं और परफ़ॉर्मेंस पर लगने वाले जुर्माने से बचते हैं अपने ऐप्लिकेशन का बिल्ड रिलीज़ करना ज़रूरी है. पुष्टि करने वाली लेयर, सामान्य मकसद पर निर्भर करती हैं एपीआई के एंट्री पॉइंट में रुकावट डालने वाला लेयरिंग सिस्टम.

सिंगल क्रोनोस वैलिडेशन लेयर

पहले, Vulkan ने पुष्टि करने के लिए कई लेयर उपलब्ध कराई थीं. इन लेयर को चालू करना पड़ता था एक खास क्रम में. 1.1.106.0 Vulkan SDK वर्शन रिलीज़ होने के बाद, आपका ऐप्लिकेशन सिर्फ़ एक बार पुष्टि करने की सुविधा चालू करनी होगी लेयर, VK_LAYER_KHRONOS_validation का इस्तेमाल करके, पिछली सभी सुविधाओं का ऐक्सेस पाएं वैलिडेशन लेयर.

अपने APK में पैकेज की गई पुष्टि करने वाली लेयर का इस्तेमाल करें

आपके APK में पैकेजिंग वैलिडेशन लेयर की मदद से, यह पक्का किया जाता है कि वे बेहतर तरीके से काम कर रहे हैं या नहीं. पुष्टि करने वाली लेयर, पहले से बनी बाइनरी के तौर पर उपलब्ध होती हैं या इन्हें इनसे बनाया जा सकता है सोर्स कोड.

पहले से बनी बाइनरी का इस्तेमाल करें

GitHub से, Android Vulkan की पुष्टि करने वाली लेयर की सबसे नई बाइनरी डाउनलोड करें रिलीज़ पेज पर जाएं.

अपने APK में लेयर जोड़ने का सबसे आसान तरीका, पहले से बनी हुई लेयर को एक्सट्रैक्ट करना है आपके मॉड्यूल की src/main/jniLibs/ डायरेक्ट्री में, एबीआई के साथ बाइनरी डायरेक्ट्री (जैसे कि arm64-v8a या x86-64) बरकरार हैं, इस तरह:

src/main/jniLibs/
  arm64-v8a/
    libVkLayer_khronos_validation.so
  armeabi-v7a/
    libVkLayer_khronos_validation.so
  x86/
    libVkLayer_khronos_validation.so
  x86-64/
    libVkLayer_khronos_validation.so

सोर्स कोड से पुष्टि करने वाली लेयर बनाएं

पुष्टि करने वाले लेयर के सोर्स कोड में डीबग करने के लिए, ख्रोनोस ग्रुप GitHub डेटा स्टोर करने की जगह पर जाएं और बिल्ड के निर्देश दिए गए हैं.

पुष्टि करना कि पुष्टि करने वाली लेयर सही तरीके से पैकेज की गई है

इससे कोई फ़र्क़ नहीं पड़ता कि आपने पहले से बनीKronos की लेयर या बनाई हुई लेयर का इस्तेमाल किया है या नहीं बनाने पर, आपके APK में एक फ़ाइनल फ़ाइल स्ट्रक्चर तैयार होता है, जैसे कि निम्न:

lib/
  arm64-v8a/
    libVkLayer_khronos_validation.so
  armeabi-v7a/
    libVkLayer_khronos_validation.so
  x86/
    libVkLayer_khronos_validation.so
  x86-64/
    libVkLayer_khronos_validation.so

निम्न आदेश यह सत्यापित करने का तरीका दिखाता है कि आपके APK में सत्यापन शामिल है या नहीं लेयर उम्मीद के मुताबिक:

$ jar -tf project.apk | grep libVkLayer
lib/x86_64/libVkLayer_khronos_validation.so
lib/armeabi-v7a/libVkLayer_khronos_validation.so
lib/arm64-v8a/libVkLayer_khronos_validation.so
lib/x86/libVkLayer_khronos_validation.so

इंस्टेंस बनाते समय, पुष्टि करने वाली लेयर चालू करें

Vulkan API, इंस्टेंस बनाते समय ऐप्लिकेशन को लेयर चालू करने की अनुमति देता है. एंट्री जिन पॉइंट को लेयर इंटरसेप्ट करता है उनमें से एक ऑब्जेक्ट पहला पैरामीटर:

  • VkInstance
  • VkPhysicalDevice
  • VkDevice
  • VkCommandBuffer
  • VkQueue

vkEnumerateInstanceLayerProperties() पर कॉल करें का इस्तेमाल करें. Vulkan लेयर को तब चालू करता है, जब vkCreateInstance() लागू करता है.

नीचे दिया गया कोड स्निपेट दिखाता है कि कोई ऐप्लिकेशन, Vulkan API का इस्तेमाल इन कामों के लिए कैसे कर सकता है प्रोग्राम के हिसाब से क्वेरी करें और लेयर चालू करें:

// Enable just the Khronos validation layer.
static const char *layers[] = {"VK_LAYER_KHRONOS_validation"};

// Get the layer count using a null pointer as the last parameter.
uint32_t instance_layer_present_count = 0;
vkEnumerateInstanceLayerProperties(&instance_layer_present_count, nullptr);

// Enumerate layers with a valid pointer in the last parameter.
VkLayerProperties layer_props[instance_layer_present_count];
vkEnumerateInstanceLayerProperties(&instance_layer_present_count, layer_props);

// Make sure selected validation layers are available.
VkLayerProperties *layer_props_end = layer_props + instance_layer_present_count;
for (const char* layer:layers) {
  assert(layer_props_end !=
  std::find_if(layer_props, layer_props_end, [layer](VkLayerProperties layerProperties) {
    return strcmp(layerProperties.layerName, layer) == 0;
  }));
}

// Create a Vulkan instance, requesting all enabled layers or extensions
// available on the system
VkInstanceCreateInfo instanceCreateInfo{
  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
  .pNext = nullptr,
  .pApplicationInfo = &appInfo,
  .enabledLayerCount = sizeof(layers) / sizeof(layers[0]),
  .ppEnabledLayerNames = layers,

डिफ़ॉल्ट लॉगकैट आउटपुट

पुष्टि करने वाली लेयर, लॉगकैट में चेतावनी और गड़बड़ी के मैसेज दिखाता है. इस तरह के मैसेज से लेबल किए गए VALIDATION टैग. पुष्टि करने वाली लेयर का मैसेज कुछ ऐसा दिखता है ( आसानी से स्क्रोल करने के लिए यहां लाइन ब्रेक जोड़े गए हैं):

Validation -- Validation Error:
  [ VUID-VkDeviceQueueCreateInfo-pQueuePriorities-parameter ]
Object 0: VK_NULL_HANDLE, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xd6d720c6 |
vkCreateDevice: required parameter
  pCreateInfo->pQueueCreateInfos[0].pQueuePriorities specified as NULL.
The Vulkan spec states: pQueuePriorities must be a valid pointer to an array of
  queueCount float values
  (https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html
  #VUID-VkDeviceQueueCreateInfo-pQueuePriorities-parameter)

डीबग कॉलबैक चालू करें

Debug Utils एक्सटेंशन VK_EXT_debug_utils की मदद से आपका ऐप्लिकेशन डीबग मैसेंजर, जो ऐप्लिकेशन से दिए गए किसी ऐप्लिकेशन को पुष्टि करने वाली लेयर के मैसेज भेजता है कॉलबैक. आपका डिवाइस इस एक्सटेंशन को लागू नहीं कर सकता, लेकिन इसे सबसे हाल की पुष्टि लेयर. इसे कॉल किया गया एक बहिष्कृत एक्सटेंशन भी है VK_EXT_debug_report, जिससे मिलती-जुलती सुविधाएं मिलती हैं, अगर VK_EXT_debug_utils उपलब्ध नहीं है.

Debug Utils एक्सटेंशन का इस्तेमाल करने से पहले, पक्का करें कि आपका डिवाइस या एक लोड की गई पुष्टि करने वाली लेयर इसके साथ काम करती हो. नीचे दिए गए उदाहरण में, यह पता लगाना कि डीबग यूटिल्स एक्सटेंशन काम करता है या नहीं. साथ ही, कॉलबैक को रजिस्टर करें, अगर यह एक्सटेंशन, डिवाइस या पुष्टि करने वाली लेयर के साथ काम करता है.

// Get the instance extension count.
uint32_t inst_ext_count = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, nullptr);

// Enumerate the instance extensions.
VkExtensionProperties inst_exts[inst_ext_count];
vkEnumerateInstanceExtensionProperties(nullptr, &inst_ext_count, inst_exts);

// Check for debug utils extension within the system driver or loader.
// Check if the debug utils extension is available (in the driver).
VkExtensionProperties *inst_exts_end = inst_exts + inst_ext_count;
bool debugUtilsExtAvailable = inst_exts_end !=
  std::find_if(inst_exts, inst_exts_end, [](VkExtensionProperties
    extensionProperties) {
    return strcmp(extensionProperties.extensionName,
      VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0;
  });

if ( !debugUtilsExtAvailable ) {
  // Also check the layers for the debug utils extension.
  for (auto layer: layer_props) {
    uint32_t layer_ext_count;
    vkEnumerateInstanceExtensionProperties(layer.layerName, &layer_ext_count,
      nullptr);
    if (layer_ext_count == 0) continue;
    VkExtensionProperties layer_exts[layer_ext_count];
    vkEnumerateInstanceExtensionProperties(layer.layerName, &layer_ext_count,
    layer_exts);

    VkExtensionProperties * layer_exts_end = layer_exts + layer_ext_count;
    debugUtilsExtAvailable = layer_exts != std::find_if(
      layer_exts, layer_exts_end,[](VkExtensionProperties extensionProperties) {
        return strcmp(extensionProperties.extensionName,
        VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0;
      });
    if (debugUtilsExtAvailable) {
        // Add the including layer into the layer request list if necessary.
        break;
    }
  }
}

if (!debugUtilsExtAvailable) return; // since this snippet depends on debugUtils

const char * enabled_inst_exts[] = { ..., VK_EXT_DEBUG_UTILS_EXTENSION_NAME };
uint32_t enabled_extension_count =
  sizeof(enabled_inst_exts)/sizeof(enabled_inst_exts[0]);

// Pass the instance extensions into vkCreateInstance.
VkInstanceCreateInfo instance_info = {};
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_info.enabledExtensionCount = enabled_extension_count;
instance_info.ppEnabledExtensionNames = enabled_inst_exts;

// NOTE: Can still return VK_ERROR_EXTENSION_NOT_PRESENT if validation layer
// isn't loaded.
vkCreateInstance(&instance_info, nullptr, &instance);

auto pfnCreateDebugUtilsMessengerEXT =
  (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
    tutorialInstance, "vkCreateDebugUtilsMessengerEXT");
auto pfnDestroyDebugUtilsMessengerEXT =
  (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
    tutorialInstance, "vkDestroyDebugUtilsMessengerEXT");

// Create the debug messenger callback with your the settings you want.
VkDebugUtilsMessengerEXT debugUtilsMessenger;
if (pfnCreateDebugUtilsMessengerEXT) {
  VkDebugUtilsMessengerCreateInfoEXT messengerInfo;
  constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog =
    VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
    VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;

constexpr VkDebugUtilsMessageTypeFlagsEXT kMessagesToLog =
  VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
  VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
  VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;

  messengerInfo.sType           = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
  messengerInfo.pNext           = nullptr;
  messengerInfo.flags           = 0;
  messengerInfo.messageSeverity = kSeveritiesToLog;
  messengerInfo.messageType     = kMessagesToLog;

  // The DebugUtilsMessenger callback is explained in the following section.
  messengerInfo.pfnUserCallback = &DebugUtilsMessenger;
  messengerInfo.pUserData       = nullptr; // Custom user data passed to callback

  pfnCreateDebugUtilsMessengerEXT(instance, &messengerInfo, nullptr,
    &debugUtilsMessenger);
}

// Later, when shutting down Vulkan, call the following:
if (pfnDestroyDebugUtilsMessengerEXT) {
    pfnDestroyDebugUtilsMessengerEXT(instance, debugUtilsMessenger, nullptr);
}

जब आपका ऐप्लिकेशन रजिस्टर हो जाता है और कॉलबैक चालू हो जाता है, तब सिस्टम डीबग करता है उसे मैसेज कर सकता है.

#include <android/log.h>

VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsMessenger(
                        VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
                        VkDebugUtilsMessageTypeFlagsEXT messageTypes,
                        const VkDebugUtilsMessengerCallbackDataEXT *callbackData,
                        void *userData)
{
  const char validation[]  = "Validation";
  const char performance[] = "Performance";
  const char error[]       = "ERROR";
  const char warning[]     = "WARNING";
  const char unknownType[] = "UNKNOWN_TYPE";
  const char unknownSeverity[] = "UNKNOWN_SEVERITY";
  const char* typeString      = unknownType;
  const char* severityString  = unknownSeverity;
  const char* messageIdName   = callbackData->pMessageIdName;
  int32_t messageIdNumber     = callbackData->messageIdNumber;
  const char* message         = callbackData->pMessage;
  android_LogPriority priority = ANDROID_LOG_UNKNOWN;

  if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
    severityString = error;
    priority = ANDROID_LOG_ERROR;
  }
  else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
    severityString = warning;
    priority = ANDROID_LOG_WARN;
  }
  if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
     typeString = validation;
  }
  else if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) {
     typeString = performance;
  }

  __android_log_print(priority,
                     "AppName",
                     "%s %s: [%s] Code %i : %s",
                     typeString,
                     severityString,
                     messageIdName,
                     messageIdNumber,
                     message);

  // Returning false tells the layer not to stop when the event occurs, so
  // they see the same behavior with and without validation layers enabled.
  return VK_FALSE;
}

बाहरी पुष्टि लेयर का इस्तेमाल करें

आपको अपने APK में पुष्टि करने वाली लेयर को पैकेज करने की ज़रूरत नहीं है; Android पर चलने वाले डिवाइस 9 (एपीआई लेवल 28) और उसके बाद वाले वर्शन, आपकी बाइनरी के बाहर पुष्टि करने वाली लेयर का इस्तेमाल कर सकते हैं और डाइनैमिक तौर पर बंद और चालू करें. पुश करने के लिए, इस सेक्शन में दिया गया तरीका अपनाएं आपके टेस्ट डिवाइस पर पुष्टि करने वाली लेयर:

पुष्टि करने के लिए बाहरी लेयर का इस्तेमाल करने के लिए, अपने ऐप्लिकेशन को चालू करें

Android के सुरक्षा मॉडल और नीतियां, अन्य सुरक्षा मॉडल और नीतियों से काफ़ी अलग होती हैं प्लैटफ़ॉर्म. बाहरी पुष्टि करने वाली लेयर लोड करने के लिए, इनमें से कोई एक शर्त सही होना चाहिए:

  • टारगेट ऐप्लिकेशन, डीबग करने लायक है. इस विकल्प की वजह से, ज़्यादा डीबग हो सकता है जानकारी हो, लेकिन इससे आपके ऐप्लिकेशन की परफ़ॉर्मेंस पर बुरा असर पड़ सकता है.

  • टारगेट ऐप्लिकेशन, ऑपरेटिंग सिस्टम के userdebug बिल्ड पर चलता है रूट ऐक्सेस करने की अनुमति देता है.

  • सिर्फ़ Android 11 (एपीआई लेवल 30) या उसके बाद वाले वर्शन को टारगेट करने वाले ऐप्लिकेशन: आपका टारगेट Android मेनिफ़ेस्ट फ़ाइल में ये शामिल हैं meta-data एलिमेंट:

    <meta-data android:name="com.android.graphics.injectLayers.enable"
      android:value="true"/>
    

पुष्टि करने वाली बाहरी लेयर लोड करें

Android 9 (एपीआई लेवल 28) और इसके बाद के वर्शन वाले डिवाइसों पर, Vulkan यह जानकारी लोड कर पाता है पुष्टि करने की लेयर जोड़ें. शुरू होने की तारीख Android 10 (एपीआई लेवल 29) में, Vulkan पुष्टि करने वाली लेयर को किसी अलग APK का इस्तेमाल करें. अपनी पसंद का तरीका चुनें जब तक आपके Android वर्शन पर यह सुविधा काम करती हो.

अपने डिवाइस के लोकल स्टोरेज से, पुष्टि करने वाली लेयर की बाइनरी लोड करें

क्योंकि Vulkan आपके डिवाइस के अस्थायी डेटा स्टोरेज में बाइनरी को ढूंढता है डायरेक्ट्री, आपको पहले Android डीबग ब्रिज (adb), इस तरह है:

  1. फ़ाइल को लोड करने के लिए, adb push कमांड का इस्तेमाल करें डिवाइस पर मौजूद अपने ऐप्लिकेशन के डेटा स्टोरेज में बाइनरी की जानकारी दें:

    $ adb push libVkLayer_khronos_validation.so /data/local/tmp
    
  2. adb shell और run-as का इस्तेमाल करें आपके ऐप्लिकेशन की प्रोसेस के ज़रिए लेयर लोड करने के लिए कमांड देते हैं. इसका मतलब है कि बाइनरी डिवाइस पर वही ऐक्सेस हो जो ऐप्लिकेशन के पास है, लेकिन रूट ऐक्सेस करने की ज़रूरत नहीं है.

    $ adb shell run-as com.example.myapp cp
      /data/local/tmp/libVkLayer_khronos_validation.so .
    $ adb shell run-as com.example.myapp ls libVkLayer_khronos_validation.so
    
  3. लेयर को चालू करें.

किसी दूसरे APK से, पुष्टि करने वाली लेयर की बाइनरी लोड करें

आप adb का इस्तेमाल करके, ऐसा APK इंस्टॉल कर सकते हैं जो लेयर को शामिल करें और फिर लेयर को चालू करें.

adb install --abi abi path_to_apk

ऐप्लिकेशन के बाहर लेयर चालू करें

Vulkan लेयर को हर ऐप्लिकेशन के हिसाब से या दुनिया भर में चालू किया जा सकता है. हर ऐप्लिकेशन के हिसाब से सेटिंग परसिस्टेंट रहता है, जबकि ग्लोबल प्रॉपर्टी हटा दी जाती है डिवाइस को फिर से चालू करें.

हर ऐप्लिकेशन के हिसाब से लेयर चालू करें

यहां हर ऐप्लिकेशन के हिसाब से लेयर चालू करने का तरीका बताया गया है:

  1. लेयर चालू करने के लिए, adb शेल सेटिंग का इस्तेमाल करें:

    $ adb shell settings put global enable_gpu_debug_layers 1
    
  2. यह लेयर चालू करने के लिए, टारगेट ऐप्लिकेशन तय करें:

    $ adb shell settings put global gpu_debug_app <package_name>
    
  3. चालू करने के लिए लेयर की सूची (ऊपर से नीचे तक), हर लेयर को अलग करें कोलन लगाकर लेयर:

    $ adb shell settings put global gpu_debug_layers <layer1:layer2:layerN>
    

    क्योंकि हमारे पास एक Kronos पुष्टि करने वाली लेयर है, इसलिए आदेश ऐसा दिखेगा:

    $ adb shell settings put global gpu_debug_layers VK_LAYER_KHRONOS_validation
    
  4. इसके अंदर की लेयर खोजने के लिए, एक या उससे ज़्यादा पैकेज बताएं:

    $ adb shell settings put global
      gpu_debug_layer_app <package1:package2:packageN>
    

यह देखने के लिए कि सेटिंग चालू हैं या नहीं, इन निर्देशों का इस्तेमाल करें:

$ adb shell settings list global | grep gpu
enable_gpu_debug_layers=1
gpu_debug_app=com.example.myapp
gpu_debug_layers=VK_LAYER_KHRONOS_validation

आपकी लागू की गई सेटिंग सभी डिवाइस में फिर से चालू रहती हैं. इसलिए, शायद आप लेयर लोड होने के बाद, सेटिंग मिटाएं:

$ adb shell settings delete global enable_gpu_debug_layers
$ adb shell settings delete global gpu_debug_app
$ adb shell settings delete global gpu_debug_layers
$ adb shell settings delete global gpu_debug_layer_app

दुनिया भर में लेयर की सुविधा चालू करें

अगली बार फिर से चालू होने तक, दुनिया भर में एक या एक से ज़्यादा लेयर चालू की जा सकती हैं. यह नेटिव सहित सभी ऐप्लिकेशन के लिए लेयर लोड करने की कोशिश करता है एक्ज़ीक्यूटेबल.

$ adb shell setprop debug.vulkan.layers <layer1:layer2:layerN>