2
votes

Been delving into un-managed DirectX 11 for the first time (bear with me) and there's an issue that, although asked several times over the forums still leaves me with questions.

I am developing as app in which objects are added to the scene over time. On each render loop I want to collect all vertices in the scene and render them reusing a single vertex and index buffer for performance and best practice. My question is regarding the usage of dynamic vertex and index buffers. I haven't been able to fully understand their correct usage when scene content changes.

vertexBufferDescription.Usage               = D3D11_USAGE_DYNAMIC;
vertexBufferDescription.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDescription.CPUAccessFlags      = D3D11_CPU_ACCESS_WRITE;
vertexBufferDescription.MiscFlags           = 0;
vertexBufferDescription.StructureByteStride = 0;

Should I create the buffers when the scene is initialized and somehow update their content in every frame? If so, what ByteSize should I set in the buffer description? And what do I initialize it with?

Or, should I create it the first time the scene is rendered (frame 1) using the current vertex count as its size? If so, when I add another object to the scene, don't I need to recreate the buffer and changing the buffer description's ByteWidth to the new vertex count? If my scene keeps updating its vertices on each frame, the usage of a single dynamic buffer would loose its purpose this way...

I've been testing initializing the buffer on the first time the scene is rendered, and from there on, using Map/Unmap on each frame. I start by filling in a vector list with all the scene objects and then update the resource like so:

void Scene::Render() 
{
    (...)

    std::vector<VERTEX> totalVertices;
    std::vector<int> totalIndices;
    int totalVertexCount = 0;
    int totalIndexCount = 0;

    for (shapeIterator = models.begin(); shapeIterator != models.end(); ++shapeIterator)
    {
            Model* currentModel = (*shapeIterator);

            // totalVertices gets filled here...
    }

     // At this point totalVertices and totalIndices have all scene data

    if (isVertexBufferSet)
    {
        // This is where it copies the new vertices to the buffer.
        // but it's causing flickering in the entire screen...
        D3D11_MAPPED_SUBRESOURCE resource;
        context->Map(vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
        memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));
        context->Unmap(vertexBuffer, 0);
    }
    else
    {
        // This is run in the first frame. But what if new vertices are added to the scene?
        vertexBufferDescription.ByteWidth = sizeof(VERTEX) * totalVertexCount;
        UINT stride = sizeof(VERTEX);
        UINT offset = 0;

        D3D11_SUBRESOURCE_DATA resourceData;
        ZeroMemory(&resourceData, sizeof(resourceData));
        resourceData.pSysMem = &totalVertices[0];

        device->CreateBuffer(&vertexBufferDescription, &resourceData, &vertexBuffer);
        context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
        isVertexBufferSet = true;
    }

In the end of the render loop, while keeping track of the buffer position of the vertices for each object, I finally invoke Draw():

    context->Draw(objectVertexCount, currentVertexOffset);
}

My current implementation is causing my whole scene to flicker. But no memory leaks. Wonder if it has anything to do with the way I am using the Map/Unmap API?

Also, in this scenario, when would it be ideal to invoke buffer->Release()? Tips or code sample would be great! Thanks in advance!

1
Copying the vertices to a vertex buffer each frame seems like a very inefficient thing to do unless each vertex is changing every frame which seems unlikely for most things. it's much more normal to create the buffers once.jcoder
In the meantime I managed to fix the flickering issue. The memcpy was wrong, and I the amount of bytes to be copied was being passed on incorrectly. It has to be sizeof(VERTEX) * totalVertices.size().VOliveira
@jcoder You are correct. I forgot to mention that I am controlling the scene's dirty state precisely to leave the buffer as is most of the time. I am just not sure if vertex/index buffer creation couldn't be done on init() rather than on the first frame, like in the code sample.VOliveira

1 Answers

3
votes

At the memcpy into the vertex buffer you do the following:

memcpy(resource.pData, &totalVertices[0], sizeof(totalVertices));

sizeof( totalVertices ) is just asking for the size of a std::vector< VERTEX > which is not what you want.

Try the following code:

memcpy(resource.pData, &totalVertices[0], sizeof( VERTEX ) * totalVertices.size() );

Also you don't appear to calling IASetVertexBuffers when isVertexBufferSet is true. Make sure you do so.