extern crate bindgen; use regex::Regex; use std::env; use std::path::PathBuf; use find_winsdk::{SdkInfo, SdkVersion}; fn find_d3d12_header() -> Option { let info = SdkInfo::find(SdkVersion::V10_0).unwrap().unwrap(); let path = std::path::Path::new(info.installation_folder()) .join("Include") // adding ".0" is a really sad necessity :( .join(format!("{}.0", info.product_version())) .join("um") .join("d3d12.h") .to_str() .expect("Path to WinSDK is not valid UTF-8") .to_owned(); eprintln!("Trying to find d3d12.h at {}", path); Some(path) } fn patch_d3d12_header() -> String { let d3d12_contents = std::fs::read_to_string( find_d3d12_header().expect("Cannot find d3d12.h"), ) .expect("Something went wrong reading d3d12.h"); let cpu_regex = Regex::new(concat!( r"(D3D12_CPU_DESCRIPTOR_HANDLE\s*", r"\(\s*STDMETHODCALLTYPE\s*\*GetCPUDescriptorHandleForHeapStart\s*\)", r"\(\s*ID3D12DescriptorHeap\s*\*\s*This\);)" )) .unwrap(); let mut patched_contents = cpu_regex.replace_all( &d3d12_contents, concat!( "void(STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart)", "(\n\tID3D12DescriptorHeap *This, ", "D3D12_CPU_DESCRIPTOR_HANDLE* pHandle);" ), ); let gpu_regex = Regex::new(concat!( r"(D3D12_GPU_DESCRIPTOR_HANDLE\s*", r"\(\s*STDMETHODCALLTYPE\s*\*GetGPUDescriptorHandleForHeapStart\s*\)", r"\(\s*ID3D12DescriptorHeap\s*\*\s*This\);)" )) .unwrap(); gpu_regex.replace_all( &patched_contents, concat!( "void(STDMETHODCALLTYPE *GetGPUDescriptorHandleForHeapStart)", "(\n\tID3D12DescriptorHeap *This, ", "D3D12_GPU_DESCRIPTOR_HANDLE* pHandle);" ), ).to_string() } fn main() { // ToDo: move to bindgen::Builder configuration? // Tell cargo to tell rustc to link the system d3d12 and dxgi // shared libraries. println!("cargo:rustc-link-lib=d3d12"); println!("cargo:rustc-link-lib=dxgi"); // we have no __uuidof, so let's use oldschool way println!("cargo:rustc-link-lib=dxguid"); // Tell cargo to invalidate the built crate whenever the wrapper changes println!("cargo:rerun-if-changed=wrapper.h"); // The bindgen::Builder is the main entry point // to bindgen, and lets you build up options for // the resulting bindings. let bindings = bindgen::Builder::default() // The input header we would like to generate // bindings for. .clang_arg("-std=c99") .header_contents("d3d12_patched.h", &patch_d3d12_header()) .header("wrapper.h") .layout_tests(false) // DXGI and D3D types, vars and functions .whitelist_type(".*DXGI.*") .whitelist_type(".*D3D12.*") .whitelist_var(".*DXGI.*") .whitelist_var(".*D3D12.*") .whitelist_var(".*IID_.*") .whitelist_function(".*DXGI.*") .whitelist_function(".*D3D12.*") .whitelist_function("Enum.*") .whitelist_function("CopyBufferRegion") // WinAPI functions from .whitelist_function("CreateEventW") .whitelist_function("WaitForSingleObject") .whitelist_function("CloseHandle") // Tell cargo to invalidate the built crate whenever any of the // included header files changed. .parse_callbacks(Box::new(bindgen::CargoCallbacks)) // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); // Write the bindings to the $OUT_DIR/bindings.rs file. let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); bindings .write_to_file(out_path.join("bindings.rs")) .expect("Couldn't write bindings!"); }