Skip to content
2017Knight2017Public

About

Brand New Doom Engine in Rust ECS and Vulkan

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

169 Commits

Folders and files

Repository files navigation

Demo gif

Vuldu

Vul[kan] du[um] is a Doom port written by me completely from scratch in Rust, with Vulkan rendering and the ECS pattern in the game loop. The project's ultimate goal is to achieve maximum performance on large maps through multithreaded computations, which was fundamentally impossible in the original Id Tech 1.

How to Run

Note: Vuldu requires a GPU with Vulkan 1.3 support.

First, download the latest release, as well as the wad you want to run (for example, DOOM2.WAD). To run it, open the command line in the game folder and enter:

./vuldu -i your/path/to/DOOM2.WAD 

You can view the application's parameters using ./vuldu -h

Technology Stack

  • winit => Window management
  • hecs => Implementation of the ECS world and entities
  • rodio => Spatial audio
  • serde => Parsing of toml tables
  • cxx => FFI bridge between Rust and the C++ renderer
  • earcut algorithm => Floor triangulation

It is important to note that I deliberately chose two libraries for multithreading, as they work differently and solve opposite problems:

Rayon is optimized for maximum performance. It achieves this through work stealing: if a thread finishes its work, it takes parts of the work from another thread. It works perfectly for preparing data during loading.

However, practice shows that "work stealing" is unstable when the game's framerate depends on it. Therefore, I chose micropool, which works on the principle of busy waiting: after finishing their work, threads do not go to sleep, but wait so that they can start executing the next task as quickly as possible. It works perfectly when more data needs to be processed without significantly increasing the load.

Benchmarks & Performance Profile

Vuldu is engineered with data locality in mind to keep frame allocations close to zero during gameplay.

For the stress test, the Okuplok Slaughter Map (oku2v31.wad) was used — this involves roughly 23,000 active monsters and heavy geometry.

Test Environment

  • Map: DOOM2.WAD + oku2v31.wad
  • Entities: ~23,000 active monsters
  • Profiling Tool: Linux perf

CPU & Cache Metrics (perf stat)

Here are the metrics by the Linux perf. The low Cache Miss percentage is achieved by storing components on the hecs world and using a custom thread pool (micropool for frame tasks + rayon for loading):

Metric Measurements Notes
L1 Data Cache Miss Rate 3.75% (1.83B misses / 48.8B loads) High cache locality
IPC (Instructions / Cycle) 1.35 (101.7B inst / 75.4B cycles) ALU barely stalls
Branch Miss Rate 2.20% (304M misses / 13.8B branches) Predictable execution
Execution Time 42.9s (34.7s user / 1.48s sys) Stable CPU-bound workload

An L1 miss rate of 3.75% across 23,000 entities confirms that the chosen ECS approach packs AI state directly into the CPU cache without bottlenecking on memory bandwidth.

Project Architecture

The project is designed so that the crates are loosely coupled with each other in a strictly one-way order:

↓ Renderer ↓

The FFI bridge leads to renderer_cpp/, where the Vulkan class is implemented in C++ and safely abstracted in src/lib.rs for subsequent use of its methods in Rust. The graphics pipeline is designed with mass resource processing and minimization of draw calls in mind.

Objects and UI make extensive use of Instancing, allowing tens of thousands of instances to be displayed on screen with almost no impact on FPS.

> App <

The main coordination center of the project. In App::resumed() you can find the window initialization code, while WindowEvent::RedrawRequested contains the code for redrawing it.

Overall, in App, all other crates are merged together in the form of GraphicsContext and GameContext, while also handling audio and user input.

↑ Engine ↑

This is where all ECS systems related to movement, vision, sound propagation, etc. live. Engine can modify level and entity data during gameplay.

There is more code inspired by John Carmack's original source code here than anywhere else in the project.

↑ Wad Parser ↑

In this crate, bytes from the wad are converted into textures and levels. All file resource management is handled through the WadManager object, which stores lumps associated with their source file.

In src/textures/, textures from the patch format are converted into an array of PLAYPAL color indices. In src/vertices/, sectors and the linedefs surrounding them are triangulated into floors and walls and turned into a fully-fledged 3D scene.

Building

For a local build, you need the Vulkan SDK. After installing it, clone the repository to your computer:

cd your/local/path
git clone https://github.com/2017Knight2017/Vuldu.git

Place the wad you plan to run (for example, DOOM2.WAD) there as well. After that, compile and run the project using cargo:

cargo build
cargo run -- -i DOOM2.WAD

License

Vuldu is licensed under GNU General Public License 3.0.

About

Brand New Doom Engine in Rust ECS and Vulkan

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages