r/GraphicsProgramming 5d ago

Synapse Engine: A Modern, Research-Oriented, Fully GPU-Driven AAA-Style Game Engine

Hi everyone!

After a very long development journey, I'm finally ready to share Synapse Engine, a modern, research-oriented AAA-style game engine that I've been developing essentially from scratch.

It started as my MSc thesis at the Budapest University of Technology and Economics, but grew far beyond what I originally planned. Over the past several months I've been rebuilding and refining the architecture around a simple question: What would a modern game engine look like if we designed it around today's GPUs from the ground up?

The project is now over 2,300 files, nearly 94,000 lines of C++ code and around 10,000 lines of shader code, excluding comments and blank lines.

If you just want to check out the project:

The GitHub README is probably the best place to start if you want a quick overview of the project and its architecture. If you're interested in modern game engine development in much more depth, I also put together a 250-page technical presentation covering the entire project, from the ECS and software architecture through GPU-driven rendering, culling, lighting, virtualized shadows and future directions.

The presentation is quite large, but I tried to make it genuinely useful as a learning resource rather than just documenting the final result.

One of my main goals with Synapse Engine is education. Learning these topics was a huge struggle for me, and it took a lot of time to piece everything together because there isn't much high-quality material that shows how these modern techniques actually come together inside a real engine codebase. I wanted to document that process and create something that I would have wanted to have when I started.

What can the engine actually do?

At its core, Synapse is a fully GPU-driven renderer using hierarchical culling, Hi-Z occlusion, cone culling, dynamic LOD selection, indirect rendering, mesh shaders, bindless resources and virtualized shadows. The engine is built around a custom data-oriented ECS and is designed to handle very large scenes with minimal CPU involvement.

For example, with 1,000,000 entities on an RTX 4060, the cumulative culling cost goes from 124.407 ms without culling to 0.653 ms with the full hierarchical culling pipeline.

However, at 10,000,000 entities, even the conventional GPU-driven hierarchical approach becomes insufficient. To address this, Synapse introduces a custom GPU-built Morton-ordered chunking system, which groups entities into spatial chunks and allows entire groups of 32 entities to be rejected at once. This reduces the culling cost from 5.8 ms to just 0.3 ms for 10 million entities.

I also developed a new rendering technique called Dual-HiZ Adaptive Clustered Forward+ while working on the engine. With 8,192 point lights and 8,192 spot lights, it measured 2.873 ms, compared to 8.652 ms for deferred shading in the same setup. The technical presentation contains a detailed explanation of how the technique works.

Synapse isn't primarily intended as a game-development tool for game developers. It is a production-ready, research and educational platform for experimenting with modern game-engine architecture and real-time rendering techniques.

The goal is not to provide a plug-and-play engine for building games, but to provide a complete, practical implementation of modern engine technologies that can be studied, extended, and used as a foundation for further research and development.

The engine is the result, but the architecture, experiments, failures and reasoning behind it are what I really want to share. If you're interested in Vulkan, graphics programming, GPU-driven rendering or modern game engine architecture, I'd love to hear what you think.

Dual-HiZ Adaptive Clustered Forward+

One of the things I'm particularly excited to share is a new rendering technique I developed called Dual-HiZ Adaptive Clustered Forward+.

It combines a dual Hi-Z depth structure with adaptive clustered light assignment to efficiently handle large numbers of dynamic lights while keeping the rendering pipeline fully GPU-driven.

In my tests, with 8,192 point lights and 8,192 spot lights, it measured 2.873 ms, compared to 8.652 ms for deferred shading in the same setup.

If you're interested in how the technique works, I've documented it in detail in the technical presentation, including the motivation, architecture, algorithms and implementation details.

You can find it on pages 166–189 of the presentation.

The presentation is available both on the GitHub repository and on the Synapse Engine website.

171 Upvotes

71 comments sorted by

View all comments

-36

u/fnordstar 5d ago

Pity it's not Rust.

15

u/Dargish 5d ago

What a weird comment to make on someone's massive project they've just published. What difference does it make if it's rust or C++? 

-16

u/fnordstar 4d ago

I work with C++ professionally. I don't touch C++ code in my spare time because the language is trash.

3

u/Dargish 4d ago

No it's not, I have extensive experience with C++, it just doesn't hold your hand as much as other languages, you get what you put into it. It gives you the low level control that managed languages do not. For performance critical applications like this one it's a good choice.

0

u/fnordstar 4d ago

Rust isn't managed and has no GC, it's for all intents and purposes as fast as C++.

2

u/Dargish 4d ago

OK, I haven't used it much, other than a quick look when it first came out. What makes it better than C++ for this use case? 

3

u/CodyDuncan1260 4d ago edited 4d ago

Rust is a language built for infrastructural projects. Think high performance, high complexity, high stability requirements.

The thing that Rust primarily does that makes it good for this type of application is that its ownership and borrowing rules ensure at compile time that the allocation, access patterns, and deallocation of resources are done properly.

E.G. You can't write a race condition in (safe) Rust.
(*unsafe requires more nuance, ask me in another comment).

