以编程方式创建 directx 11 纹理,三种不同方法的优缺点
msdn 文档解释了在 directx 11 中有多种方法以编程方式填充 directx 11 纹理:
(1) 使用默认使用纹理创建纹理,并使用内存中的数据对其进行初始化
(2) 使用动态使用创建纹理,使用 DeviceContext Map 获取指向纹理内存的指针,写入到它,然后使用 Unmap 来指示您已完成(此时我猜它已复制到 GPU)
(3) 使用暂存用法创建纹理并遵循与动态纹理相同的步骤,但随后调用 ID3D11DeviceContext .CopyResource 使用此暂存纹理依次填充(非不可变的)默认或动态纹理。
然而,文档根本没有解释每种方法的优缺点,而且我对 directx 还很陌生,所以我根本不清楚。
在 directx 11 中以编程方式创建纹理的每种方法的优缺点是什么?
旁注:我读到,在暂存纹理的上下文中,从 GPU 读取的内容不会被缓冲,因此您必须自己进行双缓冲。但我不知道这是否准确,也不知道它是否适用于使用分段纹理进行书写(甚至不知道它的真正含义)。
第二个旁注: Map 方法文档称它获取指向子资源中数据的指针,并拒绝 GPU 访问该子资源。当GPU想要访问底层数据已经被Map调用的纹理时,它会做什么?失速? (我问是因为这听起来像是我询问的利弊的一部分)
The msdn documentation explains that in directx 11 there are multiple ways to fill a directx 11 texture programmatically:
(1) Create the texture with default usage texture and initialize it with data from memory
(2) Create the texture with dynamic usage, use DeviceContext Map to get a pointer to texture memory, write to it, then use Unmap to indicate you are done (at which point I guess it is copied to the gpu)
(3) Create the texture with staging usage and follow same steps as for dynamic texture, but follow that with a call to ID3D11DeviceContext.CopyResource to use this staging texture to in turn fill a (non immutable) default or dynamic texture.
However the documentation doesn't explain pros and cons of each method at all, and I am still quite new to directx, so it is not at all clear to me.
What are the pros and cons of each of these ways of creating a texture programmatically in directx 11?
Side note: I have read that in the context of staging textures, reading back from the gpu isn't buffered so you have to do your own double buffering. But I don't know whether this was accurate and whether it applies to writing using staging textures (or even really what it means).
Second side note: The Map method documentation says it gets a pointer to data in a subresource and denies the GPU access to that subresource. When the GPU wants to access a texture whose underlying data has been called by Map, what does it do? Stall? (I ask because this sounds like part of the pros and cons I inquired about)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正确的答案取决于您要使用纹理的用途。这三个选项是将数据从 CPU 获取到纹理的不同方式。如果这是渲染目标,您通常不会提供来自 CPU 的初始数据,因此您可以忽略这些:创建纹理,然后在准备好渲染到其中时(可能先对其进行 Clear() 处理)。
因此,假设您在应用程序内存中确实有想要进入纹理的数据:
如果这只是一个静态纹理(我的意思是,读取纹理的数量远多于写入纹理的数量),那么您需要 USAGE_DEFAULT 或USAGE_IMMUTABLE 纹理。与 USAGE_DYNAMIC 相比,这些通常针对 GPU 读取性能进行了优化。如果您在创建纹理时手头有数据,那么选项 (1) 最简单,使用最少的中间内存,并且在 DX11 中,可以在与渲染线程不同的单独线程上完成到 GPU 的数据传输。如果您在创建纹理时没有数据,请在有数据时使用 UpdateSubresource() 或选项 (3) 提供数据。
如果它是动态纹理,意味着您经常从 CPU 提供新内容(基于 CPU 的视频播放是典型情况:CPU 每帧提供一次数据,然后由 GPU 每帧读取一次),那么您可能想要使用 USAGE_DYNAMIC 和选项 (2)。 USAGE_DYNAMIC 纹理针对从 CPU 到 GPU 的流数据进行了优化,而不仅仅是针对 GPU 读取。硬件供应商之间的细节(和性能影响)有所不同,但通常您只想在确实将数据从 CPU 流式传输到 GPU 时才使用 USAGE_DYNAMIC,而不仅仅是因为它是预先加载静态数据的便捷方法。
选项 (3) 更专业,可用于将初始数据加载到静态纹理中(重用暂存表面来加载许多纹理的数据)或用于流数据以进行相对动态的使用。它使您能够精确控制 GPU/CPU 同步以及用于传输的中间内存。通常,您会使用一圈暂存缓冲区和 D3D11_MAP_FLAG_DO_NOT_WAIT 来检查每个缓冲区是否仍在被先前的 CopyResource 使用。我认为这是一个专家选项——如果您不小心,可能会阻止 CPU 和 GPU 异步运行,从而严重损害性能。
全面披露:我在 Nvidia 从事 D3D 驱动程序的工作,但这些是我个人的意见。
The right answer depends on what you're going to use the texture for. Those three options are different ways of getting data from the CPU into the texture. If this is a rendertarget, you generally aren't providing initial data from the CPU, so you can ignore these: create the texture, and when you're ready render into it (perhaps Clear()ing it first).
So assuming you do have data in application memory that you want to get into the texture:
If this is just a static texture (by that I mean the texture is read from much more than it is written to), then you want a USAGE_DEFAULT or USAGE_IMMUTABLE texture. These are generally optimized for GPU read performance compared to USAGE_DYNAMIC. If you have the data handy when you create the texture, then option (1) is easiest, uses the least intermediate memory, and in DX11 the data transfer to the GPU can be done on a separate thread from your rendering thread. If you don't have the data at the time you create the texture, use UpdateSubresource() or option (3) to provide the data when you have it.
If it's a dynamic texture, meaning that you provide new contents from the CPU frequently (CPU-based video playback is the canonical case: data is provided by CPU once per frame, then read by the GPU once per frame) then you probably want to use USAGE_DYNAMIC and option (2). USAGE_DYNAMIC textures are optimized for streaming data from the CPU to the GPU rather than simply for GPU reads. The details (and performance implications) vary between hardware vendors, but usually you only want to use USAGE_DYNAMIC if you really are streaming data from CPU to GPU, rather than simply because it's a convenient way to load static data up-front.
Option (3) is more specialized, and can be used for either initial data load into a static texture (reuse the staging surface(s) for loading data for many textures) or for streaming data for relatively dynamic use. It gives you precise control over GPU/CPU synchronization and over the intermediate memory used for transfers. Usually you'd use a ring of staging buffers, and D3D11_MAP_FLAG_DO_NOT_WAIT to check whether each buffer is still in use by a previous CopyResource. I consider this an expert option -- if you're not careful you can hurt perf badly by preventing the CPU and GPU from running asynchronously.
Full disclosure: I work on the D3D driver at Nvidia, but these are my personal opinions.