Files
CFDManager/rust/README.md
T
NotBigGhostandClaude Opus 5 f5c9e61589 Порт редактора SimVulcan на Rust
Та же программа на ash + winit + egui: орбитальная камера, три плоскости сетки,
загрузка .obj, три режима отображения, единый проход динамического рендеринга с
глубинным вложением и submit через synchronization2. Шейдеры общие с C++-версией —
build.rs компилирует их из shaders/ и вшивает SPIR-V в бинарь.

Пять крейтов повторяют карту целей CMake, но инвариант «весь Vulkan в одном месте»
теперь проверяет компилятор: у simv-mesh и simv-editor нет ash в зависимостях.

Расхождения, вынужденные языком, а не вкусом:
 * App переехал в исполняемый крейт — в C++ граф целей цикличен (core владеет vk,
   vk принимает core::Window&), и держится это лишь на том, что simv_vk видит
   заголовки core, не линкуя цель; Cargo такой цикл отвергает;
 * состояние сцены возвращается из замыкания интерфейса, а не ставится сеттерами:
   замыкание вызывается из метода рендерера, трогать рендерер оттуда нельзя;
 * выгрузка меша на видеокарту уехала из середины записи кадра, где C++-версия
   зовёт vkDeviceWaitIdle уже после захвата образа цепочки показа.

Vulkan-контекст и цепочка показа написаны руками: замены vk-bootstrap в экосистеме
Rust нет. Обёртки Buffer и Image, лежащие в C++-версии без применения, здесь
задействованы всеми потребителями.

13 тестов, из них три перенесены из Catch2 дословно. cargo clippy -D warnings чист,
слой валидации молчит.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 20:58:19 +03:00

6.4 KiB
Raw Blame History

SimVulcan на Rust

Порт редактора SimVulcan с C++20 на Rust. Делает то же самое: орбитальная камера над тремя опорными плоскостями сетки, цветные оси XYZ, загрузка .obj и три режима отображения модели. Тот же Vulkan 1.3 с динамическим рендерингом и synchronization2, те же шейдеры.

Существует ради сравнения: обе версии лежат в репозитории рядом и собираются независимо. Разбор различий с цифрами — в ../docs/rust_vs_cpp.md.

Требования

  • Rust 1.82+ (проверялось на 1.97.1)
  • Vulkan SDK 1.3.290+ — нужен только glslangValidator для сборки шейдеров (ищется в %VULKAN_SDK%\Bin, затем в PATH)
  • Драйвер Vulkan 1.3 с fillModeNonSolid

Сборка и запуск

cd rust
cargo build --release
./target/release/SimVulcan

Запускать можно из любого каталога. Шейдеры вшиты в исполняемый файл на этапе сборки, а assets/meshes ищется подъёмом по предкам от самого бинаря — в отличие от C++-версии, которой нужен запуск из её собственного каталога.

Рядом с исполняемым файлом создаётся pipeline_cache.bin — сериализованный VkPipelineCache, он перечитывается при следующем запуске. Файл одноразовый: если конвейеры повели себя странно, его можно удалить.

Слой валидации Khronos запрашивается во всех конфигурациях, включая --release, — как и в C++-версии. Если слоя нет, приложение об этом предупредит и пойдёт дальше.

Для работы над кодом собирайте cargo build без --release. В профиле выпуска стоит lto = "thin", и правка одной строки заставляет заново оптимизировать и слинковать весь бинарь: 52 секунды против 5 в отладочной сборке. Замеры — в ../docs/rust_vs_cpp.md.

Тесты

cargo test

Чистая математика без видеокарты: габариты меша, сварка вершин, чтение Cube.obj, пространство отсечения камеры. Тесты живут прямо в модулях (#[cfg(test)] mod tests), отдельной цели под них нет.

Раскладка

Пять крейтов повторяют карту целей CMake из корня репозитория:

crates/simv-core/     журнал с категориями, окно                     → log, chrono, winit
crates/simv-mesh/     чтение .obj, сварка вершин, габариты           → glam, tobj
crates/simv-vk/       весь Vulkan + build.rs (GLSL → SPIR-V)         → ash, gpu-allocator,
                                                                       egui-ash-renderer
crates/simv-editor/   камера, ввод, панели                           → egui
crates/simv-app/      App и точка входа                              → всё вышеперечисленное

Главный инвариант проекта — «весь Vulkan живёт в одном месте» — здесь проверяет компилятор: у simv-mesh и simv-editor в зависимостях нет ни ash, ни simv-vk, так что нарушить границу нельзя даже по невнимательности.

Шейдеры общие с C++-версией: build.rs крейта simv-vk компилирует ../../shaders/editor/*.{vert,frag} тем же glslangValidator -V --target-env vulkan1.3 и кладёт SPIR-V в OUT_DIR, откуда он попадает в бинарь через include_bytes!.

Чем отличается от C++-версии

Снаружи — почти ничем, кроме внешнего вида панелей: вместо Dear ImGui взят egui. Причина: крейт imgui — это биндинги, и сборка всё равно тянула бы за собой исходники Dear ImGui на C++, что обесценило бы сравнение.

Внутри отличия сведены в отдельный документ, здесь только самые заметные:

  • App живёт в исполняемом крейте, а не в simv-core. В C++ граф целей цикличен (core::App владеет vk::Renderer, vk::Renderer принимает core::Window&), и держится это лишь на том, что simv_vk не линкует simv_core, а видит его заголовки. Cargo цикл между крейтами отвергает.
  • Состояние сцены возвращается из замыкания интерфейса, а не ставится сеттерами. Замыкание вызывается из метода рендерера, поэтому трогать рендерер оттуда нельзя.
  • Загруженный меш выгружается на видеокарту после кадра, а не из середины записи команд, как в C++, где колбэк панели дёргает vkDeviceWaitIdle уже после захвата образа цепочки показа.
  • Buffer и Image задействованы. В C++ обе обёртки собираются в цель simv_vk, но ими не пользуется никто.
  • Нет pImpl. Приватные поля модуля дают ту же изоляцию, ради которой в C++ заведён struct Renderer::Impl.
  • Цикл событий принадлежит winit. ShouldClose/PollEvents заменены методами ApplicationHandler.