//! Компиляция GLSL в SPIR-V на этапе сборки — аналог `cmake/ShaderCompile.cmake`. //! //! Шейдеры берутся из общего с C++-версией каталога `shaders/` в корне репозитория: //! обе сборки компилируют одни и те же файлы теми же ключами, поэтому расхождение в //! картинке нельзя списать на шейдер. //! //! В отличие от CMake результат не копируется рядом с исполняемым файлом, а зашивается //! в бинарь через `include_bytes!`. Отсюда исчезают и `FindSpvPath`, и POST_BUILD-копия, //! и требование «запускать из каталога исполняемого файла». use std::path::{Path, PathBuf}; use std::process::Command; fn main() { let manifest = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); // crates/simv-vk → rust → корень репозитория. let shader_root = manifest.join("../../../shaders"); let shader_root = shader_root.canonicalize().unwrap_or(shader_root); let editor_dir = shader_root.join("editor"); println!("cargo:rerun-if-env-changed=VULKAN_SDK"); println!("cargo:rerun-if-changed={}", editor_dir.display()); let compiler = find_glslang(); let mut sources: Vec = std::fs::read_dir(&editor_dir) .unwrap_or_else(|e| panic!("не читается каталог шейдеров {}: {e}", editor_dir.display())) .filter_map(|entry| entry.ok().map(|e| e.path())) .filter(|p| { matches!( p.extension().and_then(|e| e.to_str()), Some("vert") | Some("frag") ) }) .collect(); // Порядок обхода каталога зависит от файловой системы — сортируем, чтобы сборка // была воспроизводимой. sources.sort(); assert!( !sources.is_empty(), "в {} нет ни одного .vert/.frag", editor_dir.display() ); let out_editor = out_dir.join("editor"); std::fs::create_dir_all(&out_editor).unwrap(); for src in &sources { println!("cargo:rerun-if-changed={}", src.display()); let name = src.file_name().unwrap().to_string_lossy().to_string(); let dst = out_editor.join(format!("{name}.spv")); let output = Command::new(&compiler) .arg("-V") .args(["--target-env", "vulkan1.3"]) // glslangValidator требует -I<путь> без пробела. .arg(format!("-I{}", shader_root.display())) .arg("-o") .arg(&dst) .arg(src) .output() .unwrap_or_else(|e| panic!("не запускается {}: {e}", compiler.display())); if !output.status.success() { panic!( "GLSL → SPIR-V не удалось для {}:\n{}{}", src.display(), String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); } } } /// Ищем компилятор там же, где его ищет CMake: сначала в Vulkan SDK, потом в PATH. fn find_glslang() -> PathBuf { let exe = if cfg!(windows) { "glslangValidator.exe" } else { "glslangValidator" }; if let Ok(sdk) = std::env::var("VULKAN_SDK") { let candidate = Path::new(&sdk).join("Bin").join(exe); if candidate.exists() { return candidate; } let candidate = Path::new(&sdk).join("bin").join(exe); if candidate.exists() { return candidate; } } PathBuf::from(exe) }