2.3.1资源操控
Direct3D11提供了许多不同的技术来修改或操纵资源的内容。
映射资源Mapping Resources
从CPU读取和写入缓冲区内容的主要方法是设备上下文的Map/Unmap方法。如果资源设置了CPU读取或写入访问标志,则应用程序可以将资源的内容映射到系统内存。
CPU对GPU的资源更新 https://www.vaczh.com/article/detail-41.html
HRESULT Map(
ID3DllResource *pResource,
UINT Subresource,
D3D11_MAP MapType,
UINT MapFlags,
D3D11_MAPPED_SUBRES0URCE *pMappedResource
);
void Unmap(
ID3DllResource *pResource,
UINT Subresource
);
要映射的资源和子资源分别在pResource和subresource参数中指定。接下来,在MapType参数中指定映射类型,该参数指示是否读取或写入资源,以及如何执行任何写入。D3D11_MAP枚举的成员如清单2.50所示。
enum D3D11_MAP {
D3D11_MAP_READ,
D3D11_MAP_WRITE,
D3D11_MAP_READ_WRITE,
D3D11_MAP_WRITE_DISCARDJ
D3D11_MAP_WRITE_N0_0VERWRITE
}
枚举中的前三个值是不言自明的。如果要读取资源,则必须已使用D3D11_CPU_ACCESS_read标志创建该资源;如果要写入资源,则该资源必须已使用D3 D11_CPU_ACCESS_WRITE标志创建。读取资源时,其内容将在pMappedResource参数所指向的D3D11_MAPPED_SUBRESOURCE结构中可用。当写入资源时,应用程序使用相同的D3D11_MAPPED_SUBRES0URCE结构来标记将所需资源数据写入的位置。在读取和写入时,资源的内容可用,然后可以被应用程序覆盖,从而将资源的内容“映射”到系统内存。取消映射资源的调用将使资源中的任何书面更改生效.
D3D11_MAP_WRITE_DISCARD和D3D11_MAP_WRITE_NO_OVERWRITE标志一起使用以允许动态资源使用。D3D11_MAP_WRITE_DISCARD映射类型在映射资源时会使资源的内容无效,即使当前仅映射子资源也是如此。D3D11_MAP_WRITE_NO_OVERWRITE映射类型允许写入自上次调用D3D11_MAP_WRITE_DISCARD以来先前未更新的缓冲区的一部分。通过这种方式,已经加载到动态资源中的资源的内容可以开始使用,而资源的其他部分仍在被填充.
从映射的子资源结构中读取或写入资源后,最终必须取消映射该资源,以允许GPU继续使用它。这只需使用ID3DllDeviceContext::Unmap()方法即可,该方法标识要取消映射的资源和子资源索引。
资源映射的一个重要考虑因素是,一次必须映射一个完整的子资源。这意味着无法读取/写入子资源的一部分,尽管可以映射整个子资源,同时只更新其中的一小部分。根据子资源的大小,这可能涉及到向系统内存传输和从系统内存传输大量内存。在某些情况下,这是不可行的,但在其他情况下,有一种方法只更新子资源的一部分是有益的。我们将在“更新子资源”部分看到这样的方法。
使用map和unmap方法的一个常见示例是在管道执行中使用常量缓冲区时更新其内容。在这种情况下,资源将被D3D11_MAP_WRITE标志所覆盖,因为我们对读取常量缓冲区的内容不感兴趣。相反,我们只将新数据写入缓冲区。一旦数据被写入到pMappedResource结构提供的系统内存中,该源将被取消映射,然后可以绑定到管道中使用。
更新子资源
另一种可用于修改资源内容的机制是devicecontext的UpdateSubresource()方法。此方法与资源映射的不同之处在于,它只写入资源,不允许读取其内容。这个方法的原型如清单2.51所示
void UpdateSubresource(
ID3D11Resource *pDstResource,
UINT DstSubresource,
const D3D11_B0X *pDstBox,
const void *pSrcData,
UINT SrcRowPitch,
UINT SrcDepthPitch
);
在清单2.50中,我们可以看到要写入资源的数据被赋予了指向其内存位置的指针。这伴随着以字节为单位测量的数据块的行间距和深度间距。目标由指向资源的指针和子资源索引标识。通过在D3D11_B0X中识别子资源,可以只写入子资源的一部分。虽然源数据是以字节为单位提供的,并且与数据本身有关,但目的地是以索引为单位提供,并不取决于资源的格式。
与映射资源的方法不同,update子资源方法只能写入子资源的一部分。如果只需要更新大资源的一小部分,那么更新子资源方法在某些条件下可以执行得更好,因为它将使用更少的带宽。
这种资源更新的一个例子可以是基于用户所采取的操作来更改纹理的内容。如果用户选择的选项需要修改纹理的一小部分,则可以使用更新子资源方法轻松执行此操作。