3 poin oleh GN⁺ 2024-02-11 | 1 komentar | Bagikan ke WhatsApp
  • API grafis eksperimental sysgpu milik Mach engine membutuhkan artefak shader untuk Direct3D 12, sehingga DXC milik Microsoft dibangun ulang dalam bentuk yang lebih mudah digunakan secara statis dan lintas platform
  • DXIL untuk Direct3D 12 lebih dekat ke LLVM bitcode pascapemrosesan yang diekspor oleh fork LLVM/Clang 3.7 milik Microsoft, sehingga strukturnya bergantung pada “output compiler yang nyata” alih-alih spesifikasi
  • Runtime keluarga WebGPU biasanya mengubah WGSL ke HLSL lalu membuat DXBC/DXIL dengan FXC atau DXC, tetapi karena beban distribusi DXC, FXC yang tua dan lambat mudah menjadi default
  • DXC yang ada sulit ditautkan secara statis, dan biner penandatanganan/validasi proprietari bernama dxil.dll hanya didistribusikan terutama untuk Windows dan Linux x86, sehingga kompilasi shader DirectX offline di macOS atau CI Arm Linux terhambat
  • mach-dxcompiler menulis ulang build CMake menjadi Zig build.zig dan menghapus ketergantungan DLL untuk menyediakan library dxcompiler statis dan CLI dxc, tetapi masih ada keterbatasan pada ABI MSVC, pengujian musl, output SPIR-V, dan dukungan SM6.7

Alasan Mach membangun ulang DXC

  • Mach engine sedang membuat API grafis eksperimental bernama sysgpu dengan Zig, dengan target dukungan backend Metal, Vulkan, Direct3D, dan OpenGL
  • Pada backend Direct3D 12, program shader harus dikompilasi ke format yang bisa dikonsumsi oleh Direct3D 12
  • Dalam proses ini, terlihat bahwa compiler shader DirectX DXC milik Microsoft menciptakan pengalaman distribusi yang rumit dan tidak nyaman bagi pengembang game

Kompilasi shader DirectX yang beralih dari FXC ke DXC

  • API grafis DirectX menggunakan HLSL sebagai bahasa shading
  • Compiler HLSL sebelum Direct3D 11 disebut FXC, yaitu effects compiler
  • FXC dikenal di kalangan pengembang game sebagai compiler yang lambat dan kualitas pembuatan kodenya kurang baik
    • Ini bisa merugikan baik dari sisi kecepatan kompilasi shader maupun performa saat dijalankan
  • Dengan Direct3D 12 dan Shader Model 6.0, Microsoft secara resmi menandai FXC yang dulu disertakan di Windows OS sebagai deprecated, lalu memperkenalkan DXC, fork berbasis LLVM/Clang v3.7
  • DXC dipublikasikan di Microsoft/DirectXShaderCompiler, dan Microsoft juga mendistribusikan biner pra-build
  • Di fork LLVM milik Microsoft, perubahan terkait HLSL ditandai dengan komentar // HLSL Change Start dan // HLSL Change End

DXBC dan DXIL yang dikonsumsi driver Direct3D

  • Karena setiap produsen GPU memiliki struktur perangkat keras dan kebutuhan yang berbeda, biner native tempat HLSL akhirnya dijalankan juga berbeda antara GPU Intel, NVIDIA, dan AMD
  • Microsoft menyediakan API frontend seperti Direct3D dan HLSL, sementara IHV seperti Intel, AMD, dan NVIDIA menulis driver untuk menghubungkannya ke bentuk yang dekat dengan ISA perangkat keras
  • Pada DirectX 9~11, driver mengonsumsi DXBC
    • Pengembang game mengompilasi HLSL ke DXBC dengan CLI fxc.exe atau API d3dcompiler
    • Driver mengubah DXBC menjadi biner yang benar-benar akan dijalankan di GPU
    • DXBC adalah format proprietari nonpublik yang digunakan antara Microsoft dan produsen driver GPU
  • Sejak DirectX 12 dan Shader Model 6.0, DXIL menjadi format resmi yang dikonsumsi produsen driver DirectX 12
  • DXIL lebih dekat ke bentuk bitcode setelah code generation dan optimization pass dari LLVM 3.7, ditambah container/wrapper kustom kecil
  • Dokumen DXIL bukan benar-benar spesifikasi terpisah, melainkan bergantung pada bitcode yang benar-benar diekspor oleh fork LLVM 3.7 milik Microsoft setelah perubahan HLSL dan optimisasi

