【问题标题】:Why doesn't `Texture2D` expose its pixel data?为什么 `Texture2D` 不暴露其像素数据?
【发布时间】:2012-09-01 21:33:08
【问题描述】:

我可以很容易地想到在Texture2D 中更改单个像素会很有用的许多情况,尤其是因为在不断地每帧执行GetData<>(); SetData<>(); 或绘制到RenderTarget2D.

是否有任何真正的理由为单个像素公开 setter 方法?如果没有,有没有办法不使用上述方法修改单个像素?

【问题讨论】:

  • 如果纹理加载到 GPU 内存中会怎样?在这种情况下,它不能直接寻址,因此您必须将其加载到主内存中,对其进行修改,然后再将其加载回 GPU。
  • @EdS。有趣的是,我没有想到这一点。那么纹理存储在GPU内存中?我以为它都加载到了 RAM 中。
  • @EdS。你有这方面的参考吗?
  • 您可以将GetDataSetData 与矩形区域一起使用,您可以将其设置为单个像素大小。是什么让您认为假设的 GetPixel/SetPixel 会更快?
  • 如果纹理存储在 RAM 中,与设置整个数组相比,在数组中设置单个索引会更快。我发现它们存储在 VRAM 中。

标签: c# graphics xna xna-4.0 texture2d


【解决方案1】:

出于性能原因,纹理数据在初始化纹理时几乎总是由图形驱动程序复制到视频内存 (VRAM)。这使得 GPU 上运行的着色器获取纹理显着更快;如果每个纹理缓存未命中都必须通过 PCIe 总线获取丢失的数据,您肯定会不高兴!

但是,正如您所注意到的,这会使 CPU 读取或修改数据变得困难和/或变慢。不仅 PCIe 总线相对较慢,而且 VRAM 通常不能被 CPU 直接寻址;数据通常必须使用特殊的低级 DMA 命令传输。这正是您在使用 XNA 的 GetData<>()SetData<>() 时看到性能下降的原因:杀死您的不是函数调用开销,而是它们必须在您背后将数据来回复制到 VRAM 的事实。

如果您想修改 VRAM 中的数据,低级渲染 API(例如 OpenGL 或 Direct3D 11)为您提供三个选项:

  1. 在更改之前临时“映射”像素数据(包括将其复制回主内存)并在编辑完成时“取消映射”它(将更改提交回 VRAM)。这可能是GetData<>()SetData<>() 在内部做的事情。
  2. 使用像 OpenGL 的 glTexSubImage2D() 这样的函数,它基本上跳过“映射”步骤,将新的像素数据直接复制回 VRAM,覆盖之前的内容。
  3. 通过运行将纹理写入作为渲染目标的着色器,指示 GPU 代表您进行修改。

XNA 建立在 Direct3D 之上,因此它也必须在这些限制范围内工作。所以,没有原始像素数据给你!

(顺便说一句,以上所有内容也适用于 GPU 缓冲区数据。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-30
    • 2015-09-26
    • 1970-01-01
    • 2018-12-25
    • 2018-06-19
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    相关资源
    最近更新 更多