【问题标题】:What does ID3D11Device::CreateBuffer do under the hood?ID3D11Device::CreateBuffer 在幕后做了什么?
【发布时间】:2020-05-21 00:41:49
【问题描述】:

我知道这个函数会创建一个“缓冲区”。但究竟什么是缓冲区?它是内存中的COM 对象吗?如果是,那么在我的理解中,这个函数接受一个描述符和一些初始数据在内存中创建这个COM对象,然后将输入ID3D11Buffer**指向的ID3D11Buffer指针设置到接口在新创建的 COM 对象中。一旦 COM 对象被创建,初始化数据就不再需要了,我们可以删除它们。一旦我们调用 ID3DBuffer::Release(),下划线的 COM 对象就会被销毁。我的理解正确吗?

【问题讨论】:

  • 一般来说,您不需要也无法知道。这些缓冲区可以在 Direct3D 设备(比如硬件 Nvidia 卡)或软件中通过 Warp 驱动程序创建。或者可能根本没有缓冲区。你不知道也不需要知道。只需按照文档说明进行操作即可。
  • 好吧,但我认为我需要比文档更多的解释才能使语法对我有意义,例如为什么我需要输入 ID3D11Buffer**,以及它将指向什么在我调用 CreateBuffer 函数后
  • Windows 编程不能以这种方式工作。我们经常做一些事情,因为这就是文档所说的。您不知道缓冲区指向的位置,就像您不知道 HWND 实际包含什么一样。只需在文档说需要时使用它。

标签: c++ graphics directx computer-science directx-11


【解决方案1】:

CreateBuffer 返回一个 COM 接口对象ID3D11Buffer*。只要它具有非零引用计数(它从 1 开始;每次调用 AddRef 加 1,每次调用 Release 减 1)然后它控制的任何资源都是活动的。

至于资源究竟分配在哪里,这真的取决于。您可能会发现 this article 很有趣,因为它涵盖了 Direct3D 分配资源的不同方式。

更新:您还应该阅读此Microsoft Docs 介绍 DirectX 使用的 COM 子集。

【讨论】:

  • 感谢您的回复!我会读这篇文章。顺便问一下,CreateBuffer是返回一个COM接口对象还是一个指向COM接口对象的指针?
  • 它是一个指针,但你不能deletefree 它。您只能使用AddRef / Release 来控制它的生命周期。
【解决方案2】:

在一般情况下,缓冲区是一个连续的、托管的内存区域。

内存是一大组读/写元素的地址(当然,每个地址一个元素),比如 8 位元素的 230 个地址构成 1GiB 内存。

如果只有一个程序并且它静态使用这些地址(例如,从 0x1000 到 0x2000 的地址用于存储项目列表),则不需要管理内存,在这种情况下,缓冲区只是一个连续的地址范围。

但是,如果有多个程序或程序内存使用是动态的(例如,这取决于要求从输入中读取多少项),则必须管理内存。
您必须跟踪哪些范围已经在使用,哪些没有。因此,缓冲区成为具有它们的属性的连续地址范围(例如,它是否在使用中)。
缓冲区的属性在不同的内存分配器之间可能会有很大差异,一般来说,我们说缓冲区是托管,因为我们让内存分配器来处理它:找到一个合适的空闲范围,将其标记为已使用,告诉它是否可以将缓冲区向后移动,完成后将其标记为空闲。


对于每个共享的内存都是如此,因此对于主内存 (RAM) 和图形内存当然也是如此。
这是显卡内部的内存,就像主内存一样被访问(从 CPU 的角度来看)。

CreateBuffer 返回的是主内存中的 COM 对象,其中包含处理刚刚分配的缓冲区所需的元数据。
它不包含缓冲区本身,因为此 COM 对象始终在内存中,而缓冲区通常不包含(它在图形内存中)。

CreateBuffer 要求图形驱动程序在所要求的内存中找到合适的空闲地址范围,并填写一些元数据
在 CPU 可以访问主内存之前,有必要设置一些元数据表(页表)作为其保护机制的一部分。
如果 CPU 需要访问图形内存也是如此(可能需要一些额外的步骤,以便在必要时管理 MMIO)。
GPU 也有页表,因此如果 GPU 必须访问主存储器,则还必须创建这些页表。

您知道了解缓冲区的使用方式很重要。
要考虑的另一件事是 GPU 使用高度优化的内存格式 - 例如,用于表面的缓冲区可以被描绘为内存的矩形区域。
纹理使用的缓冲区也是如此。
但是两者的存储方式不同:表面是线性存储的,每一行一个接一个,而纹理缓冲区是平铺的(就像它是由许多,比如说,16x16 表面一个接一个线性存储的)。
这使得采样和过滤更快。
此外,某些 GPU 可能需要在内存的特定区域中具有纹理图像,在另一个区域中具有顶点缓冲区等等。

因此,在分配缓冲区时,为图形驱动程序提供做出最佳选择所需的所有信息非常重要。

一旦找到缓冲区,驱动程序(或 D3D 运行时)将在请求时初始化缓冲区。
它可以通过复制数据或通过页表别名(如果音调允许的话)并最终使用某种形式的 Copy-On-Write 来做到这一点。
但是,它不再需要源数据(请参阅this)。

CreateBuffer 返回的 COM 对象是一个方便的代理,然后将其处理掉,感谢通常的 AddRef/Release 机制,它还要求图形驱动程序释放缓冲区。


【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-04
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 2016-03-19
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    相关资源
    最近更新 更多