বেশিরভাগ স্পষ্ট গ্রাফিক্স API ত্রুটি-পরীক্ষা করে না কারণ এটি করার ফলে কর্মক্ষমতা জরিমানা হতে পারে। Vulkan-এর বৈধতা স্তর রয়েছে যা ডেভেলপমেন্টের সময় ত্রুটি-পরীক্ষা প্রদান করে, আপনার অ্যাপের রিলিজ বিল্ডে কর্মক্ষমতা জরিমানা এড়ায়। বৈধতা স্তরগুলি একটি সাধারণ উদ্দেশ্য স্তর ব্যবস্থার উপর নির্ভর করে যা API এন্ট্রি পয়েন্টগুলিকে বাধা দেয়।
একক ক্রোনস যাচাইকরণ স্তর
পূর্বে, Vulkan একাধিক বৈধতা স্তর প্রদান করত যা একটি নির্দিষ্ট ক্রমে সক্ষম করার প্রয়োজন ছিল। 1.1.106.0 Vulkan SDK রিলিজ থেকে শুরু করে, আপনার অ্যাপটিকে পূর্ববর্তী বৈধতা স্তরগুলি থেকে সমস্ত বৈশিষ্ট্য পেতে শুধুমাত্র একটি একক বৈধতা স্তর , VK_LAYER_KHRONOS_validation , সক্ষম করতে হবে।
আপনার APK-তে প্যাকেজ করা বৈধতা স্তরগুলি ব্যবহার করুন
আপনার APK-এর মধ্যে প্যাকেজিং ভ্যালিডেশন লেয়ারগুলি সর্বোত্তম সামঞ্জস্যতা নিশ্চিত করে। ভ্যালিডেশন লেয়ারগুলি পূর্বনির্মিত বাইনারি হিসাবে উপলব্ধ অথবা সোর্স কোড থেকে তৈরি করা যায়।
পূর্বে তৈরি বাইনারি ব্যবহার করুন
GitHub রিলিজ পৃষ্ঠা থেকে সর্বশেষ Android Vulkan Validation স্তর বাইনারিগুলি ডাউনলোড করুন।
আপনার APK-তে লেয়ার যোগ করার সবচেয়ে সহজ উপায় হল আপনার মডিউলের src/main/jniLibs/ ডিরেক্টরিতে পূর্বনির্মিত লেয়ার বাইনারিগুলি এক্সট্র্যাক্ট করা, ABI ডিরেক্টরিগুলি (যেমন 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
সোর্স কোড থেকে বৈধতা স্তর তৈরি করুন
ভ্যালিডেশন লেয়ার সোর্স কোড ডিবাগ করতে, Khronos Group GitHub রিপোজিটরি থেকে সর্বশেষ সোর্সটি টেনে আনুন এবং সেখানে থাকা বিল্ড নির্দেশাবলী অনুসরণ করুন।
যাচাই করুন যে বৈধতা স্তরটি সঠিকভাবে প্যাকেজ করা হয়েছে।
আপনি Khronos-এর প্রি-বিল্ট লেয়ার অথবা সোর্স থেকে তৈরি লেয়ার দিয়ে তৈরি করুন না কেন, বিল্ড প্রক্রিয়াটি আপনার 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() কল করুন। vkCreateInstance() কার্যকর হলে Vulkan স্তরগুলি সক্ষম করে।
নিম্নলিখিত কোড স্নিপেটটি দেখায় যে কীভাবে একটি অ্যাপ প্রোগ্রাম্যাটিকভাবে কোয়েরি করতে এবং স্তরগুলি সক্ষম করতে 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,
ডিফল্ট লগক্যাট আউটপুট
ভ্যালিডেশন লেয়ারটি logcat-এ 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 এক্সটেনশন ব্যবহার করার আগে, আপনার ডিভাইস বা লোড করা ভ্যালিডেশন লেয়ার এটি সমর্থন করে কিনা তা নিশ্চিত করা উচিত। নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে 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 (API লেভেল 28) এবং তার উপরে চলমান ডিভাইসগুলি আপনার বাইনারি থেকে বাইরের ভ্যালিডেশন লেয়ার ব্যবহার করতে পারে এবং সেগুলিকে গতিশীলভাবে বন্ধ এবং চালু করতে পারে। আপনার টেস্ট ডিভাইসে ভ্যালিডেশন লেয়ার পুশ করতে এই বিভাগের ধাপগুলি অনুসরণ করুন:
আপনার অ্যাপকে বাহ্যিক বৈধতা স্তর ব্যবহার করতে সক্ষম করুন
অ্যান্ড্রয়েডের নিরাপত্তা মডেল এবং নীতিগুলি অন্যান্য প্ল্যাটফর্ম থেকে উল্লেখযোগ্যভাবে আলাদা। বহিরাগত যাচাইকরণ স্তরগুলি লোড করতে, নিম্নলিখিত শর্তগুলির মধ্যে একটি সত্য হতে হবে:
টার্গেট অ্যাপটি ডিবাগযোগ্য । এই বিকল্পটি আরও ডিবাগ তথ্য প্রদান করে, তবে আপনার অ্যাপের কর্মক্ষমতাকে নেতিবাচকভাবে প্রভাবিত করতে পারে।
টার্গেট অ্যাপটি অপারেটিং সিস্টেমের একটি ইউজারডিবাগ বিল্ডে চালানো হয় যা রুট অ্যাক্সেস প্রদান করে।
শুধুমাত্র Android 11 (API লেভেল 30) বা তার বেশি ভার্সনের জন্য অ্যাপ: আপনার টার্গেট Android ম্যানিফেস্ট ফাইলে নিম্নলিখিত
meta-dataউপাদান রয়েছে:<meta-data android:name="com.android.graphics.injectLayers.enable" android:value="true"/>
একটি বহিরাগত যাচাইকরণ স্তর লোড করুন
অ্যান্ড্রয়েড ৯ (এপিআই লেভেল ২৮) এবং তার উচ্চতর ভার্সন চালিত ডিভাইসগুলি ভলকানকে আপনার অ্যাপের স্থানীয় স্টোরেজ থেকে ভ্যালিডেশন লেয়ার লোড করার অনুমতি দেয়। অ্যান্ড্রয়েড ১০ (এপিআই লেভেল ২৯) থেকে শুরু করে, ভলকান একটি পৃথক APK থেকেও ভ্যালিডেশন লেয়ার লোড করতে পারে। আপনার অ্যান্ড্রয়েড ভার্সন যতক্ষণ পর্যন্ত এটি সমর্থন করে ততক্ষণ আপনি আপনার পছন্দের যেকোনো পদ্ধতি বেছে নিতে পারেন।
আপনার ডিভাইসের স্থানীয় স্টোরেজ থেকে একটি বৈধতা স্তর বাইনারি লোড করুন
যেহেতু Vulkan আপনার ডিভাইসের অস্থায়ী ডেটা স্টোরেজ ডিরেক্টরিতে বাইনারিটি খোঁজে, তাই আপনাকে প্রথমে Android Debug Bridge (adb) ব্যবহার করে বাইনারিটিকে সেই ডিরেক্টরিতে পুশ করতে হবে, নিম্নরূপ:
ডিভাইসে আপনার অ্যাপের ডেটা স্টোরেজে লেয়ার বাইনারি লোড করতে
adb pushকমান্ড ব্যবহার করুন:$ adb push libVkLayer_khronos_validation.so /data/local/tmp
আপনার অ্যাপ প্রক্রিয়ার মাধ্যমে লেয়ারটি লোড করতে
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
অন্য APK থেকে একটি বৈধতা স্তর বাইনারি লোড করুন
আপনি adb ব্যবহার করে এমন একটি APK ইনস্টল করতে পারেন যাতে লেয়ারটি থাকে এবং তারপর লেয়ারটি সক্রিয় করতে পারেন ।
adb install --abi abi path_to_apk
অ্যাপ্লিকেশনের বাইরে স্তরগুলি সক্ষম করুন
আপনি প্রতি-অ্যাপ অথবা বিশ্বব্যাপী ভলকান স্তরগুলি সক্ষম করতে পারেন। প্রতি-অ্যাপ সেটিংস রিবুট জুড়ে স্থায়ী হয় , যখন রিবুট করার সময় বিশ্বব্যাপী বৈশিষ্ট্যগুলি সাফ করা হয়।
প্রতি-অ্যাপ ভিত্তিতে স্তরগুলি সক্ষম করুন
নিম্নলিখিত ধাপগুলি প্রতি-অ্যাপ ভিত্তিতে স্তরগুলি কীভাবে সক্ষম করবেন তা বর্ণনা করে:
স্তরগুলি সক্ষম করতে adb শেল সেটিংস ব্যবহার করুন:
$ adb shell settings put global enable_gpu_debug_layers 1স্তরগুলি সক্ষম করার জন্য লক্ষ্য অ্যাপ্লিকেশনটি নির্দিষ্ট করুন:
$ adb shell settings put global gpu_debug_app <package_name>
প্রতিটি স্তরকে একটি কোলন দ্বারা পৃথক করে (উপর থেকে নীচে) সক্রিয় করার জন্য স্তরগুলির তালিকা নির্দিষ্ট করুন:
$ adb shell settings put global gpu_debug_layers <layer1:layer2:layerN>
যেহেতু আমাদের একটি মাত্র Khronos ভ্যালিডেশন লেয়ার আছে, তাই কমান্ডটি সম্ভবত এরকম দেখাবে:
$ adb shell settings put global gpu_debug_layers VK_LAYER_KHRONOS_validationএর ভেতরে স্তর অনুসন্ধানের জন্য এক বা একাধিক প্যাকেজ নির্দিষ্ট করুন:
$ 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>