Порт редактора 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>
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user