[SOLVED]Render Thread vs Task System

Started by
2 comments, last by AxeGuywithanAxe 7 years, 5 months ago

Hello, So I'm currently in the process of moving my engine from a game thread / render thread implementation, to a game thread with a task based system and a separate submission thread, which will be used to translate command lists . I seem to be having issues with the managing some of the benefits of the sequential nature of a separate render thread. One of these benefits is sequential resource creation and destruction. For instance, lets say I need to initialize a resource prior to rendering a frame, render the frame, and then release the resource. In a sequential environment, that would require me to send 3 jobs to the render thread, but this becomes more complicated in a job based environment. Another example is if I have to create a resource, update the resource, and then render the frame. There are hundreds of different permutations that I can think of that at the end of the day rely on resource acquisition and release. I was thinking of having a sync point during the frame, probably after the world updates, but what if I need to update a resource before that frame sync? Anyway, I don't want to ramble, but any help would be appreciated.

Advertisement

Hm....I don't think you have to sacrafice your "sequential order" for any reason. I assume that you keep standing with a "queue" that is somehow used to issue render commands, or actions that require a gpu context (that is not really shared between threads). Keep this queue and let a thread poll this queue at maximum frequence. In your update thread, you can issue tasks....a task itself has to be able to isse another task when it is finished...think of it as event based programming: Your command queue gets 5 commands, when the first is finished, a sixth command is appended in the queue.... and all commands are issued in order. No problem at all.

This approach would require you to have at least two worker pools....a single pool for the "gpu enabled" thread, and a pool for arbitrary tasks. Thats what one would usually do, i guess. Works in my own engine like a charm. As for temorary ressource creation: Don't do it at all. Initialize your component once and keep it until you don't use it any more. Having that said, I'm breaking this rule too, for example for debugging and profiling purpouses and it's no problem at all if you use the described mechanism.

I wonder if you're making your jobs overly granular. I'm not sure you really want your jobs allocating and releasing GPU memory at all because those simply shouldn't be per-frame tasks in most cases. Sure, you might have some things that pull resources from a pool of pre-allocated objects, but I would expect most rendering to be built around static allocations done ahead of time. Remember that at the end of the day, the purpose of the job system is to break things across multiple threads and cores. If you're going to have long dependent chains of jobs that have to run on the same thread or very sequentially anyway, you're spending a lot of effort without gaining much. The goal is to compartmentalize and decompose the pipeline in a flexible way.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

Thank you both for your responses. @Promit, I have certain tasks like updating vertex buffers/index buffers/etc that can only be done on the render thread, for OpenGL. So that's why I currently have some small tasks . But I believe that I've found a solid way to handle what I want to do. I have 4 phases for my renderer. 1) Visibility Determination , 2) Game Data Extraction, 3) Command List Building 4) Command List Execution. I've decided to add a function called FlushRenderingCommands. which will flush all commands to the that need to be run on the render thread. I've also decided to make the render thread handle the orchestration of the last 2 phases of my pipeline. The game thread will orchestrate the visibility determination and game data extraction phases by queuing tasks to the job manager. When those two phases are done. The "WorldFrame" is sent to the render thread, where the render thread will do the same thing but for the last two phases, and after that flush any pending render commands. This means that any resource that needs to be updated after the current frame will not be run until after phase 4 and render commands that happened prior to rendering the current frame will be run before the current frame needs it.

This topic is closed to new replies.

Advertisement