Known Issue: Direct3D 11 UpdateSubresource and Deferred Contexts

The UpdateSubresource method on the D3D11DeviceContext interface takes as one of it’s parameters an optional destination offset:

void UpdateSubresource( [in] ID3D11Resource *pDstResource, [in] UINT DstSubresource, [in] const D3D11_BOX *pDstBox, [in] const void *pSrcData, [in] UINT SrcRowPitch, [in] UINT SrcDepthPitch );

 This works as advertised for the immediate device context which operates directly on the GPU, but there is a problem when it is used in a deferred context through the software runtime emulation unless pDstBox is NULL or 0,0,0. The work-around for this problem is now included in the Remarks documenting the UpdateSubresource function in the Windows DirectX Graphics documentation on MSDN and in the June 2010 DirectX SDK. The work-around assumes that any driver-level command list optimization is implemented ‘correctly’, hence the call to CheckFeatureSupport.

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;
           /= 4;
               alignedBox.bottom   /= 4;

          pAdjustedSrcData = ((const BYTE*)pSrcData) - (alignedBox.front * srcDepthPitch) - ( * srcRowPitch) - (alignedBox.left * srcBytesPerElement);

     pDeviceContext->UpdateSubresource( pDstResource, dstSubresource, pDstBox, pAdjustedSrcData, srcRowPitch, srcDepthPitch );

     if( pDidWorkAround )
          *pDidWorkAround = needWorkaround;

     return hr;

Update: To avoid breaking any existing applications that relied on the ‘incorrect’ behavior, UpdateSubresource with DirectX 11.1 still behaves this way. The UpdateSubresource1 method, however, does not have this issue.

Comments (3)

  1. The workaround works for most of the cases. But the pointer pAdjustedSrcData is unsafe. UpdateSubResource will check if the fourth parameter is a valid read pointer. So if unfortunately this pointer points to a buffer which is not for read, UpdateSubresource will fail.

  2. btw, do you know what is the "m_bBC" variable and how is it set?

  3. walbourn says:

    m_bBC is an external variable that indicates the format of the resource is actually a Block Compressed format (BC1, BC2, BC3, BC4, BC5, BC6H, BC7)