在 DirectX 11 中渲染
Rendering in DirectX 11
帧开始时,我进行逻辑更新并在之后进行渲染。
在我的渲染代码中,我做了一些平常的事情。我设置了一些状态、缓冲区、纹理,并通过调用 Draw 结束。
m_deviceContext->Draw(
nbVertices,
0);
在帧结束时我调用 present 来显示渲染帧。
// Present the back buffer to the screen since rendering is complete.
if(m_vsync_enabled)
{
// Lock to screen refresh rate.
m_swapChain->Present(1, 0);
}
else
{
// Present as fast as possible.
m_swapChain->Present(0, 0);
}
平常的东西。现在,当我调用 Draw 时,根据 MSDN
Draw submits work to the rendering pipeline.
这是否意味着数据已发送到 GPU 并且主线程(称为 Draw 的那个)继续?还是等待渲染完成?
在我看来,只有 Present 函数才能让主线程等待渲染完成。
有多个调用可以触发GPU开始工作,Draw
是一个。其他的包括 Dispatch
、CopyResource
等。MSDN 文档试图说明的是像 PSSetShader
这样的东西。 IASetPrimitiveTopology
等在您调用 Draw
.
之前不会真正执行任何操作
当您调用 Present
时,它被视为 'end of frame' 的隐式指示符,但您的程序通常可以在第一帧完成之前继续为下一帧设置渲染调用,并且显示。默认情况下,Windows 将允许您在阻塞 Present
调用上的 CPU 线程之前最多提前 3 帧排队,让 GPU 赶上——在实时渲染中,您通常不希望输入和渲染之间的延迟非常高。
然而,事实是 GPU/CPU 同步很复杂,而且 Direct3D 运行时也在处理请求以最小化内核调用开销,因此在将许多绘图提交给命令后实际工作可能会很顺利-队列。 This old article 让您了解其工作原理。在现代GPU上,还可以进行内存分页、设置物理显存区域等各种内存操作
顺便说一句,所有这些 'magic' 都不存在于 Direct3D 12 中,但这意味着应用程序必须在 'right' 时间做所有事情以确保它既高效又实用。程序员更直接地建立命令队列,触发各种像素和计算 GPU 引擎的工作,并处理所有由 Direct3 11 运行时更抽象和自动处理的杂乱事情。即便如此,最终视频驱动程序是真正与硬件对话的人,因此他们也可以进行其他类型的优化。
这里要牢记的一般经验法则:
- 创建资源非常昂贵,尤其是运行时着色器编译(通过 HLSL 编译器)和运行时着色器 blob 优化(通过驱动程序)
- 将资源复制到 GPU(即从 CPU 内存加载纹理数据)需要供应有限的总线带宽:最好在静态缓冲区中保留纹理、VB 和 IB 数据你再利用。
- 从 GPU 复制资源(即将 GPU 内存移动到 CPU 内存)使用比转到 GPU 慢的反向通道:尽量避免需要从 GPU 回读
- 每次绘制调用提交更大的几何块有助于分摊开销(即,为 10,000 个具有相同 state/shader 的三角形调用绘制一次比为 1000 个三角形调用绘制 10 次要快得多 state/shaders 之间).
帧开始时,我进行逻辑更新并在之后进行渲染。 在我的渲染代码中,我做了一些平常的事情。我设置了一些状态、缓冲区、纹理,并通过调用 Draw 结束。
m_deviceContext->Draw(
nbVertices,
0);
在帧结束时我调用 present 来显示渲染帧。
// Present the back buffer to the screen since rendering is complete.
if(m_vsync_enabled)
{
// Lock to screen refresh rate.
m_swapChain->Present(1, 0);
}
else
{
// Present as fast as possible.
m_swapChain->Present(0, 0);
}
平常的东西。现在,当我调用 Draw 时,根据 MSDN
Draw submits work to the rendering pipeline.
这是否意味着数据已发送到 GPU 并且主线程(称为 Draw 的那个)继续?还是等待渲染完成?
在我看来,只有 Present 函数才能让主线程等待渲染完成。
有多个调用可以触发GPU开始工作,Draw
是一个。其他的包括 Dispatch
、CopyResource
等。MSDN 文档试图说明的是像 PSSetShader
这样的东西。 IASetPrimitiveTopology
等在您调用 Draw
.
当您调用 Present
时,它被视为 'end of frame' 的隐式指示符,但您的程序通常可以在第一帧完成之前继续为下一帧设置渲染调用,并且显示。默认情况下,Windows 将允许您在阻塞 Present
调用上的 CPU 线程之前最多提前 3 帧排队,让 GPU 赶上——在实时渲染中,您通常不希望输入和渲染之间的延迟非常高。
然而,事实是 GPU/CPU 同步很复杂,而且 Direct3D 运行时也在处理请求以最小化内核调用开销,因此在将许多绘图提交给命令后实际工作可能会很顺利-队列。 This old article 让您了解其工作原理。在现代GPU上,还可以进行内存分页、设置物理显存区域等各种内存操作
顺便说一句,所有这些 'magic' 都不存在于 Direct3D 12 中,但这意味着应用程序必须在 'right' 时间做所有事情以确保它既高效又实用。程序员更直接地建立命令队列,触发各种像素和计算 GPU 引擎的工作,并处理所有由 Direct3 11 运行时更抽象和自动处理的杂乱事情。即便如此,最终视频驱动程序是真正与硬件对话的人,因此他们也可以进行其他类型的优化。
这里要牢记的一般经验法则:
- 创建资源非常昂贵,尤其是运行时着色器编译(通过 HLSL 编译器)和运行时着色器 blob 优化(通过驱动程序)
- 将资源复制到 GPU(即从 CPU 内存加载纹理数据)需要供应有限的总线带宽:最好在静态缓冲区中保留纹理、VB 和 IB 数据你再利用。
- 从 GPU 复制资源(即将 GPU 内存移动到 CPU 内存)使用比转到 GPU 慢的反向通道:尽量避免需要从 GPU 回读
- 每次绘制调用提交更大的几何块有助于分摊开销(即,为 10,000 个具有相同 state/shader 的三角形调用绘制一次比为 1000 个三角形调用绘制 10 次要快得多 state/shaders 之间).