bkaradzic / bgfx

Cross-platform, graphics API agnostic, "Bring Your Own Engine/Framework" style rendering library.
https://bkaradzic.github.io/bgfx/overview.html
BSD 2-Clause "Simplified" License
15.09k stars 1.95k forks source link

Provide support for supplying a complete command buffer to the renderer #496

Open ghost opened 9 years ago

ghost commented 9 years ago

With regard to language bindings, one big area of overhead with JNI and other language binding systems is that each call to native code is much more expensive than than a regular call. For a few calls it's not a big deal, but when you get into thousands+ of calls, the overhead can become significant.

It would be great if we could implement our own command builder in the binding language. It would generate an entire command buffer for a frame (or close) which would be passed over in one native call with something like: bgfx::frame(&mycmdbuf)

This way we can eliminate virtually all of the command generation call overhead for language bindings.

I intend to look into implementing this but just wanted to get feedback on the idea, thanks!

bkaradzic commented 9 years ago

That's interesting idea. I already had plan to add command baking, which would allow you to once set draw state and then recall it over multiple frames with single call. Your idea is similar.

james4k commented 9 years ago

Would be great for the Go bindings as well. +1

bkaradzic commented 9 years ago

Looked into this a bit more, and there is no simple way of exposing raw commands to you. I do some validation and packing internally. Technically I can let you do all that, but it will break every time I want to change any internals.

The best way to do it, is language binding, record stream of invoked commands, and then flush it at some point:

Pseudo code:

func SetTexture(<args>) {
    stream.write(ESetTexture, <args...>);
}

func Frame() {
    flush(stream);
}

Then on C++ side implement flush interpreter:

void flush(stream)
{
    while (true)
    {
        cmd = stream.read();
        switch (cmd)
        {
        case ESetTexture:
            bgfx::setTexture(<args...>);
            break;
        ...
        }
    }
}

Is this something you were thinking about?

james4k commented 9 years ago

I've considered that in the past, but then you've got an extra layer of buffering, so you're having to make a trade off. But, it is probably the right trade off in the case of non-zero cost bindings with no alternative.