Jump to content
  • Advertisement

Vulkan New API Rendering Architecture

This topic is 434 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I'm currently updating my rendering architecture to gain more performance from the newer APIs , DX12/Vulkan, while still supporting D3D11 and I wanted to get some advice on the architecture to use. As far as I know there are two main architectures ; the first is using a single main thread. This thread performs gameplay logic using a task system, and once that is complete, performs visibility and drawcall logic using a task system and submits commands back on the main thread. As far as I know, the benefits of this approach is reducing input latency, but a consequence is that you have to wait for rendering tasks to complete before you perform game logic again. The second is a main thread and a render thread. After gameplay logic is computed, the main thread syncs data with the rendering thread. The rendering thread will compute visibility , draw call , and command buffer generation using the task system and submits command lists on the rendering thread. A benefit of this approach is that it does not block the computation of gameplay logic, but creates a frame of latency.

Share this post

Link to post
Share on other sites
Using a gameplay / render thread doesn't add any latency as the critical path for a frame remains completely unchanged - it's still update + render.
Say update and render cost 4ms each. Each frame takes 8ms to compute, regardless of whether you're using on thread or two.
With the two-threads plus pipelining solution, you start a new frame once every 4ms, so your framerate doubles, but latency is still 8ms per frame :o

Two threads is a bad architecture though because it doesn't scale. Let's say that a job system gives a 4x speed boost on a 4-core CPU.
The single-threaded version now takes 2ms per frame and has 4x the original framerate.

However, you can have your cake and eat it too. Add the job system to the two-threads pipelined version and it's now starting a new frame once every 1ms for 8x the original framerate... However because you're actively using two threads instead of one, let's say the job system now only gives a 2x speex boost instead of 4x: that means a frame takes 4ms total but a new one is started once every 2ms, so it actually does end up with the same framerate as the single-thread plus jobs version, but double the latency :o

In the real world, a lot of code remains serial and doesn't end up fully utilising the job system though, so personally I do still use the K-threads pipelined plus a job system model. I also place my "per system" threads into the job system's thread pool. e.g. on a 4-core CPU, I have one jobs+gameplay thread, one jobs+render thread, and two jobs-only threads.

The main difference with the new APIs is that the generation of command buffers can benefit from threading/jobs.
You can generate command buffer in jobs/threads on D3D11, but you don't gain any performance by doing so, so there's little point. In D3D12, I've found that you need to be recording a few thousand draw calls at a time to see any benefit from a job system... So in my engine, when I'm about to record a commamd buffer, I check if the backend reports that it supports fast threaded command buffers (i.e. is D3D12/Vulkan) and also if the draw-item count is over 1000 or not, and then either record the commands immediately on the render thread, or spawn several jobs.

As for rendering architecture itself, a more interesting question to me is whether to make a state-machine renderer like the underlying APIs, or a stateless renderer like BGGX or mine :D

Share this post

Link to post
Share on other sites

Thank you again for another response! I think I may have described my pattern wrong. For the main thread and render thread system.. both are using a job system to distribute tasks. So my approach is similar to yours (one game thread, one render thread , and the rest will be job threads). The "only main thread" method I was also talking about is based off of umbra-ignite-2015-jrmy-virga-dishonored- 

where they queue the game logic tasks and render tasks from the main thread. 

I guess it makes sense that it would not increase latency, I have just read about how companies like id-software , arkane , and a few other studios explain that that was the reason why they chose the main thread / task system model.

Share this post

Link to post
Share on other sites

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!