คอมไพเลอร์ตัวควบคุมเงา Vulkan บน Android

แอป Vulkan ต้องจัดการตัวให้เฉดสีแตกต่างจากการทำงานของแอป OpenGL ES ใน OpenGL ES คุณให้ตัวปรับแสงเงาเป็นชุดสตริงที่ประกอบขึ้นเป็นข้อความต้นฉบับของ โปรแกรมเฉดสี GLSL ในทางตรงกันข้าม Vulkan API ต้องการให้คุณใส่เฉดสี รูปแบบของจุดแรกเข้าในโมดูล SPIR-V

NDK รุ่น 12 ขึ้นไปมีไลบรารีรันไทม์สำหรับคอมไพล์ GLSL เป็น SPIR-V ไลบรารีรันไทม์จะเหมือนกับไลบรารีใน โปรเจ็กต์โอเพนซอร์ส Shaderc และใช้โปรเจ็กต์เดียวกัน คอมไพเลอร์อ้างอิง Glslang GLSL เป็น แบ็กเอนด์ โดยค่าเริ่มต้น เวอร์ชัน Shaderc ของ คอมไพเลอร์จะถือว่าคุณกำลังคอมไพล์สำหรับ Vulkan หลังจากตรวจสอบว่ารหัสของคุณใช้ได้กับ Vulkan คอมไพเลอร์จะเปิดใช้ส่วนขยาย KHR_vulkan_glsl โดยอัตโนมัติ เดอะแชเดร์ค ของคอมไพเลอร์จะสร้างโค้ด SPIR-V ที่สอดคล้องกับ Vulkan ด้วย

คุณสามารถเลือกคอมไพล์โมดูล SPIR-V ลงในแอป Vulkan ระหว่างการพัฒนา หรือที่เรียกว่าการคอมไพล์ ก่อนเวลา หรือ AOT หรือ คุณสามารถให้แอปของคุณคอมไพล์จาก เครื่องมือปรับแสงเงาที่มีการจัดส่งหรือที่สร้างขึ้นตามขั้นตอน ซอร์สในระหว่างรันไทม์ การดำเนินการนี้เรียกว่าการคอมไพล์รันไทม์ Android Studio ได้ผสานรวมการรองรับในการสร้างเครื่องมือให้เฉดสี Vulkan

เนื้อหาส่วนที่เหลือในหน้านี้จะให้รายละเอียดเพิ่มเติมเกี่ยวกับแนวทางปฏิบัติแต่ละข้อ จากนั้นจึงอธิบาย วิธีผสานรวมการคอมไพล์ตัวปรับแสงเงาในแอป Vulkan

วิดีโอรวมคลิป AOT

การคอมไพล์ AOT ของเครื่องมือสร้างเงามี 2 วิธีตามที่อธิบายไว้ในส่วนต่อไปนี้

ใช้ Android Studio

การใส่เฉดสีใน app/src/main/shaders/ ทำให้ Android Studio รู้จักเครื่องมือให้เฉดสีจาก นามสกุลไฟล์ และจะดำเนินการต่อไปนี้ให้เสร็จสิ้น

  • คอมไพล์ไฟล์ตัวปรับแสงซ้ำทั้งหมดซ้ำภายในไดเรกทอรีนั้น
  • เพิ่มค่าต่อท้าย .spv ลงในไฟล์ตัวปรับแสงเงา SPIR-V ที่คอมไพล์แล้ว
  • แพ็กเงา SPIRV ลงในไดเรกทอรี assets/shaders/ ของ APK

แอปพลิเคชันจะโหลดตัวปรับแสงเงาที่คอมไพล์จากตำแหน่ง assets/shaders/ ที่เกี่ยวข้องขณะรันไทม์ โครงสร้างไฟล์ตัวปรับแสงเงา 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 คอมไพล์ภายในบล็อก DSL shaders ของ Graderc ได้ ดังที่แสดงในตัวอย่างต่อไปนี้

ดึงดูด

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

Kotlin

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

