ID3D11DeviceContext::UpdateSubresource 方法 (d3d11.h)
请参阅 基本全息影像示例。
CPU 将数据从内存复制到不可映射内存中创建的子资源。
语法
void UpdateSubresource(
[in] ID3D11Resource *pDstResource,
[in] UINT DstSubresource,
[in, optional] const D3D11_BOX *pDstBox,
[in] const void *pSrcData,
[in] UINT SrcRowPitch,
[in] UINT SrcDepthPitch
);
参数
[in] pDstResource
类型: ID3D11Resource*
指向目标资源的指针, (ID3D11Resource) 。
[in] DstSubresource
类型: UINT
一个从零开始的索引,用于标识目标子资源。 有关更多详细信息,请参阅 D3D11CalcSubresource 。
[in, optional] pDstBox
类型: const D3D11_BOX*
指向框的指针,该框定义要将资源数据复制到其中的目标子资源部分。 缓冲区的坐标以字节为单位,纹理的纹素以字节为单位。 如果 为 NULL,则数据将写入目标子资源,且没有偏移量。 源的维度必须符合目标, (看到 D3D11_BOX) 。
空框导致无操作。 如果顶部值大于或等于底部值,或者左值大于或等于右值,或者前值大于或等于后的值,则框为空。 当框为空时, UpdateSubresource 不执行更新操作。
[in] pSrcData
类型: const void*
指向内存中源数据的指针。
[in] SrcRowPitch
类型: UINT
源数据一行的大小。
[in] SrcDepthPitch
类型: UINT
源数据一个深度切片的大小。
返回值
无
备注
对于着色器常量缓冲区;将 pDstBox 设置为 NULL。 不能使用此方法部分更新着色器常量缓冲区。
在如下的情况下,资源不能用作目标:
- 资源是使用 不可变 或 动态 使用情况创建的。
- 资源创建为深度模具资源。
- 资源是使用多重采样功能创建的, (请参阅 DXGI_SAMPLE_DESC) 。
UpdateSubresource 的性能取决于目标资源是否存在争用。 例如,当应用程序执行 Draw 调用并在 GPU 实际执行 绘图 调用之前在同一顶点缓冲区上调用 UpdateSubresource 时,将发生 顶 点缓冲区资源的争用。
- 当资源争用时, UpdateSubresource 将执行源数据的 2 个副本。 首先,由 CPU 将数据复制到命令缓冲区可访问的临时存储空间。 此复制发生在 方法返回之前。 然后,GPU 执行第二次复制,将源数据复制到不可映射的内存中。 第二次复制以异步方式发生,因为它在刷新命令缓冲区时由 GPU 执行。
- 如果没有资源争用, 则 UpdateSubresource 的行为依赖于它更快 (从 CPU 的角度来看) :将数据复制到命令缓冲区,然后在刷新命令缓冲区时执行第二次复制,或者让 CPU 将数据复制到最终资源位置。 这取决于基础系统的体系结构。
此视觉对象中的每个块表示一个数据元素,每个元素的大小取决于资源的格式。 例如,如果资源格式DXGI_FORMAT_R32G32B32A32_FLOAT,则每个元素的大小将为 128 位或 16 个字节。 此 3D 体积纹理的宽度为 2,高度为 3,深度为 4。
若要计算给定资源的源行间距和源深度间距,请使用以下公式:
- 源行间距 = [以字节为单位的一个元素的大小] * [一行中的元素数]
- 源深度间距 = [源行间距] * [行数 (高度) ]
- 源行间距 = 16 * 2 = 32
- 源深度间距 = 16 * 2 * 3 = 96
例如,以下代码片段演示如何在 2D 纹理中指定目标区域。 假设目标纹理为 512x512,操作会将 pData 指向的数据复制到 [ (120,100) .目标纹理中 (200,220) ]。 此外,假设 rowPitch 已使用正确的值 (初始化,如上述) 所述。 front 和 back 分别设置为 0 和 1,因为通过将 front 等于 back,框在技术上是空的。
D3D11_BOX destRegion;
destRegion.left = 120;
destRegion.right = 200;
destRegion.top = 100;
destRegion.bottom = 220;
destRegion.front = 0;
destRegion.back = 1;
pd3dDeviceContext->UpdateSubresource( pDestTexture, 0, &destRegion, pData, rowPitch, 0 );
一维情况类似。 以下代码片段演示如何在 1D 纹理中指定目标区域。 使用与上述相同的假设,只是纹理的长度为 512。
D3D11_BOX destRegion;
destRegion.left = 120;
destRegion.right = 200;
destRegion.top = 0;
destRegion.bottom = 1;
destRegion.front = 0;
destRegion.back = 1;
pd3dDeviceContext->UpdateSubresource( pDestTexture, 0, &destRegion, pData, rowPitch, 0 );
有关各种资源类型以及 UpdateSubresource 如何使用每种资源类型的信息,请参阅 Direct3D 11 中的资源简介。
在延迟上下文上调用 UpdateSubresource
如果应用程序在具有非 (0,0,0,0) 偏移量的目标框的延迟上下文上调用 UpdateSubresource,并且如果驱动程序不支持命令列表,则 UpdateSubresource 不恰当地将该目标框偏移量应用于 pSrcData 参数。 若要解决此行为,请使用以下代码:
HRESULT UpdateSubresource_Workaround(
ID3D11Device *pDevice,
ID3D11DeviceContext *pDeviceContext,
ID3D11Resource *pDstResource,
UINT dstSubresource,
const D3D11_BOX *pDstBox,
const void *pSrcData,
UINT srcBytesPerElement,
UINT srcRowPitch,
UINT srcDepthPitch,
bool* pDidWorkAround )
{
HRESULT hr = S_OK;
bool needWorkaround = false;
D3D11_DEVICE_CONTEXT_TYPE contextType = pDeviceContext->GetType();
if( pDstBox && (D3D11_DEVICE_CONTEXT_DEFERRED == contextType) )
{
D3D11_FEATURE_DATA_THREADING threadingCaps = { FALSE, FALSE };
hr = pDevice->CheckFeatureSupport( D3D11_FEATURE_THREADING, &threadingCaps, sizeof(threadingCaps) );
if( SUCCEEDED(hr) )
{
if( !threadingCaps.DriverCommandLists )
{
needWorkaround = true;
}
}
}
const void* pAdjustedSrcData = pSrcData;
if( needWorkaround )
{
D3D11_BOX alignedBox = *pDstBox;
// convert from pixels to blocks
if( m_bBC )
{
alignedBox.left /= 4;
alignedBox.right /= 4;
alignedBox.top /= 4;
alignedBox.bottom /= 4;
}
pAdjustedSrcData = ((const BYTE*)pSrcData) - (alignedBox.front * srcDepthPitch) - (alignedBox.top * srcRowPitch) - (alignedBox.left * srcBytesPerElement);
}
pDeviceContext->UpdateSubresource( pDstResource, dstSubresource, pDstBox, pAdjustedSrcData, srcRowPitch, srcDepthPitch );
if( pDidWorkAround )
{
*pDidWorkAround = needWorkaround;
}
return hr;
}
要求
目标平台 | Windows |
标头 | d3d11.h |
Library | D3D11.lib |