LukasBanana / LLGL

Low Level Graphics Library (LLGL) is a thin abstraction layer for the modern graphics APIs OpenGL, Direct3D, Vulkan, and Metal
BSD 3-Clause "New" or "Revised" License
2.05k stars 139 forks source link

Refactor "SetVertexBufferArray" to "SetVertexBuffers" #13

Open LukasBanana opened 6 years ago

LukasBanana commented 6 years ago

The idea is to get rid of all ...Array interfaces as well as Set...Array functions in the CommandBuffer interface. Instead, the new ResourceHeap interface should be used, which complies with the new rendering APIs. The SetVertexBufferArray function should be refactored to the following:

void SetVertexBuffers(std::uint32_t numVertexBuffers, Buffer* const * vertexBuffers);

For all renderers (except OpenGL) this can be trivially implemented by using an uninitialized local C-style array that is passed to the native renderer API like this:

void D3D11CommandBuffer::SetVertexBuffers(
    std::uint32_t  numVertexBuffers,
    Buffer* const* vertexBuffers)
{
    /* Uninitialized local arrays are trivially constructed on the stack */
    ID3D11Buffer* buffers[g_maxVertexBuffers];
    UINT strides[g_maxVertexBuffers];
    UINT offsets[g_maxVertexBuffers];

    /* Convert vertex buffer array to native parameters */
    numVertexBuffers = std::min(numVertexBuffers, g_maxVertexBuffers);
    for (std::uint32_t i = 0; i < numVertexBuffers; ++i)
    {
        auto vertexBufferD3D = LLGL_CAST(D3D11VertexBuffer*, vertexBuffers[i]);
        buffers[i] = vertexBufferD3D->GetNative();
        strides[i] = vertexBufferD3D->GetStride();
        offsets[i] = 0;
    }

    /* Pass local arrays to native API */
    context_->IASetVertexBuffers(0, numVertexBuffers, buffers, strides, offsets);
}

This works analogous to the SetViewports and SetScissors functions.

For OpenGL, however, this requires a little more effort. The idea is to convert the GLVertexArrayObject member variable in GLVertexBuffer into shared pointer. Then all vertex buffers used in a call to SetVertexBuffers refer to the same VAO. When these buffers are used in the SetVertexBuffers function for the first time, this VAO is created 'on the fly'. When they are used together once more, this VAO can be reused. This allows to dynamically change the vertex buffers without letting the client programmer manage a BufferArray object.

Caveat: To make a buffer usable for multiple sets of vertex buffers, each GLVertexBuffer must hold a container of shared pointers. Otherwise, some VAOs could be created and deleted every frame :-( So either each GLVertexBuffer needs this list, which must be iterated for each buffer used in the SetVertexBuffers function, or some sort of hash map must be involved to quickly find the correct VAO for a set of buffers.

Alternative 1: Get rid of all ...Array interfaces except of BufferArray (but only for vertex buffer arrays).

Alternative 2: Both SetVertexBufferArray and SetVertexBuffers are supported. The former one is supported for optimization purposes and the latter one is supported for flexibility purposes.

Update (12/07/2018): Maybe the GL_ARB_vertex_attrib_binding extension can help here.

LukasBanana commented 6 years ago

The TextureArray and SamplerArray interfaces have been removed with 1d49e1f. Use ResourceHeap interface instead (shown in Tutorial02: Tessellation).