Games for Windows and the DirectX SDK blog

Technical tips, tricks, and news about game development for Microsoft platforms including desktop, Xbox One, and UWP


Project maintained by walbourn Hosted on GitHub Pages — Theme by mattgraham
Home | Posts by Tag | Posts by Month

Known Issue - Direct3D 11 UpdateSubresource and Deferred Contexts

direct3d

Originally posted to Chuck Walbourn's Blog on MSDN,

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 Microsoft Docs 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;
     auto 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 = reinterpret_cast<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;
}

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.