我可以很容易地想到在许多情况下更改Texture2D
中的单个像素会很有用,尤其是因为在每帧不断执行GetData<>(); SetData<>();
或绘制RenderTarget2D
时会带来性能打击和不便。
不公开单个像素的setter方法有什么真正的原因吗?如果没有,是否有一种方法可以在不使用上述方法的情况下修改单个像素?
由于性能原因,初始化纹理时,图形驱动程序几乎总是将纹理数据复制到视频存储器(VRAM)中。这使得GPU上运行的着色器获取纹理的速度显著加快;如果每个纹理缓存未命中都必须通过PCIe总线获取丢失的数据,那么您肯定不会高兴!
然而,正如您所注意到的,这会使CPU读取或修改数据变得困难和/或缓慢。PCIe总线不仅相对较慢,而且VRAM通常不能由CPU直接寻址;通常必须使用特殊的低级别DMA命令来传输数据。这正是为什么在使用XNA的GetData<>()
和SetData<>()
时会看到性能下降的原因:杀死你的不是函数调用开销,而是它们必须在背后将数据来回复制到VRAM。
如果您想修改VRAM中的数据,低级别渲染API(例如OpenGL或Direct3D 11)为您提供了三个选项:
- 在更改之前临时"映射"像素数据(包括将其复制回主内存),并在编辑完成时"取消映射"(将更改提交回VRAM)。这可能是
GetData<>()
和SetData<>()
内部正在做的事情 - 使用类似OpenGL的
glTexSubImage2D()
的函数,该函数基本上跳过"映射"步骤,将新的像素数据直接复制回VRAM,覆盖以前的内容 - 指示GPU代表您进行修改,方法是运行将纹理写入渲染目标的着色器
XNA是建立在Direct3D之上的,因此它也必须在这些限制范围内工作。所以,没有原始像素数据!
(顺便说一句,以上所有内容对于GPU缓冲区数据也是正确的。)