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

96 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SimVulcan на Rust
Порт редактора `SimVulcan` с C++20 на Rust. Делает то же самое: орбитальная камера над
тремя опорными плоскостями сетки, цветные оси XYZ, загрузка `.obj` и три режима
отображения модели. Тот же Vulkan 1.3 с динамическим рендерингом и synchronization2,
те же шейдеры.
Существует ради сравнения: обе версии лежат в репозитории рядом и собираются
независимо. Разбор различий с цифрами — в [`../docs/rust_vs_cpp.md`](../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`
## Сборка и запуск
```sh
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`](../docs/rust_vs_cpp.md).
## Тесты
```sh
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`.