کامپایلرهای سایه زن Vulkan در اندروید

یک برنامه Vulkan باید سایه بان ها را متفاوت از روشی که یک برنامه OpenGL ES انجام می دهد مدیریت کند: در OpenGL ES، شما یک سایه زن را به عنوان مجموعه ای از رشته ها ارائه می دهید که متن منبع یک برنامه سایه زن GLSL را تشکیل می دهند. در مقابل، Vulkan API از شما می خواهد که یک سایه زن به شکل یک نقطه ورودی در یک ماژول SPIR-V ارائه دهید.

NDK Release 12 به بعد شامل یک کتابخانه زمان اجرا برای کامپایل GLSL در SPIR-V است. کتابخانه زمان اجرا مانند پروژه منبع باز Shaderc است و از همان کامپایلر مرجع Glslang GLSL به عنوان انتهای خود استفاده می کند. به طور پیش فرض، نسخه Shaderc کامپایلر فرض می کند که شما برای Vulkan کامپایل می کنید. پس از بررسی اینکه آیا کد شما برای Vulkan معتبر است، کامپایلر به طور خودکار پسوند KHR_vulkan_glsl را فعال می کند. نسخه Shaderc کامپایلر نیز کد SPIR-V سازگار با Vulkan را تولید می کند.

می‌توانید در طول توسعه، ماژول‌های SPIR-V را در برنامه Vulkan خود کامپایل کنید، تمرینی به نام کامپایل پیش از زمان یا AOT . از طرف دیگر، می توانید از برنامه خود بخواهید آنها را از منبع سایه زن ارسال شده یا تولید شده رویه ای در صورت نیاز در طول زمان اجرا، کامپایل کند. این عمل کامپایل در زمان اجرا نامیده می شود. اندروید استودیو پشتیبانی یکپارچه ای برای ساخت سایه زن های Vulkan دارد.

بقیه این صفحه جزئیات بیشتری در مورد هر تمرین ارائه می دهد و سپس نحوه ادغام کامپایل سایه زن را در برنامه Vulkan خود توضیح می دهد.

تدوین AOT

دو راه برای دستیابی به کامپایل Shader AOT وجود دارد که در بخش های زیر توضیح داده شده است.

از اندروید استودیو استفاده کنید

با قرار دادن سایه‌زن‌ها در app/src/main/shaders/ ، Android Studio سایه‌ها را با پسوند فایل‌شان تشخیص می‌دهد و اقدامات زیر را انجام می‌دهد:

  • همه فایل های سایه زن را به صورت بازگشتی در آن دایرکتوری کامپایل کنید.
  • پسوند spv. را به فایل های سایه زن کامپایل شده SPIR-V اضافه کنید.
  • سایه بان های SPIRV را در فهرست assets/shaders/ APK بسته بندی کنید.

برنامه در زمان اجرا سایه بان های کامپایل شده را از assets/shaders/ مکان مربوطه بارگذاری می کند. ساختار فایل shader spv کامپایل شده مشابه ساختار فایل سایه زن GLSL برنامه در زیر app/src/main/shaders/ است:

AAsset* file = AAssetManager_open(assetManager,
                     "shaders/tri.vert.spv", AASSET_MODE_BUFFER);
size_t fileLength = AAsset_getLength(file);
char* fileContent = new char[fileLength];
AAsset_read(file, fileContent, fileLength);

پرچم های کامپایل Shaderc را می توان در داخل بلوک shaders gradle DSL پیکربندی کرد، همانطور که در مثال زیر نشان داده شده است:

شیار

android {
  defaultConfig {
    shaders {
      glslcArgs.addAll(['-c', '-g'])
      scopedArgs.create('lights') {
        glslcArgs.addAll(['-DLIGHT1=1', '-DLIGHT2=0'])
      }
    }
  }
}

کاتلین

android {
  defaultConfig {
    shaders {
        glslcArgs += listOf("-c", "-g")
        glslcScopedArgs("lights", "-DLIGHT1=1", "-DLIGHT2=0")
    }
  }
}

glslcArgs برای همه کامپایل های سایه زن اعمال می شود. scopedArgs فقط هنگام کامپایل برای آن محدوده اعمال می شود. مثال بالا یک lights آرگومان scope ایجاد می کند که فقط برای سایه زن های GLSL تحت پوشه app/src/main/shaders/lights/ اعمال می شود. برای لیست کامل پرچم های کامپایل موجود به glslc مراجعه کنید. توجه داشته باشید که Shaderc در داخل NDK یک عکس فوری از آن مخزن github در زمان انتشار NDK است. می‌توانید پرچم‌های دقیق پشتیبانی شده برای آن نسخه را با دستور glslc --help دریافت کنید، همانطور که در بخش بعدی توضیح داده شد.

کامپایل خط فرمان آفلاین

سایه بان های GLSL را می توان با استفاده از کامپایلر خط فرمان glslc مستقل از برنامه اصلی به SPIR-V کامپایل کرد. نسخه NDK نسخه 12 و نسخه‌های بعدی نسخه‌ای از glslc از پیش ساخته شده و ابزارهای مرتبط را در فهرست راهنمای <android-ndk-dir>/shader-tools/ بسته‌بندی می‌کند تا از این مدل استفاده پشتیبانی کند.

کامپایلر نیز از پروژه Shaderc موجود است. برای ساختن یک نسخه باینری، دستورالعمل های آنجا را دنبال کنید.

glslc مجموعه ای غنی از گزینه های خط فرمان را برای کامپایل سایه بان برای برآوردن نیازهای مختلف برای یک برنامه فراهم می کند.

ابزار glslc یک فایل تک منبعی را در یک ماژول SPIR-V با یک نقطه ورودی تک سایه زن کامپایل می کند. به طور پیش فرض، فایل خروجی همان نام فایل منبع است، اما پسوند .spv .

شما از پسوندهای نام فایل استفاده می‌کنید تا به ابزار glslc بگویید کدام مرحله سایه‌زن گرافیکی را کامپایل کند، یا اینکه آیا شیدر محاسباتی در حال کامپایل است. برای اطلاعات در مورد نحوه استفاده از این پسوندهای نام فایل و گزینه هایی که می توانید با این ابزار استفاده کنید، مشخصات مرحله Shader را در راهنمای glslc ببینید.

تدوین زمان اجرا

برای کامپایل JIT سایه بان ها در طول زمان اجرا، NDK کتابخانه libshaderc را فراهم می کند که دارای API های C و C++ است.

برنامه های C++ باید از C++ API استفاده کنند. توصیه می‌کنیم برنامه‌های زبان‌های دیگر از C API استفاده کنند، زیرا C ABI سطح پایین‌تری دارد و احتمالاً پایداری بهتری را ارائه می‌کند.

مثال زیر نحوه استفاده از C++ API را نشان می دهد:

#include <iostream>
#include <string>
#include <vector>
#include <shaderc/shaderc.hpp>

std::vector<uint32_t> compile_file(const std::string& name,
                                   shaderc_shader_kind kind,
                                   const std::string& data) {
  shaderc::Compiler compiler;
  shaderc::CompileOptions options;

  // Like -DMY_DEFINE=1
  options.AddMacroDefinition("MY_DEFINE", "1");

  shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv(
      data.c_str(), data.size(), kind, name.c_str(), options);

  if (module.GetCompilationStatus() !=
      shaderc_compilation_status_success) {
    std::cerr << module.GetErrorMessage();
  }

  std::vector<uint32_t> result(module.cbegin(), module.cend());
  return result;
}

در پروژه های خود ادغام شوید

می توانید کامپایلر سایه زن Vulkan را با استفاده از فایل Android.mk پروژه یا Gradle در برنامه خود ادغام کنید.

Android.mk

مراحل زیر را برای استفاده از فایل Android.mk پروژه خود برای ادغام کامپایلر سایه زن انجام دهید.

  1. خطوط زیر را در فایل Android.mk خود قرار دهید:
    include $(CLEAR_VARS)
         ...
    LOCAL_STATIC_LIBRARIES := shaderc
         ...
    include $(BUILD_SHARED_LIBRARY)
    
    $(call import-module, third_party/shaderc)
    
  2. APP_STL را روی یکی از c++_static ، c++_shared ، gnustl_static ، یا gnustl_shared در Application.mk برنامه تنظیم کنید.

ادغام Gradle's CMake

  1. در یک پنجره ترمینال، به ndk_root/sources/third_party/shaderc/ بروید.
  2. دستور زیر را برای ساخت Shaderc NDK اجرا کنید. شما فقط باید این دستور را یک بار در هر نسخه NDK که استفاده می کنید اجرا کنید:
    $ ../../../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \
    APP_STL:=<stl_version> APP_ABI=all libshaderc_combined
    

    این دستور دو پوشه را در <ndk_root>/sources/third_party/shaderc/ قرار می دهد. ساختار دایرکتوری به شرح زیر است:

    include/
      shaderc/
        shaderc.h
        shaderc.hpp
    libs/
      <stl_version>/
        {all of the abis}
           libshaderc.a
    
  3. شامل و لبه های تولید شده را با استفاده از target_include_directories و target_link_libraries اضافه کنید، همانطور که معمولاً برای کتابخانه های خارجی مشابه انجام می دهید. نوع STL برنامه شما باید با یکی از انواع stl مشخص شده در stl_version مطابقت داشته باشد. NDK استفاده از c++_shared یا c++_static را توصیه می‌کند، اگرچه gnustl_static و gnustl_shared نیز پشتیبانی می‌شوند.

آخرین Shaderc را دریافت کنید

Shaderc در NDK از درخت منبع Android می آید که یک عکس فوری از مخزن بالادست Shaderc است. اگر به آخرین Shaderc نیاز دارید، برای جزئیات به دستورالعمل ساخت مراجعه کنید. مراحل سطح بالا به شرح زیر است:

  1. دانلود جدیدترین Shaderc:
    git clone https://github.com/google/shaderc.git
  2. به روز رسانی وابستگی ها:
    ./utils/git-sync-deps
  3. ساخت شادرک:
    <ndk_dir>/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \
        APP_STL:=c++_static APP_ABI=all libshaderc_combined -j16
    
  4. پروژه خود را طوری پیکربندی کنید که از بیلد Shaderc خود در فایل اسکریپت بیلد خود استفاده کنید.