Rencana DXIR yang hilang dan peralihan ke upstream LLVM

  • Pada masa DirectX 12 dan Shader Model 6.0, Microsoft pernah merencanakan DXIR, IR tingkat tinggi yang belum dioptimalkan, lalu DXC akan menurunkannya menjadi DXIL yang teroptimasi
  • Pada 2021, ungkapan yang mengisyaratkan kemungkinan pembuatan DXIR dihapus
  • Pada 2019, seorang karyawan Microsoft menjawab bahwa hampir tidak ada dokumentasi tentang proses penurunan dari DXIR ke DXIL, dan DXIR bukan format resmi melainkan lebih dekat ke LLVM IR pertama setelah CodeGen
  • Pada 2023, seorang karyawan Microsoft menyatakan bahwa fork LLVM milik DXC menghapus atau merusak sebagian besar lapisan code generation dan infrastruktur LLVM
    • Untuk menambahkan pembuatan DXBC ke DXC, fitur LLVM yang rusak harus dipulihkan, dan mereka mengatakan DXC tidak akan menangani itu
  • Sejak Maret 2022, Microsoft mengusulkan dan menjalankan pekerjaan untuk meng-upstream dukungan kompilasi HLSL ke jalur utama LLVM/Clang
  • Rencana transisi ini juga mencakup penambahan kembali dukungan legacy LLVM v3.7 bitcode writing ke LLVM/Clang modern

Beban distribusi DXC pada WebGPU dan game engine

  • Lapisan abstraksi grafis yang ingin menyatukan API grafis modern seperti Metal, Direct3D 12, dan Vulkan juga membutuhkan bahasa shading terpadu
  • Implementasi WebGPU saat ini kadang menargetkan jalur yang dalam jangka panjang langsung menghasilkan DXIL, tetapi pada praktiknya kebanyakan belum melakukannya
  • Jalur WebGPU yang umum adalah sebagai berikut
    • Bahasa teks WGSL diubah saat runtime menjadi HLSL
    • HLSL dikompilasi dengan compiler HLSL menjadi DXBC atau DXIL
    • DXBC/DXIL yang sudah dioptimalkan diberikan ke driver grafis, lalu driver mengubahnya ke representasi intermediate dan machine code spesifik vendor
  • Vulkan/SPIR-V juga memiliki struktur di mana driver harus mengompilasi SPIR-V menjadi biner native
    • Beberapa driver bisa mengasumsikan SPIR-V sudah dioptimalkan, tetapi ini berbeda tergantung GPU mobile atau desktop
    • Valve Fossilize menyimpan cache biner nyata hasil kompilasi driver untuk setiap kombinasi GPU dan versi driver
  • DXIL selalu berupa LLVM bitcode setelah optimization pass, sedangkan SPIR-V bisa berupa bentuk yang sudah dioptimalkan atau belum
  • Hanya Apple Metal yang mendukung API yang langsung mengompilasi ke format biner native perangkat keras target sebenarnya

Pilihan yang dibuat oleh dxcompiler.dll dan dxil.dll

  • Runtime WebGPU melakukan konversi WGSL→HLSL→DXIL saat runtime, sehingga harus memilih antara DXC baru dan FXC lama
  • Berdasarkan dokumentasi Bevy, FXC sudah tua, lambat, dan tidak dirawat, tetapi tidak memerlukan distribusi DLL tambahan
  • Sebaliknya, DXC lebih baru, lebih cepat, dan dirawat, tetapi aplikasi harus mendistribusikan dxcompiler.dll dan dxil.dll bersama aplikasi
  • Masalah pilihan ini memengaruhi bukan hanya Bevy, tetapi juga pengguna Rust wgpu dan pengguna Dawn WebGPU
  • Akibatnya, banyak perangkat lunak akhirnya menjadikan FXC yang tua, lambat, dan tidak dirawat sebagai default

Mengapa penautan statis DXC sulit

  • Fork LLVM milik Microsoft tidak mendukung penautan statis
  • Jika SHARED di file CMake diubah menjadi STATIC, sekitar 15 library statis akan dihasilkan, tetapi pengalaman penautannya lebih buruk daripada satu library tunggal
  • Jika mencoba memakai library OBJECT di CMake, perubahan HLSL Microsoft memperlihatkan saling ketergantungan implisit di luar dependensi logis
  • Sebagian implementasi antarmuka COM di DXC dirancang untuk memuat dxcompiler.dll dan dxil.dll sebagai library dinamis lalu memanggil dirinya sendiri
  • Sulit membuat DXC statis hanya dengan mengubah pengaturan build

dxil.dll proprietari dan penandatanganan shader

  • dxil.dll tidak dihasilkan meski DirectXShaderCompiler dibangun dari source, tetapi didistribusikan di rilis GitHub untuk Windows x86/Arm dan Linux x86
  • Menurut spesifikasi D3D12 Shader Cache API, D3D12 hanya menerima shader yang sudah ditandatangani, dan jika optimisasi atau patch runtime dilakukan, shader harus divalidasi dan ditandatangani ulang
  • Pada rilis pratinjau Shader Model 6.8, dxil.dll/libdxil.so tidak disediakan
    • DXIL target SM6.8 yang dihasilkan compiler tersebut belum final dan tidak bisa divalidasi
    • Distribusi atau eksekusi pada mesin yang bukan mode pengembang tidak didukung
  • Tanpa dxil.dll, shader tidak ditandatangani/divalidasi
  • Shader yang tidak ditandatangani/divalidasi tidak dapat dijalankan jika mesin Windows tidak dalam Developer Mode

Kompilasi offline dan batasan platform

  • Mach ingin menghindari distribusi dependensi DXC yang berat saat tidak diperlukan dan melakukan kompilasi shader offline
  • Microsoft hanya mendistribusikan dxil.dll untuk Windows x86/Arm dan Linux x86
  • Biner Linux aarch64 dan biner macOS tidak disediakan
  • Karena itu, tidak mungkin membuat build game lintas platform untuk Windows dari macOS atau melakukan kompilasi shader DirectX offline di pipeline CI Arm Linux
  • Untuk menjalankan biner penandatanganan proprietari, dibutuhkan mesin Windows atau Linux x86_64

Bagian yang diubah oleh mach-dxcompiler

  • Sekitar 10,5 ribu baris build system CMake yang ada ditulis ulang menjadi build.zig milik Zig
  • Hanya dua bagian yang umumnya dibutuhkan konsumen, yaitu library dxcompiler.dll dan biner kompilasi/pengujian offline dxc.exe, yang dijadikan target build
  • Hasilnya diringkas menjadi sekitar 1 ribu baris logika build.zig
  • Codebase Microsoft di-fork untuk memperbaiki struktur DXC yang mengharapkan keberadaan dxcompiler.dll dan dxil.dll
    • Menyimulasikan DLL entrypoint
    • Menonaktifkan fungsi output informasi versi compiler yang berasal dari DLL
    • Mengemulasikan pemuatan function pointer library dinamis
  • mach-dxcompiler dikonfigurasi dalam bentuk yang tidak bergantung pada dxil.dll
  • Di mesin macOS, shader HLSL dapat dikompilasi tanpa dxil.dll proprietari, dan menghasilkan file bytecode DXIL yang byte-for-byte identik dengan yang dijalankan di mesin Windows biasa

Hasil dan cara penggunaan

  • Rilis menyertakan biner pra-build untuk library dxcompiler statis dan CLI dxc
  • Tidak ada ketergantungan pada dxil.dll proprietari
  • Target yang dibangun di pipeline CI adalah sebagai berikut
    • macOS: Apple Silicon aarch64 dan Intel x86_64
    • Linux: musl dan glibc, aarch64 dan x86_64
    • Windows: x86_64 dan aarch64, termasuk MinGW/GNU ABI
  • Library ini mengekspos API C kecil sebagai alternatif API COM yang ada
  • Pengembang game Zig dapat menggunakan API Zig di repositori, dan contoh penggunaannya dapat dilihat di pengujian src/main.zig
  • Secara default, pengguna cukup mengunduh dan memakai biner pra-build
  • Build dari source dapat dilakukan dari repositori mach-dxcompiler hanya dengan zig dan git, tetapi membutuhkan versi Zig yang ditentukan
