我正在使用 RTX 3060 GPU(笔记本电脑版本),我正在尝试渲染 100 万个三角形(通过 500,000 个实例四边形的实例化),GPU 似乎花费了大约 40 毫秒,如 nsight 所示,而 CPU 实际上什么也没做。我的着色器是简单的顶点和片段着色器,其中没有其他内容。这看起来非常微不足道,因为我认为 GPU 可以轻松渲染数百万个三角形。主渲染循环如下所示:
m_RenderData.InitialColorPass->Use();
m_RenderData.InitialColorPass->SetUniformMat4("ViewProjection", ViewProjectionMatrix);
InstanceBatch.BeginInstanceBatch();
glDrawElementsInstanced(
GL_TRIANGLES,
(GLuint)(Instance.GetCount()),
GL_UNSIGNED_INT,
nullptr,
(GLuint)(InstanceBatch.GetNumberOfInstances())
);
InstanceBatch.EndInstanceBatch();
在开始实例批处理中,我取消映射包含矩阵数据的缓冲区
if (m_CurrentBufferIndex == 0)
m_InstanceBuffer.UnMap();
else if (m_CurrentBufferIndex == 1)
m_InstanceSecondBuffer.UnMap();
else
m_InstanceThirdBuffer.UnMap();
m_InstanceVAO.Bind();
然后在最终实例批处理中,我只需重新映射缓冲区范围,我在启用异步标志和三重缓冲的情况下执行此操作。
if (m_CurrentBufferIndex == 0)
{
m_BufferMapBase = (float*)m_InstanceSecondBuffer.MapBufferRange();
m_InstanceVAO.AttachVertexBuffer(m_InstanceSecondBuffer, 1, m_AttributeDataCopy.Offsets[1], m_AttributeDataCopy.Strides[1]);
m_CurrentBufferIndex = 1;
}
else if (m_CurrentBufferIndex == 1)
{
m_BufferMapBase = (float*)m_InstanceThirdBuffer.MapBufferRange();
m_InstanceVAO.AttachVertexBuffer(m_InstanceThirdBuffer, 1, m_AttributeDataCopy.Offsets[1], m_AttributeDataCopy.Strides[1]);
m_CurrentBufferIndex = 2;
}
else
{
m_BufferMapBase = (float*)m_InstanceBuffer.MapBufferRange();
m_InstanceVAO.AttachVertexBuffer(m_InstanceBuffer, 1, m_AttributeDataCopy.Offsets[1], m_AttributeDataCopy.Strides[1]);
m_CurrentBufferIndex = 0;
}
起初我认为这是缓冲区同步问题并等待 GPU,这就是我实现三重缓冲的原因,虽然这实际上将 CPU 时间减少到零(每帧大约 2 毫秒),但 GPU 仍然需要很长时间。我开始认为这可能是硬件限制,但 3060 即使在笔记本电脑上也是强大的 GPU。接下来,我认为在控制面板中启用和禁用了垂直同步,但这似乎没有任何作用。我的集成显卡(amd ryzen 7 5800)也略胜于我的专用 3060。
我最近开始收到的一个警告是 [Core-Warn] 像素路径性能警告:像素传输与 3D 渲染同步。 当我最初重新映射缓冲区或使用新大小重建缓冲区时,会发生一次这种情况。
我发现了问题,结果发现其中一个映射的缓冲区错误地附加到顶点数组,所以我只使用双缓冲而不是我想要的三重缓冲,因为每一帧都没有映射,因此绘制调用将从空缓冲区。现在回想起来,对于如此多的数据,GPU 使用率高而 CPU 使用率低似乎是显而易见的。