MadDog
Member
I'm quite pleased with this, although Dzz, Rixed and Squidge have helped me out with my daft code. (sorry if I missed someone out)
The design has been borrowed from the Xbox360.
GPU == 940
What I have, and this can be changed to suit, is 8 * 2k buffers. The CPU writes and the GPU reads. The last thing I write of a command is its ID. The first thing I write is a 'SLEEP' command to what will be the next command. This means that, and I have an assert to check, the current command being written is always flagged as a 'SLEEP' command until its ready to be read and also even before its ready the following command is a 'SLEEP' until written to. This stops the GPU getting ahead of the CPU and start reading old data.
When I add a command I check to see if the size of the command will fit in the current buffer, if it will not I write a command telling the GPU to move to the next command buffer and the start writing to the start of the next buffer. When I do this check if the buffer i'm about to move into is the one the GPU is currently reading I wait, this stops the CPU from catching up with the GPU. Also this check only has to happen when it moves to a new buffer so the cost of reading an uncached control var is minimal.
All commands are rounded up to multiples of 4 bytes, this helps to make sure I don't get unaligned memory problems. Every command has a header of four bytes defined as two shorts. One is the command ID and the second is the size in dwords (4bytes) This is because the GPU read and CPU write command buffer pos pointers are dword pointers. So to move to the next command I do pos += current_command->size;
As the write I write a SLEEP command thats defined as zero it makes the ID and size zero in one go. Also when I setup the memory space for the GPU I zero its ram and so when the GPU starts up it will just spin on a SLEEP command.
In the GPU code I just have a big switch statement.
Hope that all made sence, its a nice simple method that needs no semephores just an uncached var the GPU writes to when it moves to a new command buffer and the CPU reads when its going to move to the next command.
(I do use a semephore to stop the CPU getting too many frames ahead, but I think that its not to do with the command buffer)
The design has been borrowed from the Xbox360.
GPU == 940
What I have, and this can be changed to suit, is 8 * 2k buffers. The CPU writes and the GPU reads. The last thing I write of a command is its ID. The first thing I write is a 'SLEEP' command to what will be the next command. This means that, and I have an assert to check, the current command being written is always flagged as a 'SLEEP' command until its ready to be read and also even before its ready the following command is a 'SLEEP' until written to. This stops the GPU getting ahead of the CPU and start reading old data.
When I add a command I check to see if the size of the command will fit in the current buffer, if it will not I write a command telling the GPU to move to the next command buffer and the start writing to the start of the next buffer. When I do this check if the buffer i'm about to move into is the one the GPU is currently reading I wait, this stops the CPU from catching up with the GPU. Also this check only has to happen when it moves to a new buffer so the cost of reading an uncached control var is minimal.
All commands are rounded up to multiples of 4 bytes, this helps to make sure I don't get unaligned memory problems. Every command has a header of four bytes defined as two shorts. One is the command ID and the second is the size in dwords (4bytes) This is because the GPU read and CPU write command buffer pos pointers are dword pointers. So to move to the next command I do pos += current_command->size;
As the write I write a SLEEP command thats defined as zero it makes the ID and size zero in one go. Also when I setup the memory space for the GPU I zero its ram and so when the GPU starts up it will just spin on a SLEEP command.
In the GPU code I just have a big switch statement.
Hope that all made sence, its a nice simple method that needs no semephores just an uncached var the GPU writes to when it moves to a new command buffer and the CPU reads when its going to move to the next command.
(I do use a semephore to stop the CPU getting too many frames ahead, but I think that its not to do with the command buffer)