NoesisGUI

Using Command Buffers

All the operations that the RenderSystem send to the graphic device are managed using CommandBuffers. A CommandBuffer is a powerful abstraction where graphic actions are stored in a optimal format to be executed later. This is something very similar to display lists in OpenGL. Instead of sending shaders, states and primitives to the driver, you compile all these commands to a CommandBuffer that can be applied later.

CommandBuffers offer two main advantages:

  • CommandBuffers creation are thread-safe. Several command buffers can be created in parallel threads. Of course, the execution of the CommandBuffer must be done in the main thread. This allows for interesting scenarios. For example you could generate several shadow maps in different threads. When the CommandBuffers are already generated you send them synchronously to the RenderSystem with the Apply() method.
  • A CommandBuffer can be implemented very efficiently in each platform. Applying a command buffer is a lot faster that passing through a generic interface abstracting a generic decive.

How to use Command Buffers

Command Buffers are created through the IRenderSystem::CreateCommandBuffer method. The Command Buffer object provides all the method that are needed to display primitives.

////////////////////////////////////////////////////////////////////////////////////////////////////
/// CommandBuffer
////////////////////////////////////////////////////////////////////////////////////////////////////
class NS_RENDER_RENDERSYSTEM_API CommandBuffer: public Core::BaseComponent
{
public:
    /// Constructor
    CommandBuffer();
    /// Destructor
    ~CommandBuffer();

    /// Clears the command buffer
    void Reset();

    /// Adds another command buffer
    void Append(const Ptr<CommandBuffer> commands);

    /// Clears the current RenderTarget and DepthStencil
    /// \param clearColor Clear the render target
    /// \param color Clear the render target to this ARGB color
    /// \param clearZ Clear the depth buffer
    /// \param z Clear the depth buffer to this new z value which ranges from 0 to 1
    /// \param clearStenil Clear the stencil buffer
    /// \param stencil Clear the stencil buffer to this new value which ranges from 0 to 2n - 1
    ///                (n is the bit depth of the stencil buffer).
    virtual void Clear(NsBool clearColor, NsUInt color, NsBool clearZ, NsFloat32 z,
        NsBool clearStencil, NsUInt stencil) = 0;

    /// Sets a new set of render targets
    virtual void SetColorBuffer(const Ptr<IRenderTarget>& color0,
                                const Ptr<IRenderTarget>& color1 = 0,
                                const Ptr<IRenderTarget>& color2 = 0,
                                const Ptr<IRenderTarget>& color3 = 0) = 0;

    /// Set a depth-stencil resource
    virtual void SetDepthBuffer(const Ptr<IRenderTarget>& depth) = 0;

    /// Resolves a render target to a texture
    virtual void Resolve(const Ptr<IRenderTarget>& renderTarget) = 0;

    /// Apply a shader
    virtual void SetShader(const Ptr<IShader>& shader, NsSize technique, NsSize pass) = 0;

    /// Apply a constant buffer
    virtual void SetConstantBuffer(const Ptr<IConstantBuffer>& cBuffer) = 0;

    /// Apply a vertex source
    virtual void SetVertices(const Ptr<IVertexSource>& vertices) = 0;

    /// Apply a index buffer
    virtual void SetIndices(const Ptr<IIndexBuffer>& indices) = 0;

    /// Renders the specified geometric primitive
    /// \param primitiveType Type of primitive to render
    /// \param startVertexLocation Index of the first vertex
    /// \param numVertices Number of vertices to draw
    virtual void Draw(PrimitiveType primitiveType, NsInt32 startVertexLocation,
        NsUInt32 numVertices) = 0;

    /// Renders the specified geometric primitive
    /// \param primitiveType Type of primitive to render
    /// \param baseVertexIndex Offset from the start of the vertex buffer to the first vertex
    /// \param minIndex Minimum vertex index for vertices used during this call. This is a zero
    ///        based index relative to baseVertexIndex
    ///// \param numVertices Number of vertices used during this call. The first vertex is located
    /////        at index: baseVertexIndex + minIndex
    /// \param startIndex Index of the first index
    /// \param numIndices Number of indices to draw
    virtual void DrawIndexed(PrimitiveType primitiveType, NsInt32 baseVertexIndex,
        NsUInt32 minIndex, NsUInt32 numVertices, NsUInt32 startIndex, NsUInt32 numIndices) = 0;

    /// Copy the content of the back-buffer renderview to the front buffer of the associated window
    virtual void Swap(const Ptr<IRenderView>& renderView) = 0;
};

What follows is a simple example that generate a command buffer that draw in the current active rendertarget a triangle list using the current shader.

void BuildCommandBuffer()
{
    Ptr<IRenderSystem> renderSystem = NsGetKernel()->GetSystem(NSS("RenderSystem"));
    mCommandBuffer = renderSystem->CreateCommandBuffer();

    mCommandBuffer->SetVertices(meshData->mVertexSource);
    mCommandBuffer->SetIndices(meshData->mIndexBuffer);

    mCommandBuffer->DrawIndexed(PrimitiveType_TriangleList, baseVertexIndex, minIndex, numVertices,
        startIndex, numIndices);
}
© 2017 Noesis Technologies