Directx10和Directx11很多resource类都有个Map()函数,个人感觉它是一个蛮重要的CPU和GPU沟通桥梁。下面以ID3D11DeviceContext::Map()为例讲下。
ID3D11DeviceContext::Map官方解释是:ID3D11DeviceContext::Map Method Get a pointer to the data contained in a subresource, and deny the GPU access to that subresource.
Syntax HRESULT Map( ID3D11Resource *pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE *pMappedResource );
个人理解总结是当需要用CPU读写(GPU的)subresouce(最常用如buffer)时,就用Map()得到该subresource的pointer(D3D11_MAPPED_SUBRESOURCE*),然后将D3D11_MAPPED_SUBRESOURCE::pData强制转换成CPU理解的类型(struct,class),CPU就可以对得到的struct*或class*读写了。
附录D3D11_MAPPED_SUBRESOURCE结构体 typedef struct D3D11_MAPPED_SUBRESOURCE { void *pData; UINT RowPitch; UINT DepthPitch; } D3D11_MAPPED_SUBRESOURCE;
Map函数使用的几个经典场景1:debug时用CPU读写GPU之前读写的buffer(比如GPU计算输出的结果),然后再通过CPU输出来检验对错。 //将GPU读或读写的buffer *pGBuffer拷贝到可给CPU读的buffer并返回,以便调试 ID3D11Buffer* GPUBaseApp::CreateAndCopyToDebugBuf(ID3D11Buffer* pGBuffer) { D3D11_BUFFER_DESC bufferDesc; ZeroMemory(&bufferDesc,sizeof(bufferDesc)); pGBuffer->GetDesc(&bufferDesc); bufferDesc.CPUAccessFlags=D3D11_CPU_ACCESS_READ; bufferDesc.Usage=D3D11_USAGE_STAGING; bufferDesc.BindFlags=0; bufferDesc.MiscFlags=0; ID3D11Buffer* pDebugBuffer=NULL;
if( SUCCEEDED(m_pDevice->CreateBuffer(&bufferDesc,NULL,&pDebugBuffer)) ) { m_pDeviceContext->CopyResource(pDebugBuffer,pGBuffer); } return pDebugBuffer; }
HRESULT Function() { //============================================== /
//=============================================== //看Direct Compute的计算结果 ID3D11Buffer* debugOutBuffer=NULL; ID3D11Buffer* debugInBuffer=NULL;
debugOutBuffer=CreateAndCopyToDebugBuf(m_pOutBuffer); debugInBuffer=CreateAndCopyToDebugBuf(m_pInputBuffer);
VoronoiOutBufType* pOut=NULL; VoronoiInBufType* pIn=NULL;
D3D11_MAPPED_SUBRESOURCE mappedOutResource; D3D11_MAPPED_SUBRESOURCE mappedInResource;
m_pDeviceContext->Map(debugOutBuffer,0,D3D11_MAP_READ,0,&mappedOutResource); pOut=(VoronoiOutBufType*)mappedOutResource.pData;
m_pDeviceContext->Map(debugInBuffer,0,D3D11_MAP_READ,0,&mappedInResource); pIn=(VoronoiInBufType*)mappedInResource.pData;
//printf("OutBuffer的结果如下:/n"); //for(int i=0;i<30;i++) // printf("%d %f/n",pOut[i].index,pOut[i].dist);
m_pDeviceContext->Unmap(debugOutBuffer,0); SAFE_RELEASE(debugOutBuffer);
m_pDeviceContext->Unmap(debugInBuffer,0); SAFE_RELEASE(debugInBuffer);
//===============================================
//============================================== /
}
Map函数使用的几个经典场景2:更新GPU Shader中Constant buffer,把CPU中新的数据struct CB_MouseInfo mouseInfo写入GPU中Constant Buffer。 struct CB_MouseInfo { UINT x; UINT y; UINT btDown; };
CB_MouseInfo mouseInfo;
HRESULT GPUBaseApp::UpDateMouseInfoCB() { HRESULT hr=S_OK;
D3D11_MAPPED_SUBRESOURCE subData;
ZeroMemory(&subData,sizeof(subData));
m_pDeviceContext->Map(m_pConstantBuffer,0,D3D11_MAP_WRITE_DISCARD,0,&subData);
memcpy(subData.pData,&mouseInfo,sizeof(CB_MouseInfo));
m_pDeviceContext->Unmap(&subData,0);
return hr; }
注意点,当调用了Map(),最后记得调用ID3D11DeviceContext::Unmap Method使得GPU重新获取对该resouce的读写权。 Invalidate the pointer to a resource and re-enable the GPU's access to that resource.
Syntax void Unmap( ID3D11Resource *pResource, UINT Subresource );
Parameters:
pResource ID3D11Resource A pointer to a ID3D11Resource interface.
Subresource UINT A subresource to be unmapped.