git clone https://github.com/hexops/mach-dxcompiler
cd mach-dxcompiler/
zig build -Dfrom_source -Dtarget=aarch64-macos
zig build -Dfrom_source -Dtarget=x86_64-windows-gnu
zig build -Dfrom_source -Dtarget=x86_64-linux-gnu

Keterbatasan saat ini dan syarat pemeliharaan

  • Biner Windows MSVC ABI saat ini belum bisa dibangun karena bug kecil pada binding C
  • Biner Linux musl dapat dibangun, tetapi belum diuji
  • Mach engine berencana menggunakan Zig sendiri sebagai bahasa shading, bukan HLSL, sehingga dukungan output SPIR-V tidak dibangun dan tidak ada rencana tambahan
  • Saat ini tidak ada rencana pembaruan dukungan untuk SM6.7 yang baru dirilis
  • Sebagian build system CMake milik LLVM belum sepenuhnya dipindahkan, dan detail terkait masih tersisa di generated-include/
  • Proyek ini ada untuk menyelesaikan masalah Mach, dan saat ini isu ditangani oleh satu orang
  • Jika ditemukan jalur yang lebih baik, proyek ini bisa ditandai deprecated

1 komentar

 
GN⁺ 2024-02-11
Pendapat Hacker News
  • Ini tulisan yang merangkum dengan baik betapa berantakannya lapisan dasar kompilasi shader lintas API 3D
    Meski berfokus pada D3D dan Microsoft, API 3D lain juga tidak jauh lebih baik. Misalnya, di host Linux kita tidak bisa melakukan cross-compile shader Metal; itu hanya bisa dilakukan di macOS dan Windows yang relatif baru
    Jika tim Mach bisa membuat gagasan memakai Zig sebagai compiler shader lintas API 3D semulus “Zig sebagai toolchain cross-compile”, ini bisa menjadi hal terbesar dalam grafika komputer sejak sekitar 1995

    • Kalau itu terjadi, ini juga akan menjadi kabar sangat baik bagi Zig. Baik sebagai bahasa maupun sebagai toolchain, posisinya akan semakin kuat
    • Saya penasaran kenapa shader Metal tidak bisa di-cross-compile di host Linux. Bukankah itu sekadar berarti belum ada yang mengimplementasikannya?
    • Kalau bisa di Windows, bukankah itu berarti juga bisa di Linux lewat Wine?
  • Ini juga terkait dengan Godot
    Katanya, “Alasan ini dijadikan opsional adalah karena dukungan Direct3D 12 saat ini bergantung pada distribusi pustaka proprietari dxil.dll dari DirectX Shader Compiler bersama Godot, dan distribusi perangkat lunak proprietari bertentangan dengan misi proyek Godot”
    https://godotengine.org/article/dev-snapshot-godot-4-3-dev-3...

    • Saya penasaran bagian mana tepatnya dari dxil/dxc yang proprietari. Saya sedang mencoba memahami kekacauan lisensi di https://github.com/microsoft/DirectXShaderCompiler
    • Pengguna akhir sama sekali tidak akan peduli soal ini. Mirip saat beberapa distribusi Linux ketika instalasi bertanya “Apakah Anda ingin mengunduh dan memasang driver pihak ketiga?”
      Saya ingin GPU, Wi-Fi, dan Bluetooth saya berfungsi, jadi sebaiknya dicentang secara default
    • Bukankah dxil.dll itu managed code, yaitu kode “dotnet”?
  • Mengenai bagian “tidak perlu mendistribusikan .dll tambahan bersama aplikasi”, sudah banyak video game yang mendistribusikan middleware proprietari seperti Bink, SpeedTree, dan PhysX dengan cara seperti itu
    Kebanyakan launcher seperti Steam, GOG, dan Epic juga membutuhkan .DLL masing-masing, dan banyak game memakai D3D11On12. Banyak game rilis yang daftar file terpasangnya berisi dxil.dll
    Jadi saya sungguh penasaran, apa masalahnya dengan mendistribusikan satu DLL tambahan? Pekerjaan merekayasa balik dan mengimplementasikan ulang code signing di sini luar biasa, terutama karena output-nya sama bit demi bit dengan output dxil.dll. Tapi saya sangat malas, jadi mungkin saya akan memilih jalan yang lebih mudah, yaitu mendistribusikan DLL

    • Implementasi open source ini bisa dimasukkan ke engine game yang sudah ada tanpa programmer perlu tahu atau memahami apa itu dxil.dll
      Misalnya, engine Mach bisa memakainya saat membuat compiler yang mengompilasi kode Zig menjadi shader untuk berbagai platform target, dan pengguna akhir bisa langsung memakainya sebagai bagian dari fitur inti Mach tanpa konfigurasi atau dependensi tambahan
    • Game bukan hanya game AAA, dan aplikasi grafis juga bukan hanya game. Sesuatu yang baik-baik saja untuk game AAA rata-rata berukuran 100GB mungkin tidak cocok untuk game 30MB di itch.io, yang 24MB di antaranya adalah DXC, atau untuk viewer, converter, dan animator model 3D di situs web pribadi
      Bahkan pada game AAA, maupun game dan perangkat lunak lain, ini menambah dependensi tambahan yang bisa rusak di luar kendali kita. Di perusahaan tempat saya dulu bekerja, kami harus menerima middleware tertentu hanya dalam bentuk DLL dan library lalu melakukan linking, sehingga upgrade Visual Studio membutuhkan lebih banyak usaha dan kami juga harus mendapat versi baru. Karena perusahaan middleware itu belum melakukan upgrade di pihak mereka, kami sampai harus melakukan QA kompatibilitas VS baru.
      Tentu saja memiliki source code bukan berarti pembaruan menjadi tanpa gesekan, tetapi gesekannya jauh berkurang dan kita tidak perlu menunggu pihak lain. Visual Studio belakangan tampaknya mencoba menjaga kompatibilitas mundur untuk library C++ biner, tetapi menurut saya itu bukan sesuatu yang bisa diandalkan dalam jangka panjang
      Selain itu, semua ini mengasumsikan kode tetap berada pada platform dan target yang sama. Pada suatu titik, kita mungkin ingin memperlakukan platform lain sebagai host atau target, dan tanpa source code hal itu bisa menjadi sangat sulit atau mustahil. Untuk sesuatu yang spesifik platform seperti DXIL, ini mungkin tidak terlihat sebagai masalah besar, tetapi tulisan itu juga mengatakan bahwa karena sifat DXIL sebagai blob biner, prekompilasi shader tidak mungkin dilakukan di luar arsitektur Windows dan Linux tertentu yang disediakan Microsoft lewat DLL
    • Seperti yang ditunjukkan, hal itu sendiri bukan masalah besar. Namun poin yang benar-benar menarik di bagian akhir tulisan adalah kemampuan untuk cross-build dari OS/arsitektur mana pun
  • Apakah “tanda tangan”[1] yang dilakukan DXIL.dll pada akhirnya hanya MD5 yang dimodifikasi?
    1: https://github.com/hexops/DirectXShaderCompiler/blob/4190bb0...

    • Meski tulisan dari pihak Mach sangat bagus, cukup membuat frustrasi karena mereka tidak langsung mengatakan apa sebenarnya “tanda tangan” itu
      Siapa pun yang membaca tulisannya dengan cermat sampai bagian itu mestinya bisa tahu bahwa itu pasti hash dasar atau semacamnya, dan skenario terburuknya pun hanya sebatas seseorang perlu melakukan reverse engineering assembly
      Setelah bersusah payah sejauh itu, tidak masalah untuk mengkritik Microsoft secara terbuka. Apalagi jika yang dibicarakan adalah kode open source yang bisa digali dan ditemukan oleh siapa pun yang tertarik; terima kasih kepada msk yang sudah menemukannya
    • Bagian seperti ini yang benar-benar saya suka dari HN. Ada orang-orang yang bisa melihat kode C acak yang mengutak-atik memori lalu berkata, “ini terlihat seperti X yang dimodifikasi.” Bagi orang seperti saya yang terutama memakai bahasa tingkat tinggi, ini cukup mencengangkan
    • RenderDoc sudah punya kode untuk menangani ini sejak 2021, lengkap dengan komentar yang dijelaskan dengan baik
      https://github.com/baldurk/renderdoc/blob/4a620bb5a16b4de4e2...
    • “Tanda tangan” itu sejak awal memang teater keamanan yang tidak masuk akal. Lihat saja bahwa semua API grafis lain berjalan baik-baik saja tanpa hal seperti itu. Senang ada seseorang yang memublikasikan algoritma “tanda tangan” tersebut
  • Saya suka kutipan[0] dari pihak Microsoft ini. Katanya, karena fork LLVM milik DXC telah banyak menghapus atau merusak lapisan code generation dan infrastruktur LLVM, mendukung pembuatan DXBC di DXC akan membutuhkan pekerjaan besar untuk memperbaiki dan memulihkan fitur LLVM yang rusak
    Karena skala masalahnya besar dan sumber daya tim terbatas, mereka tidak akan menyelesaikan masalah ini di compiler DXC baru; ke depannya Clang mungkin bisa mendukung pembuatan DXBC, tetapi untuk sementara mereka berfokus pada dukungan pembuatan DXIL dan SPIR-V, sehingga akan sulit memulainya selama beberapa tahun. Menyegarkan melihat mereka menjelaskan dengan tegas hal yang tidak akan dikerjakan
    [0] https://github.com/microsoft/DirectXShaderCompiler/issues/57...

  • Saya sangat menyarankan untuk melihat ekosistem Mach. Khususnya mach-sysgpu, yang merupakan implementasi ulang WebGPU secara penuh, dan sebagian besarnya ditulis oleh Ali Chraghi yang berusia 17 tahun

  • Di sisi SDL, mereka sedang membuat bahasa shader dalam bentuk SDL_gpu yang berbeda dari yang sudah ada, untuk dimasukkan ke SDL3. Saya sudah cukup lama mengamatinya karena ini bisa menjadi cara cross-platform untuk menangani grafis 3D game

    • Saya penasaran apakah SDL_gpu benar-benar berbeda secara bermakna dari WebGPU. Dilihat dari tujuannya, keduanya tampak hampir sama: membuat abstraksi penyebut umum terkecil yang mudah diakses di atas DX12/Vulkan/Metal
      Bedanya mungkin SDL_gpu masih dalam tahap awal, sedangkan WebGPU sudah memiliki dua implementasi publik yang bagus
  • Cara yang tidak terlalu bikin pusing tampaknya adalah sesuatu seperti HLSL/GLSL → SPIR-V ↔ DXIL, atau menulis shader langsung dalam SPIR-V
    vkd3d milik Wine tampaknya punya konverter DXIL → SPIR-V, dan karena ini adalah bahasa antara yang jauh lebih sederhana daripada konverter bahasa shading tingkat tinggi, mungkin bisa lebih tangguh
    Namun saya penasaran apakah ada compiler HLSL → DXIL berbasis C99 yang murni dan sederhana, yang bisa dikompilasi tanpa GCC atau Clang, bukan monster LLVM ini

    • SPIR-V → DXIL jelas menarik dan tampak layak dieksplorasi. Baru-baru ini saya tahu ada tool bernama spirv2dxil di Mesa, tetapi saya tidak tahu seberapa tangguh dan lengkap fiturnya dibandingkan HLSL → DXC → DXIL
    • Tolong jangan sampai “menulis shader langsung dalam SPIR-V” menjadi jawabannya
      Untuk menjawab pertanyaannya: tidak ada. Konversi dari HLSL ke DXIL praktis berada dalam genggaman Microsoft, dan hampir tidak ada upaya untuk keluar dari sana
  • Menggunakan Zig sendiri sebagai bahasa shading itu keren. Zig benar-benar bahasa tunggal. Ia juga sistem build, dan juga bahasa shading!