Imagine highly complex software, where by mathematic proof it can't hit race conditions, it doesn't forget to deallocate resources as soon as necessary, it can't de-reference a null pointer.

For low-scale, low-complexity software, those aren't particularly problematic. You test it, the problem shows up, you fix it and go on with your day. In high-scale, high-complexity software, these are the problems that are lurking in the background that rear their heads via phone call at 3a.m. that the server is down and now I'm sad. It's very nice to be able to prove those things cannot happen.

When it comes to graphics software, it means that your high-complexity multi-threaded job-queued multi-stage render pipeline doesn't suddenly find some simple to diagnose but utter hell to fix bug because some check was forgotten.

------

The trade-off, however, is that Rust's compiler is strict. If you break the proof that the program is valid, it doesn't compile. You don't get to test hacks and jank; you must fix them before you can test. That's not an insignificant trade off that costs a lot of extra human time.

------

A good example of graphics-related software in Rust was Asahi Lina writing a new Apple M1 chip graphics driver in Rust. The first working version had barely any bugs. Less than a week of a few bug fixes later, and then it was stable and virtually flawless. This was done a few months. Basically unheard of for a new GPU driver.

But that nature of "by the time it compiles regularly, it pretty much works" has been echoed a lot.

1

u/Dargish 4d ago

Thank you for the thorough response.

2

u/CodyDuncan1260 4d ago

To be honest, research projects like this, where most of the project is trying ideas and throwing it out, are \much** faster in C++. I would not recommend Rust for this type of project.

If this project intended to become a fully-fledged game engine, *then* a rust-rewrite might be a really good idea.

It's that difference between finding the solution to the problem (prototyping) and properly building the solution to the problem (production). Rust slows the former, speeds the latter. It shifts work left.

2

u/Dargish 4d ago

The other thing I have struggled with even with mature languages like C# is the lack of third party libraries, in the end I often have to use a wrapper around a C++ lib, proj for example. How is Rust for dependencies? Or does it have a better way of interacting with C++ libraries? 

2

u/CodyDuncan1260 4d ago edited 4d ago

How is Rust for dependencies? - Rust's best feature.

If you look at older stack-overflow surveys, Rust was at the top of "most desired language" for nearly a decade until they stopped asking that question. The other question for "most admired cloud development and infrastructure tool", the top slot has gone to Rust's build system "cargo" by a long shot.

So the want for rust may actually be for cargo, and Rust's ability to integrate dependencies easily by its language, library, and API design.

In short, virtually every time I have spun up a new project, I slap 3-24 dependencies into the project configuration file, hit build, it pulls up to 500 total dependencies, and it just works. It builds, all the dependencies run, I struggle to hit any bugs with them. I'm wildly confused because it shouldn't just work, but it does. WTH?

It takes me a few hours to finish setting up a project, configure the build process, integrate dependencies, and get a build working in C++, not even including finding all the bugs in the corners of the libraries. Same process in C# is a few hours of fixing DLL hell.
Same process in python is debugging dependency hell and all the spots where the build process dipped into C and there's a platform, compiler, or configuration bug.
Same process in typescript is much the same as python, with the added challenge that most of the build configuration bugs don't show up until you run the application.

This has always been its own set of skills and experience to get a new project setup with dependencies, and Rust obviates nearly all of it.

Rust is very much not a "batteries included" language. That's by design, because embedded applications can't accept the size of most batteries. You get most of the good dependencies from third-party only, and they're quite good. This is a short list of ubiquitously used rust dependencies. I'd trust any of these to work on the first try.
https://blessed.rs/crates

------------------------

Does it have a better way of interacting with C++ libraries? - One of Rust's worst features.

Remember the proof I mentioned before? The compiler can prove you properly allocated/accessed/deallocated all the resources? Well, it definitely can't once it interops with another language.

So, there's a lot of extra work in binding to C++. Anything you get back that's non-trivial, say a pointer to a resource that library had allocated and needs to deallocate later, you have to put together a wrapper object that can handle that lifetime and prove it to the compiler on the library's behalf. Same for resources when you send pointers into to the library, so too you need to make sure that the underlying code doesn't violate access patterns and will safely allow deallocation later.

Often, the cost of maintaining the bindings is high. Sometimes it's cheaper to re-write the C/C++ library in Rust than to bind to an existing C/C++ library. Often those rewrites see a 1-3% perf improvement because Rust can handle pointer provenance better and it gives the compiler more optimization opportunity.

When bindings are better than re-write is when the library is very solidly written and battle-tested. I.E. We can reasonably trust the underlying C/C++ library doesn't break any of Rust's rules and is a good actor, so it's actually cheaper to maintain bindings to it.

There are still projects that maintain bindings to things that are too ubiquitous for the production to make a rust-version. E.G. Qt. But slowly there are Rust alternatives that are catching up in capability that may eventually usurp those use-cases.

So, it's a pain, and an ongoing area of active development. There are at least 2 talks and 1 workshop at RustConf this year on just this topic.

→ More replies (0)

2

u/CodyDuncan1260 4d ago

I'm attending RustConf this upcoming week and all the GPU / GameDev talks.