glslcArgs ใช้กับการคอมไพล์ตัวปรับแสงเงาทั้งหมด ระบบจะใช้ scopedArgs เมื่อคอมไพล์เท่านั้น สำหรับขอบเขตนั้น ตัวอย่างด้านบนสร้างอาร์กิวเมนต์ขอบเขต lights ซึ่งจะมีผลเฉพาะกับ ตัวปรับแสงเงา GLSL ภายใต้ไดเรกทอรี app/src/main/shaders/lights/ โปรดดู glslc สำหรับรายการทั้งหมด แฟล็กการคอมไพล์ที่พร้อมใช้งาน โปรดทราบว่า Shaderc ภายใน NDK คือสแนปชอตจากที่เก็บ GitHub นั้นที่ เวลาเผยแพร่ NDK คุณจะได้รับแฟล็กที่รองรับ สำหรับเวอร์ชันนั้นด้วยคำสั่ง glslc --help ตามที่กล่าวไว้ในส่วนถัดไป

การคอมไพล์บรรทัดคำสั่งแบบออฟไลน์

ระบบปรับแสงเงา GLSL สามารถคอมไพล์เป็น SPIR-V โดยไม่ขึ้นอยู่กับแอปพลิเคชันหลักโดยใช้คอมไพเลอร์บรรทัดคำสั่ง glslc NDK รุ่น 12 ขึ้นไปประกอบด้วย glslc เวอร์ชันที่สร้างไว้ล่วงหน้าและ เครื่องมือที่เกี่ยวข้องในไดเรกทอรี <android-ndk-dir>/shader-tools/ เพื่อรองรับรูปแบบการใช้งานนี้

คอมไพเลอร์ยังมีจาก Shaderc โปรเจ็กต์ ทำตามวิธีการเพื่อสร้างเวอร์ชันไบนารี

glslc จะมีชุดข้อมูลอย่างละเอียด ตัวเลือกบรรทัดคำสั่งสำหรับการคอมไพล์ตัวปรับแสงเงาเพื่อให้เป็นไปตามข้อกำหนดต่างๆ ของแอปพลิเคชัน

เครื่องมือ glslc จะรวมไฟล์แหล่งข้อมูลเดียวไปยังโมดูล SPIR-V ที่มีตัวปรับแสงเงาเดียว จุดแรกเข้า โดยค่าเริ่มต้น ไฟล์เอาต์พุตจะมีชื่อเดียวกับไฟล์ต้นฉบับ แต่มีส่วนขยาย .spv ต่อท้าย

คุณใช้นามสกุลชื่อไฟล์เพื่อบอกเครื่องมือ glslc ว่าจะต้องคอมไพล์ตัวปรับแสงเงากราฟิกแบบใด หรือว่ามีการคอมไพล์ตัวปรับแสงเงาการประมวลผลหรือไม่ สำหรับข้อมูลเกี่ยวกับวิธีใช้ชื่อไฟล์เหล่านี้ ส่วนขยาย และตัวเลือกที่คุณสามารถใช้กับเครื่องมือได้ โปรดดู ข้อกำหนดของระยะเฉดสีใน 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;
}

ผสานรวมเข้ากับโปรเจ็กต์ของคุณ

คุณสามารถผสานรวมคอมไพเลอร์ Shadter ของ 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 ของแอป

การผสานรวม CMake ของ Gradle

  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
    

    คำสั่งนี้จะวาง 2 โฟลเดอร์ใน <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 Source Tree ซึ่งเป็น ภาพรวมของที่เก็บ Shaderc ต้นทาง หากต้องการใช้ Shaderc ล่าสุด โปรดดูรายละเอียดคำแนะนำในการสร้าง ขั้นตอนระดับสูงมีดังนี้

  1. ดาวน์โหลด Shaderc ล่าสุด:
    git clone https://github.com/google/shaderc.git
  2. อัปเดตการอ้างอิง:
    ./utils/git-sync-deps
  3. สร้าง Shaderc:
    <ndk_dir>/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk \
        APP_STL:=c++_static APP_ABI=all libshaderc_combined -j16
    
  4. กำหนดค่าโปรเจ็กต์เพื่อใช้บิลด์ Shaderc ของคุณเองในไฟล์สคริปต์บิลด์