1
\$\begingroup\$

I've been writing a renderer in C++ using OpenGL. Recently I wanted to implement indirect batch rendering using glMultiDrawElementsIndirect. When I try to test this implementation, an issue occurs. For the most part I don't see anything on the screen except for in very specific circumstances. It seems as though the issue I have only occurs when I call glBufferData on my GL_DRAW_INDIRECT_BUFFER to fill it with draw calls after I've already written to it with a previous glBufferData call on the same buffer.

If I enable imGUI in my render loop I can see frames being rendered to the screen perfectly fine, but if the GUI is disabled, unless there's lag, I see nothing being rendered.

I've tested a few things that has given me some extra information about the issue I'm having.

I've tried to simulate lag in the render loop by putting the thread to sleep and that showed me that the only reason why I'm seeing any frames at all is because of some sort of lag that occurs on some frames, I haven't looked into it, but I'm sure that something happening behind the scenes is causing me to get some small amount of lag that allows me to see the frames being rendered to the screen. I then tried to only call glBufferData on my indirect buffer on the first frame and wait for a set amount of frames to set it again, I was able to get rendering as expected until the frame I specified, so I'm sure it has something to do with me writing to my indirect buffer after I've already put draw calls in it in a previous frame. In addition to this, I've tried a few things from the OpenGL library like checking glError in which there were no errors, and I attempted to call glFinish both before and after my glBufferData call to no avail, and I have tried implementing glBufferSubData which results in the same error.

I've also tried to use RenderDoc to get some information from my frames and I found that the draw calls are being made correctly each frame and I can see the scene getting drawn in each step but its still not being shown on the screen or the actual captured frame? Although I'm new to RenderDoc so I could definitely be missing something so let me know if there's some more information I can provide from that application!

I'm expecting to have behavior similar to when I was rendering mesh by mesh with glDrawElements, even though I don't intend on writing to my buffers every frame as I am now for the sake of performance, I think I should be able to because at some point in my application I know that there will be times where I may have to update a buffer multiple times in a row, maybe every frame for a few frames or who knows how long.

My render loop is currently in a state where I'm just trying to get it to work as the draw call generation and mesh data gathering will be abstracted but I'd like to solve this issue before moving on.

Here is my render loop:

// Render loop
while (!glfwWindowShouldClose(window)) 
{   
    if (isInput) 
    {
        processInput(window);
    }

    renderAPI.clear(); 

    // For drawing to scene window
    // within gui
    if (GUI->isWindowed())
    {
        sceneBuffer->Bind();  
        renderAPI.clear(); 
    } 

    draw(renderAPI); 
    if (GUI->isWindowed())
        sceneBuffer->Unbind();      

    GUI->drawGUI();

    glfwPollEvents();
    glfwSwapBuffers(window);
        
    // Handle post render duties
    while (PostRenderFunctions.size() > 0)
    {
        PostRenderFunctions.back()();
        PostRenderFunctions.pop_back(); 
    }
    Canvas->updateDeltaTime();
} 

Here is my draw call function. I have a flag so that I can just test if the data I loaded works and I don't push the same data into their buffers again.

template <typename T>           
void draw(Graphics::RenderAPI<T>& renderAPI)
{
    auto shader = renderAPI.getShader("debug");
    shader->use();
               
    for 
    (
        std::shared_ptr<Graphics::Model> model 
        : ResourceManager->getLoadedModels()
    )
    { 

        modelMatrix = model->getModelMatrix();
        shader->setUniform("view", Camera->getViewMatrix());
        shader->setUniform("projection", Camera->getProjectionMatrix());

        for (Graphics::Mesh& mesh : model->getMeshes())
        {
     
            Graphics::ElementDrawCall call;
            shaderName = mesh.getShaderName();

            if (!done)
            {
                vertexData.insert
                (
                    vertexData.end(), 
                    mesh.getVertices().begin(), 
                    mesh.getVertices().end()
                ); 

                indexData.insert
                (
                    indexData.end(), 
                    mesh.getIndices().begin(), 
                    mesh.getIndices().end()
                );

            call.count = mesh.getIndices().size();
            call.instanceCount = 1;
            call.firstIndex = currentBaseIndex;
            call.baseVertex = currentBaseVertex;
            call.baseInstance = instanceIndex;

            currentBaseIndex += mesh.getIndices().size();
            currentBaseVertex += mesh.getVertices().size();
            instanceIndex++;

            drawCalls.push_back(std::move(call));
            }
        }
    }

    renderAPI.loadData
    (
        vertexData, 
        indexData,
        drawCalls,
        "debug"
    );

    shader->setUniform("model", modelMatrix); 
        
    renderAPI.drawElements(drawCalls.size());
    done = true;
}

And here is my render API code where I believe the issue is occurring.

void Graphics::OpenGLRenderAPI::loadDataImpl
(
    std::vector<Graphics::Vertex>& vertices, 
    std::vector<unsigned int>& indices, 
    std::vector<Graphics::ElementDrawCall>& drawCalls,
    std::string shaderName
)
{
    size_t format = m_Shaders[shaderName]->getFormat().first;
    Graphics::RenderConfig& config = getRenderConfig(format, shaderName);

    if (CURRENT_FORMAT != config.format && CURRENT_FORMAT != -1)
    {
        std::cout << "BINDING NEW VAO" << std::endl;
        glBindVertexArray(config.VAO);
        glBindBuffer(GL_ARRAY_BUFFER, config.VBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, config.EBO);
        glBindBuffer(GL_DRAW_INDIRECT_BUFFER, config.IBO);

            
        CURRENT_FORMAT = config.format;
    }

    // This is where the issue occurs, it will operate normally
    // if I only call this once, but once there are draw calls 
    // written I cant call it again or else my rendering issue occurs
    // even if I were to call glBindBuffer every frame
    // I gave also tried static draw, and stream draw for the buffer
    glBufferData
    (
        GL_DRAW_INDIRECT_BUFFER, 
        sizeof(ElementDrawCall) * drawCalls.size(), 
        drawCalls.data(), 
        GL_DYNAMIC_DRAW
    );


    glBufferData(GL_ARRAY_BUFFER, sizeof(Graphics::Vertex) * vertices.size(), &vertices[0], GL_DYNAMIC_DRAW);

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), &indices[0], GL_DYNAMIC_DRAW);
 
}
\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.