Сплошная проверка документов против дерева. Код не менялся. docs/rust_vs_cpp.md — числа, снятые с чужого каталога сборки: - «775 МБ исходников зависимостей» и «10 пакетов в графе C++» получены на build/, сконфигурированном из другого дерева (его _deps содержит 262 МБ nlohmann_json, который проект не объявляет). На деле девять объявленных репозиториев дают ~400 МБ исходников; - пакетов в графе Rust 82, а не 76 (cargo tree по текущему Cargo.lock); - итог по строкам 2976/494, а не 2962/492: строка «меш» устарела на 17 строк игнорируемого диагностического теста, тесты в модулях — 176; - «перевес почти весь в Vulkan-слое» — на деле 346 из 542 (64 %), из них 305 на Context и Swapchain; остальное приходится на меш, редактор и приложение; - «ни один замер не даёт разницы в порядок величины» неверно: инкрементальная release — 52.3 против 4.4 с, это 11.9x; - граней с пятью и более вершинами в plane.obj 119, а не 121; - из Catch2 перенесены все три случая, и добавлено ещё два, а не «три перенесены дословно»; - деструктор Renderer::Impl — 22 строки, а не тридцать; - путевых зависимостей у порта две: assets/meshes с откатом на текущий каталог и pipeline_cache.bin рядом с бинарём; - граф целей CMake ацикличен, цикл существует на уровне исходников — именно поэтому CMake и молчит. rust/README.md: - объявленный rust-version = "1.82" недостижим: залоченные egui, egui-winit и epaint 0.36.1 требуют 1.95; - перечни зависимостей крейтов были неполны, приведены целиком; - build.rs читает ../../../shaders, а не ../../shaders; - тесты не «чистая математика»: тесты загрузчика читают файлы из assets/meshes и требуют клон репозитория; - assets/ порту никто не копирует, он находит корневую копию сам; - те же поправки про цикл в CMake и про момент ожидания простоя. README.md: - панель называется Mesh, а не «Mesh load»; - пресета clang-cl не существует, компилятор пресеты не фиксируют; - версии Vulkan SDK и компиляторов сборкой не проверяются; - Buffer и Image перечислены среди рабочих модулей vk/, хотя ими не пользуется никто. docs/theory/solver_2x_sdf/README.md: - предлагался несуществующий переключатель cfg.collision="bgk" и реестр операторов get; тот же файл двумя разделами ниже говорит, что оператор зафиксирован. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
114 lines
8.5 KiB
Markdown
114 lines
8.5 KiB
Markdown
# SimVulcan на Rust
|
||
|
||
Порт редактора `SimVulcan` с C++20 на Rust. Делает то же самое: орбитальная камера над
|
||
тремя опорными плоскостями сетки, цветные оси XYZ, загрузка `.obj` и три режима
|
||
отображения модели. Тот же Vulkan 1.3 с динамическим рендерингом и synchronization2,
|
||
те же шейдеры.
|
||
|
||
Существует ради сравнения: обе версии лежат в репозитории рядом и собираются
|
||
независимо. Разбор различий с цифрами — в [`../docs/rust_vs_cpp.md`](../docs/rust_vs_cpp.md).
|
||
|
||
## Требования
|
||
|
||
* Rust 1.95+ (проверялось на 1.97.1). В `Cargo.toml` объявлено `rust-version = "1.82"`,
|
||
но это значение недостижимо: залоченные `egui`, `egui-winit` и `epaint` 0.36.1 сами
|
||
требуют 1.95, и на 1.82 Cargo обрывается на разрешении зависимостей
|
||
* 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++-версии, которой нужен запуск из её собственного
|
||
каталога. В отличие от неё же, `assets/` никуда не копируется: порт находит копию в
|
||
корне репозитория, поднимаясь от `target/<профиль>/`.
|
||
|
||
Рядом с исполняемым файлом создаётся `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` и его
|
||
путь ошибки, пространство отсечения камеры и ограничители наклона и приближения,
|
||
разбор категорий журнала — тринадцать тестов плюс один помеченный `#[ignore]`
|
||
диагностический, тот самый, которым получена таблица расхождения загрузчиков. Чистой
|
||
математикой это, впрочем, не является: тесты загрузчика читают настоящие файлы из
|
||
`assets/meshes` через `$CARGO_MANIFEST_DIR`, поэтому им нужен рабочий клон репозитория.
|
||
Тесты живут прямо в модулях (`#[cfg(test)] mod tests`), отдельной цели под них нет.
|
||
|
||
## Раскладка
|
||
|
||
Пять крейтов повторяют карту целей CMake из корня репозитория:
|
||
|
||
Ниже перечислены сторонние зависимости; вдобавок каждый крейт зависит от тех крейтов
|
||
рабочего пространства, что указаны в скобках.
|
||
|
||
```
|
||
crates/simv-core/ журнал с категориями, окно → log, chrono, winit
|
||
crates/simv-mesh/ чтение .obj, сварка, габариты → glam, tobj, log, thiserror
|
||
(+ simv-core)
|
||
crates/simv-vk/ весь Vulkan + build.rs → ash, ash-window, raw-window-handle,
|
||
(GLSL → SPIR-V) gpu-allocator, egui, egui-winit,
|
||
egui-ash-renderer, winit, glam,
|
||
bytemuck, log, thiserror
|
||
(+ simv-core, simv-mesh)
|
||
crates/simv-editor/ камера, ввод, панели → egui, glam, log
|
||
(+ simv-core, simv-mesh)
|
||
crates/simv-app/ App и точка входа → четыре крейта выше
|
||
+ egui, winit, glam, log, anyhow
|
||
```
|
||
|
||
Главный инвариант проекта — «весь 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&`), тогда
|
||
как граф целей CMake ацикличен — потому CMake и молчит: `simv_vk` не линкует
|
||
`simv_core`, а лишь видит его заголовки, и символы `Window` находятся при сборке
|
||
исполняемого файла. Cargo такую схему отвергает.
|
||
* **Состояние сцены возвращается из замыкания интерфейса**, а не ставится сеттерами.
|
||
Замыкание вызывается из метода рендерера, поэтому трогать рендерер оттуда нельзя.
|
||
* **Загруженный меш выгружается на видеокарту после кадра**, а не изнутри него, как в
|
||
C++, где колбэк панели дёргает `vkDeviceWaitIdle` уже после захвата образа цепочки
|
||
показа — хотя запись команд там ещё не началась, `vkBeginCommandBuffer` идёт позже.
|
||
* **`Buffer` и `Image` задействованы.** В C++ обе обёртки собираются в цель `simv_vk`, но
|
||
ими не пользуется никто.
|
||
* **Нет pImpl.** Приватные поля модуля дают ту же изоляцию, ради которой в C++ заведён
|
||
`struct Renderer::Impl`.
|
||
* **Цикл событий принадлежит winit.** `ShouldClose`/`PollEvents` заменены методами
|
||
`ApplicationHandler`.
|